IPv4 and IPv6 have different headers, so a host that speaks only one cannot talk to a host that speaks only the other. (RFC) 6144 sorts the bridges into three families: "Besides dual-stack deployment, there are two fundamental approaches one could take to interworking between IPv4 and IPv6: tunneling and translation" (RFC 6144, section 1.1). Only translation lets an IPv6-only client reach an IPv4-only server, since a tunnel needs dual-stack hosts at its ends (section 1.1), and any network carrying both protocols uses at least one family. By the end you can predict which family a host picks, build each mechanism's addresses, follow a session and check it all with real commands.

Dual stack, and how a host picks a family

A dual-stack node, RFC 4213's IPv6/IPv4 node, speaks each protocol natively (RFC 4213, section 2). Applications mostly try addresses in the order returned (section 2.2), an order RFC 6724 sets with one table, since "IPv4 addresses MUST be represented as IPv4-mapped addresses", the ::ffff:0:0/96 form of Understanding IPv6 Addressing (RFC 6724, section 3.2). Its default table, in part (section 2.1):

Prefix          Precedence  Label
::1/128               50      0
::/0                  40      1
::ffff:0:0/96         35      4
2002::/16             30      2
2001::/32              5      5
fc00::/7               3     13

Rule 6 prefers higher precedence (RFC 6724, section 6), so native IPv6 (40) beats IPv4 (35), 6to4 (30) and (5). Because the scope rule comes first, a host with only a link-local IPv6 address uses IPv4 for global destinations (section 10.2).

Happy Eyeballs version 2 makes a dead IPv6 path cheap (RFC 8305, section 1). is queried first and A straight after, and if A answers first the client waits 50 ms for AAAA (section 3). Addresses are sorted by RFC 6724 and the families interleaved (section 4); attempts start 250 ms apart by default, within recommended bounds of 100 ms and 2 s, and the first connection to complete wins (section 5). Illustratively, with IPv6 broken:

t =   0 ms   connect to 2001:db8::10   IPv6, first after sorting
t = 250 ms   connect to 192.0.2.10     IPv4, next in the interleaved list
t = 280 ms   192.0.2.10 completes      the attempt to 2001:db8::10 is cancelled

Tunnels: IPv6 carried inside IPv4

A configured tunnel, or 6in4, puts each IPv6 packet behind an IPv4 header (RFC 4213, section 1) with protocol 41 (section 3.5), which the Internet Assigned Numbers Authority () registers as IPv6 encapsulation (IANA protocol numbers). To IPv6 the tunnel is a single hop: "The tunnel is opaque to users of the network, and it is not detectable by network diagnostic tools such as traceroute" (RFC 4213, section 3.3).

6to4 needs no explicit tunnel setup (RFC 3056, abstract): the site prefix is 2002::/16 plus the site's IPv4 address, 2002:V4ADDR::/48 (section 2), and each tunnel's far end is read from the next-hop address (section 5.3). Relays, often a different one each way, link 6to4 to native IPv6 (RFC 7526, section 3); RFC 3068 put them all on the anycast address 192.88.99.1 (RFC 3068, section 2.4). Illustratively:

IPv4 address        192.0.2.33  =  c0.00.02.21
6to4 site prefix    2002:c000:221::/48
relay anycast       192.88.99.1  ->  2002:c058:6301::   (RFC 3068, section 2.5)

Teredo, for hosts behind a where classic tunnels and 6to4 fail (RFC 4380, section 1), is an "IPv6 access of last resort" (section 3.2) over UDP port 3544 in 2001::/32 (sections 2.6 and 2.7). Its address holds the server's IPv4 address, flags, and the client's mapped port and address with every bit inverted (section 4). Illustratively:

2001:0000   c000:022d    3c5a    63bf             34ff:8eeb
prefix      server       flags   port             client address
            192.0.2.45           9c40 XOR ffff    cb00:7114 XOR ffff:ffff
                                 (40000)          (203.0.113.20)
