-
Notifications
You must be signed in to change notification settings - Fork 8
/
pcap2scn.py
executable file
·242 lines (201 loc) · 5.92 KB
/
pcap2scn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#!/usr/bin/env python
import sys
from getopt import getopt
from collections import OrderedDict
from Pdml import PdmlLoader
import Diameter as dm
from Dia import *
import os
from cPickle import load
if os.path.exists('.dia-cache'):
with open('.dia-cache', 'rb') as f:
d = load(f)
else:
d = Directory()
def group_by_code(avps):
codes = {}
for a in avps:
key = (a.code, a.vendor)
if key not in codes:
codes[key] = []
codes[key].append(a)
return codes
def get_path(a, codes):
attrs = {}
attrs['code'] = a.code
if a.vendor != 0:
attrs['vendor'] = a.vendor
path = ','.join(['%s=%d' % (x, attrs[x]) for x in attrs])
key = (a.code, a.vendor)
if len(codes[key]) != 1:
path += '[%d]' % (codes[key].index(a))
return path
def explode(m):
values = {}
def explode_avp(a, path):
vendor = a.vendor
if vendor is None:
vendor = 0
avps = d.find_avps(vendor, a.code)
# need to handle AVP name ambiguity
model_a = avps[0]
(name, datatype) = (model_a.name, model_a.datatype)
if hasattr(a, 'data') and len(a.data) > 4 and not a.avps:
assert(path not in values)
values[(path, name)] = a.data
return
paths = group_by_code(a.avps)
for i in range(len(a.avps)):
sub_a = a.avps[i]
explode_avp(sub_a, path + '/' + get_path(sub_a, paths))
paths = group_by_code(m.avps)
for i in range(len(m.avps)):
a = m.avps[i]
explode_avp(a, '/' + get_path(a, paths))
m.values = values
def lookup(msgs, val):
for m in msgs:
for k in m.values:
if m.values[k] == val:
return (m, k)
if __name__ == '__main__':
client_dump = None
client_empty = True
server_dump = None
server_empty = True
try:
opts, args = getopt(sys.argv[1:], 'c:s:', ['client=', 'server='])
for o, a in opts:
if o in ('-c', '--client'):
client_dump = open(a, 'wb')
client_dump.write('def run(f, args={}):\n')
elif o in ('-s', '--server'):
server_dump = open(a, 'wb')
server_dump.write('def run(f, args={}):\n')
except:
sys.exit(2)
pcap = args[0]
c = PdmlLoader(pcap)
if len(c.flows) == 0:
print >>sys.stderr, 'Could not find a flow in capture %s' % pcap
sys.exit(1)
elif len(c.flows) > 1:
print >>sys.stderr, 'Multiple flows in capture %s' % pcap
for flow in c.flows:
print >>sys.stderr, flow
sys.exit(1)
flow = c.flows.pop()
print('detected a flow %s:%d -> %s:%d' % flow[1:])
msgs = []
tsxs = []
for pdu in c.pdus:
m = dm.Msg.decode(pdu.content)
if m.code == 280: continue
attrs = ['ipprotocol', 'ipsrc', 'sport', 'ipdst', 'dport']
m.frm_number = pdu.pdml.frm_number
m.index = len(msgs)
m.from_client = reduce(lambda x,y: x and y, [getattr(pdu, attrs[i]) == flow[i] for i in range(len(flow))])
if m.from_client:
m.direction = 'c2s'
else:
m.direction = 's2c'
if not m.R:
e2e_id = m.e2e_id
h2h_id = m.h2h_id
m.in_response_to = None
for prev_m in msgs:
if prev_m.R and prev_m.e2e_id == e2e_id and prev_m.h2h_id == h2h_id:
m.in_response_to = prev_m
prev_m.answered_by = m
m.tsx_id = len(tsxs)
prev_m.tsx_id = len(tsxs)
tsxs.append((prev_m, m))
break
assert(m.in_response_to is not None)
explode(m)
m.anchors = {}
for a in m.all_avps():
v = a.data
anchor = lookup(msgs, v)
if anchor:
(prev_m, prev_loc) = anchor
if prev_loc not in prev_m.anchors:
prev_m.anchors[prev_loc] = []
prev_m.anchors[prev_loc].append((m.frm_number, m.from_client, a))
msgs.append(m)
for m in msgs:
for loc in m.anchors:
print('anchor %r, propagating to %r' % (loc, m.anchors[loc]))
if client_dump:
client_dump.write(' tsxs = [()]*%d\n' % len(tsxs))
if server_dump:
server_dump.write(' tsxs = [()]*%d\n' % len(tsxs))
for m in msgs:
if m.R:
emitter = '''
# frame %d
m = %s
m.send(f)
tsxs[%d] = (m.e2e_id, m.h2h_id)
''' % (m.frm_number, m.__repr__(2, 2)[2:], m.tsx_id)
else:
emitter = '''
# frame %d
m = %s
(m.e2e_id, m.h2h_id) = tsxs[%d]
m.send(f)
''' % (m.frm_number, m.__repr__(2, 2)[2:], m.tsx_id)
if m.R:
receiver = '''
# frame %d
m = Msg.recv(f)
assert(m.code == %d)
assert(m.R)
tsxs[%d] = (m.e2e_id, m.h2h_id)
''' % (m.frm_number, m.code, m.tsx_id)
else:
receiver = '''
# frame %d
m = Msg.recv(f)
assert(m.code == %d)
assert(not m.R)
assert(tsxs[%d] == (m.e2e_id, m.h2h_id))
''' % (m.frm_number, m.code, m.tsx_id)
if m.from_client:
if client_dump:
client_dump.write(emitter)
client_empty = False
if server_dump:
server_dump.write(receiver)
server_empty = False
for loc in m.anchors:
(path, name) = loc
name = name.replace('-', '_')
name = name.lower()
copy_locations = [next_loc for (next_m, from_client, next_loc) in m.anchors[loc] if not from_client]
if len(copy_locations) > 0:
server_dump.write(' %s = m.eval_path(%r).data\n' % (name, path))
for copy_loc in copy_locations:
copy_loc.var = name
else:
if client_dump:
client_dump.write(receiver)
client_empty = False
for loc in m.anchors:
(path, name) = loc
name = name.replace('-', '_')
name = name.lower()
copy_locations = [next_loc for (next_m, from_client, next_loc) in m.anchors[loc] if from_client]
if len(copy_locations) > 0:
client_dump.write(' %s = m.eval_path(%r).data\n' % (name, path))
for copy_loc in copy_locations:
copy_loc.var = name
if server_dump:
server_dump.write(emitter)
server_empty = False
if client_dump:
client_dump.write('\n f.close()\n')
client_dump.close()
if server_dump:
server_dump.write('\n f.close()\n')
server_dump.close()