git » chasquid » commit bc2b3b4

chasquid: Skip SPF if the connection has authenticated

author Alberto Bertogli
2016-10-08 17:11:01 UTC
committer Alberto Bertogli
2016-10-09 23:51:05 UTC
parent 5b0501e5840fc9d2e232fbae47dea10b856690c5

chasquid: Skip SPF if the connection has authenticated

Currently, we do SPF checks for all connections.

However, authenticated users will be sending email from different
locations, applying SPF to them will result in false positives.

So this patch makes chasquid skip SPF checking if the connection is
authenticated.

chasquid.go +27 -13
test/t-05-null_address/expected_dsr +0 -1

diff --git a/chasquid.go b/chasquid.go
index dee0ee1..16fb926 100644
--- a/chasquid.go
+++ b/chasquid.go
@@ -655,19 +655,13 @@ func (c *Conn) MAIL(params string) (code int, msg string) {
 		}
 
 		// SPF check - https://tools.ietf.org/html/rfc7208#section-2.4
-		if tcp, ok := c.netconn.RemoteAddr().(*net.TCPAddr); ok {
-			c.spfResult, c.spfError = spf.CheckHost(
-				tcp.IP, envelope.DomainOf(addr))
-			c.tr.Debugf("SPF %v (%v)", c.spfResult, c.spfError)
-			spfResultCount.Add(string(c.spfResult), 1)
-
-			// https://tools.ietf.org/html/rfc7208#section-8
-			// We opt not to fail on errors, to avoid accidents to prevent
-			// delivery.
-			if c.spfResult == spf.Fail {
-				return 550, fmt.Sprintf(
-					"SPF check failed: %v", c.spfError)
-			}
+		// We opt not to fail on errors, to avoid accidents from preventing
+		// delivery.
+		c.spfResult, c.spfError = c.checkSPF(addr)
+		if c.spfResult == spf.Fail {
+			// https://tools.ietf.org/html/rfc7208#section-8.4
+			return 550, fmt.Sprintf(
+				"SPF check failed: %v", c.spfError)
 		}
 
 		addr, err = envelope.IDNAToUnicode(addr)
@@ -680,6 +674,26 @@ func (c *Conn) MAIL(params string) (code int, msg string) {
 	return 250, "You feel like you are being watched"
 }
 
+// checkSPF for the given address, based on the current connection.
+func (c *Conn) checkSPF(addr string) (spf.Result, error) {
+	// Does not apply to authenticated connections, they're allowed regardless.
+	if c.completedAuth {
+		return "", nil
+	}
+
+	if tcp, ok := c.netconn.RemoteAddr().(*net.TCPAddr); ok {
+		res, err := spf.CheckHost(
+			tcp.IP, envelope.DomainOf(addr))
+
+		c.tr.Debugf("SPF %v (%v)", res, err)
+		spfResultCount.Add(string(res), 1)
+
+		return res, err
+	}
+
+	return "", nil
+}
+
 func (c *Conn) RCPT(params string) (code int, msg string) {
 	// params should be: "TO:<name@host>", and possibly followed by options
 	// such as "NOTIFY=SUCCESS,DELAY" (which we ignore).
diff --git a/test/t-05-null_address/expected_dsr b/test/t-05-null_address/expected_dsr
index 3585f79..b2c473b 100644
--- a/test/t-05-null_address/expected_dsr
+++ b/test/t-05-null_address/expected_dsr
@@ -20,7 +20,6 @@ Delivery to the following recipient(s) failed permanently:
 
 ----- Original message -----
 
-Received-SPF: *
 Received: from user user@testserver
 	by *
 	(envelope from "user@testserver")