Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configurable greeter #220

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"reflect"
"strings"
"text/template"
"time"

"github.com/flashmob/go-guerrilla/backends"
Expand Down Expand Up @@ -60,6 +61,9 @@ type ServerConfig struct {
// XClientOn when using a proxy such as Nginx, XCLIENT command is used to pass the
// original client's IP address & client's HELO
XClientOn bool `json:"xclient_on,omitempty"`
// GreeterTemplate will be used to greet the client.
// Defaults to defaultGreeterString
GreeterTemplate *template.Template `json:"greeter_template"`
}

type ServerTLSConfig struct {
Expand Down Expand Up @@ -151,10 +155,13 @@ var TLSClientAuthTypes = map[string]tls.ClientAuthType{
"RequireAndVerifyClientCert": tls.RequireAndVerifyClientCert,
}

const defaultMaxClients = 100
const defaultTimeout = 30
const defaultInterface = "127.0.0.1:2525"
const defaultMaxSize = int64(10 << 20) // 10 Mebibytes
const (
defaultMaxClients = 100
defaultTimeout = 30
defaultInterface = "127.0.0.1:2525"
defaultMaxSize = int64(10 << 20) // 10 Mebibytes
defaultGreeterString = "220 {{ .Hostname }} SMTP Guerrilla({{ .Version }}) #{{ .ClientID }} ({{ .ActiveClientsCount }}) {{ .Time }}"
)

// Unmarshalls json data into AppConfig struct and any other initialization of the struct
// also does validation, returns error if validation failed or something went wrong
Expand Down Expand Up @@ -279,6 +286,10 @@ func (c *AppConfig) setDefaults() error {
if err != nil {
return err
}
defaultGreeterTemplate, err := template.New("greeter").Parse(defaultGreeterString)
if err != nil {
return fmt.Errorf("unable to parse template: %v", err)
}
if len(c.Servers) == 0 {
sc := ServerConfig{}
sc.LogFile = c.LogFile
Expand All @@ -288,6 +299,7 @@ func (c *AppConfig) setDefaults() error {
sc.MaxClients = defaultMaxClients
sc.Timeout = defaultTimeout
sc.MaxSize = defaultMaxSize
sc.GreeterTemplate = defaultGreeterTemplate
c.Servers = append(c.Servers, sc)
} else {
// make sure each server has defaults correctly configured
Expand All @@ -304,6 +316,9 @@ func (c *AppConfig) setDefaults() error {
if c.Servers[i].MaxSize == 0 {
c.Servers[i].MaxSize = defaultMaxSize // 10 Mebibytes
}
if c.Servers[i].GreeterTemplate == nil {
c.Servers[i].GreeterTemplate = defaultGreeterTemplate
}
if c.Servers[i].ListenInterface == "" {
return fmt.Errorf("listen interface not specified for server at index %d", i)
}
Expand Down
19 changes: 19 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module github.com/flashmob/go-guerrilla

go 1.15

require (
github.com/asaskevich/EventBus v0.0.0-20180103000110-68a521d7cbbb
github.com/go-sql-driver/mysql v1.4.1
github.com/gomodule/redigo v2.0.0+incompatible
github.com/inconshreveable/mousetrap v1.0.0
github.com/konsorten/go-windows-terminal-sequences v1.0.2
github.com/sirupsen/logrus v1.4.2
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c
golang.org/x/sys v0.0.0-20190422165155-953cdadca894
golang.org/x/text v0.3.2
google.golang.org/appengine v1.5.0
gopkg.in/iconv.v1 v1.1.1
)
25 changes: 25 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
github.com/asaskevich/EventBus v0.0.0-20180103000110-68a521d7cbbb/go.mod h1:JS7hed4L1fj0hXcyEejnW57/7LCetXggd+vwrRnYeII=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20180308152046-7dca6fe1f437/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/iconv.v1 v1.1.1/go.mod h1:/kbQb/JfuKJjly48VfSKmiHkdA0nAzSsgDWOc3Jcb08=
26 changes: 21 additions & 5 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"crypto/tls"
"crypto/x509"
"fmt"
"github.com/sirupsen/logrus"
"io"
"io/ioutil"
"net"
Expand All @@ -16,6 +15,8 @@ import (
"sync/atomic"
"time"

"github.com/sirupsen/logrus"

"github.com/flashmob/go-guerrilla/backends"
"github.com/flashmob/go-guerrilla/log"
"github.com/flashmob/go-guerrilla/mail"
Expand Down Expand Up @@ -66,6 +67,14 @@ type allowedHosts struct {
sync.Mutex // guard access to the map
}

type greeterData struct {
Hostname string
Version string
ClientID uint64
ActiveClientsCount int
Time string
}

type command []byte

var (
Expand Down Expand Up @@ -367,9 +376,16 @@ func (s *server) handleClient(client *client) {
s.log().Infof("Handle client [%s], id: %d", client.RemoteIP, client.ID)

// Initial greeting
greeting := fmt.Sprintf("220 %s SMTP Guerrilla(%s) #%d (%d) %s",
sc.Hostname, Version, client.ID,
s.clientPool.GetActiveClientsCount(), time.Now().Format(time.RFC3339))
greeterData := greeterData{
Hostname: sc.Hostname,
Version: Version,
ClientID: client.ID,
ActiveClientsCount: s.clientPool.GetActiveClientsCount(),
Time: time.Now().Format(time.RFC3339),
}

var greeting bytes.Buffer
sc.GreeterTemplate.Execute(&greeting, greeterData)

helo := fmt.Sprintf("250 %s Hello", sc.Hostname)
// ehlo is a multi-line reply and need additional \r\n at the end
Expand Down Expand Up @@ -404,7 +420,7 @@ func (s *server) handleClient(client *client) {
for client.isAlive() {
switch client.state {
case ClientGreeting:
client.sendResponse(greeting)
client.sendResponse(greeting.String())
client.state = ClientCmd
case ClientCmd:
client.bufin.setLimit(CommandLineMaxLength)
Expand Down