Proxy protocol support, go vet.
This commit is contained in:
parent
c33eb5f9c8
commit
afa9ece3d0
2 changed files with 88 additions and 7 deletions
64
protocol.go
64
protocol.go
|
@ -48,6 +48,10 @@ func (session *session) handle(line string) {
|
||||||
|
|
||||||
switch cmd.action {
|
switch cmd.action {
|
||||||
|
|
||||||
|
case "PROXY":
|
||||||
|
session.handlePROXY(cmd)
|
||||||
|
return
|
||||||
|
|
||||||
case "HELO":
|
case "HELO":
|
||||||
session.handleHELO(cmd)
|
session.handleHELO(cmd)
|
||||||
return
|
return
|
||||||
|
@ -258,6 +262,7 @@ func (session *session) handleSTARTTLS(cmd command) {
|
||||||
session.reply(220, "Go ahead")
|
session.reply(220, "Go ahead")
|
||||||
|
|
||||||
if err := tlsConn.Handshake(); err != nil {
|
if err := tlsConn.Handshake(); err != nil {
|
||||||
|
session.logError(err, "couldn't perform handshake")
|
||||||
session.reply(550, "Handshake error")
|
session.reply(550, "Handshake error")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -417,13 +422,19 @@ func (session *session) handleAUTH(cmd command) {
|
||||||
|
|
||||||
case "LOGIN":
|
case "LOGIN":
|
||||||
|
|
||||||
session.reply(334, "VXNlcm5hbWU6")
|
encodedUsername := ""
|
||||||
|
|
||||||
if !session.scanner.Scan() {
|
if len(cmd.fields) < 3 {
|
||||||
return
|
session.reply(334, "VXNlcm5hbWU6")
|
||||||
|
if !session.scanner.Scan() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
encodedUsername = session.scanner.Text()
|
||||||
|
} else {
|
||||||
|
encodedUsername = cmd.fields[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
byteUsername, err := base64.StdEncoding.DecodeString(session.scanner.Text())
|
byteUsername, err := base64.StdEncoding.DecodeString(encodedUsername)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
session.reply(502, "Couldn't decode your credentials")
|
session.reply(502, "Couldn't decode your credentials")
|
||||||
|
@ -448,6 +459,7 @@ func (session *session) handleAUTH(cmd command) {
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
|
session.logf("unknown authentication mechanism: %s", mechanism)
|
||||||
session.reply(502, "Unknown authentication mechanism")
|
session.reply(502, "Unknown authentication mechanism")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -564,3 +576,47 @@ func (session *session) handleXCLIENT(cmd command) {
|
||||||
session.welcome()
|
session.welcome()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *session) handlePROXY(cmd command) {
|
||||||
|
|
||||||
|
if !session.server.EnableProxyProtocol {
|
||||||
|
session.reply(550, "Proxy Protocol not enabled")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cmd.fields) < 6 {
|
||||||
|
session.reply(502, "Couldn't decode the command.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
newAddr net.IP = nil
|
||||||
|
newTCPPort uint64 = 0
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
newAddr = net.ParseIP(cmd.fields[2])
|
||||||
|
|
||||||
|
newTCPPort, err = strconv.ParseUint(cmd.fields[4], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
session.reply(502, "Couldn't decode the command.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpAddr, ok := session.peer.Addr.(*net.TCPAddr)
|
||||||
|
if !ok {
|
||||||
|
session.reply(502, "Unsupported network connection")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if newAddr != nil {
|
||||||
|
tcpAddr.IP = newAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
if newTCPPort != 0 {
|
||||||
|
tcpAddr.Port = int(newTCPPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
session.welcome()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
31
smtpd.go
31
smtpd.go
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -41,10 +42,13 @@ type Server struct {
|
||||||
// Can be left empty for no authentication support.
|
// Can be left empty for no authentication support.
|
||||||
Authenticator func(peer Peer, username, password string) error
|
Authenticator func(peer Peer, username, password string) error
|
||||||
|
|
||||||
EnableXCLIENT bool // Enable XCLIENT support (default: false)
|
EnableXCLIENT bool // Enable XCLIENT support (default: false)
|
||||||
|
EnableProxyProtocol bool // Enable proxy protocol support (default: false)
|
||||||
|
|
||||||
TLSConfig *tls.Config // Enable STARTTLS support.
|
TLSConfig *tls.Config // Enable STARTTLS support.
|
||||||
ForceTLS bool // Force STARTTLS usage.
|
ForceTLS bool // Force STARTTLS usage.
|
||||||
|
|
||||||
|
Logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protocol represents the protocol used in the SMTP session
|
// Protocol represents the protocol used in the SMTP session
|
||||||
|
@ -212,12 +216,16 @@ func (session *session) serve() {
|
||||||
|
|
||||||
defer session.close()
|
defer session.close()
|
||||||
|
|
||||||
session.welcome()
|
if !session.server.EnableProxyProtocol {
|
||||||
|
session.welcome()
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
||||||
for session.scanner.Scan() {
|
for session.scanner.Scan() {
|
||||||
session.handle(session.scanner.Text())
|
line := session.scanner.Text()
|
||||||
|
session.logf("received line: %s", strings.TrimSpace(line))
|
||||||
|
session.handle(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := session.scanner.Err()
|
err := session.scanner.Err()
|
||||||
|
@ -268,6 +276,7 @@ func (session *session) welcome() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *session) reply(code int, message string) {
|
func (session *session) reply(code int, message string) {
|
||||||
|
session.logf("sending line: %d %s", code, message)
|
||||||
fmt.Fprintf(session.writer, "%d %s\r\n", code, message)
|
fmt.Fprintf(session.writer, "%d %s\r\n", code, message)
|
||||||
session.flush()
|
session.flush()
|
||||||
}
|
}
|
||||||
|
@ -286,6 +295,22 @@ func (session *session) error(err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (session *session) logf(format string, v ...interface{}) {
|
||||||
|
if session.server.Logger == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
session.server.Logger.Output(2, fmt.Sprintf(
|
||||||
|
"%s [peer:%s]",
|
||||||
|
fmt.Sprintf(format, v...),
|
||||||
|
session.peer.Addr,
|
||||||
|
))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (session *session) logError(err error, desc string) {
|
||||||
|
session.logf("%s: %v ", desc, err)
|
||||||
|
}
|
||||||
|
|
||||||
func (session *session) extensions() []string {
|
func (session *session) extensions() []string {
|
||||||
|
|
||||||
extensions := []string{
|
extensions := []string{
|
||||||
|
|
Loading…
Add table
Reference in a new issue