/
sniffer.py
270 lines (243 loc) · 11.3 KB
/
sniffer.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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# -*- coding: utf8 -*-
try:
import cairoplot, cairo
from scapy import all
import netaddr
except:
print "Erro ao importar pacotes."
sys.exit(1)
INDEX = 0
VALUE = ''
class Sniffer():
"""Sniffer class."""
def __init__(self):
""" Define dicionarios para proximo cabecalho e classe de trafego."""
self.capture_list = []
self.filtered_list = []
self.capture_dict = []
self.flowlabel_dict = {}
self.mean_next_header = 0
self.icmpv6_number = 0
self.udp_number = 0
self.next_header_dict = {}
self.address_type_dict = {}
self.traffic_class_dict = {}
self.number_of_next_header = []
self.extension_header = {
0:"Hop-By-Hop Options Extension Header",
1:"ICMPv4",
2:"IGMPv4",
4:"IP in IP Encapsulation",
6:"TCP",
8:"EGP",
17:"UDP",
41:"IPv6",
43:"Routing Extension Header",
44:"Fragmentation Extension Header",
46:"Resource Reservation Protocol (RSVP)",
47:"GRE",
50:"Encrypted Security Payload (ESP) Extension Header",
51:"Authentication Header (AH) Extension Header",
58:"ICMPv6",
59:"No Next Header",
60:"Destination Options Extension Header",
135:"Mobility Header"
}
self.traffic_dict = {
0 : "Nenhum tráfego específico",
1 : "Dados de segundo plano",
2 : "Tráfego de dados não atendido",
3 : "Reservado",
4 : "Tráfego de dados pesado atendido",
5 : "Reservado",
6 : "Tráfego interativo",
7 : "Tráfego de controle",
}
def next_header_type(self, nxt):
"""Retorna label para codigo next header."""
if self.extension_header.has_key(nxt):
return (nxt,self.extension_header[nxt])
return (nxt,'')
def traffic_class_type(self, t_class):
"""Retorna label para codigo traffic class."""
if t_class >= 0 and t_class <= 7:
return (t_class, "Tráfego controlado por congestionamento", self.traffic_dict[t_class])
elif t_class <= 15:
return (t_class, "Tráfego não controlado por congestionamento", "Tráfego não controlado por congestionamento")
return False
def analyze(self, packet):
""" Faz a analise do pacote e insere as informacoes
no dict capture_dict e na lista capture_list."""
try:
pack_dict = {}
pack_dict['mac_src'] = packet.src
pack_dict['mac_dst'] = packet.dst
ip = packet.payload
pack_dict['ip_src'] = ip.src
pack_dict['ip_src_type'] = netaddr.IPAddress(ip.src).info['IPv6'][0]['allocation']
pack_dict['ip_dst'] = ip.dst
pack_dict['ip_dst_type'] = netaddr.IPAddress(ip.dst).info['IPv6'][0]['allocation']
pack_dict['ip_dst'] = ip.dst
pack_dict['hop_limit'] = ip.hlim
pack_dict['traffic_class'] = self.traffic_class_type(ip.tc)
pack_dict['flowlabel'] = ip.fl
pack_dict['version'] = ip.version
current = ip
next_header_list = []
while hasattr(current, 'nh'):
next_header_list.append(self.next_header_type(current.nh))
current = current.payload
pack_dict['next_header'] = next_header_list
self.capture_dict.append(pack_dict)
pack_tuple = ( pack_dict['ip_src'], pack_dict['ip_src_type'], pack_dict['ip_dst'],
pack_dict['ip_dst_type'], pack_dict['next_header'],
pack_dict['hop_limit'], pack_dict['traffic_class'][0],
pack_dict['traffic_class'][1], pack_dict['traffic_class'][2],
pack_dict['flowlabel'], pack_dict['version']
)
self.capture_list.append(pack_tuple)
self.filtered_list.append(pack_tuple)
except Exception,e:
print e
def get_packet(self, sniff_filter = 'ip6'):
""" Captura e analisa 1 pacote."""
capture = all.sniff(filter = sniff_filter, count = 1)
packet = capture[0]
self.analyze(packet)
def read_file(self, filename):
""" Le arquivo compativel com wireshark (.cap) e faz analise dos pacote"""
capture = all.rdpcap(filename)
for packet in capture:
self.analyze(packet)
def list_filter(self, side, oper, value):
""" Side pode ser 'origem', 'destino' ou 'flowlabel'.
Prepara filtered_list utilizada na funcao capture_filter."""
VALUE = value
if side.lower() == 'origem':
INDEX = 0
elif side.lower() == 'destino':
INDEX = 2
elif side.lower() == 'flowlabel':
INDEX = 9
self.filtered_list[:] = filter(lambda x: x[INDEX] == int(VALUE), self.filtered_list)
return True
else:
return False
if oper == '<':
self.filtered_list[:] = filter(lambda x: netaddr.IPAddress(x[INDEX]) < netaddr.IPAddress(VALUE), self.filtered_list)
elif oper == '<=':
self.filtered_list[:] = filter(lambda x: netaddr.IPAddress(x[INDEX]) <= netaddr.IPAddress(VALUE), self.filtered_list)
elif oper == '>':
self.filtered_list[:] = filter(lambda x: netaddr.IPAddress(x[INDEX]) > netaddr.IPAddress(VALUE), self.filtered_list)
elif oper == '>=':
self.filtered_list[:] = filter(lambda x: netaddr.IPAddress(x[INDEX]) >= netaddr.IPAddress(VALUE), self.filtered_list)
elif oper == '==':
self.filtered_list[:] = filter(lambda x: netaddr.IPAddress(x[INDEX]) == netaddr.IPAddress(VALUE), self.filtered_list)
elif oper == '!=':
self.filtered_list[:] = filter(lambda x: netaddr.IPAddress(x[INDEX]) != netaddr.IPAddress(VALUE), self.filtered_list)
return True
def capture_filter(self, expression):
""" Recebe uma lista de expressoes separadas por virgula,
Faz split e executa filtro com 'E' logico.
Returna lista filtrada."""
self.filtered_list = self.capture_list[:]
expression = expression.split('; ')
for operation in expression:
opers = operation.split(' ')
if len(opers) == 3:
self.list_filter(opers[0], opers[1], opers[2])
return self.filtered_list
def set_flowlabel_list(self):
""" Cria dicionario com pacotes do mesmo fluxo para
o mesmo ip destino e ip origem."""
for packet in self.capture_dict:
src = packet['ip_src']
dst = packet['ip_dst']
flowlabel = packet['flowlabel']
self.flowlabel_dict[(src, dst, flowlabel)] = []
for packet in self.capture_dict:
src = packet['ip_src']
dst = packet['ip_dst']
flowlabel = packet['flowlabel']
self.flowlabel_dict[(src, dst, flowlabel)].append(packet)
def set_mean_next_header(self):
""" Cria media do numero de pacotes de proximo cabecalho."""
total = 0.0
for packet in self.capture_dict:
total += len(packet['next_header'])
self.mean_next_header = total / len(self.capture_dict)
def get_statistics(self):
""" Retorna lista exibida com meia de cabecalhos e tabela de fluxo"""
self.set_flowlabel_list()
self.set_mean_next_header()
stats = []
stats.append(("Media de proximos cabecalhos:", self.mean_next_header, "",""))
stats.append(("","","",""))
stats.append(("Tabela de Fluxo:","","",""))
stats.append(("IP Origem", "IP Destino", "Flowlabel","Pacotes"))
for flow in self.flowlabel_dict:
stats.append((flow[0], flow[1], str(flow[2]), str(len(self.flowlabel_dict[flow]))))
return stats
def counts_udp_icmpv6(self):
"""Contabiliza numero de pacotes ICMPv6 e UDP da captura."""
self.icmpv6_number = 0
self.udp_number = 0
for packet in self.filtered_list:
if (58,'ICMPv6') in packet[4]:
self.icmpv6_number += 1
if (17,'UDP') in packet[4]:
self.udp_number += 1
def create_graphs(self):
""" Cria graficos para nextHeader, addressType e trafficClass
Exporta como imagem para ser utilizado com o GTK."""
self.set_dicts()
background = cairo.LinearGradient(300, 0, 300, 400)
background.add_color_stop_rgb(0,0.4,0.4,0.4)
background.add_color_stop_rgb(1.0,0.1,0.1,0.1)
data = self.next_header_dict
cairoplot.donut_plot( "nextHeader.svg", data, 400, 200, gradient = True, shadow = True, inner_radius = 0.3 )
data = self.address_type_dict
cairoplot.donut_plot( "addressType.svg", data, 400, 200, gradient = True, shadow = True, inner_radius = 0.3 )
data = self.traffic_class_dict
cairoplot.donut_plot( "trafficClass.svg", data, 400, 200, gradient = True, shadow = True, inner_radius = 0.3 )
data = self.number_of_next_header
x_labels = ["Quantidade de próximos cabeçalhos"]
y_labels = [str(i) for i in range(max(data)+1)]
# cairoplot.dot_line_plot("lenNextHeader.svg", data, 400, 200, axis = False, grid = True, x_labels = [' ',' '])
cairoplot.vertical_bar_plot ( 'lenNextHeader.svg', data, 400, 200, grid = True, rounded_corners = True,
x_labels = x_labels, y_labels = y_labels)
self.counts_udp_icmpv6()
size = len(self.filtered_list)
data = [ [self.icmpv6_number, size - self.icmpv6_number], [self.udp_number, size - self.udp_number]]
colors = [ (1,0.2,0), (1,1,0) ]
x_labels = ["ICMPv6", "UDP"]
cairoplot.vertical_bar_plot ( 'extra.svg', data, 400, 200, display_values = True, grid = True,
rounded_corners = True, stack = True, x_labels = x_labels, colors = colors )
def set_dicts(self):
""" Cria os seguintes dicionarios:
address_type = {Tipo de pacote : numero de vezes que aparece na captura}
traffic_class = {Classe de Trafego : numero de vezes que aparece na captura}
next_header = {Proximo Cabecalho : numero de vezes que aparece na captura}
number_of_next_header = [Quantidade de Proximos Cabecalhos do pacote]
"""
self.next_header_dict = {}
self.address_type_dict = {}
self.traffic_class_dict = {}
self.number_of_next_header = []
for packet in self.filtered_list:
for header in packet[4]: #next_header
self.next_header_dict[header[1]] = 0
self.address_type_dict[packet[1]] = 0 #ip_src_type
self.address_type_dict[packet[3]] = 0 #ip_dst_type
self.traffic_class_dict[packet[8]] = 0 #traffic_class
self.number_of_next_header = []
for packet in self.filtered_list:
for header in packet[4]:
self.next_header_dict[header[1]] += 1
self.address_type_dict[packet[1]] += 1
self.address_type_dict[packet[3]] += 1
self.traffic_class_dict[packet[8]] += 1
self.number_of_next_header.append(len(packet[4]))
def clearAll(self):
"""Limpa listas de captura do sniffer."""
self.__init__()