feature/conn25: skip AAAA records with IPv4-in-IPv6 addresses

Skip destination IPs from AAAA records that are
in ipv4-in-ipv6 format.

Fixes https://github.com/tailscale/corp/issues/48781

Change-Id: I5eeaa9c998c79250d2e6a943fa9f26ed7feb5ec6
Signed-off-by: Mazdak Nasab <mazdak.nasab@gmail.com>
This commit is contained in:
Mazdak Nasab committed 2026-09-28 11:11:52 -07:00
1 parent 7bb87d3614
commit 8a119e1ec0
2 files changed
+43 -1

No files matched your search

+12
View File
@@ -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:
+31 -1
View File
@@ -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{