This commit is contained in:
Christian Joergensen 2014-07-14 14:51:31 +02:00
parent dd3db75d5c
commit 4bb7e21f40
3 changed files with 32 additions and 14 deletions

View file

@ -5,6 +5,7 @@ import (
"strings" "strings"
) )
// MailAddress holds an e-mail address
type MailAddress string type MailAddress string
func parseMailAddress(src string) (MailAddress, error) { func parseMailAddress(src string) (MailAddress, error) {

View file

@ -94,6 +94,11 @@ func (session *session) handleMAIL(cmd command) {
return return
} }
if !session.tls && session.server.ForceTLS {
session.reply(502, "Please turn on TLS by issuing a STARTTLS command.")
return
}
addr, err := parseMailAddress(cmd.params[1]) addr, err := parseMailAddress(cmd.params[1])
if err != nil { if err != nil {
@ -157,18 +162,18 @@ func (session *session) handleSTARTTLS(cmd command) {
return return
} }
tls_conn := tls.Server(session.conn, session.server.TLSConfig) tlsConn := tls.Server(session.conn, session.server.TLSConfig)
session.reply(250, "Go ahead") session.reply(250, "Go ahead")
if err := tls_conn.Handshake(); err != nil { if err := tlsConn.Handshake(); err != nil {
log.Printf("TLS Handshake error:", err) log.Printf("TLS Handshake error:", err)
session.reply(550, "Handshake error") session.reply(550, "Handshake error")
return return
} }
session.conn = tls_conn session.conn = tlsConn
session.reader = bufio.NewReader(tls_conn) session.reader = bufio.NewReader(tlsConn)
session.writer = bufio.NewWriter(tls_conn) session.writer = bufio.NewWriter(tlsConn)
session.scanner = bufio.NewScanner(session.reader) session.scanner = bufio.NewScanner(session.reader)
session.tls = true session.tls = true
@ -206,6 +211,14 @@ func (session *session) handleDATA(cmd command) {
return return
} }
if data.Len() > session.server.MaxMessageSize {
session.reply(550, fmt.Sprintf(
"Message exceeded max message size of %d bytes",
session.server.MaxMessageSize,
))
return
}
session.envelope.Data = data.Bytes() session.envelope.Data = data.Bytes()
err := session.deliver() err := session.deliver()
@ -283,7 +296,7 @@ func (session *session) handleAUTH(cmd command) {
return return
} }
byte_username, err := base64.StdEncoding.DecodeString(session.scanner.Text()) byteUsername, err := base64.StdEncoding.DecodeString(session.scanner.Text())
if err != nil { if err != nil {
session.reply(502, "Couldn't decode your credentials") session.reply(502, "Couldn't decode your credentials")
@ -296,15 +309,15 @@ func (session *session) handleAUTH(cmd command) {
return return
} }
byte_password, err := base64.StdEncoding.DecodeString(session.scanner.Text()) bytePassword, err := base64.StdEncoding.DecodeString(session.scanner.Text())
if err != nil { if err != nil {
session.reply(502, "Couldn't decode your credentials") session.reply(502, "Couldn't decode your credentials")
return return
} }
username = string(byte_username) username = string(byteUsername)
password = string(byte_password) password = string(bytePassword)
default: default:

View file

@ -11,6 +11,7 @@ import (
"time" "time"
) )
// Server defines the parameters for running the SMTP server
type Server struct { type Server struct {
Addr string // Address to listen on when using ListenAndServe (default: "127.0.0.1:10025") Addr string // Address to listen on when using ListenAndServe (default: "127.0.0.1:10025")
WelcomeMessage string // Initial server banner (default: "<hostname> ESMTP ready.") WelcomeMessage string // Initial server banner (default: "<hostname> ESMTP ready.")
@ -40,13 +41,15 @@ type Server struct {
MaxMessageSize int // Max message size in bytes (default: 10240000) MaxMessageSize int // Max message size in bytes (default: 10240000)
} }
// Peer represents the client connecting to the server
type Peer struct { type Peer struct {
HeloName string // Server name used in HELO/EHLO command HeloName string // Server name used in HELO/EHLO command
Username string // Username from authentication Username string // Username from authentication, if authenticated
Password string // Password from authentication Password string // Password from authentication, if authenticated
Addr net.Addr // Network address Addr net.Addr // Network address
} }
// Envelope holds a message
type Envelope struct { type Envelope struct {
Sender MailAddress Sender MailAddress
Recipients []MailAddress Recipients []MailAddress
@ -86,6 +89,7 @@ func (srv *Server) newSession(c net.Conn) (s *session, err error) {
} }
// ListenAndServe starts the SMTP server and listens on the address provided in Server.Addr
func (srv *Server) ListenAndServe() error { func (srv *Server) ListenAndServe() error {
srv.configureDefaults() srv.configureDefaults()
@ -98,6 +102,7 @@ func (srv *Server) ListenAndServe() error {
return srv.Serve(l) return srv.Serve(l)
} }
// Serve starts the SMTP server and listens on the Listener provided
func (srv *Server) Serve(l net.Listener) error { func (srv *Server) Serve(l net.Listener) error {
srv.configureDefaults() srv.configureDefaults()
@ -243,7 +248,7 @@ func (session *session) error(err error) {
func (session *session) extensions() []string { func (session *session) extensions() []string {
extensions := []string{ extensions := []string{
"SIZE 10240000", fmt.Sprintf("SIZE %d", session.server.MaxMessageSize),
} }
if session.server.TLSConfig != nil && !session.tls { if session.server.TLSConfig != nil && !session.tls {
@ -261,9 +266,8 @@ func (session *session) extensions() []string {
func (session *session) deliver() error { func (session *session) deliver() error {
if session.server.Handler != nil { if session.server.Handler != nil {
return session.server.Handler(session.peer, *session.envelope) return session.server.Handler(session.peer, *session.envelope)
} else {
return nil
} }
return nil
} }
func (session *session) close() { func (session *session) close() {