mirror of
https://github.com/mjl-/mox.git
synced 2025-07-14 07:34:36 +03:00
do not lookup cname after looking up the txt for mta-sts, and follow cnames for mocks
because the txt would already follow cnames. the additional cname lookup didn't hurt, it just didn't do anything. i probably didn't realize that before looking deeper into dns.
This commit is contained in:
@ -162,45 +162,26 @@ var (
|
||||
)
|
||||
|
||||
// LookupRecord looks up the MTA-STS TXT DNS record at "_mta-sts.<domain>",
|
||||
// following CNAME records, and returns the parsed MTA-STS record, the DNS TXT
|
||||
// record and any CNAMEs that were followed.
|
||||
func LookupRecord(ctx context.Context, resolver dns.Resolver, domain dns.Domain) (rrecord *Record, rtxt string, rcnames []string, rerr error) {
|
||||
// following CNAME records, and returns the parsed MTA-STS record and the DNS TXT
|
||||
// record.
|
||||
func LookupRecord(ctx context.Context, resolver dns.Resolver, domain dns.Domain) (rrecord *Record, rtxt string, rerr error) {
|
||||
log := xlog.WithContext(ctx)
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
log.Debugx("mtasts lookup result", rerr, mlog.Field("domain", domain), mlog.Field("record", rrecord), mlog.Field("cnames", rcnames), mlog.Field("duration", time.Since(start)))
|
||||
log.Debugx("mtasts lookup result", rerr, mlog.Field("domain", domain), mlog.Field("record", rrecord), mlog.Field("duration", time.Since(start)))
|
||||
}()
|
||||
|
||||
// ../rfc/8461:289
|
||||
// ../rfc/8461:351
|
||||
// We lookup the txt record, but must follow CNAME records when the TXT does not exist.
|
||||
var cnames []string
|
||||
// We lookup the txt record, but must follow CNAME records when the TXT does not
|
||||
// exist. LookupTXT follows CNAMEs.
|
||||
name := "_mta-sts." + domain.ASCII + "."
|
||||
var txts []string
|
||||
for {
|
||||
var err error
|
||||
txts, _, err = dns.WithPackage(resolver, "mtasts").LookupTXT(ctx, name)
|
||||
if dns.IsNotFound(err) {
|
||||
// DNS has no specified limit on how many CNAMEs to follow. Chains of 10 CNAMEs
|
||||
// have been seen on the internet.
|
||||
if len(cnames) > 16 {
|
||||
return nil, "", cnames, fmt.Errorf("too many cnames")
|
||||
}
|
||||
cname, _, err := dns.WithPackage(resolver, "mtasts").LookupCNAME(ctx, name)
|
||||
if dns.IsNotFound(err) {
|
||||
return nil, "", cnames, ErrNoRecord
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", cnames, fmt.Errorf("%w: %s", ErrDNS, err)
|
||||
}
|
||||
cnames = append(cnames, cname)
|
||||
name = cname
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, "", cnames, fmt.Errorf("%w: %s", ErrDNS, err)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
txts, _, err := dns.WithPackage(resolver, "mtasts").LookupTXT(ctx, name)
|
||||
if dns.IsNotFound(err) {
|
||||
return nil, "", ErrNoRecord
|
||||
} else if err != nil {
|
||||
return nil, "", fmt.Errorf("%w: %s", ErrDNS, err)
|
||||
}
|
||||
|
||||
var text string
|
||||
@ -215,18 +196,18 @@ func LookupRecord(ctx context.Context, resolver dns.Resolver, domain dns.Domain)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", cnames, err
|
||||
return nil, "", err
|
||||
}
|
||||
if record != nil {
|
||||
return nil, "", cnames, ErrMultipleRecords
|
||||
return nil, "", ErrMultipleRecords
|
||||
}
|
||||
record = r
|
||||
text = txt
|
||||
}
|
||||
if record == nil {
|
||||
return nil, "", cnames, ErrNoRecord
|
||||
return nil, "", ErrNoRecord
|
||||
}
|
||||
return record, text, cnames, nil
|
||||
return record, text, nil
|
||||
}
|
||||
|
||||
// Policy fetch errors.
|
||||
@ -330,7 +311,7 @@ func Get(ctx context.Context, resolver dns.Resolver, domain dns.Domain) (record
|
||||
log.Debugx("mtasts get result", err, mlog.Field("domain", domain), mlog.Field("record", record), mlog.Field("policy", policy), mlog.Field("duration", time.Since(start)))
|
||||
}()
|
||||
|
||||
record, _, _, err = LookupRecord(ctx, resolver, domain)
|
||||
record, _, err = LookupRecord(ctx, resolver, domain)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
@ -21,9 +21,12 @@ import (
|
||||
"github.com/mjl-/adns"
|
||||
|
||||
"github.com/mjl-/mox/dns"
|
||||
"github.com/mjl-/mox/mlog"
|
||||
)
|
||||
|
||||
func TestLookup(t *testing.T) {
|
||||
mlog.SetConfig(map[string]mlog.Level{"": mlog.LevelDebug})
|
||||
|
||||
resolver := dns.MockResolver{
|
||||
TXT: map[string][]string{
|
||||
"_mta-sts.a.example.": {"v=STSv1; id=1"},
|
||||
@ -37,39 +40,37 @@ func TestLookup(t *testing.T) {
|
||||
CNAME: map[string]string{
|
||||
"_mta-sts.a.cnames.example.": "_mta-sts.b.cnames.example.",
|
||||
"_mta-sts.b.cnames.example.": "_mta-sts.c.cnames.example.",
|
||||
"_mta-sts.followtemperror.example.": "_mta-sts.cnametemperror.example.",
|
||||
"_mta-sts.followtemperror.example.": "_mta-sts.temperror.example.",
|
||||
},
|
||||
Fail: []string{
|
||||
"txt _mta-sts.temperror.example.",
|
||||
"cname _mta-sts.cnametemperror.example.",
|
||||
},
|
||||
}
|
||||
|
||||
test := func(host string, expRecord *Record, expCNAMEs []string, expErr error) {
|
||||
test := func(host string, expRecord *Record, expErr error) {
|
||||
t.Helper()
|
||||
|
||||
record, _, cnames, err := LookupRecord(context.Background(), resolver, dns.Domain{ASCII: host})
|
||||
record, _, err := LookupRecord(context.Background(), resolver, dns.Domain{ASCII: host})
|
||||
if (err == nil) != (expErr == nil) || err != nil && !errors.Is(err, expErr) {
|
||||
t.Fatalf("lookup: got err %#v, expected %#v", err, expErr)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(record, expRecord) || !reflect.DeepEqual(cnames, expCNAMEs) {
|
||||
t.Fatalf("lookup: got record %#v, cnames %#v, expected %#v %#v", record, cnames, expRecord, expCNAMEs)
|
||||
if !reflect.DeepEqual(record, expRecord) {
|
||||
t.Fatalf("lookup: got record %#v, expected %#v", record, expRecord)
|
||||
}
|
||||
}
|
||||
|
||||
test("absent.example", nil, nil, ErrNoRecord)
|
||||
test("other.example", nil, nil, ErrNoRecord)
|
||||
test("a.example", &Record{Version: "STSv1", ID: "1"}, nil, nil)
|
||||
test("one.example", &Record{Version: "STSv1", ID: "1"}, nil, nil)
|
||||
test("bad.example", nil, nil, ErrRecordSyntax)
|
||||
test("multiple.example", nil, nil, ErrMultipleRecords)
|
||||
test("a.cnames.example", &Record{Version: "STSv1", ID: "1"}, []string{"_mta-sts.b.cnames.example.", "_mta-sts.c.cnames.example."}, nil)
|
||||
test("temperror.example", nil, nil, ErrDNS)
|
||||
test("cnametemperror.example", nil, nil, ErrDNS)
|
||||
test("followtemperror.example", nil, nil, ErrDNS)
|
||||
test("absent.example", nil, ErrNoRecord)
|
||||
test("other.example", nil, ErrNoRecord)
|
||||
test("a.example", &Record{Version: "STSv1", ID: "1"}, nil)
|
||||
test("one.example", &Record{Version: "STSv1", ID: "1"}, nil)
|
||||
test("bad.example", nil, ErrRecordSyntax)
|
||||
test("multiple.example", nil, ErrMultipleRecords)
|
||||
test("a.cnames.example", &Record{Version: "STSv1", ID: "1"}, nil)
|
||||
test("temperror.example", nil, ErrDNS)
|
||||
test("followtemperror.example", nil, ErrDNS)
|
||||
}
|
||||
|
||||
func TestMatches(t *testing.T) {
|
||||
|
Reference in New Issue
Block a user