mirror of
https://github.com/mjl-/mox.git
synced 2025-02-04 18:28:32 +03:00
add config field "IPsNATed" to listener, indicating the IPs are not the actual public IPs but are NATed, to skip a few DNS checks
the dns check was returning errors that could not be fixed with that setup, which makes the checks much less useful. for issue #17
This commit is contained in:
parent
8b0706e02d
commit
e6df84a8de
4 changed files with 48 additions and 19 deletions
|
@ -89,6 +89,7 @@ type ACME struct {
|
|||
|
||||
type Listener struct {
|
||||
IPs []string `sconf-doc:"Use 0.0.0.0 to listen on all IPv4 and/or :: to listen on all IPv6 addresses, but it is better to explicitly specify the IPs you want to use for email, as mox will make sure outgoing connections will only be made from one of those IPs."`
|
||||
IPsNATed bool `sconf:"optional" sconf-doc:"Set this if the specified IPs are not the public IPs, but are NATed. This makes the DNS check skip a few checks related to IPs, such as for iprev, mx, spf, autoconfig, autodiscover."`
|
||||
Hostname string `sconf:"optional" sconf-doc:"If empty, the config global Hostname is used."`
|
||||
HostnameDomain dns.Domain `sconf:"-" json:"-"` // Set when parsing config.
|
||||
|
||||
|
|
|
@ -101,6 +101,11 @@ describe-static" and "mox config describe-domains":
|
|||
IPs:
|
||||
-
|
||||
|
||||
# Set this if the specified IPs are not the public IPs, but are NATed. This makes
|
||||
# the DNS check skip a few checks related to IPs, such as for iprev, mx, spf,
|
||||
# autoconfig, autodiscover. (optional)
|
||||
IPsNATed: false
|
||||
|
||||
# If empty, the config global Hostname is used. (optional)
|
||||
Hostname:
|
||||
|
||||
|
|
|
@ -416,6 +416,16 @@ func checkDomain(ctx context.Context, resolver dns.Resolver, dialer *net.Dialer,
|
|||
}
|
||||
}
|
||||
|
||||
// If at least one listener with SMTP enabled has specified NATed IPs, we'll skip
|
||||
// some checks related to these IPs.
|
||||
var isNAT bool
|
||||
for _, l := range mox.Conf.Static.Listeners {
|
||||
if l.IPsNATed && l.SMTP.Enabled {
|
||||
isNAT = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// IPRev
|
||||
|
@ -431,14 +441,16 @@ func checkDomain(ctx context.Context, resolver dns.Resolver, dialer *net.Dialer,
|
|||
if err != nil {
|
||||
addf(&r.IPRev.Errors, "Looking up IPs for hostname: %s", err)
|
||||
}
|
||||
nextip:
|
||||
for _, ip := range mox.Conf.Static.SpecifiedSMTPListenIPs {
|
||||
for _, xip := range ips {
|
||||
if ip.Equal(xip) {
|
||||
continue nextip
|
||||
if !isNAT {
|
||||
nextip:
|
||||
for _, ip := range mox.Conf.Static.SpecifiedSMTPListenIPs {
|
||||
for _, xip := range ips {
|
||||
if ip.Equal(xip) {
|
||||
continue nextip
|
||||
}
|
||||
}
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
|
||||
type result struct {
|
||||
|
@ -512,9 +524,12 @@ func checkDomain(ctx context.Context, resolver dns.Resolver, dialer *net.Dialer,
|
|||
for i, mx := range mxs {
|
||||
ips, ourIPs, notOurIPs, err := lookupIPs(&r.MX.Errors, mx.Host)
|
||||
if err != nil {
|
||||
addf(&r.MX.Errors, "Looking up IP addresses for mx host %q: %s", mx.Host, err)
|
||||
addf(&r.MX.Errors, "Looking up IPs for mx host %q: %s", mx.Host, err)
|
||||
}
|
||||
r.MX.Records[i].IPs = ips
|
||||
if isNAT {
|
||||
continue
|
||||
}
|
||||
if len(ourIPs) == 0 {
|
||||
addf(&r.MX.Errors, "None of the IPs that mx %q points to is ours: %v", mx.Host, notOurIPs)
|
||||
} else if len(notOurIPs) > 0 {
|
||||
|
@ -643,7 +658,7 @@ func checkDomain(ctx context.Context, resolver dns.Resolver, dialer *net.Dialer,
|
|||
Version: "spf1",
|
||||
}
|
||||
for _, l := range mox.Conf.Static.Listeners {
|
||||
if !l.SMTP.Enabled {
|
||||
if !l.SMTP.Enabled || l.IPsNATed {
|
||||
continue
|
||||
}
|
||||
for _, ipstr := range l.IPs {
|
||||
|
@ -668,9 +683,9 @@ func checkDomain(ctx context.Context, resolver dns.Resolver, dialer *net.Dialer,
|
|||
}
|
||||
status, mechanism, expl, err := spf.Evaluate(ctx, record, resolver, args)
|
||||
if err != nil {
|
||||
addf(&r.SPF.Errors, "Evaluating IP address %q against %s SPF record: %s", ip, kind, err)
|
||||
addf(&r.SPF.Errors, "Evaluating IP %q against %s SPF record: %s", ip, kind, err)
|
||||
} else if status != spf.StatusPass {
|
||||
addf(&r.SPF.Errors, "IP address %q does not pass %s SPF evaluation, status not \"pass\" but %q (mechanism %q, explanation %q)", ip, kind, status, mechanism, expl)
|
||||
addf(&r.SPF.Errors, "IP %q does not pass %s SPF evaluation, status not \"pass\" but %q (mechanism %q, explanation %q)", ip, kind, status, mechanism, expl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1001,7 +1016,7 @@ When enabling MTA-STS, or updating a policy, always update the policy first (thr
|
|||
r.SRVConf.SRVs = map[string][]*net.SRV{}
|
||||
for _, req := range reqs {
|
||||
name := req.name + "_.tcp." + domain.ASCII
|
||||
instr += fmt.Sprintf("\t%s._tcp.%s IN SRV 0 1 %d %s\n", req.name, domain.ASCII+".", req.port, req.host)
|
||||
instr += fmt.Sprintf("\t%s._tcp.%-*s IN SRV 0 1 %d %s\n", req.name, len("_submissions")-len(req.name)+len(domain.ASCII+"."), domain.ASCII+".", req.port, req.host)
|
||||
r.SRVConf.SRVs[req.name] = req.srvs
|
||||
if err != nil {
|
||||
addf(&r.SRVConf.Errors, "Looking up SRV record %q: %s", name, err)
|
||||
|
@ -1030,10 +1045,12 @@ When enabling MTA-STS, or updating a policy, always update the policy first (thr
|
|||
}
|
||||
|
||||
r.Autoconf.IPs = ips
|
||||
if len(ourIPs) == 0 {
|
||||
addf(&r.Autoconf.Errors, "Autoconfig does not point to one of our IP addresses.")
|
||||
} else if len(notOurIPs) > 0 {
|
||||
addf(&r.Autoconf.Errors, "Autoconfig does not point to some IP addresses that are not ours: %v", notOurIPs)
|
||||
if !isNAT {
|
||||
if len(ourIPs) == 0 {
|
||||
addf(&r.Autoconf.Errors, "Autoconfig does not point to one of our IPs.")
|
||||
} else if len(notOurIPs) > 0 {
|
||||
addf(&r.Autoconf.Errors, "Autoconfig points to some IPs that are not ours: %v", notOurIPs)
|
||||
}
|
||||
}
|
||||
|
||||
checkTLS(&r.Autoconf.Errors, "autoconfig."+domain.ASCII, ips, "443")
|
||||
|
@ -1064,10 +1081,12 @@ When enabling MTA-STS, or updating a policy, always update the policy first (thr
|
|||
}
|
||||
match = true
|
||||
r.Autodiscover.Records = append(r.Autodiscover.Records, AutodiscoverSRV{*srv, ips})
|
||||
if len(ourIPs) == 0 {
|
||||
addf(&r.Autodiscover.Errors, "SRV target %q does not point to our IPs.", srv.Target)
|
||||
} else if len(notOurIPs) > 0 {
|
||||
addf(&r.Autodiscover.Errors, "SRV target %q points to some IPs that are not ours: %v", srv.Target, notOurIPs)
|
||||
if !isNAT {
|
||||
if len(ourIPs) == 0 {
|
||||
addf(&r.Autodiscover.Errors, "SRV target %q does not point to our IPs.", srv.Target)
|
||||
} else if len(notOurIPs) > 0 {
|
||||
addf(&r.Autodiscover.Errors, "SRV target %q points to some IPs that are not ours: %v", srv.Target, notOurIPs)
|
||||
}
|
||||
}
|
||||
|
||||
checkTLS(&r.Autodiscover.Errors, strings.TrimSuffix(srv.Target, "."), ips, "443")
|
||||
|
|
|
@ -870,6 +870,10 @@ func IPs(ctx context.Context) ([]net.IP, error) {
|
|||
var ips []net.IP
|
||||
var ipv4all, ipv6all bool
|
||||
for _, l := range Conf.Static.Listeners {
|
||||
// If NATed, we don't know our external IPs.
|
||||
if l.IPsNATed {
|
||||
return nil, nil
|
||||
}
|
||||
for _, s := range l.IPs {
|
||||
ip := net.ParseIP(s)
|
||||
if ip.IsUnspecified() {
|
||||
|
|
Loading…
Reference in a new issue