MX: dnsmessage.MustNewName("good.golang.org."),
},
},
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: dnsmessage.MustNewName("127.0.0.1."),
+ Type: dnsmessage.TypeMX,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.MXResource{
+ MX: dnsmessage.MustNewName("127.0.0.1."),
+ },
+ },
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: dnsmessage.MustNewName("1.2.3.4.5."),
+ Type: dnsmessage.TypeMX,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.MXResource{
+ MX: dnsmessage.MustNewName("1.2.3.4.5."),
+ },
+ },
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: dnsmessage.MustNewName("2001:4860:0:2001::68."),
+ Type: dnsmessage.TypeMX,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.MXResource{
+ MX: dnsmessage.MustNewName("2001:4860:0:2001::68."),
+ },
+ },
+ dnsmessage.Resource{
+ Header: dnsmessage.ResourceHeader{
+ Name: dnsmessage.MustNewName("2001:4860:0:2001::68%zone."),
+ Type: dnsmessage.TypeMX,
+ Class: dnsmessage.ClassINET,
+ Length: 4,
+ },
+ Body: &dnsmessage.MXResource{
+ MX: dnsmessage.MustNewName("2001:4860:0:2001::68%zone."),
+ },
+ },
)
case dnsmessage.TypeNS:
r.Answers = append(r.Answers,
{
name: "MX",
f: func(t *testing.T) {
- expected := []*MX{
- {
- Host: "good.golang.org.",
- },
+ expected := []string{
+ "127.0.0.1.",
+ "2001:4860:0:2001::68.",
+ "good.golang.org.",
}
expectedErr := &DNSError{Err: errMalformedDNSRecordsDetail, Name: "golang.org"}
records, err := r.LookupMX(context.Background(), "golang.org")
if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
- if !reflect.DeepEqual(records, expected) {
- t.Error("Unexpected record set")
+
+ hosts := func(records []*MX) []string {
+ var got []string
+ for _, mx := range records {
+ got = append(got, mx.Host)
+ }
+ slices.Sort(got)
+ return got
+ }
+
+ got := hosts(records)
+ if !slices.Equal(got, expected) {
+ t.Errorf("Unexpected record set: got %v, want %v", got, expected)
}
records, err = LookupMX("golang.org")
if err.Error() != expectedErr.Error() {
t.Fatalf("unexpected error: %s", err)
}
- if !reflect.DeepEqual(records, expected) {
- t.Error("Unexpected record set")
+ got = hosts(records)
+ if !slices.Equal(got, expected) {
+ t.Errorf("Unexpected record set: got %v, want %v", got, expected)
}
},
},
"errors"
"internal/nettrace"
"internal/singleflight"
+ "internal/stringslite"
"net/netip"
"sync"
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
//
// The returned mail server names are validated to be properly
-// formatted presentation-format domain names. If the response contains
-// invalid names, those records are filtered out and an error
-// will be returned alongside the remaining results, if any.
+// formatted presentation-format domain names, or numeric IP addresses.
+// If the response contains invalid names, those records are filtered out
+// and an error will be returned alongside the remaining results, if any.
//
// LookupMX uses [context.Background] internally; to specify the context, use
// [Resolver.LookupMX].
// LookupMX returns the DNS MX records for the given domain name sorted by preference.
//
// The returned mail server names are validated to be properly
-// formatted presentation-format domain names. If the response contains
-// invalid names, those records are filtered out and an error
-// will be returned alongside the remaining results, if any.
+// formatted presentation-format domain names, or numeric IP addresses.
+// If the response contains invalid names, those records are filtered out
+// and an error will be returned alongside the remaining results, if any.
func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) {
records, err := r.lookupMX(ctx, name)
if err != nil {
continue
}
if !isDomainName(mx.Host) {
- continue
+ // Check for IP address. In practice we observe
+ // these with a trailing dot, so strip that.
+ ip, err := netip.ParseAddr(stringslite.TrimSuffix(mx.Host, "."))
+ if err != nil || ip.Zone() != "" {
+ continue
+ }
}
filteredMX = append(filteredMX, mx)
}