Classroom Glossary Public page

Lab 6: Dual-Stack and NAT64 / DNS64

385 words

Chapter: 6 (NAT + IPv6 Transition)
Duration: 90 minutes
Tools: Containerlab, tayga, BIND 9, tcpdump, Wireshark
Points: 10


Objectives

  1. Deploy a Containerlab topology with an IPv6-only client and an IPv4-only server
  2. Configure NAT64 (tayga) and DNS64 (BIND 9) on the gateway
  3. Demonstrate IPv6-only client reaching an IPv4-only server via NAT64
  4. Capture NAT64 translation in Wireshark
  5. Verify Happy Eyeballs behavior on a dual-stack client

Topology

IPv6-only client                Gateway (NAT64 + DNS64)             IPv4-only server
  2001:db8:1::10  --[IPv6]--> 2001:db8:1::1 / 10.100.0.1 --[IPv4]--> 10.100.0.100
                              NAT64 prefix: 64:ff9b::/96

Setup

# topo-nat64.clab.yml
name: nat64
topology:
  nodes:
    client6:
      kind: linux
      image: alpine:latest
    gw:
      kind: linux
      image: ubuntu:22.04
    server4:
      kind: linux
      image: alpine:latest
    client46:
      kind: linux
      image: alpine:latest
  links:
    - endpoints: ["client6:eth1", "gw:eth1"]   # IPv6-only segment
    - endpoints: ["gw:eth2", "server4:eth1"]    # IPv4 segment
    - endpoints: ["client46:eth1", "gw:eth3"]   # dual-stack segment
containerlab deploy -t topo-nat64.clab.yml

Configure addresses:

# IPv6-only client
docker exec clab-nat64-client6 ip addr add 2001:db8:1::10/64 dev eth1
docker exec clab-nat64-client6 ip -6 route add default via 2001:db8:1::1

# Gateway eth1 (IPv6 side)
docker exec clab-nat64-gw ip addr add 2001:db8:1::1/64 dev eth1

# Gateway eth2 (IPv4 side)
docker exec clab-nat64-gw ip addr add 10.100.0.1/24 dev eth2

# IPv4-only server
docker exec clab-nat64-server4 ip addr add 10.100.0.100/24 dev eth1
docker exec clab-nat64-server4 ip route add default via 10.100.0.1

# Dual-stack client
docker exec clab-nat64-client46 ip addr add 10.100.1.10/24 dev eth1
docker exec clab-nat64-client46 ip addr add 2001:db8:2::10/64 dev eth1
docker exec clab-nat64-client46 ip route add default via 10.100.1.1

Part 1: Configure NAT64 (tayga) (25 min)

# Install tayga on gateway
docker exec clab-nat64-gw apt-get update -q && \
  docker exec clab-nat64-gw apt-get install -y tayga bind9

# Create tayga configuration
docker exec clab-nat64-gw bash -c "cat > /etc/tayga.conf << 'EOF'
tun-device nat64
ipv4-addr 192.168.255.1
ipv6-addr 2001:db8:1::1
prefix 64:ff9b::/96
dynamic-pool 192.168.255.0/24
data-dir /var/db/tayga
EOF"

# Enable IP forwarding
docker exec clab-nat64-gw sysctl -w net.ipv4.ip_forward=1
docker exec clab-nat64-gw sysctl -w net.ipv6.conf.all.forwarding=1

# Start tayga
docker exec clab-nat64-gw tayga --mktun
docker exec clab-nat64-gw ip link set nat64 up
docker exec clab-nat64-gw ip route add 192.168.255.0/24 dev nat64
docker exec clab-nat64-gw ip -6 route add 64:ff9b::/96 dev nat64
docker exec clab-nat64-gw tayga --daemon

Test NAT64 manually (without DNS64):

# Compute the NAT64 address for 10.100.0.100
# 64:ff9b:: + IPv4 = 64:ff9b::0a64:0064 (10.100.0.100 in hex = 0a 64 00 64)
# Python: hex(10) + hex(100) + hex(0) + hex(100) = 0a640064

docker exec clab-nat64-client6 ping6 -c 3 64:ff9b::a64:64
# Expected: ping reaches 10.100.0.100 via NAT64

Record:

  1. Did the ping succeed? What path did it take?
  2. From the gateway, run cat /var/db/tayga/dynamic.map -- what translation entry was created?

Part 2: Configure DNS64 (20 min)

