Add details to README.

This commit is contained in:
Matt 2011-05-13 08:42:05 -07:00
parent f5e0ad83ad
commit a3676c4394
4 changed files with 2027 additions and 1208 deletions

View File

@ -10,7 +10,22 @@ Libnetfilter_queue (the netfilter library, not this module) is part of the `Netf
Example
=======
Coming soon...
The following script prints a short description of each packet before accepting it::
from netfilterqueue import NetfilterQueue
class PacketPrinter(NetfilterQueue):
def handle(self, packet):
print packet
packet.accept()
p = PacketPrinter()
p.bind(1)
p.run()
To send packets destined for your LAN to the script, type something like::
iptables -I INPUT -d 192.168.0.0/24 -j NFQUEUE --queue-num 1
Installation
============
@ -46,20 +61,53 @@ To install from source::
Setup will use Cython if it is installed, regenerating the .c source from the .pyx before compiling the .so.
Usage
=====
API
===
Coming soon...
Now route packets to the queue::
Usage
=====
# iptables -I INPUT -p tcp --dport 80 -j NFQUEUE --queue-num 1
To route packets to the queue::
iptables -I <table or chain> <match specification> -j NFQUEUE --queue-num <queue number>
For example::
iptables -I INPUT -d 192.168.0.0/24 -j NFQUEUE --queue-num 1
The only special part of the rule is the target. Rules can have any match and
can be added to any table or chain.
Valid queue numbers are integers from 0 to 65,536 inclusive.
To view libnetfilter_queue stats, refer to /proc/net/netfilter/nfnetlink_queue::
cat /proc/net/netfilter/nfnetlink_queue
1 31621 0 2 4016 0 0 2 1
The fields are:
1. Queue ID
2. Bound process ID
3. Number of currently queued packets
4. Copy mode
5. Copy size
6. Number of packets dropped due to reaching max queue size
7. Number of packets dropped due to netlink socket failure
8. Total number of packets sent to queue
9. Libnetfilter_queue internal use
Limitations
===========

File diff suppressed because it is too large Load Diff

View File

@ -148,7 +148,7 @@ cdef enum:
NF_STOP
NF_MAX_VERDICT = NF_STOP
cdef class NFPacket:
cdef class Packet:
cdef nfq_q_handle *_qh
cdef nfq_data *_nfa
cdef nfqnl_msg_packet_hdr *_hdr
@ -183,7 +183,7 @@ cdef class NFPacket:
cpdef accept(self)
cpdef drop(self)
cdef class NFQueue:
cdef class NetfilterQueue:
cdef nfq_handle *h # Handle to NFQueue library
cdef nfq_q_handle *qh # A handle to the queue
cdef u_int16_t af # Address family

View File

@ -1,11 +1,11 @@
## cython: profile=True
import socket
# Constants for module users
COPY_NONE = 1
COPY_META = 2
COPY_PACKET = 3
DEFAULT_MAX_QUEUELEN = 1024
# Packet copying defaults
DEF MaxPacketSize = 0xFFFF
DEF BufferSize = 4096
@ -14,28 +14,14 @@ DEF MaxCopySize = BufferSize - MetadataSize
cdef int global_callback(nfq_q_handle *qh, nfgenmsg *nfmsg,
nfq_data *nfa, void *data) with gil:
"""
Create an NFPacket and pass it to appropriate Python/Cython callback.
Working in a Python or Cython callback, rather than directly in this
callback, results in a ~7% performance hit.
"""
# cdef nfqnl_msg_packet_hdr *_hdr = nfq_get_msg_packet_hdr(nfa)
# cdef u_int32_t id = ntohl(_hdr.packet_id)
# nfq_set_verdict(
# qh,
# id,
# NF_ACCEPT,
# 0, # TODO: adapt to use self._given_payload
# NULL # TODO: adapt to use self._given_payload
# )
packet = NFPacket()
"""Create an Packet and pass it to appropriate Python/Cython callback."""
packet = Packet()
packet.set_nfq_data(qh, nfa)
(<NFQueue>data).handle(packet)
(<NetfilterQueue>data).handle(packet)
return 1
cdef class NFPacket:
"""A packet received from NFQueue."""
cdef class Packet:
"""A packet received from NetfilterQueue."""
def __cinit__(self):
self._verdict_is_set = False
self._mark_is_set = False
@ -43,10 +29,7 @@ cdef class NFPacket:
def __str__(self):
cdef iphdr *hdr = <iphdr*>self.payload
protocol = "Unknown protocol"
for name in filter(lambda x: x.startswith("IPPROTO"), dir(socket)):
if getattr(socket, name) == hdr.protocol:
protocol = name[8:]
protocol = PROTOCOLS.get(hdr.protocol, "Unknown protocol")
return "%s packet, %s bytes" % (protocol, self.payload_len)
cdef set_nfq_data(self, nfq_q_handle *qh, nfq_data *nfa):
@ -70,9 +53,9 @@ cdef class NFPacket:
cdef void verdict(self, u_int8_t verdict):
"""Call appropriate set_verdict... function on packet."""
#if self._verdict_is_set:
# raise RuntimeWarning("Verdict already given for this packet.")
if self._verdict_is_set:
raise RuntimeWarning("Verdict already given for this packet.")
if self._mark_is_set:
nfq_set_verdict_mark( # TODO: make this use nfq_set_verdict2 if available on system
self._qh,
@ -91,9 +74,10 @@ cdef class NFPacket:
NULL # TODO: adapt to use self._given_payload
)
#self._verdict_is_set = True
self._verdict_is_set = True
def get_payload(self):
"""Return payload as Python string."""
cdef object py_string = PyString_FromStringAndSize(self.payload, self.payload_len)
return py_string
@ -120,13 +104,10 @@ cdef class NFPacket:
"""Drop the packet."""
self.verdict(NF_DROP)
cdef class NFQueue:
cdef class NetfilterQueue:
"""Handle a single numbered queue."""
def __cinit__(self, *args, **kwargs):
if "af" in kwargs:
self.af = kwargs["af"]
else:
self.af = socket.AF_INET
self.af = kwargs.get("af", PF_INET)
self.h = nfq_open()
if self.h == NULL:
@ -134,7 +115,7 @@ cdef class NFQueue:
nfq_unbind_pf(self.h, self.af) # This does NOT kick out previous
# running queues
if nfq_bind_pf(self.h, self.af) < 0:
raise OSError("Failed to bind family %s." % self.af)
raise OSError("Failed to bind family %s. Are you root?" % self.af)
def __dealloc__(self):
if self.qh != NULL:
@ -143,9 +124,9 @@ cdef class NFQueue:
# processes using this libnetfilter_queue on this protocol family!
nfq_close(self.h)
def bind(self, object handler, int queue_num, u_int32_t maxlen, u_int8_t mode=NFQNL_COPY_PACKET, u_int32_t range=MaxPacketSize):
"""Create a new queue with the given callback function."""
self.qh = nfq_create_queue(self.h, queue_num, <nfq_callback*>global_callback, <void*>handler)
def bind(self, int queue_num, u_int32_t maxlen=DEFAULT_MAX_QUEUELEN, u_int8_t mode=NFQNL_COPY_PACKET, u_int32_t range=MaxPacketSize):
"""Create and bind to a new queue."""
self.qh = nfq_create_queue(self.h, queue_num, <nfq_callback*>global_callback, <void*>self)
if self.qh == NULL:
raise OSError("Failed to create queue %s." % queue_num)
@ -174,6 +155,151 @@ cdef class NFQueue:
with nogil:
rv = recv(fd, buf, sizeof(buf), 0)
def handle(self, NFPacket packet):
def handle(self, Packet packet):
"""Handle a single packet. User-defined classes should override this."""
packet.accept()
PROTOCOLS = {
0: "HOPOPT",
1: "ICMP",
2: "IGMP",
3: "GGP",
4: "IP",
5: "ST",
6: "TCP",
7: "CBT",
8: "EGP",
9: "IGP",
10: "BBN-RCC-MON",
11: "NVP-II",
12: "PUP",
13: "ARGUS",
14: "EMCON",
15: "XNET",
16: "CHAOS",
17: "UDP",
18: "MUX",
19: "DCN-MEAS",
20: "HMP",
21: "PRM",
22: "XNS-IDP",
23: "TRUNK-1",
24: "TRUNK-2",
25: "LEAF-1",
26: "LEAF-2",
27: "RDP",
28: "IRTP",
29: "ISO-TP4",
30: "NETBLT",
31: "MFE-NSP",
32: "MERIT-INP",
33: "DCCP",
34: "3PC",
35: "IDPR",
36: "XTP",
37: "DDP",
38: "IDPR-CMTP",
39: "TP++",
40: "IL",
41: "IPv6",
42: "SDRP",
43: "IPv6-Route",
44: "IPv6-Frag",
45: "IDRP",
46: "RSVP",
47: "GRE",
48: "DSR",
49: "BNA",
50: "ESP",
51: "AH",
52: "I-NLSP",
53: "SWIPE",
54: "NARP",
55: "MOBILE",
56: "TLSP",
57: "SKIP",
58: "IPv6-ICMP",
59: "IPv6-NoNxt",
60: "IPv6-Opts",
61: "any host internal protocol",
62: "CFTP",
63: "any local network",
64: "SAT-EXPAK",
65: "KRYPTOLAN",
66: "RVD",
67: "IPPC",
68: "any distributed file system",
69: "SAT-MON",
70: "VISA",
71: "IPCV",
72: "CPNX",
73: "CPHB",
74: "WSN",
75: "PVP",
76: "BR-SAT-MON",
77: "SUN-ND",
78: "WB-MON",
79: "WB-EXPAK",
80: "ISO-IP",
81: "VMTP",
82: "SECURE-VMTP",
83: "VINES",
84: "TTP",
85: "NSFNET-IGP",
86: "DGP",
87: "TCF",
88: "EIGRP",
89: "OSPFIGP",
90: "Sprite-RPC",
91: "LARP",
92: "MTP",
93: "AX.25",
94: "IPIP",
95: "MICP",
96: "SCC-SP",
97: "ETHERIP",
98: "ENCAP",
99: "any private encryption scheme",
100: "GMTP",
101: "IFMP",
102: "PNNI",
103: "PIM",
104: "ARIS",
105: "SCPS",
106: "QNX",
107: "A/N",
108: "IPComp",
109: "SNP",
110: "Compaq-Peer",
111: "IPX-in-IP",
112: "VRRP",
113: "PGM",
114: "any 0-hop protocol",
115: "L2TP",
116: "DDX",
117: "IATP",
118: "STP",
119: "SRP",
120: "UTI",
121: "SMP",
122: "SM",
123: "PTP",
124: "ISIS",
125: "FIRE",
126: "CRTP",
127: "CRUDP",
128: "SSCOPMCE",
129: "IPLT",
130: "SPS",
131: "PIPE",
132: "SCTP",
133: "FC",
134: "RSVP-E2E-IGNORE",
135: "Mobility",
136: "UDPLite",
137: "MPLS-in-IP",
138: "manet",
139: "HIP",
140: "Shim6",
255: "Reserved",
}