address     2001:0:c000:22d:3c5a:63bf:34ff:8eeb

IPv6 Rapid Deployment (6rd) applies the 6to4 arithmetic to a provider's own prefix: "Unlike 6to4, 6rd is for use only in an environment where a service provider closely manages the delivery of IPv6 service" (RFC 5969, section 1). The Customer Edge (CE) router appends IPv4 bits to the 6rd prefix (section 4), as in the RFC's example (section 7.1.1):

CE address 10.100.100.1, first 8 bits dropped   100.100.1  =  64.64.01
6rd prefix 2001:db8::/32 + those 24 bits        2001:db8:6464:100::/56
all 32 bits, illustrative                       2001:db8::/32 + 203.0.113.20 = 2001:db8:cb00:7114::/64

Stateless translation and IPv4-converted addresses

RFC 7915 converts IPv4 headers to IPv6 and back, Internet Control Message Protocol () headers included, as the Stateless IP/ICMP Translation Algorithm (SIIT) (RFC 7915, abstract). "The stateless translator does not keep any dynamic session or binding state, thus there is no requirement that the packets in a single session or flow traverse a single translator" (section 1.3).

IPv6 hosts see IPv4 hosts as IPv4-converted addresses (RFC 6052, section 1.3) under the Well-Known Prefix 64:ff9b::/96 (section 2.1) or an operator's Network-Specific Prefix: "The prefixes can only have one of the following lengths: 32, 40, 48, 56, 64, or 96" (section 2.2). RFC 8215 adds 64:ff9b:1::/48 for local use (RFC 8215, abstract). The IPv4 bits follow the prefix, skipping the zero bits 64 to 71 (RFC 6052, sections 2.2 and 2.3), as in its examples (section 2.4):

Prefix              IPv4         IPv4-converted address
2001:db8::/32       192.0.2.33   2001:db8:c000:221::
2001:db8:100::/40   192.0.2.33   2001:db8:1c0:2:21::        0x21 after the zero octet
64:ff9b::/96        192.0.2.33   64:ff9b::192.0.2.33   =   64:ff9b::c000:221

As 0064 plus ff9b is ffff, zero in one's complement, the prefix is checksum neutral (RFC 6052, section 4.2). But "Address translators MUST NOT translate packets in which an address is composed of the Well-Known Prefix and a non-global IPv4 address; they MUST drop these packets" (section 3.1), and IANA lists 192.0.2.0/24 as not globally reachable (IANA IPv4 special-purpose registry), so these examples are illustrative. 64:ff9b:1::/48 is exempt (RFC 8215, section 5); Private, Reserved, and Public IP Ranges lists the non-global blocks.

NAT64 and DNS64, step by step

Stateful NAT64 lets IPv6-only clients reach IPv4 servers through shared public IPv4 addresses (RFC 6146, abstract). DNS64 feeds it: for a name without AAAA resource records (RRs), normal for an IPv4-only server, it fetches the A record and synthesises an AAAA (RFC 6147, section 2), and "By default, DNS64 implementations MUST NOT synthesize AAAA RRs when real AAAA RRs exist" (section 5.1.1). RFC 6146's walk-through uses documentation addresses that a real translator would drop (RFC 6146, section 1.2.2):

1  H1 asks the DNS64 for the AAAA of h2.example.com
2  there is none; the DNS64 fetches A 192.0.2.1
3  it answers AAAA 64:ff9b::192.0.2.1
4  H1 sends from 2001:db8::1 port 1500 to 64:ff9b::192.0.2.1
5  the NAT64 picks port 2000 on 203.0.113.1 and creates the mapping
   (2001:db8::1,1500) <--> (203.0.113.1,2000)
6  it sends IPv4 from 203.0.113.1 port 2000 to 192.0.2.1,
   the last 32 bits of the IPv6 destination
7  the reply to 203.0.113.1 port 2000 returns to 2001:db8::1 port 1500,
   from 64:ff9b::192.0.2.1

