Skip to content

Commit

Permalink
Fixed the DNS handler to be a regular DNSScanner now that packet hand…
Browse files Browse the repository at this point in the history
…lers have been deprecated in favour of UDP stream reassembly.

darcs-hash:20090522154300-f1522-9bc0cac949e4027986a81c717b58bc8db1a3aab5.gz
  • Loading branch information
scudette committed May 22, 2009
1 parent e643c9e commit 946d57f
Showing 1 changed file with 53 additions and 50 deletions.
103 changes: 53 additions & 50 deletions src/plugins/NetworkForensics/ProtocolHandlers/DNS.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
import pyflag.DB as DB
import struct
from pyflag.ColumnTypes import StringType, PacketType, IPType

import pyflag.conf
config=pyflag.conf.ConfObject()
from NetworkScanner import StreamScannerFactory
from pyflag.ColumnTypes import StringType, TimestampType, InodeIDType, IntegerType, PacketType, guess_date, PCAPTime, IPType

class DNSString(STRING):
""" This parses names encoded in DNS. We support standard DNS
Expand Down Expand Up @@ -154,31 +157,34 @@ def __init__(self, buffer, *args, **kwargs):
## endianess is always big with DNS:
kwargs['endianess']='b'
SimpleStruct.__init__(self, buffer, *args, **kwargs)

class DNSHandler(Packets.PacketHandler):
""" Handles DNS packets.
PyFlag's PCAPFS will call us on each packet which does not belong
in a stream (e.g. UDP). We need to ensure that we only handle
things that look like DNS. In this case we assume that the port
must be 53 which is pretty good assumption for DNS although there
may be other traffic on port 53 which is not DNS.
"""
def handle(self, packet):
try:
udp = packet.find_type("UDP")
if udp.src_port==53 or udp.dest_port==53:
##print "Handling packet %s->%s" % (udp.src_port, udp.dest_port)
## Try to parse the packet as a DNS packet:
dns = DNSPacket(udp.data)

config.add_option("DNS_PORTS", default='[53,]',
help="A list of ports to be considered for DNS transactions")


class DNSScanner(StreamScannerFactory):
""" Collect information about DNS resolution """
default = True
group = "NetworkScanners"

def process_stream(self, stream, factories):
forward_stream, reverse_stream = self.stream_to_server(stream, "DNS")
print "forward_stream %s, reverse_stream %s" % (forward_stream, reverse_stream)
if reverse_stream:
fd = self.fsfd.open(inode_id=reverse_stream)
## We assume maximum length for DNS (this might be too
## short for TCP connections).
data = fd.read(1024)
try:
dns = DNSPacket(data)
dbh = DB.DBO(self.case)
## This is needed so we can iterate twice over the
## same array in case a CNAME is found
answers = [x for x in dns['Answers']]

for answer in answers:
if answer['Type']=='A':
dbh.insert('dns', packet_id = packet.id,
dbh.insert('dns', inode_id = forward_stream,
name = answer['Name'],
ip_addr = struct.unpack('>I',answer['IP Address'].data)[0])

Expand All @@ -188,53 +194,50 @@ def handle(self, packet):
## CNAME records are followed by A records.
for possible_a in answers:
if possible_a['Type']=='A' and possible_a['Name']==answer['C Name']:
dbh.insert('dns', packet_id = packet.id,
dbh.insert('dns', inode_id = forward_stream,
name = answer['Name'],
ip_addr = struct.unpack('>I',possible_a['IP Address'].data)[0])

except (AttributeError,KeyError,IOError),e:
pass

# FIXME: this does not have an InodeID
#class DNSTable(FlagFramework.CaseTable):
# """ DNS Table - holds DNS lookups """
# name = "dns"
# columns = [ [ In

class DNSInit(FlagFramework.EventHandler):
def create(self, dbh, case):
dbh.execute(
"""Create table if not exists `dns` (
`packet_id` int,
`name` VARCHAR(255) NOT NULL,
`ip_addr` int unsigned NOT NULL,
key(ip_addr)
)""")
except (AttributeError,KeyError,IOError),e:
pass

class DNSCaseTable(FlagFramework.CaseTable):
""" DNS Table - Stores DNS transactions """
name = 'dns'
columns = [
[ InodeIDType, {} ],
[ StringType, dict(name = 'DNS Name', column='name') ],
[ IPType, dict(name = 'IP Address', column='ip_addr') ],
]

import pyflag.Reports as Reports

class DNSBrowser(Reports.report):
class DNSBrowser(Reports.CaseTableReports):
""" A list of all DNS names seen in the traffic """
name = "Browse DNS"
family = "Network Forensics"
def display(self, query, result):
result.table(
elements = [ PacketType('Packet ID','packet_id', case=query['case']),
StringType("Name", 'name'),
IPType('IP Address', 'ip_addr'),
],
table = 'dns',
case=query['case'],
)
default_table = "DNSCaseTable"
columns = ['Inode', 'DNS Name', 'IP Address']

import pyflag.tests as tests

import pyflag.pyflagsh as pyflagsh

class DNSTests(tests.ScannerTest):
""" Test DNS Scanner """
test_case = "PyFlagTestCase"
test_file = "scenario/full_dump.pcap.e01"
test_file = "stdcapture_0.4.pcap.e01"
subsystem = "EWF"
fstype = "PCAP Filesystem"

def test01DNS(self):
"Test DNS handling"
env = pyflagsh.environment(case=self.test_case)
pyflagsh.shell_execv(env=env,
command="scan",
argv=["*", ## Inodes (All)
"DNSScanner",
]) ## List of Scanners

if __name__=='__main__':
test_str = 'Q\xcf\x81\x80\x00\x01\x00\x03\x00\x06\x00\x06\x04mail\x06google\x03com\x00\x00\x01\x00\x01\xc0\x0c\x00\x05\x00\x01\x00\x00\x001\x00\x0f\ngooglemail\x01l\xc0\x11\xc0-\x00\x01\x00\x01\x00\x00\x01\x1e\x00\x04B\xf9S\x13\xc0-\x00\x01\x00\x01\x00\x00\x01\x1e\x00\x04B\xf9SS\xc08\x00\x02\x00\x01\x00\x01\x03\xee\x00\x04\x01e\xc08\xc08\x00\x02\x00\x01\x00\x01\x03\xee\x00\x04\x01g\xc08\xc08\x00\x02\x00\x01\x00\x01\x03\xee\x00\x04\x01a\xc08\xc08\x00\x02\x00\x01\x00\x01\x03\xee\x00\x04\x01b\xc08\xc08\x00\x02\x00\x01\x00\x01\x03\xee\x00\x04\x01c\xc08\xc08\x00\x02\x00\x01\x00\x01\x03\xee\x00\x04\x01d\xc08\xc0\x88\x00\x01\x00\x01\x00\x01=\xcd\x00\x04\xd8\xef5\t\xc0\x98\x00\x01\x00\x01\x00\x01=\xcd\x00\x04@\xe9\xb3\t\xc0\xa8\x00\x01\x00\x01\x00\x01=\xcd\x00\x04@\xe9\xa1\t\xc0\xb8\x00\x01\x00\x01\x00\x01=\xcd\x00\x04@\xe9\xb7\t\xc0h\x00\x01\x00\x01\x00\x01=\xcd\x00\x04Bf\x0b\t\xc0x\x00\x01\x00\x01\x00\x01=\xcd\x00\x04@\xe9\xa7\t'
Expand Down

0 comments on commit 946d57f

Please sign in to comment.