mirror of
https://blitiri.com.ar/repos/chasquid
synced 2026-01-26 20:35:56 +00:00
domaininfo: New package to track domain (security) information
This patch introduces a new "domaininfo" package, which implements a database with information about domains. In particular, it tracks incoming and outgoing security levels. That information is used in incoming and outgoing SMTP to prevent downgrades.
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/golang/glog"
|
||||
"golang.org/x/net/idna"
|
||||
|
||||
"blitiri.com.ar/go/chasquid/internal/domaininfo"
|
||||
"blitiri.com.ar/go/chasquid/internal/envelope"
|
||||
"blitiri.com.ar/go/chasquid/internal/smtp"
|
||||
"blitiri.com.ar/go/chasquid/internal/trace"
|
||||
@@ -32,11 +33,13 @@ var (
|
||||
|
||||
// Exported variables.
|
||||
var (
|
||||
tlsCount = expvar.NewMap("chasquid/smtpOut/tlsCount")
|
||||
tlsCount = expvar.NewMap("chasquid/smtpOut/tlsCount")
|
||||
slcResults = expvar.NewMap("chasquid/smtpOut/securityLevelChecks")
|
||||
)
|
||||
|
||||
// SMTP delivers remote mail via outgoing SMTP.
|
||||
type SMTP struct {
|
||||
Dinfo *domaininfo.DB
|
||||
}
|
||||
|
||||
func (s *SMTP) Deliver(from string, to string, data []byte) (error, bool) {
|
||||
@@ -44,7 +47,8 @@ func (s *SMTP) Deliver(from string, to string, data []byte) (error, bool) {
|
||||
defer tr.Finish()
|
||||
tr.Debugf("%s -> %s", from, to)
|
||||
|
||||
mx, err := lookupMX(envelope.DomainOf(to))
|
||||
toDomain := envelope.DomainOf(to)
|
||||
mx, err := lookupMX(toDomain)
|
||||
if err != nil {
|
||||
// Note this is considered a permanent error.
|
||||
// This is in line with what other servers (Exim) do. However, the
|
||||
@@ -68,6 +72,7 @@ func (s *SMTP) Deliver(from string, to string, data []byte) (error, bool) {
|
||||
// Do we use insecure TLS?
|
||||
// Set as fallback when retrying.
|
||||
insecure := false
|
||||
secLevel := domaininfo.SecLevel_PLAIN
|
||||
|
||||
retry:
|
||||
conn, err := net.DialTimeout("tcp", mx+":"+*smtpPort, smtpDialTimeout)
|
||||
@@ -110,15 +115,25 @@ retry:
|
||||
if config.InsecureSkipVerify {
|
||||
tr.Debugf("Insecure - using TLS, but cert does not match %s", mx)
|
||||
tlsCount.Add("tls:insecure", 1)
|
||||
secLevel = domaininfo.SecLevel_TLS_INSECURE
|
||||
} else {
|
||||
tlsCount.Add("tls:secure", 1)
|
||||
tr.Debugf("Secure - using TLS")
|
||||
secLevel = domaininfo.SecLevel_TLS_SECURE
|
||||
}
|
||||
} else {
|
||||
tlsCount.Add("plain", 1)
|
||||
tr.Debugf("Insecure - NOT using TLS")
|
||||
}
|
||||
|
||||
if toDomain != "" && !s.Dinfo.OutgoingSecLevel(toDomain, secLevel) {
|
||||
// We consider the failure transient, so transient misconfigurations
|
||||
// do not affect deliveries.
|
||||
slcResults.Add("fail", 1)
|
||||
return tr.Errorf("Security level check failed (level:%s)", secLevel), false
|
||||
}
|
||||
slcResults.Add("pass", 1)
|
||||
|
||||
// c.Mail will add the <> for us when the address is empty.
|
||||
if from == "<>" {
|
||||
from = ""
|
||||
|
||||
@@ -2,12 +2,30 @@ package courier
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"blitiri.com.ar/go/chasquid/internal/domaininfo"
|
||||
)
|
||||
|
||||
func newSMTP(t *testing.T) (*SMTP, string) {
|
||||
dir, err := ioutil.TempDir("", "smtp_test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
dinfo, err := domaininfo.New(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return &SMTP{dinfo}, dir
|
||||
}
|
||||
|
||||
// Fake server, to test SMTP out.
|
||||
func fakeServer(t *testing.T, responses map[string]string) string {
|
||||
l, err := net.Listen("tcp", "localhost:0")
|
||||
@@ -72,7 +90,8 @@ func TestSMTP(t *testing.T) {
|
||||
fakeMX["to"] = host
|
||||
*smtpPort = port
|
||||
|
||||
s := &SMTP{}
|
||||
s, tmpDir := newSMTP(t)
|
||||
defer os.Remove(tmpDir)
|
||||
err, _ := s.Deliver("me@me", "to@to", []byte("data"))
|
||||
if err != nil {
|
||||
t.Errorf("deliver failed: %v", err)
|
||||
@@ -132,7 +151,8 @@ func TestSMTPErrors(t *testing.T) {
|
||||
fakeMX["to"] = host
|
||||
*smtpPort = port
|
||||
|
||||
s := &SMTP{}
|
||||
s, tmpDir := newSMTP(t)
|
||||
defer os.Remove(tmpDir)
|
||||
err, _ := s.Deliver("me@me", "to@to", []byte("data"))
|
||||
if err == nil {
|
||||
t.Errorf("deliver not failed in case %q: %v", rs["_welcome"], err)
|
||||
|
||||
Reference in New Issue
Block a user