NAT64 thus translates both address and port (RFC 6146, section 1.2.1), like the NAT of NAT explained, and without existing state only IPv6 nodes can open sessions (section 1.1). DNS64 shares with it only the prefix and optional static parameters (RFC 6147, section 2).

How a host learns the prefix

A host that synthesises for itself learns the prefix by querying the AAAA records of ipv4only.arpa, whose addresses are 192.0.0.170 and 192.0.0.171 (RFC 7050, section 2.2), with the Checking Disabled (CD) bit clear, or a DNS64 would not synthesise; the answers show the prefix around those addresses, and a positive A answer marks a resolver that is not a DNS64 (section 3). Router Advertisements (RAs), covered in Neighbor Discovery, can carry the prefix instead, in the PREF64 option, type 38, coded 0 to 5 for /96, /64, /56, /48, /40 and /32 (RFC 8781, section 4).

464XLAT: two translations, no tunnel

464XLAT carries IPv4-only applications across an IPv6-only network and tunnels nothing: it is "a simple and scalable technique to quickly deploy limited IPv4 access service to IPv6-only edge networks without encapsulation" (RFC 6877, abstract). The customer-side translator (CLAT) translates statelessly, 1:1, between a private IPv4 and a global IPv6 address, as SIIT does; the provider-side translator (PLAT) is a stateful NAT64, (section 2). The CLAT acts only for IPv4 literals or IPv4-only sockets (section 5.2), and its private address may come from 192.0.0.0/29, a prefix for systems that send no IPv4 on the wire (RFC 7335, section 1). In one cellular network, up to the end of 2018, under 1% of traffic needed the CLAT (RFC 9313, section 4.5.2). and inbound IPv4 stay out of reach (RFC 6877, section 1).

IPv4 as a service

Dual-Stack Lite () tunnels IPv4 in IPv6 from the customer's Basic Bridging BroadBand (B4) element to an Address Family Transition Router (AFTR), a tunnel endpoint and an IPv4 NAT on one node (RFC 6333, sections 1 and 6.1), a shared NAT; "There is no protocol family translation involved in this approach" (section 4.1). Mapping of Address and Port (MAP) shares an address by dividing its ports (RFC 7597, section 1): MAP with Encapsulation (MAP-E) carries IPv4 in IPv6 (abstract), and MAP using Translation (MAP-T) translates it (RFC 7599, section 1).

What breaks

IPv4 literals. Behind IPv6-only access, IPv4 literals and older APIs fail unless a CLAT, Happy Eyeballs version 2 or Bump-in-the-Host with DNS64 steps in (RFC 8683, section 4.6), and protocols that protect IP header information are "essentially incompatible with NAT64" (RFC 6146, section 5.1).

Signed answers. The Domain Name System Security Extensions () clash with synthesis "because DNSSEC is designed to detect changes to DNS answers, and DNS64 may alter answers coming from an authoritative server" (RFC 6147, section 3). A validating DNS64 (vDNS64) may synthesise when DNSSEC OK (DO) is set and CD clear, setting the Authentic Data () bit, but "If the CD bit is set and DO is set, then vDNS64 MAY perform validation, but MUST NOT perform synthesis" (section 5.5): a validating host must then do DNS64 itself (section 3). RFC 8683 cites studies putting the breakage at about 1.7% of cases (RFC 8683, section 4.1). RFC 8880 reversed RFC 7050's demand that the discovery name be signed (RFC 7050, section 4): "the 'ipv4only.arpa' zone MUST be an insecure delegation" (RFC 8880, section 5); see DNSSEC end to end.

Resolvers. A device using a resolver other than the one learned from the network can seriously break DNS64 and NAT64 (RFC 8880, section 3.1), a cost of choosing a public resolver.

