mirror of
https://github.com/decke/smtprelay.git
synced 2026-01-17 06:39:24 -07:00
Client certificate for relay
This commit is contained in:
committed by
Bernhard Fröhlich
parent
42d1721751
commit
0e352a9bb6
44
config.go
44
config.go
@@ -46,6 +46,8 @@ var (
|
|||||||
command = flagset.String("command", "", "Path to pipe command")
|
command = flagset.String("command", "", "Path to pipe command")
|
||||||
remotesStr = flagset.String("remotes", "", "Outgoing SMTP servers")
|
remotesStr = flagset.String("remotes", "", "Outgoing SMTP servers")
|
||||||
strictSender = flagset.Bool("strict_sender", false, "Use only SMTP servers with Sender matches to From")
|
strictSender = flagset.Bool("strict_sender", false, "Use only SMTP servers with Sender matches to From")
|
||||||
|
remoteCert = flagset.String("remote_certificate", "", "Client SSL certificate for remote STARTTLS/TLS")
|
||||||
|
remoteKey = flagset.String("remote_key", "", "Client SSL private key for remote STARTTLS/TLS")
|
||||||
|
|
||||||
// additional flags
|
// additional flags
|
||||||
_ = flagset.String("config", "", "Path to config file (ini format)")
|
_ = flagset.String("config", "", "Path to config file (ini format)")
|
||||||
@@ -67,6 +69,36 @@ func localAuthRequired() bool {
|
|||||||
return *allowedUsers != ""
|
return *allowedUsers != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func remoteCertAndKeyReadable() bool {
|
||||||
|
certSet := *remoteCert != ""
|
||||||
|
keySet := *remoteKey != ""
|
||||||
|
|
||||||
|
// Both must be set or both must be unset
|
||||||
|
if certSet != keySet {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both are set, verify files exist and are accessible
|
||||||
|
if certSet && keySet {
|
||||||
|
if _, err := os.Stat(*remoteCert); err != nil {
|
||||||
|
log.Error().
|
||||||
|
Str("cert", *remoteCert).
|
||||||
|
Err(err).
|
||||||
|
Msg("cannot access remote client certificate file")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(*remoteKey); err != nil {
|
||||||
|
log.Error().
|
||||||
|
Str("key", *remoteKey).
|
||||||
|
Err(err).
|
||||||
|
Msg("cannot access remote client key file")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func setupAliases() {
|
func setupAliases() {
|
||||||
if *aliasFile != "" {
|
if *aliasFile != "" {
|
||||||
aliases, err := AliasLoadFile(*aliasFile)
|
aliases, err := AliasLoadFile(*aliasFile)
|
||||||
@@ -137,6 +169,11 @@ func setupRemotes() {
|
|||||||
logger.Fatal().Msg(fmt.Sprintf("error parsing url: '%s': %v", remoteURL, err))
|
logger.Fatal().Msg(fmt.Sprintf("error parsing url: '%s': %v", remoteURL, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *remoteCert != "" && *remoteKey != "" && (r.Scheme == "smtps" || r.Scheme == "starttls") {
|
||||||
|
r.ClientCertPath = *remoteCert
|
||||||
|
r.ClientKeyPath = *remoteKey
|
||||||
|
}
|
||||||
|
|
||||||
remotes = append(remotes, r)
|
remotes = append(remotes, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,6 +290,13 @@ func ConfigLoad() {
|
|||||||
log.Warn().Msg("no remotes or command set; mail will not be forwarded!")
|
log.Warn().Msg("no remotes or command set; mail will not be forwarded!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !remoteCertAndKeyReadable() {
|
||||||
|
log.Fatal().
|
||||||
|
Str("remote_certificate", *remoteCert).
|
||||||
|
Str("remote_key", *remoteKey).
|
||||||
|
Msg("remote_certificate and remote_key must both be set or both be empty")
|
||||||
|
}
|
||||||
|
|
||||||
setupAllowedNetworks()
|
setupAllowedNetworks()
|
||||||
setupAllowedPatterns()
|
setupAllowedPatterns()
|
||||||
setupAliases()
|
setupAliases()
|
||||||
|
|||||||
16
remotes.go
16
remotes.go
@@ -7,13 +7,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Remote struct {
|
type Remote struct {
|
||||||
SkipVerify bool
|
SkipVerify bool
|
||||||
Auth smtp.Auth
|
Auth smtp.Auth
|
||||||
Scheme string
|
Scheme string
|
||||||
Hostname string
|
Hostname string
|
||||||
Port string
|
Port string
|
||||||
Addr string
|
Addr string
|
||||||
Sender string
|
Sender string
|
||||||
|
ClientCertPath string
|
||||||
|
ClientKeyPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseRemote creates a remote from a given url in the following format:
|
// ParseRemote creates a remote from a given url in the following format:
|
||||||
|
|||||||
16
smtp.go
16
smtp.go
@@ -340,6 +340,14 @@ func SendMail(r *Remote, from string, to []string, msg []byte) error {
|
|||||||
ServerName: r.Hostname,
|
ServerName: r.Hostname,
|
||||||
InsecureSkipVerify: r.SkipVerify,
|
InsecureSkipVerify: r.SkipVerify,
|
||||||
}
|
}
|
||||||
|
// Load client certificate on-demand, just before connection
|
||||||
|
if r.ClientCertPath != "" && r.ClientKeyPath != "" {
|
||||||
|
cert, err := tls.LoadX509KeyPair(r.ClientCertPath, r.ClientKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.Certificates = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
conn, err := tls.Dial("tcp", r.Addr, config)
|
conn, err := tls.Dial("tcp", r.Addr, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -366,6 +374,14 @@ func SendMail(r *Remote, from string, to []string, msg []byte) error {
|
|||||||
ServerName: c.serverName,
|
ServerName: c.serverName,
|
||||||
InsecureSkipVerify: r.SkipVerify,
|
InsecureSkipVerify: r.SkipVerify,
|
||||||
}
|
}
|
||||||
|
// Load client certificate on-demand, just before use
|
||||||
|
if r.ClientCertPath != "" && r.ClientKeyPath != "" {
|
||||||
|
cert, err := tls.LoadX509KeyPair(r.ClientCertPath, r.ClientKeyPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.Certificates = []tls.Certificate{cert}
|
||||||
|
}
|
||||||
if testHookStartTLS != nil {
|
if testHookStartTLS != nil {
|
||||||
testHookStartTLS(config)
|
testHookStartTLS(config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,10 @@
|
|||||||
; Mailjet.com
|
; Mailjet.com
|
||||||
;remotes = starttls://user:pass@in-v3.mailjet.com:587
|
;remotes = starttls://user:pass@in-v3.mailjet.com:587
|
||||||
|
|
||||||
|
; Exchange Online (O365) SMTP relay
|
||||||
|
; (Change netloc to your own Exchange MX endpoint)
|
||||||
|
; remotes = starttls://contoso-com.mail.protection.outlook.com:25
|
||||||
|
|
||||||
; Ignore remote host certificates
|
; Ignore remote host certificates
|
||||||
;remotes = starttls://user:pass@server:587?skipVerify
|
;remotes = starttls://user:pass@server:587?skipVerify
|
||||||
|
|
||||||
@@ -131,5 +135,11 @@
|
|||||||
; Multiple remotes, space delimited
|
; Multiple remotes, space delimited
|
||||||
;remotes = smtp://127.0.0.1:1025 starttls://user:pass@smtp.mailgun.org:587
|
;remotes = smtp://127.0.0.1:1025 starttls://user:pass@smtp.mailgun.org:587
|
||||||
|
|
||||||
|
; Client SSL certificate for remote STARTTLS/TLS
|
||||||
|
; remote_certificate = /path/to/certificate-chain.pem
|
||||||
|
|
||||||
|
; Client SSL private key for remote STARTTLS/TLS
|
||||||
|
; remote_key = /path/to/private-key.pem
|
||||||
|
|
||||||
; Pipe messages to external command
|
; Pipe messages to external command
|
||||||
;command = /usr/local/bin/script
|
;command = /usr/local/bin/script
|
||||||
|
|||||||
Reference in New Issue
Block a user