Merge pull request #7 from orware/master

Add Allowed Sender IPs/Ranges Functionality to MailRelay
This commit is contained in:
Doug Lauder
2025-05-24 16:20:51 -04:00
committed by GitHub
4 changed files with 59 additions and 0 deletions

View File

@ -27,11 +27,18 @@ func sendMail(e *mail.Envelope, config *relayConfig) error {
msg.WriteString("\r\n") msg.WriteString("\r\n")
Logger.Infof("starting email send -- from:%s, starttls:%t", e.MailFrom.String(), config.STARTTLS) Logger.Infof("starting email send -- from:%s, starttls:%t", e.MailFrom.String(), config.STARTTLS)
Logger.Infof("Client Remote IP: %s", e.RemoteIP)
var err error var err error
var conn net.Conn var conn net.Conn
var client *smtp.Client var client *smtp.Client
var writer io.WriteCloser var writer io.WriteCloser
if AllowedSendersFilter.Blocked(e.RemoteIP) {
Logger.Info("Remote IP of " + e.RemoteIP + " not allowed to send email.")
return errors.Wrap(err, "Remote IP of "+e.RemoteIP+" not allowed to send email.")
}
tlsconfig := &tls.Config{ tlsconfig := &tls.Config{
InsecureSkipVerify: config.SkipVerify, //nolint:gosec InsecureSkipVerify: config.SkipVerify, //nolint:gosec
ServerName: config.Server, ServerName: config.Server,

1
go.mod
View File

@ -6,6 +6,7 @@ require (
github.com/asaskevich/EventBus v0.0.0-20180103000110-68a521d7cbbb // indirect github.com/asaskevich/EventBus v0.0.0-20180103000110-68a521d7cbbb // indirect
github.com/flashmob/go-guerrilla v1.6.1 github.com/flashmob/go-guerrilla v1.6.1
github.com/go-sql-driver/mysql v1.5.0 // indirect github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/jpillora/ipfilter v1.2.2
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1

7
go.sum
View File

@ -8,6 +8,8 @@ github.com/flashmob/go-guerrilla v1.6.1 h1:MLkqzRFUJveVAWuQ3s2MNPTAWbvXLt8EFsBor
github.com/flashmob/go-guerrilla v1.6.1/go.mod h1:ZT9TRggRsSY4ZVndoyx8TRUxi3tM/nOYtKWKDX94H0I= github.com/flashmob/go-guerrilla v1.6.1/go.mod h1:ZT9TRggRsSY4ZVndoyx8TRUxi3tM/nOYtKWKDX94H0I=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/jpillora/ipfilter v1.2.2 h1:lfENG7V1/T+ZutAtSbt6gssvzj3Ql0JmcFlqS/BES2E=
github.com/jpillora/ipfilter v1.2.2/go.mod h1:xvAYjA+48eM9E5+sg9yI55N5lE9sefckjsnDvSiEA+g=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@ -16,6 +18,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/phuslu/iploc v1.0.20200807 h1:LIBm2Y9l5zmUvnJhQgMcLZ0iVwuG+5/L6AgbMwSOpE4=
github.com/phuslu/iploc v1.0.20200807/go.mod h1:Q/0VX0txvbxekt4NhWIi3Q3eyZ139lHhnlzvDxyXhuc=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -24,8 +28,11 @@ github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

44
main.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bufio"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
@ -10,6 +11,7 @@ import (
"syscall" "syscall"
log "github.com/flashmob/go-guerrilla/log" log "github.com/flashmob/go-guerrilla/log"
"github.com/jpillora/ipfilter"
) )
const ( const (
@ -23,6 +25,9 @@ const (
// Logger is the global logger // Logger is the global logger
var Logger log.Logger var Logger log.Logger
// Global List of Allowed Sender IPs:
var AllowedSendersFilter = ipfilter.New(ipfilter.Options{})
type mailRelayConfig struct { type mailRelayConfig struct {
SMTPServer string `json:"smtp_server"` SMTPServer string `json:"smtp_server"`
SMTPPort int `json:"smtp_port"` SMTPPort int `json:"smtp_port"`
@ -36,6 +41,7 @@ type mailRelayConfig struct {
LocalListenIP string `json:"local_listen_ip"` LocalListenIP string `json:"local_listen_ip"`
LocalListenPort int `json:"local_listen_port"` LocalListenPort int `json:"local_listen_port"`
AllowedHosts []string `json:"allowed_hosts"` AllowedHosts []string `json:"allowed_hosts"`
AllowedSenders string `json:"allowed_senders"`
TimeoutSecs int `json:"timeout_secs"` TimeoutSecs int `json:"timeout_secs"`
} }
@ -53,12 +59,16 @@ func run() error {
var test bool var test bool
var testsender string var testsender string
var testrcpt string var testrcpt string
var checkIP bool
var ipToCheck string
var verbose bool var verbose bool
flag.StringVar(&configFile, "config", "/etc/mailrelay.json", "specifies JSON config file") flag.StringVar(&configFile, "config", "/etc/mailrelay.json", "specifies JSON config file")
flag.BoolVar(&test, "test", false, "sends a test message to SMTP server") flag.BoolVar(&test, "test", false, "sends a test message to SMTP server")
flag.StringVar(&testsender, "sender", "", "used with 'test' to specify sender email address") flag.StringVar(&testsender, "sender", "", "used with 'test' to specify sender email address")
flag.StringVar(&testrcpt, "rcpt", "", "used with 'test' to specify recipient email address") flag.StringVar(&testrcpt, "rcpt", "", "used with 'test' to specify recipient email address")
flag.BoolVar(&verbose, "verbose", false, "verbose output") flag.BoolVar(&verbose, "verbose", false, "verbose output")
flag.BoolVar(&checkIP, "checkIP", false, "Checks a provided IP address to see if it would be allowed")
flag.StringVar(&ipToCheck, "ip", "", "used with 'checkIP' to specify IP address to test")
flag.Parse() flag.Parse()
appConfig, err := loadConfig(configFile) appConfig, err := loadConfig(configFile)
@ -67,6 +77,34 @@ func run() error {
return fmt.Errorf("loading config: %w", err) return fmt.Errorf("loading config: %w", err)
} }
if appConfig.AllowedSenders != "*" {
file, err := os.Open(appConfig.AllowedSenders)
if err != nil {
return fmt.Errorf("failed opening file: %s", err)
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var allowedIPsAndRanges []string
for scanner.Scan() {
allowedIPsAndRanges = append(allowedIPsAndRanges, scanner.Text())
}
file.Close()
for _, eachline := range allowedIPsAndRanges {
fmt.Println(eachline)
}
AllowedSendersFilter = ipfilter.New(ipfilter.Options{
//AllowedIPs: []string{"192.168.0.0/24"},
AllowedIPs: allowedIPsAndRanges,
BlockByDefault: true,
})
}
err = Start(appConfig, verbose) err = Start(appConfig, verbose)
if err != nil { if err != nil {
flag.Usage() flag.Usage()
@ -90,6 +128,11 @@ func run() error {
return nil return nil
} }
if checkIP {
Logger.Infof("Checking to see if %s is allowed to send email: %t", ipToCheck, AllowedSendersFilter.Allowed(ipToCheck))
return nil
}
// Wait for SIGINT // Wait for SIGINT
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM) signal.Notify(c, os.Interrupt, syscall.SIGTERM)
@ -125,6 +168,7 @@ func configDefaults(config *mailRelayConfig) {
config.LocalListenIP = DefaultLocalListenIP config.LocalListenIP = DefaultLocalListenIP
config.LocalListenPort = DefaultLocalListenPort config.LocalListenPort = DefaultLocalListenPort
config.AllowedHosts = []string{"*"} config.AllowedHosts = []string{"*"}
config.AllowedSenders = "*"
config.TimeoutSecs = DefaultTimeoutSecs config.TimeoutSecs = DefaultTimeoutSecs
} }