# Configure BIND 9 DNS64 on gateway
docker exec clab-nat64-gw bash -c "cat >> /etc/bind/named.conf.options << 'EOF'
    // DNS64 configuration
    dns64 64:ff9b::/96 {
        clients { any; };
        exclude { 64:ff9b::/96; };
    };
EOF"

docker exec clab-nat64-gw service named restart

# Add a test A record for server4 that DNS64 will synthesize
docker exec clab-nat64-gw bash -c "cat > /etc/bind/db.virtuslab.test << 'EOF'
\$ORIGIN virtuslab.test.
\$TTL 60
@ IN SOA ns1 admin ( 2026052901 3600 900 604800 60 )
@ IN NS ns1
ns1 IN A 10.100.0.1
ipv4only IN A 10.100.0.100
EOF"
# Add zone to named.conf
echo 'zone "virtuslab.test" { type master; file "/etc/bind/db.virtuslab.test"; };' | \
  docker exec -i clab-nat64-gw tee -a /etc/bind/named.conf.local

docker exec clab-nat64-gw service named reload

Test DNS64 synthesis:

# Configure IPv6 client to use gateway as DNS resolver
docker exec clab-nat64-gw ip addr add 2001:db8:1::53/64 dev eth1  # DNS resolver IP

# Query DNS64 - should synthesize AAAA from A
docker exec clab-nat64-client6 nslookup ipv4only.virtuslab.test 2001:db8:1::1
# Expected: returns 64:ff9b::a64:64 (NAT64 prefix + IPv4 address)

Record:

  1. What AAAA record did DNS64 synthesize for ipv4only.virtuslab.test?
  2. Is the synthesized AAAA record in the 64:ff9b::/96 prefix?
  3. Ping the hostname from the IPv6-only client: does it reach the IPv4-only server?
docker exec clab-nat64-client6 ping6 -c 3 ipv4only.virtuslab.test

Part 3: Wireshark NAT64 Translation Capture (15 min)

# Capture on the gateway's both interfaces simultaneously
docker exec clab-nat64-gw tcpdump -i eth1 -n -w /tmp/ipv6_side.pcap &
docker exec clab-nat64-gw tcpdump -i eth2 -n -w /tmp/ipv4_side.pcap &

docker exec clab-nat64-client6 ping6 -c 5 64:ff9b::a64:64

docker exec clab-nat64-gw killall tcpdump 2>/dev/null
docker cp clab-nat64-gw:/tmp/ipv6_side.pcap /tmp/
docker cp clab-nat64-gw:/tmp/ipv4_side.pcap /tmp/

Open both PCAPs in Wireshark.

Record:

  1. On the IPv6 side (eth1): what is the source and destination IPv6 address of the ICMPv6 echo?
  2. On the IPv4 side (eth2): what is the source and destination IPv4 address of the translated ICMP echo?
  3. How did tayga map 64:ff9b::a64:64 to 10.100.0.100? Show the bit-level mapping.

Part 4: Happy Eyeballs on Dual-Stack Client (15 min)

# Give the dual-stack client both IPv4 and IPv6 routes to a host
# Create a server with both IPv4 and IPv6 addresses
docker exec clab-nat64-gw ip addr add 2001:db8:2::1/64 dev eth3
docker exec clab-nat64-client46 ip -6 route add default via 2001:db8:2::1

# Use curl with verbose output to observe Happy Eyeballs
docker exec clab-nat64-client46 curl -v --max-time 5 \
  https://1.1.1.1/  2>&1 | grep -E "(Connected|IPv[46]|Trying)"

Record:

  1. Does curl attempt IPv6 first or IPv4 first?
  2. Which connection actually succeeds?
  3. What is the Happy Eyeballs specification for which protocol to try first, and by how long?

Lab Report

  1. Explain the difference between NAT44 and NAT64. What type of addresses does each translate between?
  2. DNS64 synthesizes AAAA records. What happens when a DNSSEC-validating resolver receives a DNS64-synthesized AAAA? Why does this cause a problem?
  3. Draw (ASCII art acceptable) the packet flow when an IPv6-only client connects to an IPv4-only server via NAT64/DNS64. Label each segment with the IP version used.

Cleanup

containerlab destroy -t topo-nat64.clab.yml

Grading (10 points)

Item Points
Manual NAT64 ping: IPv6 client reaches IPv4 server; translation map shown 2
DNS64 synthesis: AAAA record correctly synthesized and verified 2
Wireshark capture: IPv6 and IPv4 headers correctly identified on each side 3
Lab report: NAT44 vs NAT64 distinction; DNSSEC interaction; packet flow diagram 3