title: Using python to add protocol to Wireshark capture
body: <p>For the last number of years I've been using Wireshark to successfully capture and analyse samples of network traffic. I then typically need to modify this capture file by encapsulating it within a GTP layer such that I can post process the pcap with a proprietary tool. I have always achieved this successfully in the linux environment using a python script adding a "fixed" GTP headed to each TCP / UDP packet utilising something like</p>
  
  <pre><code>import sys
  import dpkt
  from dpkt.ip import IP
  from dpkt.udp import UDP
  from optparse import OptionParser
  import struct
  import socket
  # from pcapy import *
  
  ETHERNET_SRC = "\x01\x02\x03\x04\x05\x06"
  ETHERNET_DST = "\xA1\xA2\xA3\xA4\xA5\xA6"
  
  GGSN_IP_SRC= "\xd5\xe9\x82\x38"      #"213.233.130.56"
  GGSN_IP_DST= "\xd5\xe9\x82\x37"      #"213.233.130.55"
  
  userip = None
  global_userip = "\x0a\x44\x17\x5b"
  total_packets_writes = 0
  pcap_writer = None
  
  # pcap file pid383_session1_272017012778276.pcap is on the Destkop
  
  # GTP HEADER FOR CREATE PDP CONTEXT
  
  # TID \x84\xba\x40\x11 for downstream
  # TID 81fbe032 for upstream 
  # ip client 0a 44 17 5b 
  
  gtp_pdp_context_request = "\x32\x10\x00\xa1\x00\x00\x00\x00\x20\xac\x00\x00\x02\x72\x02\x71"\
      "\x10\x72\x87\x72\xf6\x0f\xfc\x10\x84\xba\x40\x11\x11\x80\xce\x00"\
      "\x11\x14\x0a\x80\x00\x02\xf1\x21\x83\x00\x15\x05\x74\x65\x73\x74"\
      "\x31\x02\x68\x73\x08\x76\x6f\x64\x61\x66\x6f\x6e\x65\x02\x69\x65"\
      "\x84\x00\x1d\x80\xc0\x23\x06\x01\x06\x00\x06\x00\x00\x80\x21\x10"\
      "\x01\x01\x00\x10\x81\x06\x00\x00\x00\x00\x83\x06\x00\x00\x00\x00"\
      "\x85\x00\x04\xd5\xe9\x82\x38\x85\x00\x04\xd5\xe9\x82\x38\x86\x00"\
      "\x07\x91\x53\x83\x97\x23\x75\x33\x87\x00\x0f\x02\x22\x92\x1f\x93"\
      "\x96\xfe\xfe\x74\x05\x01\x01\x00\x4f\x00\x97\x00\x01\x01\x98\x00"\
      "\x08\x01\x72\xf2\x10\x0b\xcc\xcc\x65\x99\x00\x02\x40\x01\x9a\x00"\
      "\x08\x53\x88\x85\x40\x19\x74\x27\x50"
  
  
  gtp_pdp_context_response="\x32\x11\x00\x57\x80\xce\x00\x11\x20\xac\x00\x00\x01\x80\x08\xfe"\
      "\x10\x81\xfb\xe0\x32\x11\x95\xca\x80\x32\x7f\x10\x9b\xfb\x08\x80"\
      "\x00\x06\xf1\x21"   "\x0a\x44\x17\x5b"     "\x84\x00\x14\x80\x80\x21\x10\x03"\
      "\x01\x00\x10\x81\x06\x59\x13\x40\xa4\x83\x06\x59\x13\x40\x24\x85"\
      "\x00\x04\xd5\xe9\x82\x37\x85\x00\x04\xd5\xe9\x82\x37\x87\x00\x0f"\
      "\x02\x22\x92\x1f\x93\x96\xfe\xfe\x74\x05\x01\x01\x00\x4f\x00"
  
  
  gtp_pdp_user_data_up = "\x30\xff\x00\x3c\x81\xfb\xe0\x32"
  gtp_pdp_user_data_down = "\x30\xff\x00\x3c\x80\xce\x00\x11"
  
  
  # GTP HEADER FOR PDP UPDATE
  """
  0000   32 12 00 3f 95 ca 80 32 20 ad 00 00 10 84 ba 40
  0010   11 14 0a 85 00 04 d5 e9 82 38 85 00 04 d5 e9 82
  0020   38 87 00 0f 02 22 92 1f 93 96 fe fe 74 05 01 01
  0030   00 4a 00 97 00 01 01 98 00 08 01 72 f2 10 0b cc
  0040   cc 65 99 00 02 40 01"""
  
  def parseOptions():
          """Parse the user options"""
  
          usage = "Usage: %prog [options]"
  
          p = OptionParser(usage)
  
          p.add_option("-f", "--pcapfile", dest="pcapfile", 
                  help="Pcapfile for add the GTP header.")
  
          p.add_option("-i", "--userip", dest="userip", 
                  help="User IP address.")
  
          p.add_option("-r", "--remove", dest="remove",action="store_true", 
                  help="Remove the GTP layer.")
  
          p.add_option("-v", "--verbose",action="count",dest="verbose",default=0,
                  help="Shows extra information.")
          return p
  
  
  def generatePdpContextRequest(w):
      eth = dpkt.ethernet.Ethernet(src=ETHERNET_SRC,dst=ETHERNET_DST)
      udp = UDP(sport=1024, dport=2123,data = gtp_pdp_context_request)
      ip = IP(src=GGSN_IP_SRC,dst=GGSN_IP_DST, data = udp)
  
      ip.p = 17 
      ip.data = udp
      ip.len = 8 + 20 + len(gtp_pdp_context_request) 
      udp.ulen = 8 + len(gtp_pdp_context_request)
      eth.data = ip
  
      w.writepkt(eth)
  
  def generatePdpContextResponse(w):
          eth = dpkt.ethernet.Ethernet(src=ETHERNET_DST,dst=ETHERNET_SRC)
          udp = UDP(sport=2123, dport=1024,data = gtp_pdp_context_response)
          ip = IP(src=GGSN_IP_DST,dst=GGSN_IP_SRC,data=udp)
          #ip = IP (dst='\x01\x02\x03\x04', src='\x05\x06\x07\x08',data = udp)
  
          ip.p = 17
          ip.data = udp
          ip.len = 8 + 20 + len(gtp_pdp_context_response)
          udp.ulen = 8 + len(gtp_pdp_context_response)
          eth.data = ip
  
          w.writepkt(eth)
  
  def generateUserData(w,isUp,length,data):
  
      if(isUp):
          srceth= ETHERNET_SRC
          dsteth= ETHERNET_DST
          srcip = GGSN_IP_SRC
          dstip = GGSN_IP_DST
          gtp_header = "\x30\xff" + struct.pack("&gt;h",length) + "\x81\xfb\xe0\x32" 
          srcport = 1024
          dstport = 2152
      else:
          srceth= ETHERNET_DST
          dsteth= ETHERNET_SRC
          srcip = GGSN_IP_DST
          dstip = GGSN_IP_SRC
          gtp_header = "\x30\xff" + struct.pack("&gt;h",length) + "\x84\xba\x40\x11"
          srcport = 2152 
          dstport = 1024 
  
      f_data = gtp_header + data
      f_length = 8 + length
  
      udp = UDP(sport = srcport,dport=dstport,data=f_data)
      ip = IP(src=srcip,dst=dstip,data = udp)
      eth = dpkt.ethernet.Ethernet(src=srceth,dst=dsteth,data = ip)
  
      ip.p = 17
      ip.len = 20 + 8+ f_length
      udp.ulen = 8 + f_length
  
      w.writepkt(eth) 
  
  def processPcapFile(filename):
  
      total_packets = 0
      total_packets_writes = 0
      total_packets_nowrites = 0
      total_bogus_packets = 0
  
      pcap=dpkt.pcap.Reader(file(filename,"rb"))
  
      try:
          for ts, buf in pcap:
              total_packets += 1
              if pcap.datalink() == dpkt.pcap.DLT_LINUX_SLL:
                  l2 = dpkt.sll.SLL(buf)
                  else:
                  l2 = dpkt.ethernet.Ethernet(buf)
  
              raw_data = l2.data
  
              if (str(type(l2.data)) != "&lt;class 'dpkt.ip.IP'&gt;"):
                  """ Check for other types of encapsulation """
                  if (str(type(l2.data)) == "&lt;class 'dpkt.pppoe.PPPoE'&gt;"):
                      raw_data = l2.data.ppp.ip 
                  else:   
                      total_bogus_packets += 1
                      continue
  
              ip = raw_data 
  
              if(socket.inet_ntoa(ip.src) == userip):
                  direction = True
                  newip = IP(src=global_userip,dst=ip.dst,p=ip.p,len=ip.len,data=ip.data)
                  generateUserData(pcap_writer,direction,ip.len,str(newip))   
                  total_packets_writes += 1
              elif(socket.inet_ntoa(ip.dst) == userip):
                  direction = False
                  total_packets_writes += 1
                  newip = IP(src=ip.src,dst=global_userip,p=ip.p,len=ip.len,data=ip.data)
                  generateUserData(pcap_writer,direction,ip.len,str(newip))   
              else:
                  total_packets_nowrites += 1
      except:
          e = sys.exc_info()[0]
              print("ERROR during processing packets:",e, " packet:",total_packets)
  
      print "Total bogus packets&gt;:", total_bogus_packets
      print "Total user packets writes:",total_packets_writes
      print "Total nonuser packets    :",total_packets_nowrites
  
  
  def removeGTPLayerFromPcapfile(filename):
  
          total_packets_writes = 0
          total_bogus_packets = 0
  
      f = open("%sGTP.pcap" % filename ,"w")
      writer = dpkt.pcap.Writer(f)
  
      pcap=dpkt.pcap.Reader(file(filename,"rb"))
  
          for ts, buf in pcap:
                  if pcap.datalink() == dpkt.pcap.DLT_LINUX_SLL:
                          l2 = dpkt.sll.SLL(buf)
                  else:
                          l2 = dpkt.ethernet.Ethernet(buf)
  
  
                  if (str(type(l2.data)) != "&lt;class 'dpkt.ip.IP'&gt;"):
                          total_bogus_packets += 1
                          continue
  
                  ip = l2.data
          udp = ip.data
          gtp = udp.data
  
          gtp_length = int(gtp[0])
          # print "%d %x" % (gtp_length,gtp_length)
          if (gtp_length ==0):
              offset = 8
          else:
              offset = 12
              eth = dpkt.ethernet.Ethernet(src=ETHERNET_DST,dst=ETHERNET_SRC,data=gtp[offset:])
          writer.writepkt(eth) 
  
          total_packets_writes += 1
  
      writer.close()
      f.close()
  
          print "Total bogus packets&gt;:", total_bogus_packets
          print "Total packets writes:",total_packets_writes
  
  
  if __name__ == "__main__":
  
          parser = parseOptions()
          (options, args) = parser.parse_args()
          if(options.pcapfile == None):
                  parser.error("Argument is required")
                  sys.exit(1)
  
      if (options.remove == True):
          print "Removing GTP Layer from pcapfile."
          removeGTPLayerFromPcapfile(options.pcapfile)                
          sys.exit(0)
  
          if(options.userip == None):
                  parser.error("Argument is required")
                  sys.exit(1)
  
      userip = options.userip
  
      f = open("%sGTP.pcap" % options.pcapfile ,"w")
      pcap_writer = dpkt.pcap.Writer(f)
  
      generatePdpContextRequest(pcap_writer)
      generatePdpContextResponse(pcap_writer)
  
      processPcapFile(options.pcapfile)
  
      pcap_writer.close()
      f.close()
  
      sys.exit(0) 
  </code></pre>
  
  <p><a href="http://i.stack.imgur.com/7YuCc.jpg" rel="nofollow">Wireshark Printscreen </a></p>
  
  <p>As I mentioned this always operated successfully in the linux environment whereby each additional GTP header was correctly interporated as Hex , however my problem is I need to port this to windows and now suddenly my additional GTP headers are being interporated as ascii instead of hex which is resulting in an invalid resultant pcap. I'm wondering if this is something related to Winpcap V Libpcap or if there are other causes and indeed if anyone has any suggestions on how to resolve this.</p>
  
  <p>kind regards</p>
  
  <p>Mandraker</p>