For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

TCP DNS64 Query

Problem this snippet solves:

This code is to support TCP DNS64 query. It is based on NAT64 DNS64 Codeshare contributed by Nat Thirasuttakorn and Configuring IP Address Sharing in a Large Scale Network: DNS64/NAT64 Deployment Guide version 1.4.

Please be noted that this code is only tested in test environment. Any suggestions are welcome.

Code :

when RULE_INIT {
set static::dns64prefix "0064ff9b0000000000000000"
}
when CLIENT_ACCEPTED {
TCP::collect
}
when CLIENT_DATA {
set query [TCP::payload]
binary scan $query @6S qdcount 

# only intercept AAAA QTYPE and reject AXFR/IXFR QTYPE
set index 14
while { $qdcount > 0 } {
binary scan $query @${index}c count
while { $count != 0 } {
incr index [expr {$count + 1}]
binary scan $query @${index}c count
}
incr index
binary scan $query @${index}S qtype
# 28 = AAAA, 251 = IXFR, 252 = AXFR
switch $qtype {
28 {
}
251 -
252 {
reject
return
}
default {
TCP::release
event disable all
return
}
}
incr index 4
incr qdcount -1
}
TCP::release
}
when SERVER_CONNECTED {
log local0. ""
set retry 0
TCP::collect
}
when SERVER_DATA {
log local0. ""

# change AAAA to A QTYPE only if ANCOUNT is 0
if { !$retry } {
binary scan [TCP::payload] @8S ancount
if { $ancount != 0 } {
return
}
binary scan $query @6S qdcount
set index 14
    while { $qdcount > 0 } {
binary scan $query @${index}c count
while { $count != 0 } {
incr index [expr {$count + 1}]
binary scan $query @${index}c count
}
incr index
binary scan $query @${index}S qtype
if { $qtype == 28 } {
set modified_query [binary format a* [string replace $query $index [expr {$index + 1}] [binary format S 1]]]
}
incr index 4
incr qdcount -1
    }
if { [info exists modified_query] } {
TCP::respond $modified_query
TCP::payload replace 0 [TCP::payload length] ""
incr retry
}

# add DNS64 prefix to A RR
} else {
set a_index_list ""

binary scan [TCP::payload] S@6SSSS len qdcount ancount nscount arcount
if { [TCP::payload length] < $len } {
TCP::collect
return
}
set index 14
    while { $qdcount > 0 } {
binary scan [TCP::payload] @${index}c count
while { $count != 0 } {
incr index [expr {$count + 1}]
binary scan [TCP::payload] @${index}c count
}
incr index
binary scan [TCP::payload] @${index}S qtype
if { $qtype == 1 } {
TCP::payload replace $index 2 [binary format S 28]
}
incr index 4
incr qdcount -1
    }

    while { $ancount > 0 || $nscount > 0 || $arcount > 0 } {
binary scan [TCP::payload] @${index}cc count pointer
set loop 0
while { $count != 0 && $loop < 30 } {
incr loop
set pointer_prefix [expr {($count >> 6) & 0x3}]
set pointer_index [expr {(($count & 0x3f) << 8) + ($pointer & 0xff)}]
if { $pointer_prefix == 3 } {
set save_pointer $pointer_index
foreach a $a_index_list {
if { $pointer_index < $a } {
break
}
incr pointer_index 12
}
# rewrite DNS compression pointer to appropriate value
if { $pointer_index > $save_pointer } {
TCP::payload replace $index 2 [binary format S [expr {$pointer_index | 0xc000}]]
}
incr index 2
break
} else {
incr index [expr {$count + 1}]
binary scan [TCP::payload] @${index}cc count pointer
}
}
binary scan [TCP::payload] @${index}SSIS qtype qclass ttl rdlength
incr index 10
if { $qtype == 1 } {
lappend a_index_list $index
binary scan [TCP::payload] @${index}cccc a b c d
set rdlength 16
TCP::payload replace [expr {$index - 10}] 14 [binary format SSISH24cccc 28 $qclass $ttl $rdlength $static::dns64prefix $a $b $c $d]
} elseif { $qtype == 2 } {
binary scan [TCP::payload] @${index}a${rdlength} rdata 
for { set x 0 } { $x < [expr {$rdlength - 1}] } { incr x } {
binary scan $rdata x${x}cc count pointer
set pointer_prefix [expr {($count >> 6) & 0x3}]
set pointer_index [expr {(($count &0x3f) << 8) + ($pointer & 0xff)}]
if { $pointer_prefix == 3 } {
set save_pointer $pointer_index
foreach a $a_index_list {
if { $pointer_index < $a } {
break
}
incr pointer_index 12
}
# rewrite DNS compression pointer to appropriate value
if { $pointer_index > $save_pointer } {
TCP::payload replace [expr {$index + $x}] 2 [binary format S [expr {$pointer_index | 0xc000}]]
}
}
}
}
incr index $rdlength
if { $ancount > 0 } {
incr ancount -1
} elseif  { $nscount > 0 } {
incr nscount -1
} else {
incr arcount -1
}
}
TCP::payload replace 0 2 [binary format S [expr {[TCP::payload length] - 2}]]
}
TCP::release
TCP::collect
}
Published Oct 15, 2016
Version 1.0
No CommentsBe the first to comment