mirror of
https://github.com/foxcpp/maddy.git
synced 2025-04-06 22:47:37 +03:00
As revealed by latency tracing using runtime/trace, MTA-STS cache miss essentially doubles the connection time for outbound delivery. This is mostly because MTA-STS lookup have to estabilish a TCP+TLS connection to obtain the policy text (shame on Google for pushing that terribly misdesigned protocol, but, well, it is better than nothing so we adopt it). Additionally, there is a number of additional DNS lookups needed (e.g. TLSA record for DANE). This commit rearranges connection code so it is possible to run all "additional" queries in parallel with the connection estabilishment. However, this changes the behavior of TLS requirement checks (including MTA-STS). The connection to the candidate MX is already estabilished and STARTTLS is always attempted if it is available. Only after that the policy check is done, using the result of TLS handshake attempt (if any). If for whatever reason, the candidate MX cannot be used, the connection is then closed. This might bring additional overhead in case of configuration errors on the recipient side, but it is believed to not be a major problem since this should not happen often.
87 lines
2.4 KiB
Go
87 lines
2.4 KiB
Go
package target
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/foxcpp/maddy/internal/address"
|
|
"github.com/foxcpp/maddy/internal/dns"
|
|
"github.com/foxcpp/maddy/internal/module"
|
|
)
|
|
|
|
func SanitizeForHeader(raw string) string {
|
|
return strings.Replace(raw, "\n", "", -1)
|
|
}
|
|
|
|
func GenerateReceived(ctx context.Context, msgMeta *module.MsgMetadata, ourHostname, mailFrom string) (string, error) {
|
|
if msgMeta.Conn == nil {
|
|
return "", errors.New("can't generate Received for a locally generated message")
|
|
}
|
|
|
|
builder := strings.Builder{}
|
|
|
|
// Empirically guessed value that should be enough to fit
|
|
// the entire value in most cases.
|
|
builder.Grow(256 + len(msgMeta.Conn.Hostname))
|
|
|
|
if !msgMeta.DontTraceSender && (strings.Contains(msgMeta.Conn.Proto, "SMTP") ||
|
|
strings.Contains(msgMeta.Conn.Proto, "LMTP")) {
|
|
|
|
// INTERNATIONALIZATION: See RFC 6531 Section 3.7.3.
|
|
hostname, err := dns.SelectIDNA(msgMeta.SMTPOpts.UTF8, msgMeta.Conn.Hostname)
|
|
if err == nil {
|
|
builder.WriteString("from ")
|
|
builder.WriteString(hostname)
|
|
}
|
|
|
|
if tcpAddr, ok := msgMeta.Conn.RemoteAddr.(*net.TCPAddr); ok {
|
|
builder.WriteString(" (")
|
|
if msgMeta.Conn.RDNSName != nil {
|
|
rdnsName, err := msgMeta.Conn.RDNSName.GetContext(ctx)
|
|
if err == nil && rdnsName != nil && rdnsName.(string) != "" {
|
|
// INTERNATIONALIZATION: See RFC 6531 Section 3.7.3.
|
|
encoded, err := dns.SelectIDNA(msgMeta.SMTPOpts.UTF8, rdnsName.(string))
|
|
if err == nil {
|
|
builder.WriteString(encoded)
|
|
builder.WriteRune(' ')
|
|
}
|
|
}
|
|
|
|
}
|
|
builder.WriteRune('[')
|
|
builder.WriteString(tcpAddr.IP.String())
|
|
builder.WriteString("])")
|
|
}
|
|
}
|
|
|
|
ourHostname, err := dns.SelectIDNA(msgMeta.SMTPOpts.UTF8, ourHostname)
|
|
if err == nil {
|
|
builder.WriteString(" by ")
|
|
builder.WriteString(SanitizeForHeader(ourHostname))
|
|
}
|
|
|
|
// INTERNATIONALIZATION: See RFC 6531 Section 3.7.3.
|
|
mailFrom, err = address.SelectIDNA(msgMeta.SMTPOpts.UTF8, mailFrom)
|
|
if err == nil {
|
|
builder.WriteString(" (envelope-sender <")
|
|
builder.WriteString(SanitizeForHeader(mailFrom))
|
|
builder.WriteString(">)")
|
|
}
|
|
|
|
if msgMeta.Conn.Proto != "" {
|
|
builder.WriteString(" with ")
|
|
if msgMeta.SMTPOpts.UTF8 {
|
|
builder.WriteString("UTF8")
|
|
}
|
|
builder.WriteString(msgMeta.Conn.Proto)
|
|
}
|
|
builder.WriteString(" id ")
|
|
builder.WriteString(msgMeta.ID)
|
|
builder.WriteString("; ")
|
|
builder.WriteString(time.Now().Format(time.RFC1123Z))
|
|
|
|
return builder.String(), nil
|
|
}
|