2
0
forked from drew/smtprelay

1 Commits

Author SHA1 Message Date
Jonathon Reinhart
190c615029 Add SystemD unit file 2021-04-01 23:44:42 -04:00
6 changed files with 41 additions and 110 deletions

View File

@@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.16
- name: Set up Go 1.15
uses: actions/setup-go@v2.1.3
with:
go-version: 1.16
go-version: 1.15
id: go
- name: Check out code into the Go module directory

View File

@@ -20,11 +20,11 @@ jobs:
- name: Set BUILD_TIME env
run: echo BUILD_TIME=$(date) >> ${GITHUB_ENV}
- uses: wangyoucao577/go-release-action@v1.16
- uses: wangyoucao577/go-release-action@v1.15
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: "https://golang.org/dl/go1.16.3.linux-amd64.tar.gz"
goversion: "https://golang.org/dl/go1.15.8.linux-amd64.tar.gz"
extra_files: LICENSE README.md smtprelay.ini
ldflags: -s -w -X "main.appVersion=${{ env.APP_VERSION }}" -X "main.buildTime=${{ env.BUILD_TIME }}"

View File

@@ -3,9 +3,8 @@ package main
import (
"flag"
"net"
"net/smtp"
"regexp"
"strings"
"net/smtp"
"github.com/vharitonsky/iniflags"
"github.com/sirupsen/logrus"
@@ -22,8 +21,7 @@ var (
logLevel = flag.String("log_level", "info", "Minimum log level to output")
hostName = flag.String("hostname", "localhost.localdomain", "Server hostname")
welcomeMsg = flag.String("welcome_msg", "", "Welcome message for SMTP session")
listenStr = flag.String("listen", "127.0.0.1:25 [::1]:25", "Address and port to listen for incoming SMTP")
listenAddrs = []protoAddr{}
listen = flag.String("listen", "127.0.0.1:25 [::1]:25", "Address and port to listen for incoming SMTP")
localCert = flag.String("local_cert", "", "SSL certificate for STARTTLS/TLS")
localKey = flag.String("local_key", "", "SSL private key for STARTTLS/TLS")
localForceTLS = flag.Bool("local_forcetls", false, "Force STARTTLS (needs local_cert and local_key)")
@@ -43,10 +41,6 @@ var (
versionInfo = flag.Bool("version", false, "Show version information")
)
func localAuthRequired() bool {
return *allowedUsers != ""
}
func setupAllowedNetworks() {
for _, netstr := range splitstr(*allowedNetsStr, ' ') {
@@ -136,39 +130,6 @@ func setupRemoteAuth() {
}
}
type protoAddr struct {
protocol string
address string
}
func splitProto(s string) protoAddr {
idx := strings.Index(s, "://")
if idx == -1 {
return protoAddr {
address: s,
}
}
return protoAddr {
protocol: s[0 : idx],
address: s[idx+3 : len(s)],
}
}
func setupListeners() {
for _, listenAddr := range strings.Split(*listenStr, " ") {
pa := splitProto(listenAddr)
if localAuthRequired() && pa.protocol == "" {
log.WithField("address", pa.address).
Fatal("Local authentication (via allowed_users file) " +
"not allowed with non-TLS listener")
}
listenAddrs = append(listenAddrs, pa)
}
}
func ConfigLoad() {
iniflags.Parse()
@@ -182,5 +143,4 @@ func ConfigLoad() {
setupAllowedNetworks()
setupAllowedPatterns()
setupRemoteAuth()
setupListeners()
}

View File

@@ -1,44 +0,0 @@
package main
import (
"testing"
)
func TestSplitProto(t *testing.T) {
var tests = []struct {
input string
proto string
addr string
}{
{
input: "localhost",
proto: "",
addr: "localhost",
},
{
input: "tls://my.local.domain",
proto: "tls",
addr: "my.local.domain",
},
{
input: "starttls://my.local.domain",
proto: "starttls",
addr: "my.local.domain",
},
}
for i, test := range tests {
testName := test.input
t.Run(testName, func(t *testing.T) {
pa := splitProto(test.input)
if pa.protocol != test.proto {
t.Errorf("Testcase %d: Incorrect proto: expected %v, got %v",
i, test.proto, pa.protocol)
}
if pa.address != test.addr {
t.Errorf("Testcase %d: Incorrect addr: expected %v, got %v",
i, test.addr, pa.address)
}
})
}
}

44
main.go
View File

@@ -81,7 +81,7 @@ func addrAllowed(addr string, allowedAddrs []string) bool {
func senderChecker(peer smtpd.Peer, addr string) error {
// check sender address from auth file if user is authenticated
if localAuthRequired() && peer.Username != "" {
if *allowedUsers != "" && peer.Username != "" {
user, err := AuthFetch(peer.Username)
if err != nil {
// Shouldn't happen: authChecker already validated username+password
@@ -276,7 +276,7 @@ func main() {
Debug("starting smtprelay")
// Load allowed users file
if localAuthRequired() {
if *allowedUsers != "" {
err := AuthLoadFile(*allowedUsers)
if err != nil {
log.WithField("file", *allowedUsers).
@@ -288,9 +288,7 @@ func main() {
var servers []*smtpd.Server
// Create a server for each desired listen address
for _, listen := range listenAddrs {
logger := log.WithField("address", listen.address)
for _, listenAddr := range strings.Split(*listen, " ") {
server := &smtpd.Server{
Hostname: *hostName,
WelcomeMessage: *welcomeMsg,
@@ -300,38 +298,44 @@ func main() {
Handler: mailHandler,
}
if localAuthRequired() {
if *allowedUsers != "" {
server.Authenticator = authChecker
}
var lsnr net.Listener
var err error
switch listen.protocol {
case "":
logger.Info("listening on address")
lsnr, err = net.Listen("tcp", listen.address)
if strings.Index(listenAddr, "://") == -1 {
log.WithField("address", listenAddr).
Info("listening on address")
lsnr, err = net.Listen("tcp", listenAddr)
} else if strings.HasPrefix(listenAddr, "starttls://") {
listenAddr = strings.TrimPrefix(listenAddr, "starttls://")
case "starttls":
server.TLSConfig = getTLSConfig()
server.ForceTLS = *localForceTLS
logger.Info("listening on address (STARTTLS)")
lsnr, err = net.Listen("tcp", listen.address)
log.WithField("address", listenAddr).
Info("listening on address (STARTTLS)")
lsnr, err = net.Listen("tcp", listenAddr)
} else if strings.HasPrefix(listenAddr, "tls://") {
listenAddr = strings.TrimPrefix(listenAddr, "tls://")
case "tls":
server.TLSConfig = getTLSConfig()
logger.Info("listening on address (TLS)")
lsnr, err = tls.Listen("tcp", listen.address, server.TLSConfig)
default:
logger.WithField("protocol", listen.protocol).
log.WithField("address", listenAddr).
Info("listening on address (TLS)")
lsnr, err = tls.Listen("tcp", listenAddr, server.TLSConfig)
} else {
log.WithField("address", listenAddr).
Fatal("unknown protocol in listen address")
}
if err != nil {
logger.WithError(err).Fatal("error starting listener")
log.WithFields(logrus.Fields{
"address": listenAddr,
}).WithError(err).Fatal("error starting listener")
}
servers = append(servers, server)

View File

@@ -0,0 +1,11 @@
[Unit]
Description=SMTP Relay
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=/opt/smtprelay/bin/smtprelay -config /etc/smtprelay/smtprelay.ini
[Install]
WantedBy=multi-user.target