NAT64 DNS64

Problem this snippet solves:

Contributed by: nat at f5.com Last update: June 15, 2010 15:35PM (US Pacific Time)

This is a solution that allows client from IPv6 network to communicate to IPv4 network through BIG-IP. It actually contains 2 iRules:- NAT64 and DNS64 iRule (see iRule source section below).

Here is how it works:-

  • Suppose IPv6 client is going to connect to www.f5.com which resides in IPv4 network
  • First, IPv6 client performs DNS resolution. IPv6 client sends DNS AAAA query to BIG-IP.
  • BIG-IP transforms AAAA to A query by DNS64 iRule
  • BIG-IP forwards A query from previous step to DNS pool in IPv4 domain
  • DNS server in IPv4 domain replies to BIG-IP
  • BIG-IP performs appropriate transformation such as changing from A to AAAA query and changing IPv4 address to IPv6 address before forwarding DNS answer back to IPv6 client. BIG-IP uses fix 96-bit prefix address concatenate with 32-bit IPv4 address to form new dynamic IPv6 address. This steps is once again done by DNS64 iRule.
  • Once IPv6 client gets the answer to AAAA query (as IPv6 destination address). It opens connection to the IPv6 destination address. Traffic to the IPv6 destination must be routed through BIG-IP
  • BIG-IP receives IPv6 traffic from client, perform src and dst address translation, and forwards to IPv4 network. This step is done by NAT64 iRule.

Please be noted. This iRule is still in experimental stage and it may contains redundant routine. Any comment/feedback is welcome.

Code :

# virtual server configuration
virtual dns64 {
   pool dns64
   destination 2001:123::1.domain
   ip protocol udp
   rules dns64
}
virtual nat64 {
   translate address enable
   snat automap
   destination 2002:123::.any
   mask ffff:ffff:ffff:ffff:ffff:ffff::
   rules nat64
}
# Pool for DNS server in IPv4 domain
pool dns64 {
   members 172.27.4.209:domain {}
}
# NAT64 iRule
when CLIENT_ACCEPTED {
    node [string range [IP::addr  [IP::local_addr]  mask ::ffff:ffff] 0 end]
}

# DNS64 iRule
when RULE_INIT {
    set static::prefix "200201230000000000000000"
}
when CLIENT_DATA {
    binary scan [UDP::payload] SSSSSS id flags qdcount ancount nscount arcount
    # Total Header length = 12 bytes
    set index 12

    # Question Section: it is usually 1 (qdcount=1), we may not need to loop here actually.
    # also assume no pointer (dns compression) here
    while { $qdcount > 0 } {
        binary scan [UDP::payload] @${index}c count
        while { $count != 0 } {
            incr index [expr $count + 1]
            binary scan [UDP::payload] @${index}c count
        }
        incr index
        binary scan [UDP::payload] @${index}SS qtype qclass
# change to A record
if { $qtype == 28 } {
UDP::payload replace ${index} 2 [binary format S 1]
}
        incr index 4
        incr qdcount -1
    }
}
when SERVER_DATA {
    binary scan [UDP::payload] SSSSSS id flags qdcount ancount nscount arcount
    # Total Header length = 12 bytes
    set index 12

    # Question Section: it is usually 1 (qdcount=1), we may not need to loop here actually.
    while { $qdcount > 0 } {
        binary scan [UDP::payload] @${index}c count
        while { $count != 0 } {
            incr index [expr $count + 1]
            binary scan [UDP::payload] @${index}c count
        }
        incr index
        binary scan [UDP::payload] @${index}SS qtype qclass
# change A(1) to AAAA(28) record
if { $qtype == 1 } {
UDP::payload replace ${index} 2 [binary format S 28]
}
        incr index 4
        incr qdcount -1
    }
    # The Answer, Authority and Additional Sections
    while { $ancount > 0 || $nscount > 0 || $arcount > 0} {
        binary scan [UDP::payload] @${index}cc count pointer
        set loop 0
        while { $count != 0 and $loop < 30 } {
            incr loop
            set pointer_prefix [expr ($count >> 6) & 0x3]
            set pointer_index [expr (($count &0x3f)<<8) | $pointer  ]
            if { $pointer_prefix == 3 } {
                incr index 2
                break
            } else {
                incr index [expr $count + 1]
                binary scan [UDP::payload] @${index}cc count pointer
            }
        }
        binary scan [UDP::payload] @${index}SSIS qtype qclass ttl rdlength
        incr index 10
        if { $qtype == 1 } {
            # change A to AAAA record
            binary scan [UDP::payload] @${index}cccc a b c d
            # change length from 4 to 6
            set rdlength 16
            # change IPv4 to IPv6
            UDP::payload replace [expr ${index} - 10] 14 [binary format SSISH24cccc 28 \
                $qclass $ttl $rdlength $static::prefix $a $b $c $d]
        }
        incr index $rdlength
        if { $ancount > 0 } {
            incr ancount -1
        } elseif  { $nscount > 0 } {
            incr nscount -1
        } else {
            incr arcount -1
        }
    }
}
Published Mar 18, 2015
Version 1.0
No CommentsBe the first to comment