1

Hi everyone this is my first time doing PCAP programming using Python for the programming language, this is for a task for University and I have mostly got everything I need to complete the task except for one small detail.

I just need to get an output of the source and destination port numbers (HTTP Port 80 for example) associated with the IP addresses.

I'm happy for the answer to be a pointer to the right direction to help me work it out for myself. Otherwise if it's easier for it to be just answered, I would like a basic explanation on what was used and how it resolves the problem so I can understand it better for when I do more future PCAP programming in my studies and research.

This is being utilized on a Unix system running FreeBSD 10.3

I have tried using dpkt.tcp, dpkt.udp, dpkt.ip libraries as well as tried some socket libraries to see if I can achieve the result I am looking for, but not having much luck. I'll be honest, I'm not sure what I need to use.

EDIT: I did try using tcp.sport and tcp.dport, still had no luck.

The main area of focus is where I have added the comments.

import datetime
import time
import sys
import dpkt
import socket

def printPcap(pcap):
    for (ts,buf) in pcap:
        try:
            eth = dpkt.ethernet.Ethernet(buf)
            if eth.type == dpkt.ethernet.ETH_TYPE_IP:
                ip = eth.data
                ipsrc = socket.inet_ntoa(ip.src)        
                ipdst = socket.inet_ntoa(ip.dst)

                srcport = ??? ###Stuck here for source port
                dstport = ??? ###Stuck here for destination port

                if ip.p == dpkt.ip.IP_PROTO_TCP:        
                    TCP = ip.data
                    iptype = 'tcp'
                elif ip.p == dpkt.ip.IP_PROTO_UDP:   
                    UDP = ip.data
                    iptype = 'udp'
                len = str(ip.len)
                ttl = str(ip.ttl)

                ###My current output
                print '[' +str(datetime.datetime.utcfromtimestamp(ts))+ '] - ' \
                        +ipsrc+ ':' +srcport+ ' -> ' +ipdst+ ':' +dstport+ \
                        ' ('+iptype+', len='+len+', ttl='+ttl+')'

        except:
            pass

SAMPLE EXPECTED OUTPUT:

[2018-08-16 02:48:10.238506] - 172.16.11.2:61016 -> 172.16.10.2:80 (tcp, len=52, ttl=63)
Gil Hamilton
  • 11,973
  • 28
  • 51
NoMReG
  • 21
  • 1
  • 5

2 Answers2

0

Perhaps use ip.data to get the TCP packet and the sport and/or dport?

ip = eth.data

if ip.p == dpkt.ip.IP_PROTO_TCP:
    tcp = ip.data
    print('source port: {}, dest port: {}'.format(tcp.sport, tcp.dport))
jspcal
  • 50,847
  • 7
  • 72
  • 76
  • Just gave that a try just now, unfortunately it doesn't seem to work (I must be going crazy!). Just doesn't seem to output anything. I forgot to mention I did try using tcp.sport and tcp.dport as well. – NoMReG Apr 25 '19 at 16:52
  • Perhaps the packets are not IP/TCP? Try printing some diagnostics to see what packet types are being read. – jspcal Apr 25 '19 at 16:56
  • Hate to ask, but how do I go about diagnostics to determine the packet types? It's my first time doing PCAP programming. – NoMReG Apr 25 '19 at 16:59
  • Maybe print some log messages at each step to see what the packet types being read are. – jspcal Apr 25 '19 at 17:02
0

The problem is that your print statement is bogus, but you've hidden that with the "bare except". Using the bare except is considered very poor practice in python for exactly this reason. See also answers to this question: Should I always specify an exception type in `except` statements?

Specifically, your print statement is attempting to concatenate an integer to a string which isn't valid.

So, repaired, and with:

                if ip.p == dpkt.ip.IP_PROTO_TCP:
                    TCP = ip.data
                    iptype = 'tcp'
                    srcport = TCP.sport
                    dstport = TCP.dport
                elif ip.p == dpkt.ip.IP_PROTO_UDP:
                    UDP = ip.data
                    iptype = 'udp'
                    srcport = UDP.sport
                    dstport = UDP.dport

and this print statement, it works:

                print("[{}] - {}:{} -> {}:{} ({}, len={}, ttl={})".format(
                      datetime.datetime.utcfromtimestamp(ts), ipsrc, srcport,
                      ipdst, dstport, iptype, len, ttl))

Finally, at the very least, I would change your except clause to something like this to detect such issues in the future:

        except Exception as exc:
            print("Exception: {}".format(exc))

(Note that I've used the python3-compatible print function syntax here, which also works fine with python2's print statement.)

EDIT:
One other thing just occurred to me. If the first IP packet encountered is neither TCP or UDP, srcport and dstport will not be defined and that will cause an AttributeError exception. Leaving that for you to clean up.

Gil Hamilton
  • 11,973
  • 28
  • 51
  • Thank you Gil for explaining this for me! Makes a lot more sense now that I can see what went wrong. Also thanks for telling me about the "bare except" issue as well as I would not have known about that. I'll be sure to consider these issues in my future learning for programming. – NoMReG Apr 27 '19 at 02:03