1# Copyright (c) 2003-2016 CORE Security Technologies
2#
3# This software is provided under under a slightly modified version
4# of the Apache Software License. See the accompanying LICENSE file
5# for more information.
6#
7
8from impacket import ImpactPacket, ImpactDecoder, structure
9
10O_ETH = 0
11O_IP  = 1
12O_ARP = 1
13O_UDP = 2
14O_TCP = 2
15O_ICMP = 2
16O_UDP_DATA = 3
17O_ICMP_DATA = 3
18
19MAGIC = '"\xD4\xC3\xB2\xA1'
20
21class PCapFileHeader(structure.Structure):
22    structure = (
23        ('magic', MAGIC),
24        ('versionMajor', '<H=2'),
25        ('versionMinor', '<H=4'),
26        ('GMT2localCorrection', '<l=0'),
27        ('timeAccuracy', '<L=0'),
28        ('maxLength', '<L=0xffff'),
29        ('linkType', '<L=1'),
30        ('packets','*:=[]'),
31    )
32
33class PCapFilePacket(structure.Structure):
34    structure = (
35        ('tsec', '<L=0'),
36        ('tmsec', '<L=0'),
37        ('savedLength', '<L-data'),
38        ('realLength', '<L-data'),
39        ('data',':'),
40    )
41
42    def __init__(self, *args, **kargs):
43        structure.Structure.__init__(self, *args, **kargs)
44        self['data'] = ''
45
46class PcapFile:
47    def __init__(self, fileName = None, mode = 'rb'):
48        if not fileName is None:
49           self.file = open(fileName, mode)
50        self.hdr = None
51        self.wroteHeader = False
52
53    def reset(self):
54        self.hdr = None
55        self.file.seek(0)
56
57    def close(self):
58        self.file.close()
59
60    def fileno(self):
61        return self.file.fileno()
62
63    def setFile(self, file):
64        self.file = file
65
66    def setSnapLen(self, snapLen):
67        self.createHeaderOnce()
68        self.hdr['maxLength'] = snapLen
69
70    def getSnapLen(self):
71        self.readHeaderOnce()
72        return self.hdr['maxLength']
73
74    def setLinkType(self, linkType):
75        self.createHeaderOnce()
76        self.hdr['linkType'] = linkType
77
78    def getLinkType(self):
79        self.readHeaderOnce()
80        return self.hdr['linkType']
81
82    def readHeaderOnce(self):
83        if self.hdr is None:
84           self.hdr = PCapFileHeader.fromFile(self.file)
85
86    def createHeaderOnce(self):
87        if self.hdr is None:
88           self.hdr = PCapFileHeader()
89
90    def writeHeaderOnce(self):
91        if not self.wroteHeader:
92           self.wroteHeader = True
93           self.file.seek(0)
94           self.createHeaderOnce()
95           self.file.write(str(self.hdr))
96
97    def read(self):
98       self.readHeaderOnce()
99       try:
100          pkt = PCapFilePacket.fromFile(self.file)
101          pkt['data'] = self.file.read(pkt['savedLength'])
102          return pkt
103       except:
104          return None
105
106    def write(self, pkt):
107        self.writeHeaderOnce()
108        self.file.write(str(pkt))
109
110    def packets(self):
111        self.reset()
112        while 1:
113           answer = self.read()
114           if answer is None: break
115           yield answer
116
117def process(onion):
118    # for dhcp we only want UDP packets
119    if len(onion) <= O_UDP: return
120    if onion[O_UDP].protocol != ImpactPacket.UDP.protocol:
121       return
122
123    # we only want UDP port 67
124    if ((onion[O_UDP].get_uh_dport() != 67) and
125        (onion[O_UDP].get_uh_sport() != 67)): return
126
127    # we've got a dhcp packet
128
129def main():
130    import sys
131
132    f_in = open(sys.argv[1],'rb')
133    try:
134       f_out = open(sys.argv[2],'wb')
135       f_out.write(str(PCapFileHeader()))
136    except:
137       f_out = None
138
139    hdr = PCapFileHeader()
140    hdr.fromString(f_in.read(len(hdr)))
141
142    #hdr.dump()
143
144    decoder = ImpactDecoder.EthDecoder()
145    while 1:
146       pkt = PCapFilePacket()
147       try:
148          pkt.fromString(f_in.read(len(pkt)))
149       except:
150          break
151       pkt['data'] = f_in.read(pkt['savedLength'])
152       hdr['packets'].append(pkt)
153       p = pkt['data']
154       try:    in_onion = [decoder.decode(p[1])]
155       except: in_onion = [decoder.decode(p[0])]
156       try:
157          while 1: in_onion.append(in_onion[-1].child())
158       except:
159          pass
160
161       process(in_onion)
162       pkt.dump()
163       #print "%r" % str(pkt)
164
165       if f_out:
166          #print eth
167
168          pkt_out = PCapFilePacket()
169          pkt_out['data'] = str(eth.get_packet())
170
171          #pkt_out.dump()
172
173          f_out.write(str(pkt_out))
174
175if __name__ == '__main__':
176   main()
177
178