There was a question in the Wireshark Q&A site that prompted this post. A user wanted to pull out IP Addresses but only from the “Answer Records” section of DNS. All the information in Authority or Additional records section were to be ignored. The picture below describes what he was trying to accomplish with tshark.
Types of scripting
The problem is TShark does not actually expose an object model to a scripting language. The user gets the values of the fields “dns.qry.name” and “dns.resp.addr” which are tagged fields using the display filter format. Without doubt, this is a powerful capability of TShark but extending this to support adhoc scripting requirements is difficult. The solution is to dump the entire packet as text and parse if offline – a difficult ask.
How would you accomplish this with a scriptable object model ?
Unsniff Network Analyzer exposes an object model to scripting languages like Ruby and VBScript. So you can put together a quick script to walk down the protocol try which ever way you want. Lets do this example in Ruby.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
require 'win32ole' raise "Usage: pdns <pcap-file>" unless ARGV.length == 1 UnsniffDB = WIN32OLE.new("Unsniff.Database") UnsniffDB.New("temp.usnf") UnsniffDB.Import("libpcap",ARGV[0]) UnsniffDB.PacketIndex.each do |pkt| next unless pkt.Description =~ /QUERY Response/ dnslayer = pkt.FindLayer("DNS") answers = dnslayer.FindField("Answer Records") next if answers.nil? print "\n\nDNS Records in pkt #{pkt.ID} #{pkt.Description}\n" answers.SubFields.each do |rec| print rec.FindField("Type").Value.ljust(30) print rec.FindField("Name").Value.ljust(20) print rec.FindField("RDATA").Value.ljust(20) print "\n" end end UnsniffDB.Close() File.delete("temp.usnf") |
Once you get hold of the packets you want, you use the same field names in the GUI to navigate the protocol tree. The key pieces in the above ruby code are :
- Import the pcap file
1 |
UnsniffDB.Import("libpcap",ARGV[0]) |
- Iterate over all packets and only work on QUERY Response. The same string is shown in the user interface, so it is easy to remember this string.
1 2 |
UnsniffDB.PacketIndex.each do |pkt| next unless pkt.Description =~ /QUERY Response/ |
- Find the “Answer Records” section in the “DNS” layer and process each record
1 2 3 4 |
dnslayer = pkt.FindLayer("DNS") answers = dnslayer.FindField("Answer Records") .. answers.SubFields.each do |rec| |
Running this
If you run the above script
1 |
ruby pdns.rb mycapture.pcap |
You get something like this
1 2 3 4 5 6 7 8 9 10 11 |
DNS Records in pkt 5 QUERY Response ad.doubleclick.net CNAME. Canonical name ad.doubleclick.net dart.l.doubleclick.net A. IPv4 address dart.l.doubleclick.net74.125.236.188 A. IPv4 address dart.l.doubleclick.net74.125.236.187 DNS Records in pkt 6 QUERY Response www.espncricinfo.com CNAME. Canonical name www.espncricinfo.comwwwakamai.espncricinfo.com CNAME. Canonical name wwwakamai.espncricinfo.comcontent.cricinfo.com.edgesuite.net CNAME. Canonical name content.cricinfo.com.edgesuite.neta1850.g.akamai.net A. IPv4 address a1850.g.akamai.net 67.148.47.42 A. IPv4 address a1850.g.akamai.net 67.148.47.40 |
Add Unsniff to your toolkit
The beauty of Unsniff is you can script higher layer objects the same way using the UserObjects model. For example you can save all Images matching a certain name or size or whatever. Check out the samples here
- Download Unsniff Network Analyzer for free here