DNS Decoding
Problem this snippet solves:
Sample iRule that does DNS decoding, for DNS protocol debugging and studying :)
June 3 2014 : We have got few customers using this script in production and having system rebooted due to possible indefinite loop in this script. There are possible risks with the while loops without any protection. As the original contributor kindly mentions this is debugging and studying sample, those who want to use this script in their production should understand what it is doing and improve security by their selves. Kimihito.
Code :
when RULE_INIT { array set ::type2name { 1 A 2 NS 3 MD 4 MF 5 CNAME 6 SOA 7 MB 8 MG 9 MR 10 NULL 11 WKS 12 PTR 13 HINFO 14 MINFO 15 MX 16 TXT 17 RP 18 AFSDB 19 X25 20 ISDN 21 RS 22 NSAP 23 NSAP_PTR 24 SIG 25 KEY 26 PX 27 GPOS 28 AAAA 29 LOC 30 NXT 31 EID 32 NIMLOC 33 SRV 34 ATMA 35 NAPTR 36 KX 37 CERT 38 A6 39 DNAME 40 SINK 41 OPT 42 APL 43 DS 44 SSHFP 45 IPSECKEY 46 RRSIG 47 NSEC 48 DNSKEY 49 DHCID 55 HIP 99 SPF 100 UINFO 101 UID 102 GID 103 UNSPEC 249 TKEY 250 TSIG 251 IXFR 252 AXFR 253 MAILB 254 MAILA 32768 TA 32769 DLV 65281 WINS 65282 WINS_R } array set ::class2name { 1 IN 2 CS 3 CH 4 HS 254 NONE 255 ANY } array set ::qr2txt { 0 "query" 1 "response" } array set ::opcode2txt { 0 "Standard query" 1 "Inverse query" 2 "Server status request" 4 "Zone change notification" 5 "Dynamic update" } array set ::rcode2txt { 0 "No error condition" 1 "Format error" 2 "Server failure" 3 "Name Error" 4 "Not Implemented" 5 "Refused" 6 "Name exists" 7 "RRset exists" 8 "RRset does not exist" 9 "Not authoritative" 10 "Name out of zone" 16 "TSIG Signature Failure" 17 "Key not recognized" 18 "Signature out of time window" 19 "Bad TKEY Mode" 20 "uplicate key name" 21 "Algorithm not supported" 22 "Bad Truncation" } } when CLIENT_DATA { binary scan [UDP::payload] SSSSSS id flags qdcount ancount nscount arcount set qr [expr ($flags >> 15)&0x1] set opcode [expr ($flags >> 11)& 0xf] set aa [expr ($flags >> 10)& 0x1] set tc [expr ($flags >> 9)& 0x1] set rd [expr ($flags >> 8)& 0x1] set ra [expr ($flags >> 7)& 0x1] set z [expr ($flags >> 4)& 0x7] set rcode [expr $flags & 0xf] #log local0. "DEBUG: ID=$id Query=$qr Opcode=$opcode Authoritative=$aa Truncate=$tc Recursion_Desired=$rd \ Recursion_Available=$ra Reserve(000)=$z Response_Code=$rcode Questions=$qdcount Answers=$ancount Name_Servers=$nscount \ Additionals=$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 incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}c name new_count incr index $count incr index set count $new_count if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } binary scan [UDP::payload] @${index}SS qtype qclass log local0. "Question: $dname qtype=$::type2name($qtype) qclass=$::class2name($qclass)" unset dname incr index 4 incr qdcount -1 } } when SERVER_DATA { binary scan [UDP::payload] SSSSSS id flags qdcount ancount nscount arcount set qr [expr ($flags >> 15)&0x1] set opcode [expr ($flags >> 11)& 0xf] set aa [expr ($flags >> 10)& 0x1] set tc [expr ($flags >> 9)& 0x1] set rd [expr ($flags >> 8)& 0x1] set ra [expr ($flags >> 7)& 0x1] set z [expr ($flags >> 4)& 0x7] set rcode [expr $flags & 0xf] #log local0. "DEBUG: ID=$id Query=$qr Opcode=$opcode Authoritative=$aa Truncate=$tc Recursion_Desired=$rd \ Recursion_Available=$ra Reserve(000)=$z Response_Code=$rcode Questions=$qdcount Answers=$ancount Name_Servers=$nscount \ Additionals=$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 incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}c name new_count incr index $count incr index set count $new_count if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } binary scan [UDP::payload] @${index}SS qtype qclass log local0. "Question: $dname qtype=$::type2name($qtype) qclass=$::class2name($qclass)" unset dname incr index 4 incr qdcount -1 } # The Answer, Authority and Additional Sections while { $ancount > 0 || $nscount > 0 || $arcount > 0} { binary scan [UDP::payload] @${index}S pointer if { [expr ($pointer >> 14) & 0x3] == 3 } { set saveindex $index set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}S name pointer incr index $count if { [expr ($pointer >> 14) & 0x3] == 3 } { if { not [info exists saveindex] } { set saveindex $index } set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } if { [info exists saveindex] } { set index $saveindex incr index 2 unset saveindex } binary scan [UDP::payload] @${index}SSIS type class ttl rdlength incr index 10 if { [info exists dname] } { set savename $dname; unset dname } switch $type { 1 { # A binary scan [UDP::payload] @${index}cccc a b c d set addr [expr ($a+0x100)%0x100].[expr ($b+0x100)%0x100].[expr ($c+0x100)%0x100].[expr ($d+0x100)%0x100] log local0. "$::type2name($type): $savename $addr" incr index $rdlength } 12 - 9 - 8 - 7 - 5 - 4 - 3 - 2 { # NS, MD, MF, CNAME, MB, MG, MR, PTR, MINFO binary scan [UDP::payload] @${index}S pointer if { [expr ($pointer >> 14) & 0x3] == 3 } { set saveindex $index set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}S name pointer incr index $count if { [expr ($pointer >> 14) & 0x3] == 3 } { if { not [info exists saveindex] } { set saveindex $index } set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } if { [info exists saveindex] } { set index $saveindex incr index 2 unset saveindex } log local0. "$::type2name($type): $savename $dname" unset dname } 6 { # SOA foreach i { mname rname } { binary scan [UDP::payload] @${index}S pointer if { [expr ($pointer >> 14) & 0x3] == 3 } { set saveindex $index set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}S name pointer incr index $count if { [expr ($pointer >> 14) & 0x3] == 3 } { if { not [info exists saveindex] } { set saveindex $index } set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } if { [info exists saveindex] } { set index $saveindex incr index 2 unset saveindex } set $i $dname unset dname } # SERIAL, REFRESH, RETRY, EXPIRE binary scan [UDP::payload] @${index}IIIII serial refresh retry expire minimum incr index 20 log local0. "SOA: $mname $rname serial=$serial, refresh=$refresh, retry=$retry, \ expire=$expire minimum=$minimum" } 13 { foreach i { cpu os } { binary scan [UDP::payload] @${index}c length incr index binary scan [UDP::payload] @${index}A${length} string incr index $length set $i $string } log local0. "$::type2name($type): $cpu $os" } 14 { # MINFO # RMAILBX, EMAILBX foreach i { rmailbx emailbx } { binary scan [UDP::payload] @${index}S pointer if { [expr ($pointer >> 14) & 0x3] == 3 } { set saveindex $index set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}S name pointer incr index $count if { [expr ($pointer >> 14) & 0x3] == 3 } { if { not [info exists saveindex] } { set saveindex $index } set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } if { [info exists saveindex] } { set index $saveindex incr index 2 unset saveindex } set $i $dname unset dname } unset dname log local0. "$::type2name($type): $savename $rmailbx $emailbx" } 15 { # MX binary scan [UDP::payload] @${index}SS preference pointer incr index 2 if { [expr ($pointer >> 14) & 0x3] == 3 } { set saveindex $index set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}S name pointer incr index $count if { [expr ($pointer >> 14) & 0x3] == 3 } { if { not [info exists saveindex] } { set saveindex $index } set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } if { [info exists saveindex] } { set index $saveindex incr index 2 unset saveindex } log local0. "$::type2name($type): $savename $dname $preference" unset dname } 16 { set maxlen [expr $index + $rdlength ] while { $index < $maxlen } { binary scan [UDP::payload] @${index}c length incr index binary scan [UDP::payload] @${index}A${length} string incr index $length log local0. "$::type2name($type): $string" } } 28 { # AAAA binary scan [UDP::payload] @${index}H4H4H4H4H4H4H4H4 a b c d e f g h log local0. "$::type2name($type): $savename $a:$b:$c:$d:$e:$f:$g:$h" incr index $rdlength } 33 { # SRV binary scan [UDP::payload] @${index}SSSS priority weight port pointer incr index 6 if { [expr ($pointer >> 14) & 0x3] == 3 } { set saveindex $index set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index while { $count != 0 } { binary scan [UDP::payload] @${index}A${count}S name pointer incr index $count if { [expr ($pointer >> 14) & 0x3] == 3 } { if { not [info exists saveindex] } { set saveindex $index } set index [expr $pointer & 0x3fff] } binary scan [UDP::payload] @${index}c count incr index if { [info exists dname] } { set dname $dname.$name } else { set dname $name } } if { [info exists saveindex] } { set index $saveindex incr index 2 unset saveindex } log local0. "$::type2name($type): $savename $priority $weight $port $dname" unset dname } default { binary scan [UDP::payload] @${index}H[expr $rdlength * 2] rdata log local0. "$::type2name($type): data=0x$rdata" incr index $rdlength } } if { $ancount > 0 } { incr ancount -1 } elseif { $nscount > 0 } { incr nscount -1 } else { incr arcount -1 } } } # Introducing loop limit counters, $limitqdcount and $limitname to avoid tmm. It'd be better to apply something similar not only to CLIENT_DATA but also SERVER_DATA side. # Line 123 ~ # Total Header length = 12 bytes set index 12 # Question Section: it is usually 1 (qdcount=1), we may not need to loop here actually. # This is a protection for many Questions in a single query packet set limitqdcount 0 while { $qdcount > 0 } { # qdcount is generally 1. if { $limitqdcount > 0 } { log local0. "limitqdcount exceeded " return } binary scan [UDP::payload] @${index}c count incr index # This is a protection for too long domain name set limitname 0 while { $count != 0 } { # How long domain name of the query you allow. Setting it to 2, you allow "www.example.com" but "www.my.example.com". if { $limitname > 2 } { log local0. "limitname exceeded : too long domain name " return } binary scan [UDP::payload] @${index}A${count}c name new_count incr index $count incr index set count $new_count if { [info exists dname] } { set dname $dname.$name } else { set dname $name } incr limitname 1 } binary scan [UDP::payload] @${index}SS qtype qclass opcode rcode log local0. "Question : $dname qtype=$::type2name($qtype) qclass=$::class2name($qclass)" unset dname incr index 4 incr qdcount -1 incr limitqdcount 1 } }
Published Mar 17, 2015
Version 1.0Nat_Thirasuttakorn
Employee
Joined September 25, 2004
Nat_Thirasuttakorn
Employee
Joined September 25, 2004
No CommentsBe the first to comment