Specify any callback, no more use by inheritance

Change version to 0.3.0
Update and bugfixes in readme.rst
This commit is contained in:
Matt Fox 2011-10-14 14:14:25 -07:00
parent 76113a9ddc
commit be8ddc6219
5 changed files with 1014 additions and 861 deletions

View File

@ -12,17 +12,16 @@ Example
The following script prints a short description of each packet before accepting it. ::
from netfilterqueue import QueueHandler
from netfilterqueue import NetfilterQueue
class PacketPrinter(QueueHandler):
def handle(self, packet):
print packet
packet.accept()
def print_and_accept(pkt):
print pkt
pkt.accept()
p = PacketPrinter()
p.bind(1)
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
p.run()
nfqueue.run()
except KeyboardInterrupt:
print
@ -43,7 +42,7 @@ NetfilterQueue is a C extention module that links against libnetfilter_queue. Be
On Debian or Ubuntu, install these files with::
sudo apt-get install build-essential python-dev libnetfilter-queue-dev
apt-get install build-essential python-dev libnetfilter-queue-dev
From PyPI
---------
@ -57,12 +56,12 @@ From source
To install from source::
wget http://pypi.python.org/packages/source/N/NetfilterQueue/NetfilterQueue-0.2.tar.gz
tar -xvzf NetfilterQueue-0.2.tar.gz
cd NetfilterQueue-0.2
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
Setup will use Cython if it is installed, regenerating the .c source from the .pyx before compiling the .so.
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.
API
===
@ -74,35 +73,32 @@ API
``NetfilterQueue.COPY_PACKET``
These constants specify how much of the packet should be given to the script- nothing, metadata, or the whole packet.
QueueHandler objects
--------------------
NetfilterQueue objects
----------------------
You should define a class that inherits from QueueHandler and implenents the
handle() method. Handle() is called for each packet that appears in the queue.
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[, max_len[, mode[, range]]])``
``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. ``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.
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()``
Begin accepting packets.
``QueueHandler.handle(packet)``
Handle a single packet from the queue. You must call either
``packet.accept()`` or ``packet.drop()``.
Send packets to your callback. This method blocks.
Packet objects
--------------
Objects of this type are passed to your handle() method.
Objects of this type are passed to your callback.
``Packet.get_payload()``
Return the packet's payload as a string.
@ -118,11 +114,22 @@ Objects of this type are passed to your handle() method.
``Packet.drop()``
Drop the packet.
Callback objects
----------------
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)`` or ``callback(self, packet)``
Handle a single packet from the queue. You must call either
``packet.accept()`` or ``packet.drop()``.
Usage
=====
To route packets to the queue::
To send packets to the queue::
iptables -I <table or chain> <match specification> -j NFQUEUE --queue-num <queue number>
@ -133,7 +140,7 @@ For example::
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.
Valid queue numbers are integers from 0 to 65,535 inclusive.
To view libnetfilter_queue stats, refer to /proc/net/netfilter/nfnetlink_queue::
@ -158,7 +165,7 @@ The fields are:
8. Total number of packets sent to queue
9. Libnetfilter_queue internal use
9. Something for libnetfilter_queue's internal use
Limitations
===========
@ -190,6 +197,5 @@ License
=======
Copyright (c) 2011, Kerkhoff Technologies, Inc.
All rights reserved.
Licensed under `BSD <https://github.com/kti/python-netfilterqueue/blob/master/LICENSE.txt>`_
`MIT licensed <https://github.com/kti/python-netfilterqueue/blob/master/LICENSE.txt>`_

File diff suppressed because it is too large Load Diff

View File

@ -183,9 +183,10 @@ cdef class Packet:
cpdef accept(self)
cpdef drop(self)
cdef class QueueHandler:
cdef class NetfilterQueue:
cdef object user_callback # User callback
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
cdef packet_copy_size # Amount of packet metadata + data copied to buffer

View File

@ -1,4 +1,12 @@
## cython: profile=True
"""
Bind to a Linux netfilter queue. Send packets to a user-specified callback
function.
Copyright: (c) 2011, Kerkhoff Technologies Inc.
License: MIT; see LICENSE.txt
"""
VERSION = (0, 3, 0)
# Constants for module users
COPY_NONE = 1
COPY_META = 2
@ -14,14 +22,17 @@ DEF MaxCopySize = BufferSize - MetadataSize
cdef int global_callback(nfq_q_handle *qh, nfgenmsg *nfmsg,
nfq_data *nfa, void *data) with gil:
"""Create an Packet and pass it to appropriate Python/Cython callback."""
"""Create a Packet and pass it to appropriate callback."""
cdef NetfilterQueue nfqueue = <NetfilterQueue>data
cdef object user_callback = <object>nfqueue.user_callback
packet = Packet()
packet.set_nfq_data(qh, nfa)
(<QueueHandler>data).handle(packet)
user_callback(packet)
return 1
cdef class Packet:
"""A packet received from QueueHandler."""
"""A packet received from NetfilterQueue."""
def __cinit__(self):
self._verdict_is_set = False
self._mark_is_set = False
@ -57,7 +68,8 @@ cdef class Packet:
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
nfq_set_verdict_mark( # TODO: make this use nfq_set_verdict2 if
# available on system
self._qh,
self.id,
verdict,
@ -78,7 +90,8 @@ cdef class Packet:
def get_payload(self):
"""Return payload as Python string."""
cdef object py_string = PyString_FromStringAndSize(self.payload, self.payload_len)
cdef object py_string = PyString_FromStringAndSize(self.payload,
self.payload_len)
return py_string
cpdef Py_ssize_t get_payload_len(self):
@ -104,7 +117,7 @@ cdef class Packet:
"""Drop the packet."""
self.verdict(NF_DROP)
cdef class QueueHandler:
cdef class NetfilterQueue:
"""Handle a single numbered queue."""
def __cinit__(self, *args, **kwargs):
self.af = kwargs.get("af", PF_INET)
@ -124,9 +137,14 @@ cdef class QueueHandler:
# processes using this libnetfilter_queue on this protocol family!
nfq_close(self.h)
def bind(self, int queue_num, u_int32_t max_len=DEFAULT_MAX_QUEUELEN, u_int8_t mode=NFQNL_COPY_PACKET, u_int32_t range=MaxPacketSize):
def bind(self, int queue_num, object user_callback,
u_int32_t max_len=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)
self.user_callback = user_callback
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)
@ -155,10 +173,6 @@ cdef class QueueHandler:
with nogil:
rv = recv(fd, buf, sizeof(buf), 0)
def handle(self, Packet packet):
"""Handle a single packet. User-defined classes should override this."""
packet.accept()
PROTOCOLS = {
0: "HOPOPT",
1: "ICMP",
@ -302,4 +316,4 @@ PROTOCOLS = {
139: "HIP",
140: "Shim6",
255: "Reserved",
}
}

View File

@ -1,6 +1,6 @@
from distutils.core import setup, Extension
VERSION = "0.2" # Remember to change README.rst when version changes.
VERSION = "0.3" # Remember to change README.rst when version changes.
try:
# Use Cython