Read https://5d4a.wordpress.com/2011/08/25/having-fun-with-nfqueue-and-scapy/ http://lost-and-found-narihiro.blogspot.com/2015/02/python-scapy-nfqueue-bindings-python.html (also http://archive.is/PVPmh and https://archive.is/y81LB) has a copy of the great tutorial http://danmcinerney.org/reliable-dns-spoofing-with-python-scapy-nfqueue/ (sadly, seems no longer available at the original URL). --------[ 1. Loading NFQUEUE kernel modules ]-------- First, you need to make sure that the Linux kernel has the right modules loaded: # modprobe ip_tables # modprobe nfnetlink_queue You can see with lsmod whether these module are (a) loaded and (b) being currently used by any iptables rule(s). Observe the "Used by" column: # iptables -A OUTPUT -p icmp -d 8.8.8.8 -j NFQUEUE --queue-num 1 # lsmod Module Size Used by xt_NFQUEUE 12544 1 iptable_filter 12536 1 nfnetlink_queue 17161 0 nfnetlink 12906 1 nfnetlink_queue ip_tables 22042 1 iptable_filter x_tables 19118 3 ip_tables,iptable_filter,xt_NFQUEUE <..skipped..> Now clearing the rule: # iptables -F OUTPUT # lsmod Module Size Used by xt_NFQUEUE 12544 0 iptable_filter 12536 0 nfnetlink_queue 17161 0 nfnetlink 12906 1 nfnetlink_queue ip_tables 22042 1 iptable_filter x_tables 19118 3 ip_tables,iptable_filter,xt_NFQUEUE The /proc directory will show state of the currently used queues: cat /proc/net/netfilter/nfnetlink_queue cat /proc/net/netfilter/nf_queue cat /proc/net/netfilter/nf_log When a script is running, you should see one of the queues being used. --------[ 2. Installing Python bindings for NFQUEUE ]-------- (The name of the package for your Linux distribution may vary. For example, it may be nfqueue-bindings-python. Check with "apt-cache search nfqueue". You may also miss examples---in which case, find them online.) Install the bindings: # apt-get install python-nfqueue $ locate nfqueue | grep python /usr/lib/pyshared/python2.6/_nfqueue.so /usr/lib/pyshared/python2.7/_nfqueue.so /usr/lib/python2.6/dist-packages/_nfqueue.so /usr/lib/python2.6/dist-packages/nfqueue.py /usr/lib/python2.6/dist-packages/nfqueue.pyc /usr/lib/python2.7/dist-packages/_nfqueue.so /usr/lib/python2.7/dist-packages/nfqueue.py /usr/lib/python2.7/dist-packages/nfqueue.pyc /usr/share/doc/python-nfqueue /usr/share/doc/python-nfqueue/changelog.Debian.gz /usr/share/doc/python-nfqueue/copyright /usr/share/doc/python-nfqueue/examples /usr/share/doc/python-nfqueue/examples/example.py /usr/share/doc/python-nfqueue/examples/nfq_asyncore.py /usr/share/doc/python-nfqueue/examples/nfq_dump_pcap.py /usr/share/doc/python-nfqueue/examples/rewrite.py /usr/share/doc/python-nfqueue/examples/za.py Have a look at the examples in the above (ignore za.py). Side note: You will notice the .so libraries above. That's where all the real functionality is implemented, in C and using the libnetfilter_queue functions that talk to the kernel over nfnetlink sockets. If you are interested in how this works, read https://home.regit.org/netfilter-en/using-nfqueue-and-libnetfilter_queue/ install the "libnetfilter-queue-dev" package (on Debian), and read the C interface definitions in /usr/include/libnetfilter_queue/libnetfilter_queue.h /usr/include/libnetfilter_queue/linux_nfnetlink_queue.h --------[ 3. Examples ]-------- In http://www.cs.dartmouth.edu/~sergey/netreads/ you will find two working scripts: nfq-pass-all_py.txt -- print and pass all packets from queue #1 nfq-drop5th-icmp_py.txt -- drop every 5th ICMP packet going from a local application to 8.8.8.8 (Note that the call to unbind() before fast_open() causes a segfault on some systems; if that's the case on yours, comment it out. On other systems, this call is actually necessary for fast_open() to succeed and get the packets from the kernel; sadly, these Python bindings appear to be still rather unstable). The latter script inserts a rule into iptables, and even cleans up after itself, but too enthusiastically -- it will delete ALL rules and all user-defined chains! Hack it so that it doesn't bring down the entire firewall. Note that queue numbers must match, and that bind(socket.AF_INET) is necessary, otherwise the callbacks are never going to get called and the packets stolen from the kernel into the queue(s) won't get processed as if they were lost (or dropped).