Skip to content

Commit f77bba4

Browse files
ianlancetaylorgopherbot
authored andcommitted
net: accept a valid IP address in LookupMX
Fixes #56025 Change-Id: I202fdd0e11afeb22c5bc22d91fe4bfea8987e727 Reviewed-on: https://go-review.googlesource.com/c/go/+/651056 Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent dceee2e commit f77bba4

File tree

3 files changed

+82
-15
lines changed

3 files changed

+82
-15
lines changed
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[LookupMX] and [(*Resolver).LookupMX] now return DNS names that look
2+
like valid IP address, as well as valid domain names.
3+
Previously if a name server returned an IP address as a DNS name,
4+
LookupMX would discard it, as required by the RFCs.
5+
However, name servers in practice do sometimes return IP addresses.

src/net/dnsclient_unix_test.go

+64-8
Original file line numberDiff line numberDiff line change
@@ -2028,6 +2028,50 @@ func TestCVE202133195(t *testing.T) {
20282028
MX: dnsmessage.MustNewName("good.golang.org."),
20292029
},
20302030
},
2031+
dnsmessage.Resource{
2032+
Header: dnsmessage.ResourceHeader{
2033+
Name: dnsmessage.MustNewName("127.0.0.1."),
2034+
Type: dnsmessage.TypeMX,
2035+
Class: dnsmessage.ClassINET,
2036+
Length: 4,
2037+
},
2038+
Body: &dnsmessage.MXResource{
2039+
MX: dnsmessage.MustNewName("127.0.0.1."),
2040+
},
2041+
},
2042+
dnsmessage.Resource{
2043+
Header: dnsmessage.ResourceHeader{
2044+
Name: dnsmessage.MustNewName("1.2.3.4.5."),
2045+
Type: dnsmessage.TypeMX,
2046+
Class: dnsmessage.ClassINET,
2047+
Length: 4,
2048+
},
2049+
Body: &dnsmessage.MXResource{
2050+
MX: dnsmessage.MustNewName("1.2.3.4.5."),
2051+
},
2052+
},
2053+
dnsmessage.Resource{
2054+
Header: dnsmessage.ResourceHeader{
2055+
Name: dnsmessage.MustNewName("2001:4860:0:2001::68."),
2056+
Type: dnsmessage.TypeMX,
2057+
Class: dnsmessage.ClassINET,
2058+
Length: 4,
2059+
},
2060+
Body: &dnsmessage.MXResource{
2061+
MX: dnsmessage.MustNewName("2001:4860:0:2001::68."),
2062+
},
2063+
},
2064+
dnsmessage.Resource{
2065+
Header: dnsmessage.ResourceHeader{
2066+
Name: dnsmessage.MustNewName("2001:4860:0:2001::68%zone."),
2067+
Type: dnsmessage.TypeMX,
2068+
Class: dnsmessage.ClassINET,
2069+
Length: 4,
2070+
},
2071+
Body: &dnsmessage.MXResource{
2072+
MX: dnsmessage.MustNewName("2001:4860:0:2001::68%zone."),
2073+
},
2074+
},
20312075
)
20322076
case dnsmessage.TypeNS:
20332077
r.Answers = append(r.Answers,
@@ -2152,25 +2196,37 @@ func TestCVE202133195(t *testing.T) {
21522196
{
21532197
name: "MX",
21542198
f: func(t *testing.T) {
2155-
expected := []*MX{
2156-
{
2157-
Host: "good.golang.org.",
2158-
},
2199+
expected := []string{
2200+
"127.0.0.1.",
2201+
"2001:4860:0:2001::68.",
2202+
"good.golang.org.",
21592203
}
21602204
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
21612205
records, err := r.LookupMX(context.Background(), "golang.org")
21622206
if err.Error() != expectedErr.Error() {
21632207
t.Fatalf("unexpected error: %s", err)
21642208
}
2165-
if !reflect.DeepEqual(records, expected) {
2166-
t.Error("Unexpected record set")
2209+
2210+
hosts := func(records []*MX) []string {
2211+
var got []string
2212+
for _, mx := range records {
2213+
got = append(got, mx.Host)
2214+
}
2215+
slices.Sort(got)
2216+
return got
2217+
}
2218+
2219+
got := hosts(records)
2220+
if !slices.Equal(got, expected) {
2221+
t.Errorf("Unexpected record set: got %v, want %v", got, expected)
21672222
}
21682223
records, err = LookupMX("golang.org")
21692224
if err.Error() != expectedErr.Error() {
21702225
t.Fatalf("unexpected error: %s", err)
21712226
}
2172-
if !reflect.DeepEqual(records, expected) {
2173-
t.Error("Unexpected record set")
2227+
got = hosts(records)
2228+
if !slices.Equal(got, expected) {
2229+
t.Errorf("Unexpected record set: got %v, want %v", got, expected)
21742230
}
21752231
},
21762232
},

src/net/lookup.go

+13-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"errors"
1010
"internal/nettrace"
1111
"internal/singleflight"
12+
"internal/stringslite"
1213
"net/netip"
1314
"sync"
1415

@@ -535,9 +536,9 @@ func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (
535536
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
536537
//
537538
// The returned mail server names are validated to be properly
538-
// formatted presentation-format domain names. If the response contains
539-
// invalid names, those records are filtered out and an error
540-
// will be returned alongside the remaining results, if any.
539+
// formatted presentation-format domain names, or numeric IP addresses.
540+
// If the response contains invalid names, those records are filtered out
541+
// and an error will be returned alongside the remaining results, if any.
541542
//
542543
// LookupMX uses [context.Background] internally; to specify the context, use
543544
// [Resolver.LookupMX].
@@ -548,9 +549,9 @@ func LookupMX(name string) ([]*MX, error) {
548549
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
549550
//
550551
// The returned mail server names are validated to be properly
551-
// formatted presentation-format domain names. If the response contains
552-
// invalid names, those records are filtered out and an error
553-
// will be returned alongside the remaining results, if any.
552+
// formatted presentation-format domain names, or numeric IP addresses.
553+
// If the response contains invalid names, those records are filtered out
554+
// and an error will be returned alongside the remaining results, if any.
554555
func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
555556
records, err := r.lookupMX(ctx, name)
556557
if err != nil {
@@ -562,7 +563,12 @@ func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
562563
continue
563564
}
564565
if !isDomainName(mx.Host) {
565-
continue
566+
// Check for IP address. In practice we observe
567+
// these with a trailing dot, so strip that.
568+
ip, err := netip.ParseAddr(stringslite.TrimSuffix(mx.Host, "."))
569+
if err != nil || ip.Zone() != "" {
570+
continue
571+
}
566572
}
567573
filteredMX = append(filteredMX, mx)
568574
}

0 commit comments

Comments
 (0)