Handle too long lines. Make envelope reset into a session method.

This commit is contained in:
Christian Joergensen 2014-07-19 20:55:40 +02:00
parent 97b38af3b4
commit 0fa1acf706
3 changed files with 70 additions and 9 deletions

View file

@ -38,6 +38,10 @@ func (session *session) handle(line string) {
cmd := parseLine(line) cmd := parseLine(line)
// Commands are dispatched to the appropriate handler functions.
// If a network error occurs during handling, the handler should
// just return and let the error be handled on the next read.
switch cmd.action { switch cmd.action {
case "HELO": case "HELO":
@ -95,7 +99,7 @@ func (session *session) handleHELO(cmd command) {
if session.peer.HeloName != "" { if session.peer.HeloName != "" {
// Reset envelope in case of duplicate HELO // Reset envelope in case of duplicate HELO
session.envelope = nil session.reset()
} }
if session.server.HeloChecker != nil { if session.server.HeloChecker != nil {
@ -122,7 +126,7 @@ func (session *session) handleEHLO(cmd command) {
if session.peer.HeloName != "" { if session.peer.HeloName != "" {
// Reset envelope in case of duplicate EHLO // Reset envelope in case of duplicate EHLO
session.envelope = nil session.reset()
} }
if session.server.HeloChecker != nil { if session.server.HeloChecker != nil {
@ -197,7 +201,7 @@ func (session *session) handleRCPT(cmd command) {
} }
if len(session.envelope.Recipients) >= session.server.MaxRecipients { if len(session.envelope.Recipients) >= session.server.MaxRecipients {
session.reply(550, "Too many recipients") session.reply(452, "Too many recipients")
return return
} }
@ -243,7 +247,7 @@ func (session *session) handleSTARTTLS(cmd command) {
} }
// Reset envelope as a new EHLO/HELO is required after STARTTLS // Reset envelope as a new EHLO/HELO is required after STARTTLS
session.envelope = nil session.reset()
// Reset deadlines on the underlying connection before I replace it // Reset deadlines on the underlying connection before I replace it
// with a TLS connection // with a TLS connection
@ -291,7 +295,7 @@ func (session *session) handleDATA(cmd command) {
session.reply(250, "Thank you.") session.reply(250, "Thank you.")
} }
session.envelope = nil session.reset()
} }
@ -313,14 +317,14 @@ func (session *session) handleDATA(cmd command) {
session.server.MaxMessageSize, session.server.MaxMessageSize,
)) ))
session.envelope = nil session.reset()
return return
} }
func (session *session) handleRSET(cmd command) { func (session *session) handleRSET(cmd command) {
session.envelope = nil session.reset()
session.reply(250, "Go ahead") session.reply(250, "Go ahead")
return return
} }

View file

@ -214,10 +214,33 @@ func (session *session) serve() {
session.welcome() session.welcome()
for {
for session.scanner.Scan() { for session.scanner.Scan() {
session.handle(session.scanner.Text()) session.handle(session.scanner.Text())
} }
err := session.scanner.Err()
if err == bufio.ErrTooLong {
session.reply(500, "Line too long")
// Advance reader to the next newline
session.reader.ReadString('\n')
session.scanner = bufio.NewScanner(session.reader)
// Reset and have the client start over.
session.reset()
continue
}
break
}
} }
func (session *session) reject() { func (session *session) reject() {
@ -225,6 +248,10 @@ func (session *session) reject() {
session.close() session.close()
} }
func (session *session) reset() {
session.envelope = nil
}
func (session *session) welcome() { func (session *session) welcome() {
if session.server.ConnectionChecker != nil { if session.server.ConnectionChecker != nil {

View file

@ -1028,3 +1028,33 @@ func TestTLSTimeout(t *testing.T) {
} }
} }
func TestLongLine(t *testing.T) {
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatalf("Listen failed: %v", err)
}
defer ln.Close()
server := &smtpd.Server{}
go func() {
server.Serve(ln)
}()
c, err := smtp.Dial(ln.Addr().String())
if err != nil {
t.Fatalf("Dial failed: %v", err)
}
if err := c.Mail(fmt.Sprintf("%s@example.org", strings.Repeat("x", 65*1024))); err == nil {
t.Fatalf("MAIL failed: %v", err)
}
if err := c.Quit(); err != nil {
t.Fatalf("Quit failed: %v", err)
}
}