Packet size. RFC 4213 bounds a 6in4 tunnel's Maximum Transmission Unit (): by default "the MTU MUST be between 1280 and 1480 bytes (inclusive), but it SHOULD be 1280 bytes" (RFC 4213, section 3.2.1). A 1500-byte path leaves 1480 bytes for a 6rd tunnel (RFC 5969, section 9.1), and TCP over IPv6 subtracts 60 octets for its Maximum Segment Size () (RFC 8200, section 8.3), leaving 1420. DS-Lite's remedy is B4 to AFTR links at least 40 bytes larger, as () is unreliable (RFC 6333, section 5.3), and dropped Packet Too Big messages are not unusual (RFC 7915, section 7). The trap: "a standard 'ping' from the client to the server will succeed, because it generates small packets" (RFC 6343, section 3), and Happy Eyeballs, watching only the handshake, misses the fault (RFC 8305, section 9.1); see ICMP, ping, and traceroute.

Anycast 6to4. One experiment saw 9% to 20% of 6to4 connection attempts fail, one likely reason being filters near users that block protocol 41, and IPv4 fallback hid the failures behind delays of 7 to 20 seconds (RFC 6343, section 3). In May 2015 RFC 7526 deprecated anycast 6to4 and 192.88.99.1 but kept 2002::/16 (RFC 7526, section 4), and ruled: "In router implementations, 6to4 MUST be disabled by default" (section 5).

Masking and spoofing. If IPv6 fails while IPv4 works, Happy Eyeballs can hide it from the operator, so RFC 8305 recommends external monitoring of every address family (RFC 8305, section 9.3). Decapsulators must check the IPv4 source against the configured endpoint (RFC 4213, section 5) or, in 6rd, against the embedded IPv4 address (RFC 5969, section 9.2).

How to see it

These commands follow ip(8), ip-route(8), ip-tunnel(8), ip-address(8), tracepath(8), ping(8) and getent(1); a DS-Lite B4 is numbered 192.0.0.2 (RFC 6333, section 5.7):

ip -6 route get 64:ff9b::c000:221   # the route a synthesised destination takes
ip tunnel show                      # sit for 6in4, 6to4 and 6rd; ipip6 for a DS-Lite B4
ip address show                     # a CLAT or B4 address may sit in 192.0.0.0/29
tracepath -6 example.com            # path MTU, hop by hop
ping -6 -M do -s 1432 example.com   # 40 + 8 + 1432 = 1480 bytes; refused if the path is smaller
getent ahosts example.com           # addresses in the order getaddrinfo returns them

The example in tracepath(8) shows a 6in4 hop:

root@mops:~ # tracepath -6 3ffe:2400:0:109::2
 1?: [LOCALHOST]                              pmtu 1500
 1:  dust.inr.ac.ru                   0.411ms
 2:  dust.inr.ac.ru        asymm  1   0.390ms pmtu 1480
 2:  3ffe:2400:0:109::2               463.514ms reached
     Resume: pmtu 1480 hops 2 back 2

/etc/gai.conf reorders addresses, but its manual still shows RFC 3484's table (IPv4-mapped at 10), and one precedence line replaces the default (gai.conf(5)). curl shows which family won, and its manual puts libcurl's IPv6 head start at 200 ms (curl man page):

curl -s -o /dev/null -w '%{remote_ip} %{time_connect}\n' https://example.com
curl -6 https://example.com   # IPv6 only; -4 for IPv4 only
curl --happy-eyeballs-timeout-ms 250 https://example.com

In dig, +dns64prefix prints the DNS64 prefixes found at ipv4only.arpa, +dnssec sets DO and +cd sets CD (BIND 9 dig manual); Google Public DNS64, 2001:4860:4860::6464, helps only where a NAT64 on 64:ff9b::/96 is reachable (Google Public DNS64):

dig @2001:4860:4860::6464 ipv4only.arpa AAAA
dig @2001:4860:4860::6464 +dns64prefix
dig @2001:4860:4860::6464 +dnssec +cd ipv4only.arpa AAAA   # DO and CD set: no synthesis expected

An illustrative synthesised answer, in the zone form of RFC 8683, section 4.1:

