mirror of
https://blitiri.com.ar/repos/chasquid
synced 2025-12-17 14:37:02 +00:00
Support submission (directly) over TLS (submissions/smtps/port 465)
This patch adds support for TLS-wrapped submission connections. Instead of clients establishing a connection over plain text and then using STARTTLS to switch over a TLS connection, this new mode allows the clients to connect directly over TLS, like it's done in HTTPS. This is not an official standard yet, but it's reasonably common in practice, and provides some advantages over the traditional submission port. The default port is 465, commonly used for this; chasquid defaults to systemd file descriptor passing as for the other protocols (for now).
This commit is contained in:
@@ -161,6 +161,8 @@ func main() {
|
|||||||
systemdLs["smtp"], smtpsrv.ModeSMTP)
|
systemdLs["smtp"], smtpsrv.ModeSMTP)
|
||||||
loadAddresses(s, conf.SubmissionAddress,
|
loadAddresses(s, conf.SubmissionAddress,
|
||||||
systemdLs["submission"], smtpsrv.ModeSubmission)
|
systemdLs["submission"], smtpsrv.ModeSubmission)
|
||||||
|
loadAddresses(s, conf.SubmissionOverTlsAddress,
|
||||||
|
systemdLs["submission_tls"], smtpsrv.ModeSubmissionTLS)
|
||||||
|
|
||||||
s.ListenAndServe()
|
s.ListenAndServe()
|
||||||
}
|
}
|
||||||
|
|||||||
11
etc/systemd/system/chasquid-submission_tls.socket
Normal file
11
etc/systemd/system/chasquid-submission_tls.socket
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=chasquid mail daemon (submission over TLS sockets)
|
||||||
|
|
||||||
|
[Socket]
|
||||||
|
ListenStream=465
|
||||||
|
FileDescriptorName=submission_tls
|
||||||
|
Service=chasquid.service
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=chasquid.target
|
||||||
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=chasquid mail daemon (service)
|
Description=chasquid mail daemon (service)
|
||||||
Requires=chasquid-smtp.socket chasquid-submission.socket
|
Requires=chasquid-smtp.socket \
|
||||||
|
chasquid-submission.socket \
|
||||||
|
chasquid-submission_tls.socket
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/local/bin/chasquid \
|
ExecStart=/usr/local/bin/chasquid \
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ func Load(path string) (*Config, error) {
|
|||||||
if len(c.SubmissionAddress) == 0 {
|
if len(c.SubmissionAddress) == 0 {
|
||||||
c.SubmissionAddress = append(c.SubmissionAddress, "systemd")
|
c.SubmissionAddress = append(c.SubmissionAddress, "systemd")
|
||||||
}
|
}
|
||||||
|
if len(c.SubmissionOverTlsAddress) == 0 {
|
||||||
|
c.SubmissionOverTlsAddress = append(c.SubmissionOverTlsAddress, "systemd")
|
||||||
|
}
|
||||||
|
|
||||||
if c.MailDeliveryAgentBin == "" {
|
if c.MailDeliveryAgentBin == "" {
|
||||||
c.MailDeliveryAgentBin = "maildrop"
|
c.MailDeliveryAgentBin = "maildrop"
|
||||||
|
|||||||
@@ -44,16 +44,20 @@ type Config struct {
|
|||||||
// Default: "systemd", which means systemd passes sockets to us.
|
// Default: "systemd", which means systemd passes sockets to us.
|
||||||
// systemd sockets must be named with "FileDescriptorName=submission".
|
// systemd sockets must be named with "FileDescriptorName=submission".
|
||||||
SubmissionAddress []string `protobuf:"bytes,4,rep,name=submission_address,json=submissionAddress" json:"submission_address,omitempty"`
|
SubmissionAddress []string `protobuf:"bytes,4,rep,name=submission_address,json=submissionAddress" json:"submission_address,omitempty"`
|
||||||
|
// Addresses to listen on for submission-over-TLS (usually port 465).
|
||||||
|
// Default: "systemd", which means systemd passes sockets to us.
|
||||||
|
// systemd sockets must be named with "FileDescriptorName=submission_tls".
|
||||||
|
SubmissionOverTlsAddress []string `protobuf:"bytes,5,rep,name=submission_over_tls_address,json=submissionOverTlsAddress" json:"submission_over_tls_address,omitempty"`
|
||||||
// Address for the monitoring http server.
|
// Address for the monitoring http server.
|
||||||
// Do NOT expose this to the public internet.
|
// Do NOT expose this to the public internet.
|
||||||
// Default: no monitoring http server.
|
// Default: no monitoring http server.
|
||||||
MonitoringAddress string `protobuf:"bytes,5,opt,name=monitoring_address,json=monitoringAddress" json:"monitoring_address,omitempty"`
|
MonitoringAddress string `protobuf:"bytes,6,opt,name=monitoring_address,json=monitoringAddress" json:"monitoring_address,omitempty"`
|
||||||
// Mail delivery agent (MDA, also known as LDA) to use.
|
// Mail delivery agent (MDA, also known as LDA) to use.
|
||||||
// This should point to the binary to use to deliver email to local users.
|
// This should point to the binary to use to deliver email to local users.
|
||||||
// The content of the email will be passed via stdin.
|
// The content of the email will be passed via stdin.
|
||||||
// If it exits unsuccessfully, we assume the mail was not delivered.
|
// If it exits unsuccessfully, we assume the mail was not delivered.
|
||||||
// Default: "maildrop".
|
// Default: "maildrop".
|
||||||
MailDeliveryAgentBin string `protobuf:"bytes,6,opt,name=mail_delivery_agent_bin,json=mailDeliveryAgentBin" json:"mail_delivery_agent_bin,omitempty"`
|
MailDeliveryAgentBin string `protobuf:"bytes,7,opt,name=mail_delivery_agent_bin,json=mailDeliveryAgentBin" json:"mail_delivery_agent_bin,omitempty"`
|
||||||
// Command line arguments for the mail delivery agent. One per argument.
|
// Command line arguments for the mail delivery agent. One per argument.
|
||||||
// Some replacements will be done.
|
// Some replacements will be done.
|
||||||
// On an email sent from marsnik@mars to venera@venus:
|
// On an email sent from marsnik@mars to venera@venus:
|
||||||
@@ -66,26 +70,26 @@ type Config struct {
|
|||||||
//
|
//
|
||||||
// Default: "-f", "%from%", "-d", "%to_user%" (adequate for procmail
|
// Default: "-f", "%from%", "-d", "%to_user%" (adequate for procmail
|
||||||
// and maildrop).
|
// and maildrop).
|
||||||
MailDeliveryAgentArgs []string `protobuf:"bytes,7,rep,name=mail_delivery_agent_args,json=mailDeliveryAgentArgs" json:"mail_delivery_agent_args,omitempty"`
|
MailDeliveryAgentArgs []string `protobuf:"bytes,8,rep,name=mail_delivery_agent_args,json=mailDeliveryAgentArgs" json:"mail_delivery_agent_args,omitempty"`
|
||||||
// Directory where we store our persistent data.
|
// Directory where we store our persistent data.
|
||||||
// Default: "/var/lib/chasquid"
|
// Default: "/var/lib/chasquid"
|
||||||
DataDir string `protobuf:"bytes,8,opt,name=data_dir,json=dataDir" json:"data_dir,omitempty"`
|
DataDir string `protobuf:"bytes,9,opt,name=data_dir,json=dataDir" json:"data_dir,omitempty"`
|
||||||
// Suffix separator, to perform suffix removal of local users.
|
// Suffix separator, to perform suffix removal of local users.
|
||||||
// For example, if you set this to "-+", email to local user
|
// For example, if you set this to "-+", email to local user
|
||||||
// "user-blah" and "user+blah" will be delivered to "user".
|
// "user-blah" and "user+blah" will be delivered to "user".
|
||||||
// Including "+" is strongly encouraged, as it is assumed for email
|
// Including "+" is strongly encouraged, as it is assumed for email
|
||||||
// forwarding.
|
// forwarding.
|
||||||
// Default: "+".
|
// Default: "+".
|
||||||
SuffixSeparators string `protobuf:"bytes,9,opt,name=suffix_separators,json=suffixSeparators" json:"suffix_separators,omitempty"`
|
SuffixSeparators string `protobuf:"bytes,10,opt,name=suffix_separators,json=suffixSeparators" json:"suffix_separators,omitempty"`
|
||||||
// Characters to drop from the user part on local emails.
|
// Characters to drop from the user part on local emails.
|
||||||
// For example, if you set this to "._", email to local user
|
// For example, if you set this to "._", email to local user
|
||||||
// "u.se_r" will be delivered to "user".
|
// "u.se_r" will be delivered to "user".
|
||||||
// Default: ".".
|
// Default: ".".
|
||||||
DropCharacters string `protobuf:"bytes,10,opt,name=drop_characters,json=dropCharacters" json:"drop_characters,omitempty"`
|
DropCharacters string `protobuf:"bytes,11,opt,name=drop_characters,json=dropCharacters" json:"drop_characters,omitempty"`
|
||||||
// Path where to write the mail log to.
|
// Path where to write the mail log to.
|
||||||
// If "<syslog>", log using the syslog (at MAIL|INFO priority).
|
// If "<syslog>", log using the syslog (at MAIL|INFO priority).
|
||||||
// Default: <syslog>
|
// Default: <syslog>
|
||||||
MailLogPath string `protobuf:"bytes,11,opt,name=mail_log_path,json=mailLogPath" json:"mail_log_path,omitempty"`
|
MailLogPath string `protobuf:"bytes,12,opt,name=mail_log_path,json=mailLogPath" json:"mail_log_path,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Config) Reset() { *m = Config{} }
|
func (m *Config) Reset() { *m = Config{} }
|
||||||
@@ -100,25 +104,27 @@ func init() {
|
|||||||
func init() { proto.RegisterFile("config.proto", fileDescriptor0) }
|
func init() { proto.RegisterFile("config.proto", fileDescriptor0) }
|
||||||
|
|
||||||
var fileDescriptor0 = []byte{
|
var fileDescriptor0 = []byte{
|
||||||
// 320 bytes of a gzipped FileDescriptorProto
|
// 351 bytes of a gzipped FileDescriptorProto
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x91, 0xcd, 0x4e, 0x02, 0x31,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x92, 0x4d, 0x4f, 0x22, 0x41,
|
||||||
0x10, 0x80, 0x83, 0xab, 0xfc, 0x14, 0x50, 0x68, 0x34, 0x56, 0x4f, 0xc8, 0x05, 0x12, 0xa3, 0x17,
|
0x10, 0x86, 0xc3, 0xc2, 0xf2, 0xd1, 0xc0, 0x2e, 0x74, 0x76, 0xb3, 0xbd, 0x7a, 0x41, 0x2e, 0x90,
|
||||||
0x63, 0x3c, 0x23, 0x1c, 0x35, 0x31, 0xf0, 0x00, 0xcd, 0x2c, 0x5b, 0xba, 0x93, 0xd0, 0x76, 0xd3,
|
0x18, 0xbd, 0x18, 0xe3, 0xc9, 0x03, 0xc2, 0x51, 0xa3, 0x01, 0xef, 0x9d, 0x1a, 0xa6, 0x99, 0xe9,
|
||||||
0x29, 0x06, 0x79, 0x4d, 0x5f, 0xc8, 0x6c, 0xd1, 0xc5, 0x44, 0x8f, 0xf3, 0x7d, 0xdf, 0x64, 0x27,
|
0x64, 0xba, 0x7b, 0x52, 0xd5, 0x10, 0xe4, 0x67, 0xf8, 0x8b, 0xcd, 0x34, 0x32, 0x90, 0xe8, 0xb1,
|
||||||
0x5b, 0xd6, 0x59, 0x3a, 0xbb, 0x42, 0x7d, 0x5f, 0x78, 0x17, 0xdc, 0xf0, 0x33, 0x61, 0xf5, 0x69,
|
0x9e, 0xf7, 0x79, 0x53, 0x35, 0x93, 0x66, 0x9d, 0xa5, 0xb3, 0x2b, 0x9d, 0x5c, 0xe7, 0xe8, 0xbc,
|
||||||
0x04, 0xfc, 0x9a, 0x35, 0x73, 0x47, 0xc1, 0x82, 0x51, 0xa2, 0x36, 0xa8, 0x8d, 0x5b, 0xf3, 0x6a,
|
0x1b, 0xbe, 0xd7, 0x58, 0x7d, 0x1a, 0x00, 0x3f, 0x63, 0xcd, 0xd4, 0x91, 0xb7, 0x60, 0x94, 0xa8,
|
||||||
0xe6, 0x23, 0xd6, 0x33, 0xb0, 0x95, 0x19, 0x04, 0x90, 0x84, 0x3b, 0x25, 0x4d, 0x2a, 0x8e, 0x06,
|
0x0c, 0x2a, 0xe3, 0xd6, 0xbc, 0x9c, 0xf9, 0x88, 0xf5, 0x0c, 0x6c, 0x65, 0x0c, 0x1e, 0x24, 0xe9,
|
||||||
0xb5, 0x71, 0x32, 0xef, 0x1a, 0xd8, 0xce, 0x20, 0xc0, 0x02, 0x77, 0xea, 0x35, 0xe5, 0x37, 0xac,
|
0x9d, 0x92, 0x26, 0x12, 0x3f, 0x06, 0x95, 0x71, 0x75, 0xde, 0x35, 0xb0, 0x9d, 0x81, 0x87, 0x85,
|
||||||
0x43, 0x26, 0x14, 0x12, 0xb2, 0xcc, 0x2b, 0x22, 0x91, 0x0c, 0x92, 0x71, 0x6b, 0xde, 0x2e, 0xd9,
|
0xde, 0xa9, 0xa7, 0x88, 0x5f, 0xb0, 0x0e, 0x19, 0x9f, 0x4b, 0x88, 0x63, 0x54, 0x44, 0xa2, 0x3a,
|
||||||
0x64, 0x8f, 0xf8, 0x1d, 0xe3, 0xb4, 0x49, 0x0d, 0x12, 0xa1, 0xb3, 0x55, 0x78, 0x1c, 0xc3, 0xfe,
|
0xa8, 0x8e, 0x5b, 0xf3, 0x76, 0xc1, 0x26, 0x7b, 0xc4, 0xaf, 0x18, 0xa7, 0x75, 0x64, 0x34, 0x91,
|
||||||
0xc1, 0xfc, 0xca, 0x8d, 0xb3, 0x18, 0x9c, 0x47, 0xab, 0xab, 0xfc, 0x24, 0x1e, 0xd8, 0x3f, 0x98,
|
0x76, 0xb6, 0x14, 0x6b, 0x41, 0xec, 0x1f, 0x93, 0x83, 0x7e, 0xcf, 0xce, 0x4f, 0x74, 0xb7, 0x51,
|
||||||
0x9f, 0xfc, 0x91, 0x5d, 0x1a, 0xc0, 0xb5, 0xcc, 0xd4, 0x1a, 0xdf, 0x95, 0xff, 0x90, 0xa0, 0x95,
|
0x28, 0x7d, 0x46, 0x65, 0xef, 0x67, 0xe8, 0x89, 0xa3, 0xf2, 0xbc, 0x51, 0xf8, 0x9a, 0xd1, 0xc9,
|
||||||
0x0d, 0x32, 0x45, 0x2b, 0xea, 0x71, 0xe7, 0xbc, 0xd4, 0xb3, 0x6f, 0x3b, 0x29, 0xe5, 0x33, 0x5a,
|
0x36, 0xe3, 0xac, 0xf6, 0x0e, 0xb5, 0x4d, 0xca, 0x56, 0x3d, 0x7c, 0x5f, 0xff, 0x98, 0x1c, 0xf4,
|
||||||
0xfe, 0xc4, 0xc4, 0x7f, 0x6b, 0xe0, 0x35, 0x89, 0x46, 0x3c, 0xed, 0xe2, 0xcf, 0xde, 0xc4, 0x6b,
|
0x5b, 0xf6, 0xcf, 0x80, 0xce, 0x64, 0xac, 0x32, 0xbd, 0x51, 0xf8, 0x26, 0x21, 0x51, 0xd6, 0xcb,
|
||||||
0xe2, 0x57, 0xac, 0x19, 0xff, 0x4a, 0x86, 0x5e, 0x34, 0xe3, 0x07, 0x1a, 0xe5, 0x3c, 0x43, 0xcf,
|
0x48, 0x5b, 0xd1, 0x08, 0x9d, 0x3f, 0x45, 0x3c, 0xfb, 0x4c, 0x27, 0x45, 0xf8, 0xa0, 0x2d, 0xbf,
|
||||||
0x6f, 0x59, 0x9f, 0x36, 0xab, 0x15, 0x6e, 0x25, 0xa9, 0x02, 0x3c, 0x04, 0xe7, 0x49, 0xb4, 0x62,
|
0x63, 0xe2, 0xbb, 0x1a, 0x60, 0x42, 0xa2, 0x19, 0x2e, 0xfc, 0xfb, 0xa5, 0x37, 0xc1, 0x84, 0xf8,
|
||||||
0xd3, 0xdb, 0x8b, 0x45, 0xc5, 0xf9, 0x88, 0x9d, 0x65, 0xde, 0x15, 0x72, 0x99, 0x83, 0x87, 0x65,
|
0x7f, 0xd6, 0x0c, 0x3f, 0x35, 0xd6, 0x28, 0x5a, 0x61, 0x41, 0xa3, 0x98, 0x67, 0x1a, 0xf9, 0x25,
|
||||||
0x50, 0x9e, 0x04, 0x8b, 0xe9, 0x69, 0x89, 0xa7, 0x15, 0xe5, 0x43, 0xd6, 0x8d, 0x97, 0xae, 0x9d,
|
0xeb, 0xd3, 0x7a, 0xb5, 0xd2, 0x5b, 0x49, 0x2a, 0x07, 0x04, 0xef, 0x90, 0x04, 0x0b, 0x4e, 0x6f,
|
||||||
0x96, 0x05, 0x84, 0x5c, 0xb4, 0x63, 0xd6, 0x2e, 0xe1, 0x8b, 0xd3, 0x6f, 0x10, 0xf2, 0xb4, 0x1e,
|
0x1f, 0x2c, 0x4a, 0xce, 0x47, 0xec, 0x77, 0x8c, 0x2e, 0x97, 0xcb, 0x14, 0x10, 0x96, 0x5e, 0x21,
|
||||||
0x1f, 0xf7, 0xe1, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x04, 0x0f, 0xa4, 0xff, 0xec, 0x01, 0x00, 0x00,
|
0x89, 0x76, 0x50, 0x7f, 0x15, 0x78, 0x5a, 0x52, 0x3e, 0x64, 0xdd, 0x70, 0x69, 0xe6, 0x12, 0x99,
|
||||||
|
0x83, 0x4f, 0x45, 0x27, 0x68, 0xed, 0x02, 0x3e, 0xba, 0xe4, 0x05, 0x7c, 0x1a, 0xd5, 0xc3, 0xdb,
|
||||||
|
0xb8, 0xf9, 0x08, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x6f, 0x6c, 0xff, 0x2b, 0x02, 0x00, 0x00,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,17 +21,22 @@ message Config {
|
|||||||
// systemd sockets must be named with "FileDescriptorName=submission".
|
// systemd sockets must be named with "FileDescriptorName=submission".
|
||||||
repeated string submission_address = 4;
|
repeated string submission_address = 4;
|
||||||
|
|
||||||
|
// Addresses to listen on for submission-over-TLS (usually port 465).
|
||||||
|
// Default: "systemd", which means systemd passes sockets to us.
|
||||||
|
// systemd sockets must be named with "FileDescriptorName=submission_tls".
|
||||||
|
repeated string submission_over_tls_address = 5;
|
||||||
|
|
||||||
// Address for the monitoring http server.
|
// Address for the monitoring http server.
|
||||||
// Do NOT expose this to the public internet.
|
// Do NOT expose this to the public internet.
|
||||||
// Default: no monitoring http server.
|
// Default: no monitoring http server.
|
||||||
string monitoring_address = 5;
|
string monitoring_address = 6;
|
||||||
|
|
||||||
// Mail delivery agent (MDA, also known as LDA) to use.
|
// Mail delivery agent (MDA, also known as LDA) to use.
|
||||||
// This should point to the binary to use to deliver email to local users.
|
// This should point to the binary to use to deliver email to local users.
|
||||||
// The content of the email will be passed via stdin.
|
// The content of the email will be passed via stdin.
|
||||||
// If it exits unsuccessfully, we assume the mail was not delivered.
|
// If it exits unsuccessfully, we assume the mail was not delivered.
|
||||||
// Default: "maildrop".
|
// Default: "maildrop".
|
||||||
string mail_delivery_agent_bin = 6;
|
string mail_delivery_agent_bin = 7;
|
||||||
|
|
||||||
// Command line arguments for the mail delivery agent. One per argument.
|
// Command line arguments for the mail delivery agent. One per argument.
|
||||||
// Some replacements will be done.
|
// Some replacements will be done.
|
||||||
@@ -45,11 +50,11 @@ message Config {
|
|||||||
//
|
//
|
||||||
// Default: "-f", "%from%", "-d", "%to_user%" (adequate for procmail
|
// Default: "-f", "%from%", "-d", "%to_user%" (adequate for procmail
|
||||||
// and maildrop).
|
// and maildrop).
|
||||||
repeated string mail_delivery_agent_args = 7;
|
repeated string mail_delivery_agent_args = 8;
|
||||||
|
|
||||||
// Directory where we store our persistent data.
|
// Directory where we store our persistent data.
|
||||||
// Default: "/var/lib/chasquid"
|
// Default: "/var/lib/chasquid"
|
||||||
string data_dir = 8;
|
string data_dir = 9;
|
||||||
|
|
||||||
// Suffix separator, to perform suffix removal of local users.
|
// Suffix separator, to perform suffix removal of local users.
|
||||||
// For example, if you set this to "-+", email to local user
|
// For example, if you set this to "-+", email to local user
|
||||||
@@ -57,17 +62,17 @@ message Config {
|
|||||||
// Including "+" is strongly encouraged, as it is assumed for email
|
// Including "+" is strongly encouraged, as it is assumed for email
|
||||||
// forwarding.
|
// forwarding.
|
||||||
// Default: "+".
|
// Default: "+".
|
||||||
string suffix_separators = 9;
|
string suffix_separators = 10;
|
||||||
|
|
||||||
// Characters to drop from the user part on local emails.
|
// Characters to drop from the user part on local emails.
|
||||||
// For example, if you set this to "._", email to local user
|
// For example, if you set this to "._", email to local user
|
||||||
// "u.se_r" will be delivered to "user".
|
// "u.se_r" will be delivered to "user".
|
||||||
// Default: ".".
|
// Default: ".".
|
||||||
string drop_characters = 10;
|
string drop_characters = 11;
|
||||||
|
|
||||||
// Path where to write the mail log to.
|
// Path where to write the mail log to.
|
||||||
// If "<syslog>", log using the syslog (at MAIL|INFO priority).
|
// If "<syslog>", log using the syslog (at MAIL|INFO priority).
|
||||||
// Default: <syslog>
|
// Default: <syslog>
|
||||||
string mail_log_path = 11;
|
string mail_log_path = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,12 +55,31 @@ var (
|
|||||||
|
|
||||||
// Mode for a socket (listening or connection).
|
// Mode for a socket (listening or connection).
|
||||||
// We keep them distinct, as policies can differ between them.
|
// We keep them distinct, as policies can differ between them.
|
||||||
type SocketMode string
|
type SocketMode struct {
|
||||||
|
// Is this mode submission?
|
||||||
|
IsSubmission bool
|
||||||
|
|
||||||
|
// Is this mode TLS-wrapped? That means that we don't use STARTTLS, the
|
||||||
|
// connection is directly established over TLS (like HTTPS).
|
||||||
|
TLS bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mode SocketMode) String() string {
|
||||||
|
s := "SMTP"
|
||||||
|
if mode.IsSubmission {
|
||||||
|
s = "submission"
|
||||||
|
}
|
||||||
|
if mode.TLS {
|
||||||
|
s += "+TLS"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
// Valid socket modes.
|
// Valid socket modes.
|
||||||
const (
|
var (
|
||||||
ModeSMTP SocketMode = "SMTP"
|
ModeSMTP = SocketMode{IsSubmission: false, TLS: false}
|
||||||
ModeSubmission SocketMode = "submission"
|
ModeSubmission = SocketMode{IsSubmission: true, TLS: false}
|
||||||
|
ModeSubmissionTLS = SocketMode{IsSubmission: true, TLS: true}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Incoming SMTP connection.
|
// Incoming SMTP connection.
|
||||||
@@ -137,6 +156,7 @@ func (c *Conn) Handle() {
|
|||||||
|
|
||||||
c.tr = trace.New("SMTP.Conn", c.conn.RemoteAddr().String())
|
c.tr = trace.New("SMTP.Conn", c.conn.RemoteAddr().String())
|
||||||
defer c.tr.Finish()
|
defer c.tr.Finish()
|
||||||
|
c.tr.Debugf("Connected, mode: %s", c.mode)
|
||||||
|
|
||||||
c.tc.PrintfLine("220 %s ESMTP chasquid", c.hostname)
|
c.tc.PrintfLine("220 %s ESMTP chasquid", c.hostname)
|
||||||
|
|
||||||
@@ -314,7 +334,7 @@ func (c *Conn) MAIL(params string) (code int, msg string) {
|
|||||||
if !strings.HasPrefix(strings.ToLower(params), "from:") {
|
if !strings.HasPrefix(strings.ToLower(params), "from:") {
|
||||||
return 500, "unknown command"
|
return 500, "unknown command"
|
||||||
}
|
}
|
||||||
if c.mode == ModeSubmission && !c.completedAuth {
|
if c.mode.IsSubmission && !c.completedAuth {
|
||||||
return 550, "mail to submission port must be authenticated"
|
return 550, "mail to submission port must be authenticated"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -199,6 +199,11 @@ func (s *Server) ListenAndServe() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) serve(l net.Listener, mode SocketMode) {
|
func (s *Server) serve(l net.Listener, mode SocketMode) {
|
||||||
|
// If this mode is expected to be TLS-wrapped, make it so.
|
||||||
|
if mode.TLS {
|
||||||
|
l = tls.NewListener(l, s.tlsConfig)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
conn, err := l.Accept()
|
conn, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -213,6 +218,7 @@ func (s *Server) serve(l net.Listener, mode SocketMode) {
|
|||||||
tc: textproto.NewConn(conn),
|
tc: textproto.NewConn(conn),
|
||||||
mode: mode,
|
mode: mode,
|
||||||
tlsConfig: s.tlsConfig,
|
tlsConfig: s.tlsConfig,
|
||||||
|
onTLS: mode.TLS,
|
||||||
userDBs: s.userDBs,
|
userDBs: s.userDBs,
|
||||||
aliasesR: s.aliasesR,
|
aliasesR: s.aliasesR,
|
||||||
localDomains: s.localDomains,
|
localDomains: s.localDomains,
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ var (
|
|||||||
// TODO: Don't hard-code the default.
|
// TODO: Don't hard-code the default.
|
||||||
smtpAddr = "127.0.0.1:13444"
|
smtpAddr = "127.0.0.1:13444"
|
||||||
submissionAddr = "127.0.0.1:13999"
|
submissionAddr = "127.0.0.1:13999"
|
||||||
|
submissionTLSAddr = "127.0.0.1:13777"
|
||||||
|
|
||||||
// TLS configuration to use in the clients.
|
// TLS configuration to use in the clients.
|
||||||
// Will contain the generated server certificate as root CA.
|
// Will contain the generated server certificate as root CA.
|
||||||
@@ -46,14 +47,28 @@ var (
|
|||||||
// === Tests ===
|
// === Tests ===
|
||||||
//
|
//
|
||||||
|
|
||||||
func mustDial(tb testing.TB, mode SocketMode, useTLS bool) *smtp.Client {
|
func mustDial(tb testing.TB, mode SocketMode, startTLS bool) *smtp.Client {
|
||||||
addr := ""
|
addr := ""
|
||||||
if mode == ModeSMTP {
|
switch mode {
|
||||||
|
case ModeSMTP:
|
||||||
addr = smtpAddr
|
addr = smtpAddr
|
||||||
} else {
|
case ModeSubmission:
|
||||||
addr = submissionAddr
|
addr = submissionAddr
|
||||||
|
case ModeSubmissionTLS:
|
||||||
|
addr = submissionTLSAddr
|
||||||
}
|
}
|
||||||
c, err := smtp.Dial(addr)
|
|
||||||
|
var err error
|
||||||
|
var conn net.Conn
|
||||||
|
if mode.TLS {
|
||||||
|
conn, err = tls.Dial("tcp", addr, tlsConfig)
|
||||||
|
} else {
|
||||||
|
conn, err = net.Dial("tcp", addr)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
tb.Fatalf("(net||tls).Dial: %v", err)
|
||||||
|
}
|
||||||
|
c, err := smtp.NewClient(conn, "127.0.0.1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tb.Fatalf("smtp.Dial: %v", err)
|
tb.Fatalf("smtp.Dial: %v", err)
|
||||||
}
|
}
|
||||||
@@ -62,7 +77,7 @@ func mustDial(tb testing.TB, mode SocketMode, useTLS bool) *smtp.Client {
|
|||||||
tb.Fatalf("c.Hello: %v", err)
|
tb.Fatalf("c.Hello: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if useTLS {
|
if startTLS {
|
||||||
if ok, _ := c.Extension("STARTTLS"); !ok {
|
if ok, _ := c.Extension("STARTTLS"); !ok {
|
||||||
tb.Fatalf("STARTTLS not advertised in EHLO")
|
tb.Fatalf("STARTTLS not advertised in EHLO")
|
||||||
}
|
}
|
||||||
@@ -153,6 +168,14 @@ func TestSubmissionWithoutAuth(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAuthOnTLS(t *testing.T) {
|
||||||
|
c := mustDial(t, ModeSubmissionTLS, false)
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
auth := smtp.PlainAuth("", "testuser@localhost", "testpasswd", "127.0.0.1")
|
||||||
|
sendEmailWithAuth(t, c, auth)
|
||||||
|
}
|
||||||
|
|
||||||
func TestAuthOnSMTP(t *testing.T) {
|
func TestAuthOnSMTP(t *testing.T) {
|
||||||
c := mustDial(t, ModeSMTP, true)
|
c := mustDial(t, ModeSMTP, true)
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
@@ -285,6 +308,16 @@ func TestRepeatedStartTLS(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that STARTTLS fails on a TLS connection.
|
||||||
|
func TestStartTLSOnTLS(t *testing.T) {
|
||||||
|
c := mustDial(t, ModeSubmissionTLS, false)
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if err := c.StartTLS(tlsConfig); err == nil {
|
||||||
|
t.Errorf("STARTTLS did not fail as expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// === Benchmarks ===
|
// === Benchmarks ===
|
||||||
//
|
//
|
||||||
@@ -440,6 +473,7 @@ func realMain(m *testing.M) int {
|
|||||||
s.AddCerts(tmpDir+"/cert.pem", tmpDir+"/key.pem")
|
s.AddCerts(tmpDir+"/cert.pem", tmpDir+"/key.pem")
|
||||||
s.AddAddr(smtpAddr, ModeSMTP)
|
s.AddAddr(smtpAddr, ModeSMTP)
|
||||||
s.AddAddr(submissionAddr, ModeSubmission)
|
s.AddAddr(submissionAddr, ModeSubmission)
|
||||||
|
s.AddAddr(submissionTLSAddr, ModeSubmissionTLS)
|
||||||
|
|
||||||
localC := &courier.Procmail{}
|
localC := &courier.Procmail{}
|
||||||
remoteC := &courier.SMTP{}
|
remoteC := &courier.SMTP{}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -15,6 +15,10 @@ password secretpassword
|
|||||||
account smtpport : default
|
account smtpport : default
|
||||||
port 1025
|
port 1025
|
||||||
|
|
||||||
|
account subm_tls : default
|
||||||
|
port 1465
|
||||||
|
tls_starttls off
|
||||||
|
|
||||||
account baduser : default
|
account baduser : default
|
||||||
user unknownuser@testserver
|
user unknownuser@testserver
|
||||||
password secretpassword
|
password secretpassword
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ if ! run_msmtp -a smtpport someone@testserver < content 2> /dev/null; then
|
|||||||
fail "failed auth on the SMTP port"
|
fail "failed auth on the SMTP port"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Check deliver over the submission-over-TLS port.
|
||||||
|
if ! run_msmtp -a subm_tls someone@testserver < content 2> /dev/null; then
|
||||||
|
fail "failed submission over TLS"
|
||||||
|
fi
|
||||||
|
|
||||||
if run_msmtp nobody@testserver < content 2> /dev/null; then
|
if run_msmtp nobody@testserver < content 2> /dev/null; then
|
||||||
fail "successfuly sent an email to a non-existent user"
|
fail "successfuly sent an email to a non-existent user"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ hostname: "testserver"
|
|||||||
|
|
||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":2025"
|
smtp_address: ":2025"
|
||||||
submission_address: ":2587"
|
submission_address: ":2587"
|
||||||
|
submission_over_tls_address: ":2465"
|
||||||
monitoring_address: ":2099"
|
monitoring_address: ":2099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":2025"
|
smtp_address: ":2025"
|
||||||
submission_address: ":2587"
|
submission_address: ":2587"
|
||||||
|
submission_over_tls_address: ":2465"
|
||||||
monitoring_address: ":2099"
|
monitoring_address: ":2099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
smtp_address: ":1025"
|
smtp_address: ":1025"
|
||||||
submission_address: ":1587"
|
submission_address: ":1587"
|
||||||
|
submission_over_tls_address: ":1465"
|
||||||
monitoring_address: ":1099"
|
monitoring_address: ":1099"
|
||||||
|
|
||||||
mail_delivery_agent_bin: "test-mda"
|
mail_delivery_agent_bin: "test-mda"
|
||||||
|
|||||||
Reference in New Issue
Block a user