diff --git a/autotls/autotls.go b/autotls/autotls.go index 391a4fb..12be5eb 100644 --- a/autotls/autotls.go +++ b/autotls/autotls.go @@ -188,7 +188,7 @@ func Load(name, acmeDir, contactEmail, directoryURL string, shutdown <-chan stru // are fully served by publicIPs (only if non-empty and there is no unspecified // address in the list). If no, log an error with a warning that ACME validation // may fail. -func (m *Manager) SetAllowedHostnames(resolver dns.Resolver, hostnames map[dns.Domain]struct{}, publicIPs []string) { +func (m *Manager) SetAllowedHostnames(resolver dns.Resolver, hostnames map[dns.Domain]struct{}, publicIPs []string, checkHosts bool) { m.Lock() defer m.Unlock() @@ -210,7 +210,7 @@ func (m *Manager) SetAllowedHostnames(resolver dns.Resolver, hostnames map[dns.D } m.hosts = hostnames - if len(added) > 0 && len(publicIPs) > 0 { + if checkHosts && len(added) > 0 && len(publicIPs) > 0 { for _, ip := range publicIPs { if net.ParseIP(ip).IsUnspecified() { return @@ -225,6 +225,7 @@ func (m *Manager) SetAllowedHostnames(resolver dns.Resolver, hostnames map[dns.D publicIPstrs[ip] = struct{}{} } + xlog.Debug("checking ips of hosts configured for acme tls cert validation") for _, h := range added { ips, err := resolver.LookupIP(ctx, "ip", h.ASCII+".") if err != nil { diff --git a/autotls/autotls_test.go b/autotls/autotls_test.go index 21636a2..6cd179a 100644 --- a/autotls/autotls_test.go +++ b/autotls/autotls_test.go @@ -28,7 +28,7 @@ func TestAutotls(t *testing.T) { if err := m.HostPolicy(context.Background(), "mox.example"); err == nil || !errors.Is(err, errHostNotAllowed) { t.Fatalf("hostpolicy, got err %v, expected errHostNotAllowed", err) } - m.SetAllowedHostnames(dns.StrictResolver{}, map[dns.Domain]struct{}{{ASCII: "mox.example"}: {}}, nil) + m.SetAllowedHostnames(dns.StrictResolver{}, map[dns.Domain]struct{}{{ASCII: "mox.example"}: {}}, nil, false) l = m.Hostnames() if !reflect.DeepEqual(l, []dns.Domain{{ASCII: "mox.example"}}) { t.Fatalf("hostnames, got %v, expected single mox.example", l) @@ -79,7 +79,7 @@ func TestAutotls(t *testing.T) { t.Fatalf("private key changed after reload") } m.shutdown = make(chan struct{}) - m.SetAllowedHostnames(dns.StrictResolver{}, map[dns.Domain]struct{}{{ASCII: "mox.example"}: {}}, nil) + m.SetAllowedHostnames(dns.StrictResolver{}, map[dns.Domain]struct{}{{ASCII: "mox.example"}: {}}, nil, false) if err := m.HostPolicy(context.Background(), "mox.example"); err != nil { t.Fatalf("hostpolicy, got err %v, expected no error", err) } diff --git a/dsn/dsn_test.go b/dsn/dsn_test.go index 10e3e15..c39f516 100644 --- a/dsn/dsn_test.go +++ b/dsn/dsn_test.go @@ -130,7 +130,7 @@ func TestDSN(t *testing.T) { // Test for valid DKIM signature. mox.Context = context.Background() mox.ConfigStaticPath = "../testdata/dsn/mox.conf" - mox.MustLoadConfig() + mox.MustLoadConfig(false) msgbuf, err = m.Compose(log, false) if err != nil { t.Fatalf("composing utf-8 dsn with utf-8 support: %v", err) diff --git a/http/account_test.go b/http/account_test.go index 5ebc0f3..30b9486 100644 --- a/http/account_test.go +++ b/http/account_test.go @@ -33,7 +33,7 @@ func TestAccount(t *testing.T) { os.RemoveAll("../testdata/httpaccount/data") mox.ConfigStaticPath = "../testdata/httpaccount/mox.conf" mox.ConfigDynamicPath = filepath.Join(filepath.Dir(mox.ConfigStaticPath), "domains.conf") - mox.MustLoadConfig() + mox.MustLoadConfig(false) acc, err := store.OpenAccount("mjl") tcheck(t, err, "open account") defer acc.Close() diff --git a/http/web_test.go b/http/web_test.go index e10c3aa..99e0959 100644 --- a/http/web_test.go +++ b/http/web_test.go @@ -17,7 +17,7 @@ func TestServeHTTP(t *testing.T) { os.RemoveAll("../testdata/web/data") mox.ConfigStaticPath = "../testdata/web/mox.conf" mox.ConfigDynamicPath = filepath.Join(filepath.Dir(mox.ConfigStaticPath), "domains.conf") - mox.MustLoadConfig() + mox.MustLoadConfig(false) srv := &serve{ PathHandlers: []pathHandler{ diff --git a/http/webserver_test.go b/http/webserver_test.go index 8ad0f3f..6a1747f 100644 --- a/http/webserver_test.go +++ b/http/webserver_test.go @@ -17,7 +17,7 @@ func TestWebserver(t *testing.T) { os.RemoveAll("../testdata/webserver/data") mox.ConfigStaticPath = "../testdata/webserver/mox.conf" mox.ConfigDynamicPath = filepath.Join(filepath.Dir(mox.ConfigStaticPath), "domains.conf") - mox.MustLoadConfig() + mox.MustLoadConfig(false) srv := &serve{Webserver: true} diff --git a/imapserver/fuzz_test.go b/imapserver/fuzz_test.go index 590e317..e4cb36b 100644 --- a/imapserver/fuzz_test.go +++ b/imapserver/fuzz_test.go @@ -59,7 +59,7 @@ func FuzzServer(f *testing.F) { mox.Context = context.Background() mox.ConfigStaticPath = "../testdata/imap/mox.conf" - mox.MustLoadConfig() + mox.MustLoadConfig(false) dataDir := mox.ConfigDirPath(mox.Conf.Static.DataDir) os.RemoveAll(dataDir) acc, err := store.OpenAccount("mjl") diff --git a/imapserver/server_test.go b/imapserver/server_test.go index 9910e3c..03193f2 100644 --- a/imapserver/server_test.go +++ b/imapserver/server_test.go @@ -310,7 +310,7 @@ func startArgs(t *testing.T, first, isTLS, allowLoginWithoutTLS bool) *testconn } mox.Context = context.Background() mox.ConfigStaticPath = "../testdata/imap/mox.conf" - mox.MustLoadConfig() + mox.MustLoadConfig(false) acc, err := store.OpenAccount("mjl") tcheck(t, err, "open account") if first { diff --git a/integration_test.go b/integration_test.go index aa204e0..10ad974 100644 --- a/integration_test.go +++ b/integration_test.go @@ -53,7 +53,7 @@ func TestDeliver(t *testing.T) { // Load mox config. mox.ConfigStaticPath = "testdata/integration/config/mox.conf" filepath.Join(filepath.Dir(mox.ConfigStaticPath), "domains.conf") - if errs := mox.LoadConfig(mox.Context); len(errs) > 0 { + if errs := mox.LoadConfig(mox.Context, false); len(errs) > 0 { t.Fatalf("loading mox config: %v", errs) } diff --git a/main.go b/main.go index 06c2019..1079376 100644 --- a/main.go +++ b/main.go @@ -355,7 +355,7 @@ var loglevel string // restores any loglevel specified on the command-line, instead of using the // loglevels from the config file. func mustLoadConfig() { - mox.MustLoadConfig() + mox.MustLoadConfig(false) if level, ok := mlog.Levels[loglevel]; ok && loglevel != "" { mox.Conf.Log[""] = level mlog.SetConfig(mox.Conf.Log) @@ -478,7 +478,7 @@ are printed. c.Usage() } - _, errs := mox.ParseConfig(context.Background(), mox.ConfigStaticPath, true, false) + _, errs := mox.ParseConfig(context.Background(), mox.ConfigStaticPath, true, false, false) if len(errs) > 1 { log.Printf("multiple errors:") for _, err := range errs { diff --git a/mox-/config.go b/mox-/config.go index b43c157..359d2f4 100644 --- a/mox-/config.go +++ b/mox-/config.go @@ -139,7 +139,7 @@ func (c *Config) loadDynamic() []error { c.Dynamic = d c.dynamicMtime = mtime c.accountDestinations = accDests - c.allowACMEHosts() + c.allowACMEHosts(true) return nil } @@ -206,7 +206,7 @@ func (c *Config) WebServer() (r map[dns.Domain]dns.Domain, l []config.WebHandler return r, l } -func (c *Config) allowACMEHosts() { +func (c *Config) allowACMEHosts(checkACMEHosts bool) { for _, l := range c.Static.Listeners { if l.TLS == nil || l.TLS.ACME == "" { continue @@ -248,7 +248,7 @@ func (c *Config) allowACMEHosts() { } } - m.SetAllowedHostnames(dns.StrictResolver{Pkg: "autotls"}, hostnames, c.Static.Listeners["public"].IPs) + m.SetAllowedHostnames(dns.StrictResolver{Pkg: "autotls"}, hostnames, c.Static.Listeners["public"].IPs, checkACMEHosts) } } @@ -305,17 +305,17 @@ func writeDynamic(ctx context.Context, log *mlog.Log, c config.Dynamic) error { Conf.Dynamic = c Conf.accountDestinations = accDests - Conf.allowACMEHosts() + Conf.allowACMEHosts(true) return nil } // MustLoadConfig loads the config, quitting on errors. -func MustLoadConfig() { +func MustLoadConfig(checkACMEHosts bool) { Shutdown, ShutdownCancel = context.WithCancel(context.Background()) Context, ContextCancel = context.WithCancel(context.Background()) - errs := LoadConfig(context.Background()) + errs := LoadConfig(context.Background(), checkACMEHosts) if len(errs) > 1 { xlog.Error("loading config file: multiple errors") for _, err := range errs { @@ -329,8 +329,8 @@ func MustLoadConfig() { // LoadConfig attempts to parse and load a config, returning any errors // encountered. -func LoadConfig(ctx context.Context) []error { - c, errs := ParseConfig(ctx, ConfigStaticPath, false, false) +func LoadConfig(ctx context.Context, checkACMEHosts bool) []error { + c, errs := ParseConfig(ctx, ConfigStaticPath, false, false, checkACMEHosts) if len(errs) > 0 { return errs } @@ -350,7 +350,9 @@ func SetConfig(c *Config) { // are made, such as registering ACME identities. If skipCheckTLSKeyCerts is true, // the TLS KeyCerts configuration is not checked. This is used during the // quickstart in the case the user is going to provide their own certificates. -func ParseConfig(ctx context.Context, p string, checkOnly, skipCheckTLSKeyCerts bool) (c *Config, errs []error) { +// If checkACMEHosts is true, the hosts allowed for acme are compared with the +// explicitly configured ips we are listening on. +func ParseConfig(ctx context.Context, p string, checkOnly, skipCheckTLSKeyCerts, checkACMEHosts bool) (c *Config, errs []error) { c = &Config{ Static: config.Static{ DataDir: ".", @@ -377,7 +379,7 @@ func ParseConfig(ctx context.Context, p string, checkOnly, skipCheckTLSKeyCerts c.Dynamic, c.dynamicMtime, c.accountDestinations, errs = ParseDynamicConfig(ctx, pp, c.Static) if !checkOnly { - c.allowACMEHosts() + c.allowACMEHosts(checkACMEHosts) } return c, errs diff --git a/queue/queue_test.go b/queue/queue_test.go index f9d8fe7..86c6556 100644 --- a/queue/queue_test.go +++ b/queue/queue_test.go @@ -33,7 +33,7 @@ func setup(t *testing.T) (*store.Account, func()) { os.RemoveAll("../testdata/queue/data") mox.Context = context.Background() mox.ConfigStaticPath = "../testdata/queue/mox.conf" - mox.MustLoadConfig() + mox.MustLoadConfig(false) acc, err := store.OpenAccount("mjl") tcheck(t, err, "open account") err = acc.SetPassword("testtest") diff --git a/quickstart.go b/quickstart.go index 2f2faa2..59508d4 100644 --- a/quickstart.go +++ b/quickstart.go @@ -616,7 +616,7 @@ listed in more DNS block lists, visit: // Verify config. skipCheckTLSKeyCerts := existingWebserver - mc, errs := mox.ParseConfig(context.Background(), "config/mox.conf", true, skipCheckTLSKeyCerts) + mc, errs := mox.ParseConfig(context.Background(), "config/mox.conf", true, skipCheckTLSKeyCerts, false) if len(errs) > 0 { if len(errs) > 1 { log.Printf("checking generated config, multiple errors:") diff --git a/serve.go b/serve.go index f079172..523ba34 100644 --- a/serve.go +++ b/serve.go @@ -145,7 +145,8 @@ requested, other TLS certificates are requested on demand. mox.Conf.Log[""] = mlog.LevelDebug mlog.SetConfig(mox.Conf.Log) - mox.MustLoadConfig() + checkACMEHosts := os.Getuid() != 0 + mox.MustLoadConfig(checkACMEHosts) log := mlog.New("serve") diff --git a/smtpserver/fuzz_test.go b/smtpserver/fuzz_test.go index 1d87596..8f6fa5a 100644 --- a/smtpserver/fuzz_test.go +++ b/smtpserver/fuzz_test.go @@ -32,7 +32,7 @@ func FuzzServer(f *testing.F) { mox.Context = context.Background() mox.ConfigStaticPath = "../testdata/smtp/mox.conf" - mox.MustLoadConfig() + mox.MustLoadConfig(false) dataDir := mox.ConfigDirPath(mox.Conf.Static.DataDir) os.RemoveAll(dataDir) acc, err := store.OpenAccount("mjl") diff --git a/smtpserver/server_test.go b/smtpserver/server_test.go index 0e6635c..cef65b9 100644 --- a/smtpserver/server_test.go +++ b/smtpserver/server_test.go @@ -87,7 +87,7 @@ func newTestServer(t *testing.T, configPath string, resolver dns.Resolver) *test mox.Context = context.Background() mox.ConfigStaticPath = configPath - mox.MustLoadConfig() + mox.MustLoadConfig(false) dataDir := mox.ConfigDirPath(mox.Conf.Static.DataDir) os.RemoveAll(dataDir) var err error diff --git a/store/account_test.go b/store/account_test.go index ae4ea6b..5d76cef 100644 --- a/store/account_test.go +++ b/store/account_test.go @@ -26,7 +26,7 @@ func tcheck(t *testing.T, err error, msg string) { func TestMailbox(t *testing.T) { os.RemoveAll("../testdata/store/data") mox.ConfigStaticPath = "../testdata/store/mox.conf" - mox.MustLoadConfig() + mox.MustLoadConfig(false) acc, err := OpenAccount("mjl") tcheck(t, err, "open account") defer acc.Close() diff --git a/store/export_test.go b/store/export_test.go index f00321a..7246356 100644 --- a/store/export_test.go +++ b/store/export_test.go @@ -21,7 +21,7 @@ func TestExport(t *testing.T) { os.RemoveAll("../testdata/store/data") mox.ConfigStaticPath = "../testdata/store/mox.conf" - mox.MustLoadConfig() + mox.MustLoadConfig(false) acc, err := OpenAccount("mjl") tcheck(t, err, "open account") defer acc.Close()