diff --git a/.gitignore b/.gitignore index ad7e0ba..e84fb50 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ pip-log.txt # Unit test / coverage reports .coverage .tox +.cache # iPython temp files .ipynb_checkpoints diff --git a/docs/examples.rst b/docs/examples.rst index d99a0c2..59124ea 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -5,58 +5,11 @@ Examples Examples in dpkt/examples ------------------------- -print_packets.py -~~~~~~~~~~~~~~~~ -.. automodule:: examples.print_packets - -**Code Excerpt** - -.. code-block:: python - - # For each packet in the pcap process the contents - for timestamp, buf in pcap: - - # Print out the timestamp in UTC - print 'Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp)) - - # Unpack the Ethernet frame (mac src/dst, ethertype) - eth = dpkt.ethernet.Ethernet(buf) - print 'Ethernet Frame: ', mac_addr(eth.src), mac_addr(eth.dst), eth.type - - # Make sure the Ethernet frame contains an IP packet - # EtherType (IP, ARP, PPPoE, IP6... see http://en.wikipedia.org/wiki/EtherType) - if eth.type != dpkt.ethernet.ETH_TYPE_IP: - print 'Non IP Packet type not supported %s\n' % eth.data.__class__.__name__ - continue - - # Now unpack the data within the Ethernet frame (the IP packet) - # Pulling out src, dst, length, fragment info, TTL, and Protocol - ip = eth.data - - # Pull out fragment information (flags and offset all packed into off field, so use bitmasks) - do_not_fragment = bool(ip.off & dpkt.ip.IP_DF) - more_fragments = bool(ip.off & dpkt.ip.IP_MF) - fragment_offset = ip.off & dpkt.ip.IP_OFFMASK - - # Print out the info - print 'IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)\n' % \ - (ip_to_str(ip.src), ip_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, more_fragments, fragment_offset) - -**Example Output** - -.. code-block:: json - - Timestamp: 2004-05-13 10:17:07.311224 - Ethernet Frame: 00:00:01:00:00:00 fe:ff:20:00:01:00 2048 - IP: 145.254.160.237 -> 65.208.228.223 (len=48 ttl=128 DF=1 MF=0 offset=0) - - Timestamp: 2004-05-13 10:17:08.222534 - Ethernet Frame: fe:ff:20:00:01:00 00:00:01:00:00:00 2048 - IP: 65.208.228.223 -> 145.254.160.237 (len=48 ttl=47 DF=1 MF=0 offset=0) - - ... - +.. toctree:: + :maxdepth: 2 + print_packets + print_icmp Jon Oberheide's Examples ------------------------- diff --git a/examples/data/dns_icmp.pcap b/examples/data/dns_icmp.pcap new file mode 100644 index 0000000..c020b22 Binary files /dev/null and b/examples/data/dns_icmp.pcap differ diff --git a/examples/print_icmp.py b/examples/print_icmp.py new file mode 100644 index 0000000..753edfc --- /dev/null +++ b/examples/print_icmp.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +""" +This example expands on the print_packets example. It checks for IMCP packets and displays the ICMP contents. +""" +import dpkt +import datetime +import socket + + +def mac_addr(address): + """Convert a MAC address to a readable/printable string + + Args: + address (str): a MAC address in hex form (e.g. '\x01\x02\x03\x04\x05\x06') + Returns: + str: Printable/readable MAC address + """ + return ':'.join('%02x' % ord(b) for b in address) + + +def inet_to_str(inet): + """Convert inet object to a string + + Args: + inet (inet struct): inet network address + Returns: + str: Printable/readable IP address + """ + # First try ipv4 and then ipv6 + try: + return socket.inet_ntop(socket.AF_INET, inet) + except ValueError: + return socket.inet_ntop(socket.AF_INET6, inet) + +def print_icmp(pcap): + """Print out information about each packet in a pcap + + Args: + pcap: dpkt pcap reader object (dpkt.pcap.Reader) + """ + # For each packet in the pcap process the contents + for timestamp, buf in pcap: + + # Unpack the Ethernet frame (mac src/dst, ethertype) + eth = dpkt.ethernet.Ethernet(buf) + + # Make sure the Ethernet frame contains an IP packet + # EtherType (IP, ARP, PPPoE, IP6... see http://en.wikipedia.org/wiki/EtherType) + if eth.type != dpkt.ethernet.ETH_TYPE_IP: + print 'Non IP Packet type not supported %s\n' % eth.data.__class__.__name__ + continue + + # Now grab the data within the Ethernet frame (the IP packet) + ip = eth.data + + # Now check if this is an ICMP packet + if hasattr(ip, 'data') and ip.data.__class__.__name__ == 'ICMP': + icmp = ip.data + + # Pull out fragment information (flags and offset all packed into off field, so use bitmasks) + do_not_fragment = bool(ip.off & dpkt.ip.IP_DF) + more_fragments = bool(ip.off & dpkt.ip.IP_MF) + fragment_offset = ip.off & dpkt.ip.IP_OFFMASK + + # Print out the info + print 'Timestamp: ', str(datetime.datetime.utcfromtimestamp(timestamp)) + print 'Ethernet Frame: ', mac_addr(eth.src), mac_addr(eth.dst), eth.type + print 'IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)' % \ + (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, more_fragments, fragment_offset) + print 'ICMP: type:%d code:%d checksum:%d data: %s\n' % (icmp.type, icmp.code, icmp.sum, repr(icmp.data)) + + +def test(): + """Open up a test pcap file and print out the packets""" + with open('data/dns_icmp.pcap', 'rb') as f: + pcap = dpkt.pcap.Reader(f) + print_icmp(pcap) + + +if __name__ == '__main__': + test() diff --git a/examples/print_packets.py b/examples/print_packets.py index a822546..e61048e 100644 --- a/examples/print_packets.py +++ b/examples/print_packets.py @@ -19,16 +19,19 @@ def mac_addr(address): return ':'.join('%02x' % ord(b) for b in address) -def ip_to_str(address): - """Print out an IP address given a string +def inet_to_str(inet): + """Convert inet object to a string - Args: - address (inet struct): inet network address - Returns: - str: Printable/readable IP address + Args: + inet (inet struct): inet network address + Returns: + str: Printable/readable IP address """ - return socket.inet_ntop(socket.AF_INET, address) - + # First try ipv4 and then ipv6 + try: + return socket.inet_ntop(socket.AF_INET, inet) + except ValueError: + return socket.inet_ntop(socket.AF_INET6, inet) def print_packets(pcap): """Print out information about each packet in a pcap @@ -52,7 +55,7 @@ def print_packets(pcap): print 'Non IP Packet type not supported %s\n' % eth.data.__class__.__name__ continue - # Now unpack the data within the Ethernet frame (the IP packet) + # Now unpack the data within the Ethernet frame (the IP packet) # Pulling out src, dst, length, fragment info, TTL, and Protocol ip = eth.data @@ -63,7 +66,7 @@ def print_packets(pcap): # Print out the info print 'IP: %s -> %s (len=%d ttl=%d DF=%d MF=%d offset=%d)\n' % \ - (ip_to_str(ip.src), ip_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, more_fragments, fragment_offset) + (inet_to_str(ip.src), inet_to_str(ip.dst), ip.len, ip.ttl, do_not_fragment, more_fragments, fragment_offset) def test():