mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-18 14:47:03 +00:00
smtpsrv: Close the connection after 3 errors (lowering from 10)
Today, we close the connection after 10 errors. While this is fine for normal use, it is unnecessarily large. Lowering it to 3 helps with defense-in-depth for cross-protocol attacks (e.g. https://alpaca-attack.com/), while still being large enough for useful troubleshooting and normal operation. As part of this change, we also remove the AUTH-specific failures limit, because they're covered by the connection limit.
This commit is contained in:
@@ -145,9 +145,6 @@ type Conn struct {
|
|||||||
// Have we successfully completed AUTH?
|
// Have we successfully completed AUTH?
|
||||||
completedAuth bool
|
completedAuth bool
|
||||||
|
|
||||||
// How many times have we attempted AUTH?
|
|
||||||
authAttempts int
|
|
||||||
|
|
||||||
// Authenticated user and domain, empty if !completedAuth.
|
// Authenticated user and domain, empty if !completedAuth.
|
||||||
authUser string
|
authUser string
|
||||||
authDomain string
|
authDomain string
|
||||||
@@ -291,8 +288,10 @@ loop:
|
|||||||
// Be verbose about errors, to help troubleshooting.
|
// Be verbose about errors, to help troubleshooting.
|
||||||
c.tr.Errorf("%s failed: %d %s", cmd, code, msg)
|
c.tr.Errorf("%s failed: %d %s", cmd, code, msg)
|
||||||
|
|
||||||
|
// Close the connection after 3 errors.
|
||||||
|
// This helps prevent cross-protocol attacks.
|
||||||
errCount++
|
errCount++
|
||||||
if errCount > 10 {
|
if errCount >= 3 {
|
||||||
// https://tools.ietf.org/html/rfc5321#section-4.3.2
|
// https://tools.ietf.org/html/rfc5321#section-4.3.2
|
||||||
c.tr.Errorf("too many errors, breaking connection")
|
c.tr.Errorf("too many errors, breaking connection")
|
||||||
_ = c.writeResponse(421, "4.5.0 Too many errors, bye")
|
_ = c.writeResponse(421, "4.5.0 Too many errors, bye")
|
||||||
@@ -1016,11 +1015,6 @@ func (c *Conn) AUTH(params string) (code int, msg string) {
|
|||||||
return 503, "5.5.1 You are already wearing that!"
|
return 503, "5.5.1 You are already wearing that!"
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.authAttempts > 3 {
|
|
||||||
return 503, "5.7.8 Too many attempts, go away"
|
|
||||||
}
|
|
||||||
c.authAttempts++
|
|
||||||
|
|
||||||
// We only support PLAIN for now, so no need to make this too complicated.
|
// We only support PLAIN for now, so no need to make this too complicated.
|
||||||
// Params should be either "PLAIN" or "PLAIN <response>".
|
// Params should be either "PLAIN" or "PLAIN <response>".
|
||||||
// If the response is not there, we reply with 334, and expect the
|
// If the response is not there, we reply with 334, and expect the
|
||||||
|
|||||||
@@ -214,16 +214,13 @@ func TestBrokenAuth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWrongMailParsing(t *testing.T) {
|
func TestWrongMailParsing(t *testing.T) {
|
||||||
c := mustDial(t, ModeSMTP, false)
|
|
||||||
defer c.Close()
|
|
||||||
|
|
||||||
addrs := []string{"from", "a b c", "a @ b", "<x>", "<x y>", "><"}
|
addrs := []string{"from", "a b c", "a @ b", "<x>", "<x y>", "><"}
|
||||||
|
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
|
c := mustDial(t, ModeSMTP, false)
|
||||||
|
|
||||||
if err := c.Mail(addr); err == nil {
|
if err := c.Mail(addr); err == nil {
|
||||||
t.Errorf("Mail not failed as expected with %q", addr)
|
t.Errorf("Mail not failed as expected with %q", addr)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Mail("from@plain"); err != nil {
|
if err := c.Mail("from@plain"); err != nil {
|
||||||
t.Errorf("Mail: %v", err)
|
t.Errorf("Mail: %v", err)
|
||||||
@@ -234,6 +231,9 @@ func TestWrongMailParsing(t *testing.T) {
|
|||||||
t.Errorf("Rcpt not failed as expected with %q", addr)
|
t.Errorf("Rcpt not failed as expected with %q", addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Close()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNullMailFrom(t *testing.T) {
|
func TestNullMailFrom(t *testing.T) {
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ c <~ 334
|
|||||||
c -> dXNlckB0ZXN0c2VydmVyAHlalala==
|
c -> dXNlckB0ZXN0c2VydmVyAHlalala==
|
||||||
c <~ 501 5.5.2 Error decoding AUTH response
|
c <~ 501 5.5.2 Error decoding AUTH response
|
||||||
|
|
||||||
|
# Reconnect to avoid getting rejected due to too many errors.
|
||||||
|
c close
|
||||||
|
c tls_connect localhost:1465
|
||||||
|
c <~ 220
|
||||||
|
c -> EHLO localhost
|
||||||
|
c <... 250 HELP
|
||||||
|
|
||||||
c -> AUTH PLAIN
|
c -> AUTH PLAIN
|
||||||
c <~ 334
|
c <~ 334
|
||||||
c -> dXNlckB0ZXN0c2VydmVyAHVzZXJAdGVzdHNlcnZlcgB3cm9uZ3Bhc3N3b3Jk
|
c -> dXNlckB0ZXN0c2VydmVyAHVzZXJAdGVzdHNlcnZlcgB3cm9uZ3Bhc3N3b3Jk
|
||||||
|
|||||||
@@ -10,9 +10,5 @@ c <~ 501
|
|||||||
c -> AUTH PLAIN something
|
c -> AUTH PLAIN something
|
||||||
c <~ 501
|
c <~ 501
|
||||||
c -> AUTH PLAIN something
|
c -> AUTH PLAIN something
|
||||||
c <~ 501
|
c <~ 421 4.5.0 Too many errors, bye
|
||||||
c -> AUTH PLAIN something
|
|
||||||
c <~ 501
|
|
||||||
c -> AUTH PLAIN something
|
|
||||||
c <~ 503 5.7.8 Too many attempts, go away
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,13 @@ c <~ 250
|
|||||||
c -> DATA
|
c -> DATA
|
||||||
c <- 503 5.5.1 Sender not yet given
|
c <- 503 5.5.1 Sender not yet given
|
||||||
|
|
||||||
|
# Reconnect to avoid getting rejected due to too many errors.
|
||||||
|
c close
|
||||||
|
c tcp_connect localhost:1025
|
||||||
|
c <~ 220
|
||||||
|
c -> HELO localhost
|
||||||
|
c <~ 250
|
||||||
|
|
||||||
c -> MAIL FROM:<a@b>
|
c -> MAIL FROM:<a@b>
|
||||||
c <~ 250
|
c <~ 250
|
||||||
c -> RCPT TO: user@testserver
|
c -> RCPT TO: user@testserver
|
||||||
|
|||||||
@@ -10,11 +10,25 @@ c <- 500 5.5.2 Unknown command
|
|||||||
c -> MAIL FROM:
|
c -> MAIL FROM:
|
||||||
c <~ 500
|
c <~ 500
|
||||||
|
|
||||||
|
# Reconnect to avoid getting rejected due to too many errors.
|
||||||
|
c close
|
||||||
|
c tcp_connect localhost:1025
|
||||||
|
c <~ 220
|
||||||
|
c -> HELO localhost
|
||||||
|
c <~ 250
|
||||||
|
|
||||||
c -> MAIL FROM:<pepe>
|
c -> MAIL FROM:<pepe>
|
||||||
c <~ 501
|
c <~ 501
|
||||||
|
|
||||||
c -> MAIL FROM:<a@xn--->
|
c -> MAIL FROM:<a@xn--->
|
||||||
c <- 501 5.1.8 Malformed sender domain (IDNA conversion failed)
|
c <- 501 5.1.8 Malformed sender domain (IDNA conversion failed)
|
||||||
|
|
||||||
|
# Reconnect to avoid getting rejected due to too many errors.
|
||||||
|
c close
|
||||||
|
c tcp_connect localhost:1025
|
||||||
|
c <~ 220
|
||||||
|
c -> HELO localhost
|
||||||
|
c <~ 250
|
||||||
|
|
||||||
c -> MAIL FROM:<aaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaX@bbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbX>
|
c -> MAIL FROM:<aaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaXaaaa5aaaaX@bbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbXbbbb5bbbbX>
|
||||||
c <- 501 5.1.7 Sender address too long
|
c <- 501 5.1.7 Sender address too long
|
||||||
|
|||||||
@@ -13,12 +13,30 @@ c <- 500 5.5.2 Unknown command
|
|||||||
c -> RCPT TO:
|
c -> RCPT TO:
|
||||||
c <~ 500
|
c <~ 500
|
||||||
|
|
||||||
|
# Reconnect to avoid getting rejected due to too many errors.
|
||||||
|
c close
|
||||||
|
c tcp_connect localhost:1025
|
||||||
|
c <~ 220
|
||||||
|
c -> HELO localhost
|
||||||
|
c <~ 250
|
||||||
|
c -> MAIL FROM:<test@testy.com>
|
||||||
|
c <~ 250
|
||||||
|
|
||||||
c -> RCPT TO:<pepe>
|
c -> RCPT TO:<pepe>
|
||||||
c <~ 501
|
c <~ 501
|
||||||
|
|
||||||
c -> RCPT TO:<a@xn--->
|
c -> RCPT TO:<a@xn--->
|
||||||
c <- 501 5.1.2 Malformed destination domain (IDNA conversion failed)
|
c <- 501 5.1.2 Malformed destination domain (IDNA conversion failed)
|
||||||
|
|
||||||
|
# Reconnect to avoid getting rejected due to too many errors.
|
||||||
|
c close
|
||||||
|
c tcp_connect localhost:1025
|
||||||
|
c <~ 220
|
||||||
|
c -> HELO localhost
|
||||||
|
c <~ 250
|
||||||
|
c -> MAIL FROM:<test@testy.com>
|
||||||
|
c <~ 250
|
||||||
|
|
||||||
c -> RCPT TO:<henryⅣ@testserver>
|
c -> RCPT TO:<henryⅣ@testserver>
|
||||||
c <- 550 5.1.3 Destination address is invalid
|
c <- 550 5.1.3 Destination address is invalid
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user