1
0
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:
Alberto Bertogli
2016-10-13 02:28:30 +01:00
parent 1d7a207e00
commit c013c98283
8 changed files with 545 additions and 11 deletions

View File

@@ -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 = ""

View File

@@ -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)