mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-19 14:57:04 +00:00
chasquid: Add SPF checks
This patch makes chasquid perform SPF checks, and add the corresponding Received-SPF header.
This commit is contained in:
35
chasquid.go
35
chasquid.go
@@ -26,6 +26,7 @@ import (
|
|||||||
"blitiri.com.ar/go/chasquid/internal/envelope"
|
"blitiri.com.ar/go/chasquid/internal/envelope"
|
||||||
"blitiri.com.ar/go/chasquid/internal/queue"
|
"blitiri.com.ar/go/chasquid/internal/queue"
|
||||||
"blitiri.com.ar/go/chasquid/internal/set"
|
"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/systemd"
|
||||||
"blitiri.com.ar/go/chasquid/internal/tlsconst"
|
"blitiri.com.ar/go/chasquid/internal/tlsconst"
|
||||||
"blitiri.com.ar/go/chasquid/internal/trace"
|
"blitiri.com.ar/go/chasquid/internal/trace"
|
||||||
@@ -405,6 +406,10 @@ type Conn struct {
|
|||||||
rcptTo []string
|
rcptTo []string
|
||||||
data []byte
|
data []byte
|
||||||
|
|
||||||
|
// SPF results.
|
||||||
|
spfResult spf.Result
|
||||||
|
spfError error
|
||||||
|
|
||||||
// Are we using TLS?
|
// Are we using TLS?
|
||||||
onTLS bool
|
onTLS bool
|
||||||
|
|
||||||
@@ -593,6 +598,10 @@ func (c *Conn) MAIL(params string) (code int, msg string) {
|
|||||||
return 500, "malformed command - " + err.Error()
|
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
|
// Special case a null reverse-path, which is explicitly allowed and used
|
||||||
// for notification messages.
|
// for notification messages.
|
||||||
// It should be written "<>", we check for that and remove spaces just to
|
// 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"
|
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)
|
e.Address, err = envelope.IDNAToUnicode(e.Address)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 501, "malformed address (IDNA conversion failed)"
|
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
|
c.mailFrom = e.Address
|
||||||
return 250, "You feel like you are being watched"
|
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
|
// https://tools.ietf.org/html/rfc5322#section-3.6.7
|
||||||
v += fmt.Sprintf("on ; %s\n", time.Now().Format(time.RFC1123Z))
|
v += fmt.Sprintf("on ; %s\n", time.Now().Format(time.RFC1123Z))
|
||||||
c.data = envelope.AddHeader(c.data, "Received", v)
|
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) {
|
func (c *Conn) STARTTLS(params string, tr *trace.Trace) (code int, msg string) {
|
||||||
@@ -869,6 +894,8 @@ func (c *Conn) resetEnvelope() {
|
|||||||
c.mailFrom = ""
|
c.mailFrom = ""
|
||||||
c.rcptTo = nil
|
c.rcptTo = nil
|
||||||
c.data = nil
|
c.data = nil
|
||||||
|
c.spfResult = ""
|
||||||
|
c.spfError = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) userExists(addr string) bool {
|
func (c *Conn) userExists(addr string) bool {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ Delivery to the following recipient(s) failed permanently:
|
|||||||
|
|
||||||
----- Original message -----
|
----- Original message -----
|
||||||
|
|
||||||
|
Received-SPF: *
|
||||||
Received: from user user@testserver
|
Received: from user user@testserver
|
||||||
by *
|
by *
|
||||||
(envelope from "user@testserver")
|
(envelope from "user@testserver")
|
||||||
|
|||||||
Reference in New Issue
Block a user