diff --git a/feature/conn25/conn25.go b/feature/conn25/conn25.go index 13c5f3842..bdb112b35 100644 --- a/feature/conn25/conn25.go +++ b/feature/conn25/conn25.go @@ -1250,6 +1250,12 @@ var ( metricDNSResponseRewriteUnsupportedQuestionTypeErrorServfail = clientmetric.NewCounter( "conn25_map_dns_response_rewrite_unsupported_question_type_error_servfail", ) + + // metricDNSResponseSkippedAAAA4In6 increments when an AAAA answer for an + // app connector domain is dropped because it holds an IPv4-in-IPv6 address. + metricDNSResponseSkippedAAAA4In6 = clientmetric.NewCounter( + "conn25_map_dns_response_skipped_aaaa_4in6", + ) ) // mapDNSResponse parses and inspects the DNS response. If the domain @@ -1418,6 +1424,12 @@ func (c *Conn25) mapDNSResponse(buf []byte) []byte { return makeServFail(c.logf, hdr, question) } dstAddr = netip.AddrFrom16(r.AAAA) + + // Skip AAAA answer with IPv4-in-IPv6 address. + if dstAddr.Is4In6() { + metricDNSResponseSkippedAAAA4In6.Add(1) + continue + } } answers = append(answers, dnsResponseRewrite{domain: queriedDomain, dst: dstAddr, ttlSeconds: h.TTL}) default: diff --git a/feature/conn25/conn25_test.go b/feature/conn25/conn25_test.go index 85b9d213e..ee2e5dc86 100644 --- a/feature/conn25/conn25_test.go +++ b/feature/conn25/conn25_test.go @@ -1151,6 +1151,24 @@ func TestMapDNSResponseAssignsAddrs(t *testing.T) { }, }, }, + { + name: "v6-ip-4in6-skipped", + appDomains: []string{"example.com"}, + domain: "example.com.", + v6Addrs: []*dnsmessage.AAAAResource{ + {AAAA: netip.MustParseAddr("::ffff:1.0.0.1").As16()}, + {AAAA: netip.MustParseAddr("::1").As16()}, + }, + wantByMagicIP: map[netip.Addr]*addrs{ + netip.MustParseAddr("fd7a:115c:a1e0:a99c::"): { + domain: "example.com.", + dst: netip.MustParseAddr("::1"), + magic: netip.MustParseAddr("fd7a:115c:a1e0:a99c:0::"), + transit: netip.MustParseAddr("fd7a:115c:a1e0:a99c:40::"), + app: "app1", + }, + }, + }, { name: "multiple-ip-matches", appDomains: []string{"example.com"}, @@ -1913,6 +1931,18 @@ func TestMapDNSResponseRewritesResponses(t *testing.T) { }, ), }, + { + name: "ipv6-4in6-answer-dropped", + toMap: makeV6DNSResponse(t, domainName, []*dnsmessage.AAAAResource{ + {AAAA: netip.MustParseAddr("::ffff:1.2.3.4").As16()}, + {AAAA: netip.MustParseAddr("2606:4700::6812:1a78").As16()}, + }), + assertFx: assertParsesToAnswers( + []netip.Addr{ + netip.MustParseAddr("2606:4700::6812:100"), + }, + ), + }, { name: "not-our-domain", toMap: ipv4ResponseUnhandledDomain, @@ -2072,7 +2102,7 @@ func TestMapDNSResponseRewritesResponses(t *testing.T) { Type: dnsmessage.TypeAAAA, Class: dnsmessage.ClassINET, }, - Body: &dnsmessage.AAAAResource{AAAA: netip.MustParseAddr("1.2.3.4").As16()}, + Body: &dnsmessage.AAAAResource{AAAA: netip.MustParseAddr("2606:4700::6812:1a78").As16()}, }, { Header: dnsmessage.ResourceHeader{