ipv4only.arpa. AAAA 64:ff9b::192.0.0.170
ipv4only.arpa. AAAA 64:ff9b::192.0.0.171

A real capture from Google Public DNS, which is not a DNS64, taken at 2026-10-18T21:49:22Z:

curl -s 'https://dns.google/resolve?name=ipv4only.arpa&type=AAAA'
curl -s 'https://dns.google/resolve?name=ipv4only.arpa&type=A'
{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"ipv4only.arpa.","type":28}],"Authority":[{"name":"ipv4only.arpa.","type":6,"TTL":287,"data":"sns.dns.icann.org. noc.dns.icann.org. 2026100800 7200 3600 604800 3600"}]}
{"Status":0,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"ipv4only.arpa.","type":1}],"Answer":[{"name":"ipv4only.arpa.","type":1,"TTL":16109,"data":"192.0.0.170"},{"name":"ipv4only.arpa.","type":1,"TTL":16109,"data":"192.0.0.171"}]}

The AAAA query (type 28) got status 0, no Answer and one Authority record, the negative answer a DNS64 synthesises from (RFC 8305, section 7.2); the A query (type 1) got 192.0.0.170 and 192.0.0.171, the mark of a resolver that is not a DNS64 (RFC 7050, section 3); AD is false in both, as an insecure delegation implies (RFC 8880, section 5). The DNS header explains the flags, the dig output explainer decodes AD and CD, and the dig command builder writes -6, +dnssec and +cd, though not +dns64prefix.

Python's ipaddress decodes 6to4 (sixtofour), Teredo (teredo) and mapped addresses (ipv4_mapped), but not NAT64 (Python ipaddress documentation). A CPython 3.13.16 session; the Python playground runs CPython 3.14:

>>> import ipaddress
>>> b = ipaddress.ip_address('2002:c000:221::1'); b
IPv6Address('2002:c000:221::1')
>>> b.sixtofour
IPv4Address('192.0.2.33')
>>> t = ipaddress.ip_address('2001:0:c000:22d:3c5a:63bf:34ff:8eeb'); t
IPv6Address('2001:0:c000:22d:3c5a:63bf:34ff:8eeb')
>>> t.teredo
(IPv4Address('192.0.2.45'), IPv4Address('203.0.113.20'))
>>> n = ipaddress.ip_address('64:ff9b::192.0.2.33'); n
IPv6Address('64:ff9b::c000:221')
>>> ipaddress.IPv4Address(int(n) & 0xffffffff)
IPv4Address('192.0.2.33')
>>> n.ipv4_mapped, n.sixtofour, n.teredo
(None, None, None)

The IPv6 Toolkit shows the IPv4 inside an IPv4-mapped address and labels 64:ff9b::/96 and 2002::/16 addresses without extracting it; it does not recognise Teredo addresses or 64:ff9b:1::/48. The MTU / MSS calculator gives a 1500-byte link with 6in4 an inner MTU of 1480 and an IPv6 MSS of 1420, and with ipip v6, as in DS-Lite, 1460 and an IPv4 MSS of 1420.

What to remember

  • RFC 6144's three families are dual stack, tunnelling and translation; only translation joins IPv6-only and IPv4-only hosts.
  • RFC 6724 ranks IPv6 (40) over IPv4 (35), 6to4 (30) and Teredo (5); Happy Eyeballs spaces attempts 250 ms apart.
  • 6to4 builds 2002:V4ADDR::/48; its anycast relays were deprecated in 2015, and routers must ship it disabled.
  • 64:ff9b::/96 holds a global IPv4 address in its last 32 bits; DNS64 synthesises, NAT64 translates address and port.
  • Hosts learn the prefix from ipv4only.arpa, queried with CD clear, or from PREF64 in Router Advertisements.
  • 464XLAT translates twice and encapsulates nothing; DS-Lite and MAP-E carry IPv4 inside IPv6.
  • On a 1500-byte path a 6in4 tunnel leaves 1480 bytes and a TCP MSS of 1420; a small ping hides the fault.

Sources