This repository has been archived by the owner on Nov 1, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6
/
scapy_nflog.py
71 lines (54 loc) · 2.06 KB
/
scapy_nflog.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
# -*- coding: utf-8 -*-
from __future__ import print_function
import itertools as it, operator as op, functools as ft
from threading import Thread
from collections import deque
import os
from scapy.all import conf, SuperSocket, ETH_P_ALL, IP, Scapy_Exception
from nflog_cffi import NFLOG, NFWouldBlock
class NFLOGReaderThread(Thread):
'''Necessary only because libnetfilter_log returns
packets in batches, and scapy expects to poll/read them one-by-one.'''
daemon = True
def __init__(self, queues, **nflog_kwargs):
super(NFLOGReaderThread, self).__init__()
self.queues, self.nflog_kwargs, self.pipe = queues, nflog_kwargs, deque()
self.pipe_chk, self._pipe = os.pipe()
self.pipe_chk, self._pipe = os.fdopen(self.pipe_chk, 'r', 0), os.fdopen(self._pipe, 'w', 0)
def run(self):
nflog = NFLOG().generator(self.queues, extra_attrs=['ts'], **self.nflog_kwargs)
next(nflog)
for pkt_info in nflog:
self.pipe.append(pkt_info)
self._pipe.write('.') # block until other thread reads it
self._pipe.flush()
class NFLOGListenSocket(SuperSocket):
desc = 'read packets at layer 3 using Linux NFLOG'
queues = range(4)
def __init__( self, iface=None, type=ETH_P_ALL,
promisc=None, filter=None, nofilter=0, queues=None, nflog_kwargs=dict() ):
self.type, self.outs = type, None
if queues is None: queues = self.queues
self.nflog = NFLOGReaderThread(queues, **nflog_kwargs)
self.nflog.start()
self.ins = self.nflog.pipe_chk
def recv(self, bufsize):
self.ins.read(1) # used only for poll/sync
pkt, ts = self.nflog.pipe.popleft()
if pkt is None: return
try: pkt = IP(pkt)
except KeyboardInterrupt: raise
except:
if conf.debug_dissector: raise
pkt = conf.raw_layer(pkt)
pkt.time = ts
return pkt
def send(self, pkt):
raise Scapy_Exception(
'Cannot send anything with {}'.format(self.__class__.__name__) )
def close(self):
SuperSocket.close(self)
def install_nflog_listener(queues=None, **nflog_kwargs):
'Install as default scapy L2 listener.'
conf.L2listen = ft.partial( NFLOGListenSocket,
queues=queues, nflog_kwargs=nflog_kwargs )