1
0
mirror of https://blitiri.com.ar/repos/chasquid synced 2025-12-18 14:47:03 +00:00

chasquid: Add "Received" email headers

This patch makes chasquid add "Received" email headers, after DATA completes
and before queueing.

We only use this for debugging purposes.
This commit is contained in:
Alberto Bertogli
2016-09-23 00:16:07 +01:00
parent 5f15b4e040
commit d05b8ef189
2 changed files with 62 additions and 8 deletions

View File

@@ -376,9 +376,10 @@ type Conn struct {
maxDataSize int64 maxDataSize int64
// Connection information. // Connection information.
netconn net.Conn netconn net.Conn
tc *textproto.Conn tc *textproto.Conn
mode SocketMode mode SocketMode
tlsConnState *tls.ConnectionState
// System configuration. // System configuration.
config *config.Config config *config.Config
@@ -675,6 +676,8 @@ func (c *Conn) DATA(params string, tr *trace.Trace) (code int, msg string) {
tr.LazyPrintf("-> ... %d bytes of data", len(c.data)) tr.LazyPrintf("-> ... %d bytes of data", len(c.data))
c.addReceivedHeader()
// There are no partial failures here: we put it in the queue, and then if // There are no partial failures here: we put it in the queue, and then if
// individual deliveries fail, we report via email. // individual deliveries fail, we report via email.
msgID, err := c.queue.Put(c.mailFrom, c.rcptTo, c.data) msgID, err := c.queue.Put(c.mailFrom, c.rcptTo, c.data)
@@ -700,6 +703,34 @@ func (c *Conn) DATA(params string, tr *trace.Trace) (code int, msg string) {
return 250, msgs[rand.Int()%len(msgs)] return 250, msgs[rand.Int()%len(msgs)]
} }
func (c *Conn) addReceivedHeader() {
var v string
if c.completedAuth {
v += fmt.Sprintf("from user %s@%s\n", c.authUser, c.authDomain)
} else {
v += fmt.Sprintf("from %s\n", c.netconn.RemoteAddr().String())
}
v += fmt.Sprintf("by %s (chasquid SMTP) over ", c.hostname)
if c.tlsConnState != nil {
v += fmt.Sprintf("TLS (%#x-%#x)\n",
c.tlsConnState.Version, c.tlsConnState.CipherSuite)
} else {
v += "plain text!\n"
}
// Note we must NOT include c.rcptTo, that would leak BCCs.
v += fmt.Sprintf("(envelope from %q)\n", c.mailFrom)
// This should be the last part in the Received header, by RFC.
// The ";" is a mandatory separator. The date format is not standard but
// this one seems to be widely used.
// https://tools.ietf.org/html/rfc5322#section-3.6.7
v += fmt.Sprintf("on ; %s\n", time.Now().Format(time.RFC1123Z))
c.data = envelope.AddHeader(c.data, "Received", v)
}
func (c *Conn) STARTTLS(params string, tr *trace.Trace) (code int, msg string) { func (c *Conn) STARTTLS(params string, tr *trace.Trace) (code int, msg string) {
if c.onTLS { if c.onTLS {
return 503, "You are already wearing that!" return 503, "You are already wearing that!"
@@ -712,23 +743,34 @@ func (c *Conn) STARTTLS(params string, tr *trace.Trace) (code int, msg string) {
tr.LazyPrintf("<- 220 You experience a strange sense of peace") tr.LazyPrintf("<- 220 You experience a strange sense of peace")
client := tls.Server(c.netconn, c.tlsConfig) server := tls.Server(c.netconn, c.tlsConfig)
err = client.Handshake() err = server.Handshake()
if err != nil { if err != nil {
return 554, fmt.Sprintf("error in client handshake: %v", err) return 554, fmt.Sprintf("error in TLS handshake: %v", err)
} }
tr.LazyPrintf("<> ... jump to TLS was successful") tr.LazyPrintf("<> ... jump to TLS was successful")
// Override the connections. We don't need the older ones anymore. // Override the connections. We don't need the older ones anymore.
c.netconn = client c.netconn = server
c.tc = textproto.NewConn(client) c.tc = textproto.NewConn(server)
// Take the connection state, so we can use it later for logging and
// tracing purposes.
cstate := server.ConnectionState()
c.tlsConnState = &cstate
// Reset the envelope; clients must start over after switching to TLS. // Reset the envelope; clients must start over after switching to TLS.
c.resetEnvelope() c.resetEnvelope()
c.onTLS = true c.onTLS = true
// If the client requested a specific server and we complied, that's our
// identity from now on.
if name := c.tlsConnState.ServerName; name != "" {
c.hostname = name
}
// 0 indicates not to send back a reply. // 0 indicates not to send back a reply.
return 0, "" return 0, ""
} }

View File

@@ -3,6 +3,7 @@
package envelope package envelope
import ( import (
"fmt"
"strings" "strings"
"blitiri.com.ar/go/chasquid/internal/set" "blitiri.com.ar/go/chasquid/internal/set"
@@ -36,3 +37,14 @@ func DomainIn(addr string, locals *set.String) bool {
return locals.Has(domain) return locals.Has(domain)
} }
func AddHeader(data []byte, k, v string) []byte {
// If the value contains newlines, indent them properly.
if v[len(v)-1] == '\n' {
v = v[:len(v)-1]
}
v = strings.Replace(v, "\n", "\n\t", -1)
header := []byte(fmt.Sprintf("%s: %s\n", k, v))
return append(header, data...)
}