git » chasquid » commit 7fa4039

courier: SMTP falls back to A when MX does not exist

author Alberto Bertogli
2016-10-01 20:55:47 UTC
committer Alberto Bertogli
2016-10-09 23:51:04 UTC
parent fdaca0bedf240f236eec5e16901047e72c6e4082

courier: SMTP falls back to A when MX does not exist

Make the SMTP courier fall back to the A record when MX does not exist, as per
standard behaviour.

This is not implemented nicely, because Go's API does not give a clear signal
if the answer was that there are no MX records or something else happens.
For now, we implement it with a heuristic that should work pretty reliably,
but it's definitely not very nice.

internal/courier/smtp.go +20 -13
test/t-02-exim/run.sh +1 -2

diff --git a/internal/courier/smtp.go b/internal/courier/smtp.go
index f106a39..847d5ad 100644
--- a/internal/courier/smtp.go
+++ b/internal/courier/smtp.go
@@ -23,10 +23,6 @@ var (
 	smtpPort = flag.String("testing__outgoing_smtp_port", "25",
 		"port to use for outgoing SMTP connections, ONLY FOR TESTING")
 
-	// Bypass the MX lookup, for testing purposes.
-	bypassMX = flag.Bool("testing__bypass_mx_lookup", false,
-		"bypass MX lookup, ONLY FOR TESTING")
-
 	// Fake MX records, used for testing only.
 	fakeMX = map[string]string{}
 )
@@ -40,7 +36,6 @@ func (s *SMTP) Deliver(from string, to string, data []byte) (error, bool) {
 	defer tr.Finish()
 	tr.LazyPrintf("%s  ->  %s", from, to)
 
-	// TODO: Fall back to A if MX is not available.
 	mx, err := lookupMX(envelope.DomainOf(to))
 	if err != nil {
 		// Note this is considered a permanent error.
@@ -142,17 +137,29 @@ func lookupMX(domain string) (string, error) {
 		return v, nil
 	}
 
-	if *bypassMX {
-		return domain, nil
+	mxs, err := net.LookupMX(domain)
+	if err == nil {
+		if len(mxs) == 0 {
+			glog.Infof("domain %q has no MX, falling back to A", domain)
+			return domain, nil
+		}
+
+		return mxs[0].Host, nil
 	}
 
-	mxs, err := net.LookupMX(domain)
-	if err != nil {
+	// There was an error. It could be that the domain has no MX, in which
+	// case we have to fall back to A, or a bigger problem.
+	// Unfortunately, go's API doesn't let us easily distinguish between them.
+	// For now, if the error is permanent, we assume it's because there was no
+	// MX and fall back, otherwise we return.
+	// TODO: Find a better way to do this.
+	dnsErr, ok := err.(*net.DNSError)
+	if !ok {
+		return "", err
+	} else if dnsErr.Temporary() {
 		return "", err
-	} else if len(mxs) == 0 {
-		glog.Infof("domain %q has no MX, falling back to A", domain)
-		return domain, nil
 	}
 
-	return mxs[0].Host, nil
+	// Permanent error, we assume MX does not exist and fall back to A.
+	return domain, nil
 }
diff --git a/test/t-02-exim/run.sh b/test/t-02-exim/run.sh
index 4d936ff..fa12e8c 100755
--- a/test/t-02-exim/run.sh
+++ b/test/t-02-exim/run.sh
@@ -46,8 +46,7 @@ add_user srv-chasquid someone secretpassword
 # Bypass MX lookup, so it can find srv-exim (via our host alias).
 mkdir -p .logs
 chasquid -v=2 --log_dir=.logs --config_dir=config \
-	--testing__outgoing_smtp_port=2025 \
-	--testing__bypass_mx_lookup &
+	--testing__outgoing_smtp_port=2025 &
 
 wait_until_ready 1025