NetfilterQueue provides access to packets matched by an iptables rule in Linux. Packets so matched can be accepted, dropped, altered, or given a mark.
Libnetfilter_queue (the netfilter library, not this module) is part of the Netfilter project.
The following script prints a short description of each packet before accepting it.
from netfilterqueue import NetfilterQueue def print_and_accept(pkt): print pkt pkt.accept() nfqueue = NetfilterQueue() nfqueue.bind(1, print_and_accept) try: nfqueue.run() except KeyboardInterrupt: print
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
NetfilterQueue is a C extention module that links against libnetfilter_queue. Before installing, ensure you have:
- A C compiler
- Python development files
- Libnetfilter_queue development files and associated dependencies
On Debian or Ubuntu, install these files with:
apt-get install build-essential python-dev libnetfilter-queue-dev
To install from PyPI by pip:
pip install NetfilterQueue
To install from source:
wget http://pypi.python.org/packages/source/N/NetfilterQueue/NetfilterQueue-0.3.tar.gz tar -xvzf NetfilterQueue-0.3.tar.gz cd NetfilterQueue-0.3 python setup.py install
If Cython is installed, Distutils will use it to regenerate the .c source from the .pyx. It will then compile the .c into a .so.
NetfilterQueue.COPY_NONE
NetfilterQueue.COPY_META
NetfilterQueue.COPY_PACKET
- These constants specify how much of the packet should be given to the script- nothing, metadata, or the whole packet.
A NetfilterQueue object represents a single queue. Configure your queue with
a call to bind
, then start receiving packets with a call to run
.
QueueHandler.bind(queue_num, callback[, max_len[, mode[, range]]])
- Create and bind to the queue.
queue_num
must match the number in your iptables rule.callback
is a function or method that takes one argument, a Packet object (see below).max_len
sets the largest number of packets that can be in the queue; new packets are dropped if the size of the queue reaches this number.mode
determines how much of the packet data is provided to your script. Use the constants above.range
defines how many bytes of the packet you want to get. For example, if you only want the source and destination IPs of a IPv4 packet,range
could be 20. QueueHandler.unbind()
- Remove the queue. Packets matched by your iptables rule will be dropped.
QueueHandler.run()
- Send packets to your callback. This method blocks.
Objects of this type are passed to your callback.
Packet.get_payload()
- Return the packet's payload as a string.
Packet.get_payload_len()
- Return the size of the payload.
Packet.set_mark(mark)
- Give the packet a kernel mark.
mark
is a 32-bit number. Packet.accept()
- Accept the packet.
Packet.drop()
- Drop the packet.
Your callback can be function or a method and must accept one argument, a Packet object. You must call either Packet.accept() or Packet.drop() before returning.
callback(packet)
orcallback(self, packet)
- Handle a single packet from the queue. You must call either
packet.accept()
orpacket.drop()
.
To send 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,535 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:
- Queue ID
- Bound process ID
- Number of currently queued packets
- Copy mode
- Copy size
- Number of packets dropped due to reaching max queue size
- Number of packets dropped due to netlink socket failure
- Total number of packets sent to queue
- Something for libnetfilter_queue's internal use
More details coming soon...
Compiled with a 4096-byte buffer for packets, so it probably won't work on loopback or Ethernet with jumbo packets. If this is a problem, either lower MTU on your loopback, disable jumbo packets, or get Cython, change
DEF BufferSize = 4096
innetfilterqueue.pyx
, and rebuild.Full libnetfilter_queue API is not yet implemented:
- Omits
packet.set_payload()
for altering packet data - Omits methods for getting information about the interface a packet has arrived on or is leaving on
- Probably other stuff is omitted too
- Omits
When a packet has been marked, we use nfq_set_verdict_mark rather than nfq_set_verdict2. Apparently nfq_set_verdict_mark is broken, although it works for me.
https://github.com/kti/python-netfilterqueue
Copyright (c) 2011, Kerkhoff Technologies, Inc.