author | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-10-08 11:36:48 UTC |
committer | Alberto Bertogli
<albertito@blitiri.com.ar> 2016-10-09 23:51:05 UTC |
parent | 641406cede9a4e9fb967c08650610a65f28a69b3 |
chasquid.go | +14 | -0 |
internal/courier/smtp.go | +10 | -0 |
internal/queue/queue.go | +15 | -0 |
diff --git a/chasquid.go b/chasquid.go index ae5b261..a5ecbe2 100644 --- a/chasquid.go +++ b/chasquid.go @@ -3,6 +3,7 @@ package main import ( "bytes" "crypto/tls" + "expvar" "flag" "fmt" "io" @@ -14,6 +15,7 @@ import ( "os" "os/signal" "path/filepath" + "strconv" "strings" "syscall" "time" @@ -37,11 +39,19 @@ import ( "github.com/golang/glog" ) +// Command-line flags. var ( configDir = flag.String("config_dir", "/etc/chasquid", "configuration directory") ) +// Exported variables. +var ( + commandCount = expvar.NewMap("chasquid/smtpIn/commandCount") + responseCodeCount = expvar.NewMap("chasquid/smtpIn/responseCodeCount") + spfResultCount = expvar.NewMap("chasquid/smtpIn/spfResultCount") +) + func main() { flag.Parse() @@ -476,6 +486,7 @@ loop: break } + commandCount.Add(cmd, 1) if cmd == "AUTH" { c.tr.Debugf("-> AUTH <redacted>") } else { @@ -642,6 +653,8 @@ func (c *Conn) MAIL(params string) (code int, msg string) { c.spfResult, c.spfError = spf.CheckHost( tcp.IP, envelope.DomainOf(e.Address)) c.tr.Debugf("SPF %v (%v)", c.spfResult, c.spfError) + spfResultCount.Add(string(c.spfResult), 1) + // https://tools.ietf.org/html/rfc7208#section-8 // We opt not to fail on errors, to avoid accidents to prevent // delivery. @@ -964,6 +977,7 @@ func (c *Conn) readLine() (line string, err error) { func (c *Conn) writeResponse(code int, msg string) error { defer c.tc.W.Flush() + responseCodeCount.Add(strconv.Itoa(code), 1) return writeResponse(c.tc.W, code, msg) } diff --git a/internal/courier/smtp.go b/internal/courier/smtp.go index 6e3b916..f57faa7 100644 --- a/internal/courier/smtp.go +++ b/internal/courier/smtp.go @@ -2,6 +2,7 @@ package courier import ( "crypto/tls" + "expvar" "flag" "net" "os" @@ -29,6 +30,11 @@ var ( fakeMX = map[string]string{} ) +// Exported variables. +var ( + tlsCount = expvar.NewMap("chasquid/smtpOut/tlsCount") +) + // SMTP delivers remote mail via outgoing SMTP. type SMTP struct { } @@ -91,6 +97,7 @@ retry: // Unfortunately, many servers use self-signed certs, so if we // fail verification we just try again without validating. if insecure { + tlsCount.Add("tls:failed", 1) return tr.Errorf("TLS error: %v", err), false } @@ -101,10 +108,13 @@ retry: if config.InsecureSkipVerify { tr.Debugf("Insecure - using TLS, but cert does not match %s", mx) + tlsCount.Add("tls:insecure", 1) } else { + tlsCount.Add("tls:secure", 1) tr.Debugf("Secure - using TLS") } } else { + tlsCount.Add("plain", 1) tr.Debugf("Insecure - NOT using TLS") } diff --git a/internal/queue/queue.go b/internal/queue/queue.go index 363ff78..dd043d7 100644 --- a/internal/queue/queue.go +++ b/internal/queue/queue.go @@ -9,6 +9,7 @@ import ( "context" "crypto/rand" "encoding/base64" + "expvar" "fmt" "os" "os/exec" @@ -51,6 +52,14 @@ var ( errQueueFull = fmt.Errorf("Queue size too big, try again later") ) +// Exported variables. +var ( + putCount = expvar.NewInt("chasquid/queue/putCount") + itemsWritten = expvar.NewInt("chasquid/queue/itemsWritten") + dsnQueued = expvar.NewInt("chasquid/queue/dsnQueued") + deliverAttempts = expvar.NewMap("chasquid/queue/deliverAttempts") +) + // Channel used to get random IDs for items in the queue. var newID chan string @@ -148,6 +157,7 @@ func (q *Queue) Put(hostname, from string, to []string, data []byte) (string, er if q.Len() >= maxQueueSize { return "", errQueueFull } + putCount.Add(1) item := &Item{ Message: Message{ @@ -272,6 +282,7 @@ func ItemFromFile(fname string) (*Item, error) { func (item *Item) WriteTo(dir string) error { item.Lock() defer item.Unlock() + itemsWritten.Add(1) var err error item.CreatedAtTs, err = ptypes.TimestampProto(item.CreatedAt) @@ -394,12 +405,14 @@ func sendDSN(tr *trace.Trace, q *Queue, item *Item) { } tr.Printf("queued DSN: %s", id) + dsnQueued.Add(1) } // deliver the item to the given recipient, using the couriers from the queue. // Return an error (if any), and whether it is permanent or not. func (item *Item) deliver(q *Queue, rcpt *Recipient) (err error, permanent bool) { if rcpt.Type == Recipient_PIPE { + deliverAttempts.Add("pipe", 1) c := strings.Fields(rcpt.Address) if len(c) == 0 { return fmt.Errorf("empty pipe"), true @@ -413,8 +426,10 @@ func (item *Item) deliver(q *Queue, rcpt *Recipient) (err error, permanent bool) } else { if envelope.DomainIn(rcpt.Address, q.localDomains) { + deliverAttempts.Add("email:local", 1) return q.localC.Deliver(item.From, rcpt.Address, item.Data) } else { + deliverAttempts.Add("email:remote", 1) from := item.From if !envelope.DomainIn(item.From, q.localDomains) { // We're sending from a non-local to a non-local. This should