2
0
forked from drew/smtprelay

35 Commits

Author SHA1 Message Date
Bernhard Froehlich
0ee982ea31 Bump used Go versions to 1.17 2021-11-22 15:38:17 +00:00
Bernhard Fröhlich
287395ad91 Merge pull request #47 from alex1989hu/bump/chrj-smtpd-v031
Bump chrj/smtpd from 0.3.0 to 0.3.1
2021-11-22 11:39:33 +01:00
Alex Szakaly
3aecd3c6d6 Bump chrj/smtpd from 0.3.0 to 0.3.1
Fixes #44

Signed-off-by: Alex Szakaly <alex.szakaly@gmail.com>
2021-11-22 07:53:43 +01:00
Bernhard Fröhlich
f8960053e8 Merge pull request #46 from decke/dependabot/github_actions/wangyoucao577/go-release-action-1.21
Bump wangyoucao577/go-release-action from 1.20 to 1.21
2021-11-17 11:59:35 +01:00
dependabot[bot]
db5512d47b Bump wangyoucao577/go-release-action from 1.20 to 1.21
Bumps [wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action) from 1.20 to 1.21.
- [Release notes](https://github.com/wangyoucao577/go-release-action/releases)
- [Commits](https://github.com/wangyoucao577/go-release-action/compare/v1.20...v1.21)

---
updated-dependencies:
- dependency-name: wangyoucao577/go-release-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-16 10:07:49 +00:00
Bernhard Fröhlich
fd063ad879 Merge pull request #45 from decke/dependabot/github_actions/actions/checkout-2.4.0
Bump actions/checkout from 2.3.5 to 2.4.0
2021-11-03 11:49:27 +01:00
dependabot[bot]
85bdd060e3 Bump actions/checkout from 2.3.5 to 2.4.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 2.3.5 to 2.4.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2.3.5...v2.4.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-03 10:05:55 +00:00
Bernhard Fröhlich
5be6165865 Merge pull request #43 from decke/dependabot/github_actions/actions/checkout-2.3.5
Bump actions/checkout from 2.3.4 to 2.3.5
2021-10-18 16:00:48 +02:00
dependabot[bot]
b64a34becf Bump actions/checkout from 2.3.4 to 2.3.5
Bumps [actions/checkout](https://github.com/actions/checkout) from 2.3.4 to 2.3.5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2.3.4...v2.3.5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 10:08:18 +00:00
Bernhard Fröhlich
a2ea5ab49e Merge pull request #42 from decke/dependabot/github_actions/wangyoucao577/go-release-action-1.20
Bump wangyoucao577/go-release-action from 1.19 to 1.20
2021-08-30 14:46:38 +02:00
dependabot[bot]
94957d944f Bump wangyoucao577/go-release-action from 1.19 to 1.20
Bumps [wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action) from 1.19 to 1.20.
- [Release notes](https://github.com/wangyoucao577/go-release-action/releases)
- [Commits](https://github.com/wangyoucao577/go-release-action/compare/v1.19...v1.20)

---
updated-dependencies:
- dependency-name: wangyoucao577/go-release-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-30 10:06:39 +00:00
Bernhard Fröhlich
a5db5e1ff5 Merge pull request #41 from decke/dependabot/github_actions/actions/setup-go-2.1.4
Bump actions/setup-go from 2.1.3 to 2.1.4
2021-08-26 13:14:35 +02:00
dependabot[bot]
94776b27d9 Bump actions/setup-go from 2.1.3 to 2.1.4
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2.1.3 to 2.1.4.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2.1.3...v2.1.4)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-26 10:06:19 +00:00
Bernhard Fröhlich
81bc7addc7 Merge pull request #39 from decke/dependabot/github_actions/wangyoucao577/go-release-action-1.19
Bump wangyoucao577/go-release-action from 1.18 to 1.19
2021-07-28 22:15:07 +02:00
dependabot[bot]
e9bfe53f18 Bump wangyoucao577/go-release-action from 1.18 to 1.19
Bumps [wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action) from 1.18 to 1.19.
- [Release notes](https://github.com/wangyoucao577/go-release-action/releases)
- [Commits](https://github.com/wangyoucao577/go-release-action/compare/v1.18...v1.19)

---
updated-dependencies:
- dependency-name: wangyoucao577/go-release-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-21 10:06:34 +00:00
Bernhard Fröhlich
32032c297c Merge pull request #38 from decke/dependabot/go_modules/github.com/google/uuid-1.3.0
Bump github.com/google/uuid from 1.2.0 to 1.3.0
2021-07-13 13:10:23 +02:00
dependabot[bot]
53e52de279 Bump github.com/google/uuid from 1.2.0 to 1.3.0
Bumps [github.com/google/uuid](https://github.com/google/uuid) from 1.2.0 to 1.3.0.
- [Release notes](https://github.com/google/uuid/releases)
- [Commits](https://github.com/google/uuid/compare/v1.2.0...v1.3.0)

---
updated-dependencies:
- dependency-name: github.com/google/uuid
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-07-13 10:06:56 +00:00
Bernhard Fröhlich
02810c0a50 Merge pull request #36 from decke/dependabot/github_actions/wangyoucao577/go-release-action-1.18
Bump wangyoucao577/go-release-action from 1.17 to 1.18
2021-05-26 14:36:30 +02:00
dependabot[bot]
6b21f52037 Bump wangyoucao577/go-release-action from 1.17 to 1.18
Bumps [wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action) from 1.17 to 1.18.
- [Release notes](https://github.com/wangyoucao577/go-release-action/releases)
- [Commits](https://github.com/wangyoucao577/go-release-action/compare/v1.17...v1.18)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-26 05:59:28 +00:00
Bernhard Fröhlich
544bd081ff Merge pull request #34 from decke/dependabot/github_actions/actions/checkout-2.3.4
Bump actions/checkout from 2 to 2.3.4
2021-05-12 08:41:49 +02:00
dependabot[bot]
6a28f939de Bump actions/checkout from 2 to 2.3.4
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 2.3.4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v2.3.4)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-12 05:54:25 +00:00
Bernhard Fröhlich
f0392bdf09 Merge pull request #33 from benubois/command
Add external command support
2021-05-10 10:18:56 +02:00
Ben Ubois
3f627d3281 Move AddReceivedLine before further processing. 2021-05-08 11:56:28 -07:00
Ben Ubois
d8860fc917 Added external command support. 2021-05-07 14:08:10 -07:00
Bernhard Fröhlich
ebb53ea1b6 Merge pull request #30 from decke/dependabot/github_actions/wangyoucao577/go-release-action-v1.17
Bump wangyoucao577/go-release-action from v1.16 to v1.17
2021-04-13 20:13:18 +02:00
dependabot[bot]
a5ee525825 Bump wangyoucao577/go-release-action from v1.16 to v1.17
Bumps [wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action) from v1.16 to v1.17.
- [Release notes](https://github.com/wangyoucao577/go-release-action/releases)
- [Commits](https://github.com/wangyoucao577/go-release-action/compare/v1.16...1a87d97ce87db435508d150622a9ab5472db15ac)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-13 07:18:35 +00:00
Bernhard Froehlich
441a53cfd9 Fix code formatting with gofmt -s 2021-04-03 19:00:38 +00:00
Bernhard Froehlich
7b199cc6ae Bump Go version for CI builds to 1.16 2021-04-02 18:51:23 +00:00
Bernhard Froehlich
184d5f8611 Bump Go version for builds to 1.16.3 2021-04-02 18:49:53 +00:00
Bernhard Fröhlich
9e8b5517a6 Merge pull request #27 from decke/26-tls-reqd-for-auth
Don't allow configuration requiring authentication with non-TLS listener
2021-04-02 20:41:38 +02:00
Bernhard Fröhlich
65f0cfcfbd Merge pull request #28 from decke/dependabot/github_actions/wangyoucao577/go-release-action-v1.16
Bump wangyoucao577/go-release-action from v1.15 to v1.16
2021-04-02 20:29:02 +02:00
dependabot[bot]
410c70d86f Bump wangyoucao577/go-release-action from v1.15 to v1.16
Bumps [wangyoucao577/go-release-action](https://github.com/wangyoucao577/go-release-action) from v1.15 to v1.16.
- [Release notes](https://github.com/wangyoucao577/go-release-action/releases)
- [Commits](https://github.com/wangyoucao577/go-release-action/compare/v1.15...d00bb7360b2dd6a39f1a7ca198b8289582eee2df)

Signed-off-by: dependabot[bot] <support@github.com>
2021-04-01 07:35:56 +00:00
Jonathon Reinhart
247d187576 Don't allow a configuration requiring auth with a non-TLS listener
This fixes #26
2021-04-01 01:12:34 -04:00
Jonathon Reinhart
45a676e274 Add localAuthRequired() helper function
This just makes the configuration state a little more obvious.
2021-04-01 01:12:34 -04:00
Jonathon Reinhart
ca1ccd85e3 Refactor parsing of -listen string out into separate config function
This makes the "for each listen address" loop in main() look even cleaner.
2021-04-01 01:12:34 -04:00
10 changed files with 169 additions and 63 deletions

View File

@@ -25,7 +25,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v2
uses: actions/checkout@v2.4.0
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.

View File

@@ -7,14 +7,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.15
uses: actions/setup-go@v2.1.3
- name: Set up Go 1.17
uses: actions/setup-go@v2.1.4
with:
go-version: 1.15
go-version: 1.17
id: go
- name: Check out code into the Go module directory
uses: actions/checkout@v1
uses: actions/checkout@v2.4.0
- name: Get dependencies
run: |

View File

@@ -13,18 +13,18 @@ jobs:
goos: [freebsd, linux, windows]
goarch: ["386", amd64]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v2.4.0
- name: Set APP_VERSION env
run: echo APP_VERSION=$(echo ${GITHUB_REF} | rev | cut -d'/' -f 1 | rev ) >> ${GITHUB_ENV}
- name: Set BUILD_TIME env
run: echo BUILD_TIME=$(date) >> ${GITHUB_ENV}
- uses: wangyoucao577/go-release-action@v1.15
- uses: wangyoucao577/go-release-action@v1.21
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
goos: ${{ matrix.goos }}
goarch: ${{ matrix.goarch }}
goversion: "https://golang.org/dl/go1.15.8.linux-amd64.tar.gz"
goversion: "https://golang.org/dl/go1.17.3.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,11 +3,12 @@ package main
import (
"flag"
"net"
"regexp"
"net/smtp"
"regexp"
"strings"
"github.com/vharitonsky/iniflags"
"github.com/sirupsen/logrus"
"github.com/vharitonsky/iniflags"
)
var (
@@ -21,7 +22,8 @@ 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")
listen = flag.String("listen", "127.0.0.1:25 [::1]:25", "Address and port to listen for incoming SMTP")
listenStr = flag.String("listen", "127.0.0.1:25 [::1]:25", "Address and port to listen for incoming SMTP")
listenAddrs = []protoAddr{}
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)")
@@ -32,6 +34,7 @@ var (
allowedRecipStr = flag.String("allowed_recipients", "", "Regular expression for valid TO EMail addresses")
allowedRecipients *regexp.Regexp
allowedUsers = flag.String("allowed_users", "", "Path to file with valid users/passwords")
command = flag.String("command", "", "Path to pipe command")
remoteHost = flag.String("remote_host", "", "Outgoing SMTP server")
remoteUser = flag.String("remote_user", "", "Username for authentication on outgoing SMTP server")
remotePass = flag.String("remote_pass", "", "Password for authentication on outgoing SMTP server")
@@ -41,6 +44,9 @@ var (
versionInfo = flag.Bool("version", false, "Show version information")
)
func localAuthRequired() bool {
return *allowedUsers != ""
}
func setupAllowedNetworks() {
for _, netstr := range splitstr(*allowedNetsStr, ' ') {
@@ -55,7 +61,7 @@ func setupAllowedNetworks() {
// meaning the address refers to a host and not a network.
if !allowedNet.IP.Equal(baseIP) {
log.WithFields(logrus.Fields{
"given_net": netstr,
"given_net": netstr,
"proper_net": allowedNet,
}).Fatal("Invalid network in allowed_nets (host bits set)")
}
@@ -67,7 +73,7 @@ func setupAllowedNetworks() {
func setupAllowedPatterns() {
var err error
if (*allowedSenderStr != "") {
if *allowedSenderStr != "" {
allowedSender, err = regexp.Compile(*allowedSenderStr)
if err != nil {
log.WithField("allowed_sender", *allowedSenderStr).
@@ -76,7 +82,7 @@ func setupAllowedPatterns() {
}
}
if (*allowedRecipStr != "") {
if *allowedRecipStr != "" {
allowedRecipients, err = regexp.Compile(*allowedRecipStr)
if err != nil {
log.WithField("allowed_recipients", *allowedRecipStr).
@@ -86,7 +92,6 @@ func setupAllowedPatterns() {
}
}
func setupRemoteAuth() {
logger := log.WithField("remote_auth", *remoteAuthStr)
@@ -117,7 +122,7 @@ func setupRemoteAuth() {
host, _, err := net.SplitHostPort(*remoteHost)
if err != nil {
logger.WithField("remote_host", *remoteHost).
Fatal("Invalid remote_host")
Fatal("Invalid remote_host")
}
switch *remoteAuthStr {
@@ -130,17 +135,50 @@ 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:],
}
}
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()
// Set up logging as soon as possible
setupLogger()
if (*remoteHost == "") {
log.Warn("remote_host not set; mail will not be forwarded!")
if *remoteHost == "" && *command == "" {
log.Warn("no remote_host or command set; mail will not be forwarded!")
}
setupAllowedNetworks()
setupAllowedPatterns()
setupRemoteAuth()
setupListeners()
}

44
config_test.go Normal file
View File

@@ -0,0 +1,44 @@
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)
}
})
}
}

4
go.mod
View File

@@ -1,8 +1,8 @@
module github.com/decke/smtprelay
require (
github.com/chrj/smtpd v0.3.0
github.com/google/uuid v1.2.0
github.com/chrj/smtpd v0.3.1
github.com/google/uuid v1.3.0
github.com/sirupsen/logrus v1.8.1
github.com/vharitonsky/iniflags v0.0.0-20180513140207-a33cd0b5f3de
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad

9
go.sum
View File

@@ -1,10 +1,9 @@
github.com/chrj/smtpd v0.3.0 h1:cw1LSHDOz7N3XbkcZSF/bue9dh7ATKk5ZksfBztV6b0=
github.com/chrj/smtpd v0.3.0/go.mod h1:1hmG9KbrE10JG1SmvG79Krh4F6713oUrw2+gRp1oSYk=
github.com/chrj/smtpd v0.3.1 h1:kogHFkbFdKaoH3bgZkqNC9uVtKYOFfM3uV3rroBdooE=
github.com/chrj/smtpd v0.3.1/go.mod h1:JtABvV/LzvLmEIzy0NyDnrfMGOMd8wy5frAokwf6J9Q=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eaigner/dkim v0.0.0-20150301120808-6fe4a7ee9cfb/go.mod h1:FSCIHbrqk7D01Mj8y/jW+NS1uoCerr+ad+IckTHTFf4=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=

View File

@@ -16,7 +16,7 @@ func setupLogger() {
log = logrus.New()
// Handle logfile
if (*logFile == "") {
if *logFile == "" {
log.SetOutput(os.Stderr)
} else {
writer, err := os.OpenFile(*logFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0600)

96
main.go
View File

@@ -1,11 +1,13 @@
package main
import (
"bytes"
"crypto/tls"
"fmt"
"net"
"net/textproto"
"os"
"os/exec"
"os/signal"
"strings"
"syscall"
@@ -81,12 +83,12 @@ 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 *allowedUsers != "" && peer.Username != "" {
if localAuthRequired() && peer.Username != "" {
user, err := AuthFetch(peer.Username)
if err != nil {
// Shouldn't happen: authChecker already validated username+password
log.WithFields(logrus.Fields{
"peer": peer.Addr,
"peer": peer.Addr,
"username": peer.Username,
}).WithError(err).Warn("could not fetch auth user")
return smtpd.Error{Code: 451, Message: "Bad sender address"}
@@ -94,8 +96,8 @@ func senderChecker(peer smtpd.Peer, addr string) error {
if !addrAllowed(addr, user.allowedAddresses) {
log.WithFields(logrus.Fields{
"peer": peer.Addr,
"username": peer.Username,
"peer": peer.Addr,
"username": peer.Username,
"sender_address": addr,
}).Warn("sender address not allowed for authenticated user")
return smtpd.Error{Code: 451, Message: "Bad sender address"}
@@ -114,7 +116,7 @@ func senderChecker(peer smtpd.Peer, addr string) error {
log.WithFields(logrus.Fields{
"sender_address": addr,
"peer": peer.Addr,
"peer": peer.Addr,
}).Warn("sender address not allowed by allowed_sender pattern")
return smtpd.Error{Code: 451, Message: "Bad sender address"}
}
@@ -131,7 +133,7 @@ func recipientChecker(peer smtpd.Peer, addr string) error {
}
log.WithFields(logrus.Fields{
"peer": peer.Addr,
"peer": peer.Addr,
"recipient_address": addr,
}).Warn("recipient address not allowed by allowed_recipients pattern")
return smtpd.Error{Code: 451, Message: "Bad recipient address"}
@@ -141,7 +143,7 @@ func authChecker(peer smtpd.Peer, username string, password string) error {
err := AuthCheckPassword(username, password)
if err != nil {
log.WithFields(logrus.Fields{
"peer": peer.Addr,
"peer": peer.Addr,
"username": username,
}).WithError(err).Warn("auth error")
return smtpd.Error{Code: 535, Message: "Authentication credentials invalid"}
@@ -157,21 +159,45 @@ func mailHandler(peer smtpd.Peer, env smtpd.Envelope) error {
logger := log.WithFields(logrus.Fields{
"from": env.Sender,
"to": env.Recipients,
"to": env.Recipients,
"peer": peerIP,
"host": *remoteHost,
"uuid": generateUUID(),
})
if (*remoteHost == "") {
logger.Warning("remote_host not set; discarding mail")
if *remoteHost == "" && *command == "" {
logger.Warning("no remote_host or command set; discarding mail")
return nil
}
env.AddReceivedLine(peer)
if *command != "" {
cmdLogger := logger.WithField("command", *command)
var stdout bytes.Buffer
var stderr bytes.Buffer
cmd := exec.Command(*command)
cmd.Stdin = bytes.NewReader(env.Data)
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
cmdLogger.WithError(err).Error(stderr.String())
return nil
}
cmdLogger.Info("pipe command successful: " + stdout.String())
}
if *remoteHost == "" {
return nil
}
logger.Info("delivering mail from peer using smarthost")
env.AddReceivedLine(peer)
var sender string
if *remoteSender == "" {
@@ -197,7 +223,7 @@ func mailHandler(peer smtpd.Peer, env smtpd.Envelope) error {
logger.WithFields(logrus.Fields{
"err_code": err.Code,
"err_msg": err.Msg,
"err_msg": err.Msg,
}).Error("delivery failed")
default:
smtpError = smtpd.Error{Code: 554, Message: "Forwarding failed"}
@@ -246,7 +272,7 @@ func getTLSConfig() *tls.Config {
if *localCert == "" || *localKey == "" {
log.WithFields(logrus.Fields{
"cert_file": *localCert,
"key_file": *localKey,
"key_file": *localKey,
}).Fatal("TLS certificate/key file not defined in config")
}
@@ -276,7 +302,7 @@ func main() {
Debug("starting smtprelay")
// Load allowed users file
if *allowedUsers != "" {
if localAuthRequired() {
err := AuthLoadFile(*allowedUsers)
if err != nil {
log.WithField("file", *allowedUsers).
@@ -288,7 +314,9 @@ func main() {
var servers []*smtpd.Server
// Create a server for each desired listen address
for _, listenAddr := range strings.Split(*listen, " ") {
for _, listen := range listenAddrs {
logger := log.WithField("address", listen.address)
server := &smtpd.Server{
Hostname: *hostName,
WelcomeMessage: *welcomeMsg,
@@ -298,44 +326,38 @@ func main() {
Handler: mailHandler,
}
if *allowedUsers != "" {
if localAuthRequired() {
server.Authenticator = authChecker
}
var lsnr net.Listener
var err error
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://")
switch listen.protocol {
case "":
logger.Info("listening on address")
lsnr, err = net.Listen("tcp", listen.address)
case "starttls":
server.TLSConfig = getTLSConfig()
server.ForceTLS = *localForceTLS
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://")
logger.Info("listening on address (STARTTLS)")
lsnr, err = net.Listen("tcp", listen.address)
case "tls":
server.TLSConfig = getTLSConfig()
log.WithField("address", listenAddr).
Info("listening on address (TLS)")
lsnr, err = tls.Listen("tcp", listenAddr, server.TLSConfig)
} else {
log.WithField("address", listenAddr).
logger.Info("listening on address (TLS)")
lsnr, err = tls.Listen("tcp", listen.address, server.TLSConfig)
default:
logger.WithField("protocol", listen.protocol).
Fatal("unknown protocol in listen address")
}
if err != nil {
log.WithFields(logrus.Fields{
"address": listenAddr,
}).WithError(err).Fatal("error starting listener")
logger.WithError(err).Fatal("error starting listener")
}
servers = append(servers, server)

View File

@@ -78,3 +78,6 @@
; Sender e-mail address on outgoing SMTP server
;remote_sender =
; Pipe messages to external command
;command = /usr/local/bin/script