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
|
#!/usr/bin/env python3
import json
import re
import scapy.all
import socket
DEFAULT_HOST = '127.0.0.1'
DEFAULT_PORT = 7000
NETWORK_BUFFER_MIN_SIZE = 5
NETWORK_BUFFER_MAX_SIZE = 9216 # Please keep this value in sync with the one in config.h
PKT_TYPE_ETH_IP4 = 0x0800
PKT_TYPE_ETH_IP6 = 0x86DD
class TermColor:
WARNING = '\033[93m'
FAIL = '\033[91m'
BOLD = '\033[1m'
END = '\033[0m'
BLINK = "\x1b[5m"
class nDPIsrvdSocket:
def __init__(self, sock=None):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
def connect(self, host, port):
self.sock.connect((host, port))
self.buffer = bytes()
self.msglen = 0
self.digitlen = 0
def receive(self):
recvd = self.sock.recv(NETWORK_BUFFER_MAX_SIZE - len(self.buffer))
if len(recvd) == 0:
raise RuntimeError('socket connection broken')
self.buffer += recvd
retval = []
while self.msglen + self.digitlen < len(self.buffer):
if self.msglen == 0:
starts_with_digits = re.match(r'(^\d+){', self.buffer[:NETWORK_BUFFER_MIN_SIZE].decode(errors='strict'))
if starts_with_digits is None:
if len(self.buffer) < NETWORK_BUFFER_MIN_SIZE:
break
raise RuntimeError('Invalid packet received: {}'.format(self.buffer))
self.msglen = int(starts_with_digits[1])
self.digitlen = len(starts_with_digits[1])
if len(self.buffer) >= self.msglen + self.digitlen:
recvd = self.buffer[self.digitlen:self.msglen + self.digitlen]
self.buffer = self.buffer[self.msglen + self.digitlen:]
retval += [(recvd,self.msglen,self.digitlen)]
self.msglen = 0
self.digitlen = 0
return retval
class PcapPacket:
def __init__(self, flow_id=-1):
self.pktdump = None
self.was_dumped = False
self.was_detected = False
self.flow_id = flow_id
self.packets = []
def addPacket(self, pkt, pkt_type, pkt_ipoffset):
self.packets += [ ( pkt, pkt_type, pkt_ipoffset ) ]
@staticmethod
def getIp(packet):
if packet[1] == PKT_TYPE_ETH_IP4:
return scapy.all.IP(packet[0][packet[2]:])
elif packet[1] == PKT_TYPE_ETH_IP6:
return scapy.all.IPv6(packet[0][packet[2]:])
else:
raise RuntimeError('packet type unknown: {}'.format(packet[1]))
@staticmethod
def getTCPorUDP(packet):
p = PcapPacket.getIp(packet)
if p.haslayer(scapy.all.TCP):
return p.getlayer(scapy.all.TCP)
elif p.haslayer(scapy.all.UDP):
return p.getlayer(scapy.all.UDP)
else:
return None
def detected(self):
self.was_detected = True
def fin(self, filename_suffix):
if self.was_dumped is True:
return 'Flow already dumped.'
if self.was_detected is True:
return 'Flow detected.'
emptyTCPorUDPcount = 0;
for packet in self.packets:
p = PcapPacket.getTCPorUDP(packet)
if p is not None:
if p.haslayer(scapy.all.Padding) and len(p.payload) - len(p[scapy.all.Padding]) == 0:
emptyTCPorUDPcount += 1
if len(p.payload) == 0:
emptyTCPorUDPcount += 1
if emptyTCPorUDPcount == len(self.packets):
return 'Flow does not contain any packets with non-empty layer4 payload.'
if self.pktdump is None:
if self.flow_id == -1:
self.pktdump = scapy.all.PcapWriter('packet-{}.pcap'.format(filename_suffix),
append=True, sync=True)
else:
self.pktdump = scapy.all.PcapWriter('flow-{}-{}.pcap'.format(filename_suffix, self.flow_id),
append=False, sync=True)
for packet in self.packets:
self.pktdump.write(PcapPacket.getIp(packet))
self.pktdump.close()
self.was_dumped = True
return 'Success.'
def JsonParseBytes(json_bytes):
return json.loads(json_bytes.decode('ascii', errors='replace'), strict=False)
def validateEventName(json_dict):
if type(json_dict) is not dict:
raise RuntimeError('Argument is not a dictionary!')
event_str = None
if 'flow_event_name' in json_dict:
event = j['flow_event_name'].lower()
if event == 'new':
event_str = 'New flow'
elif event == 'end':
event_str = 'End flow'
elif event == 'idle':
event_str = 'Idle flow'
elif event == 'detected':
event_str = 'Detected'
elif event == 'detection-update':
event_str = 'Update'
elif event == 'guessed':
event_str = 'Guessed'
elif event == 'not-detected':
event_str = 'Not detected'
else:
return None
return event_str
|