Replace iniflags config file parser with peterbourgon/ff/v3

This allows us to support configuration via environment variables
which is useful in container environments.
This commit is contained in:
Bernhard Froehlich
2022-05-20 08:48:39 +00:00
parent 44560c9a0c
commit 26477177fe
3 changed files with 90 additions and 27 deletions

108
config.go
View File

@@ -1,15 +1,18 @@
package main
import (
"bufio"
"flag"
"fmt"
"io"
"net"
"os"
"regexp"
"strings"
"time"
"github.com/peterbourgon/ff/v3"
"github.com/sirupsen/logrus"
"github.com/vharitonsky/iniflags"
)
var (
@@ -18,36 +21,43 @@ var (
)
var (
logFile = flag.String("logfile", "", "Path to logfile")
logFormat = flag.String("log_format", "default", "Log output format")
logLevel = flag.String("log_level", "info", "Minimum log level to output")
hostName = flag.String("hostname", "localhost.localdomain", "Server hostname")
welcomeMsg = flag.String("welcome_msg", "", "Welcome message for SMTP session")
listenStr = flag.String("listen", "127.0.0.1:25 [::1]:25", "Address and port to listen for incoming SMTP")
flagset = flag.NewFlagSet("smtprelay", flag.ContinueOnError)
// config flags
logFile = flagset.String("logfile", "", "Path to logfile")
logFormat = flagset.String("log_format", "default", "Log output format")
logLevel = flagset.String("log_level", "info", "Minimum log level to output")
hostName = flagset.String("hostname", "localhost.localdomain", "Server hostname")
welcomeMsg = flagset.String("welcome_msg", "", "Welcome message for SMTP session")
listenStr = flagset.String("listen", "127.0.0.1:25 [::1]:25", "Address and port to listen for incoming SMTP")
localCert = flagset.String("local_cert", "", "SSL certificate for STARTTLS/TLS")
localKey = flagset.String("local_key", "", "SSL private key for STARTTLS/TLS")
localForceTLS = flagset.Bool("local_forcetls", false, "Force STARTTLS (needs local_cert and local_key)")
readTimeoutStr = flagset.String("read_timeout", "60s", "Socket timeout for read operations")
writeTimeoutStr = flagset.String("write_timeout", "60s", "Socket timeout for write operations")
dataTimeoutStr = flagset.String("data_timeout", "5m", "Socket timeout for DATA command")
maxConnections = flagset.Int("max_connections", 100, "Max concurrent connections, use -1 to disable")
maxMessageSize = flagset.Int("max_message_size", 10240000, "Max message size in bytes")
maxRecipients = flagset.Int("max_recipients", 100, "Max RCPT TO calls for each envelope")
allowedNetsStr = flagset.String("allowed_nets", "127.0.0.0/8 ::1/128", "Networks allowed to send mails")
allowedSenderStr = flagset.String("allowed_sender", "", "Regular expression for valid FROM EMail addresses")
allowedRecipStr = flagset.String("allowed_recipients", "", "Regular expression for valid TO EMail addresses")
allowedUsers = flagset.String("allowed_users", "", "Path to file with valid users/passwords")
command = flagset.String("command", "", "Path to pipe command")
remotesStr = flagset.String("remotes", "", "Outgoing SMTP servers")
// additional flags
versionInfo = flagset.Bool("version", false, "Show version information")
// internal
listenAddrs = []protoAddr{}
localCert = flag.String("local_cert", "", "SSL certificate for STARTTLS/TLS")
localKey = flag.String("local_key", "", "SSL private key for STARTTLS/TLS")
localForceTLS = flag.Bool("local_forcetls", false, "Force STARTTLS (needs local_cert and local_key)")
readTimeoutStr = flag.String("read_timeout", "60s", "Socket timeout for read operations")
readTimeout time.Duration
writeTimeoutStr = flag.String("write_timeout", "60s", "Socket timeout for write operations")
writeTimeout time.Duration
dataTimeoutStr = flag.String("data_timeout", "5m", "Socket timeout for DATA command")
dataTimeout time.Duration
maxConnections = flag.Int("max_connections", 100, "Max concurrent connections, use -1 to disable")
maxMessageSize = flag.Int("max_message_size", 10240000, "Max message size in bytes")
maxRecipients = flag.Int("max_recipients", 100, "Max RCPT TO calls for each envelope")
allowedNetsStr = flag.String("allowed_nets", "127.0.0.0/8 ::1/128", "Networks allowed to send mails")
allowedNets = []*net.IPNet{}
allowedSenderStr = flag.String("allowed_sender", "", "Regular expression for valid FROM EMail addresses")
allowedSender *regexp.Regexp
allowedRecipStr = flag.String("allowed_recipients", "", "Regular expression for valid TO EMail addresses")
allowedRecipients *regexp.Regexp
allowedUsers = flag.String("allowed_users", "", "Path to file with valid users/passwords")
command = flag.String("command", "", "Path to pipe command")
remotesStr = flag.String("remotes", "", "Outgoing SMTP servers")
remotes = []*Remote{}
versionInfo = flag.Bool("version", false, "Show version information")
)
func localAuthRequired() bool {
@@ -183,7 +193,18 @@ func setupTimeouts() {
}
func ConfigLoad() {
iniflags.Parse()
// configuration parsing
err := ff.Parse(flagset, os.Args[1:],
ff.WithEnvVarPrefix("smtprelay"),
ff.WithConfigFileFlag("config"),
ff.WithConfigFileParser(IniParser),
)
if err != nil {
//log.WithField("config_error", err).
// Fatal("Config parsing error")
os.Exit(0)
}
// Set up logging as soon as possible
setupLogger()
@@ -198,3 +219,42 @@ func ConfigLoad() {
setupListeners()
setupTimeouts()
}
// IniParser is a parser for config files in classic key/value style format. Each
// line is tokenized as a single key/value pair. The first "=" delimited
// token in the line is interpreted as the flag name, and all remaining tokens
// are interpreted as the value. Any leading hyphens on the flag name are
// ignored.
func IniParser(r io.Reader, set func(name, value string) error) error {
s := bufio.NewScanner(r)
for s.Scan() {
line := strings.TrimSpace(s.Text())
if line == "" {
continue // skip empties
}
if line[0] == '#' {
continue // skip comments
}
var (
name string
value string
index = strings.IndexRune(line, '=')
)
if index < 0 {
name, value = line, "true" // boolean option
} else {
name, value = line[:index], strings.TrimSpace(line[index:])
}
if i := strings.Index(value, " #"); i >= 0 {
value = strings.TrimSpace(value[:i])
}
if err := set(name, value); err != nil {
return err
}
}
return nil
}