for submission over IPv6, allow missing "IPv6" tag in ip address (unless in pedantic mode)

an EHLO ipv4 address looks like this: "[1.2.3.4]". for ipv6, the syntax is:
"[IPv6🔡:1]". mail user agents aren't as careful in compliance as smtp
servers. for incoming messages from smtp servers, we want to be strict (we're
eager to find a reason not to accept spam messages, and not adhering to the
standards is usually a strong spam signal), but there is no reason to punish
authenticated users.

for the syntax requirements, see ABNF rule "address-literal" in rfc 5321.

for issue #48 by @bobobo1618, thanks!
This commit is contained in:
Mechiel Lukkien 2023-07-22 14:20:50 +02:00
parent 9c25c88542
commit 70806137da
No known key found for this signature in database
2 changed files with 16 additions and 6 deletions

View file

@ -270,7 +270,7 @@ func (p *parser) xsubdomain() string {
func (p *parser) xmailbox() smtp.Path {
localpart := p.xlocalpart()
p.xtake("@")
return smtp.Path{Localpart: localpart, IPDomain: p.xipdomain()}
return smtp.Path{Localpart: localpart, IPDomain: p.xipdomain(false)}
}
// ../rfc/5321:2307
@ -281,7 +281,7 @@ func (p *parser) xldhstr() string {
}
// parse address-literal or domain.
func (p *parser) xipdomain() dns.IPDomain {
func (p *parser) xipdomain(isehlo bool) dns.IPDomain {
// ../rfc/5321:2309
// ../rfc/5321:2397
if p.take("[") {
@ -304,10 +304,20 @@ func (p *parser) xipdomain() dns.IPDomain {
p.xerrorf("invalid ip in address: %q", ipaddr)
}
isv4 := ip.To4() != nil
isAllowedSloppyIPv6Submission := func() bool {
// Mail user agents that submit are relatively likely to use IPs in EHLO and forget
// that an IPv6 address needs to be tagged as such. We can forgive them. For
// SMTP servers we are strict.
return isehlo && p.conn.submission && !moxvar.Pedantic && ip.To16() != nil
}
if ipv6 && isv4 {
p.xerrorf("ip is not ipv6")
} else if !ipv6 && !isv4 {
p.xerrorf("ip is not ipv4")
p.xerrorf("ip address is not ipv6")
} else if !ipv6 && !isv4 && !isAllowedSloppyIPv6Submission() {
if ip.To16() != nil {
p.xerrorf("ip address is ipv6, must use syntax [IPv6:...]")
} else {
p.xerrorf("ip address is not ipv4")
}
}
return dns.IPDomain{IP: ip}
}

View file

@ -772,7 +772,7 @@ func (c *conn) cmdHello(p *parser, ehlo bool) {
p.xspace()
var remote dns.IPDomain
if ehlo {
remote = p.xipdomain()
remote = p.xipdomain(true)
} else {
remote = dns.IPDomain{Domain: p.xdomain()}
if !c.submission {