author | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-10-07 22:55:28 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-10-09 23:51:05 UTC |
parent | 3d3b771b80568420a7f4e79c6d4b26d5febfb2e6 |
chasquid.go | +31 | -4 |
test/t-05-null_address/expected_dsr | +1 | -0 |
diff --git a/chasquid.go b/chasquid.go index 76de975..2bc34ff 100644 --- a/chasquid.go +++ b/chasquid.go @@ -26,6 +26,7 @@ import ( "blitiri.com.ar/go/chasquid/internal/envelope" "blitiri.com.ar/go/chasquid/internal/queue" "blitiri.com.ar/go/chasquid/internal/set" + "blitiri.com.ar/go/chasquid/internal/spf" "blitiri.com.ar/go/chasquid/internal/systemd" "blitiri.com.ar/go/chasquid/internal/tlsconst" "blitiri.com.ar/go/chasquid/internal/trace" @@ -405,6 +406,10 @@ type Conn struct { rcptTo []string data []byte + // SPF results. + spfResult spf.Result + spfError error + // Are we using TLS? onTLS bool @@ -593,6 +598,10 @@ func (c *Conn) MAIL(params string) (code int, msg string) { return 500, "malformed command - " + err.Error() } + // Note some servers check (and fail) if we had a previous MAIL command, + // but that's not according to the RFC. We reset the envelope instead. + c.resetEnvelope() + // Special case a null reverse-path, which is explicitly allowed and used // for notification messages. // It should be written "<>", we check for that and remove spaces just to @@ -611,15 +620,25 @@ func (c *Conn) MAIL(params string) (code int, msg string) { return 501, "sender address must contain a domain" } + // 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(e.Address)) + // 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) + } + } + e.Address, err = envelope.IDNAToUnicode(e.Address) if err != nil { return 501, "malformed address (IDNA conversion failed)" } - } - // Note some servers check (and fail) if we had a previous MAIL command, - // but that's not according to the RFC. We reset the envelope instead. - c.resetEnvelope() + } c.mailFrom = e.Address return 250, "You feel like you are being watched" @@ -752,6 +771,12 @@ func (c *Conn) addReceivedHeader() { // https://tools.ietf.org/html/rfc5322#section-3.6.7 v += fmt.Sprintf("on ; %s\n", time.Now().Format(time.RFC1123Z)) c.data = envelope.AddHeader(c.data, "Received", v) + + if c.spfResult != "" { + // https://tools.ietf.org/html/rfc7208#section-9.1 + v = fmt.Sprintf("%s (%v)", c.spfResult, c.spfError) + c.data = envelope.AddHeader(c.data, "Received-SPF", v) + } } func (c *Conn) STARTTLS(params string, tr *trace.Trace) (code int, msg string) { @@ -869,6 +894,8 @@ func (c *Conn) resetEnvelope() { c.mailFrom = "" c.rcptTo = nil c.data = nil + c.spfResult = "" + c.spfError = nil } func (c *Conn) userExists(addr string) bool { diff --git a/test/t-05-null_address/expected_dsr b/test/t-05-null_address/expected_dsr index b2c473b..3585f79 100644 --- a/test/t-05-null_address/expected_dsr +++ b/test/t-05-null_address/expected_dsr @@ -20,6 +20,7 @@ Delivery to the following recipient(s) failed permanently: ----- Original message ----- +Received-SPF: * Received: from user user@testserver by * (envelope from "user@testserver")