├── .gitignore ├── CHANGES.txt ├── LICENSE.txt ├── MANIFEST.in ├── README.rst ├── netfilterqueue.c ├── netfilterqueue.pxd ├── netfilterqueue.pyx └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.so 2 | build/ 3 | dist/ 4 | MANIFEST 5 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | v0.6, 15 Apr 2013 2 | Add get_mark. 3 | 4 | v0.5, 3 Apr 2013 5 | Add repeat. 6 | 7 | v0.4, 24 Dec 2012 8 | Add set_payload. 9 | 10 | v0.2, 13 May 2011 11 | Rename NetfilterQueue to QueueHandler. 12 | Add API section to README.rst. 13 | 14 | v0.1, 12 May 2011 15 | Initial release. 16 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Kerkhoff Technologies Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.txt 2 | include *.rst 3 | include *.c 4 | include *.pyx 5 | include *.pxd 6 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | NetfilterQueue 3 | ============== 4 | 5 | NetfilterQueue provides access to packets matched by an iptables rule in 6 | Linux. Packets so matched can be accepted, dropped, altered, or given a mark. 7 | 8 | Libnetfilter_queue (the netfilter library, not this module) is part of the 9 | `Netfilter project `_. 10 | 11 | Example 12 | ======= 13 | 14 | The following script prints a short description of each packet before accepting 15 | it. :: 16 | 17 | from netfilterqueue import NetfilterQueue 18 | 19 | def print_and_accept(pkt): 20 | print pkt 21 | pkt.accept() 22 | 23 | nfqueue = NetfilterQueue() 24 | nfqueue.bind(1, print_and_accept) 25 | try: 26 | nfqueue.run() 27 | except KeyboardInterrupt: 28 | print 29 | 30 | To send packets destined for your LAN to the script, type something like:: 31 | 32 | iptables -I INPUT -d 192.168.0.0/24 -j NFQUEUE --queue-num 1 33 | 34 | Installation 35 | ============ 36 | 37 | NetfilterQueue is a C extention module that links against libnetfilter_queue. 38 | Before installing, ensure you have: 39 | 40 | 1. A C compiler 41 | 42 | 2. Python development files 43 | 44 | 3. Libnetfilter_queue development files and associated dependencies 45 | 46 | On Debian or Ubuntu, install these files with:: 47 | 48 | apt-get install build-essential python-dev libnetfilter-queue-dev 49 | 50 | From PyPI 51 | --------- 52 | 53 | To install from PyPI by pip:: 54 | 55 | pip install NetfilterQueue 56 | 57 | From source 58 | ----------- 59 | 60 | To install from source:: 61 | 62 | wget http://pypi.python.org/packages/source/N/NetfilterQueue/NetfilterQueue-0.3.tar.gz 63 | tar -xvzf NetfilterQueue-0.3.tar.gz 64 | cd NetfilterQueue-0.3 65 | python setup.py install 66 | 67 | 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. 68 | 69 | API 70 | === 71 | 72 | ``NetfilterQueue.COPY_NONE`` 73 | 74 | ``NetfilterQueue.COPY_META`` 75 | 76 | ``NetfilterQueue.COPY_PACKET`` 77 | These constants specify how much of the packet should be given to the 78 | script- nothing, metadata, or the whole packet. 79 | 80 | NetfilterQueue objects 81 | ---------------------- 82 | 83 | A NetfilterQueue object represents a single queue. Configure your queue with 84 | a call to ``bind``, then start receiving packets with a call to ``run``. 85 | 86 | ``QueueHandler.bind(queue_num, callback[, max_len[, mode[, range]]])`` 87 | Create and bind to the queue. ``queue_num`` must match the number in your 88 | iptables rule. ``callback`` is a function or method that takes one 89 | argument, a Packet object (see below). ``max_len`` sets the largest number 90 | of packets that can be in the queue; new packets are dropped if the size of 91 | the queue reaches this number. ``mode`` determines how much of the packet 92 | data is provided to your script. Use the constants above. ``range`` defines 93 | how many bytes of the packet you want to get. For example, if you only want 94 | the source and destination IPs of a IPv4 packet, ``range`` could be 20. 95 | 96 | ``QueueHandler.unbind()`` 97 | Remove the queue. Packets matched by your iptables rule will be dropped. 98 | 99 | ``QueueHandler.run()`` 100 | Send packets to your callback. This method blocks. 101 | 102 | Packet objects 103 | -------------- 104 | 105 | Objects of this type are passed to your callback. 106 | 107 | ``Packet.get_payload()`` 108 | Return the packet's payload as a string. 109 | 110 | ``Packet.get_payload_len()`` 111 | Return the size of the payload. 112 | 113 | ``Packet.set_mark(mark)`` 114 | Give the packet a kernel mark. ``mark`` is a 32-bit number. 115 | 116 | ``Packet.accept()`` 117 | Accept the packet. 118 | 119 | ``Packet.drop()`` 120 | Drop the packet. 121 | 122 | Callback objects 123 | ---------------- 124 | 125 | Your callback can be function or a method and must accept one argument, a 126 | Packet object. You must call either Packet.accept() or Packet.drop() before 127 | returning. 128 | 129 | ``callback(packet)`` or ``callback(self, packet)`` 130 | Handle a single packet from the queue. You must call either 131 | ``packet.accept()`` or ``packet.drop()``. 132 | 133 | Usage 134 | ===== 135 | 136 | To send packets to the queue:: 137 | 138 | iptables -I -j NFQUEUE --queue-num 139 | 140 | For example:: 141 | 142 | iptables -I INPUT -d 192.168.0.0/24 -j NFQUEUE --queue-num 1 143 | 144 | The only special part of the rule is the target. Rules can have any match and 145 | can be added to any table or chain. 146 | 147 | Valid queue numbers are integers from 0 to 65,535 inclusive. 148 | 149 | To view libnetfilter_queue stats, refer to /proc/net/netfilter/nfnetlink_queue:: 150 | 151 | cat /proc/net/netfilter/nfnetlink_queue 152 | 1 31621 0 2 4016 0 0 2 1 153 | 154 | The fields are: 155 | 156 | 1. Queue ID 157 | 158 | 2. Bound process ID 159 | 160 | 3. Number of currently queued packets 161 | 162 | 4. Copy mode 163 | 164 | 5. Copy size 165 | 166 | 6. Number of packets dropped due to reaching max queue size 167 | 168 | 7. Number of packets dropped due to netlink socket failure 169 | 170 | 8. Total number of packets sent to queue 171 | 172 | 9. Something for libnetfilter_queue's internal use 173 | 174 | Limitations 175 | =========== 176 | 177 | More details coming soon... 178 | 179 | * Compiled with a 4096-byte buffer for packets, so it probably won't work on 180 | loopback or Ethernet with jumbo packets. If this is a problem, either lower 181 | MTU on your loopback, disable jumbo packets, or get Cython, 182 | change ``DEF BufferSize = 4096`` in ``netfilterqueue.pyx``, and rebuild. 183 | * Full libnetfilter_queue API is not yet implemented: 184 | 185 | * Omits ``packet.set_payload()`` for altering packet data 186 | * Omits methods for getting information about the interface a packet has 187 | arrived on or is leaving on 188 | * Probably other stuff is omitted too 189 | 190 | * When a packet has been marked, we use nfq_set_verdict_mark rather than 191 | nfq_set_verdict2. Apparently nfq_set_verdict_mark is 192 | `broken `_, 193 | although it works for me. 194 | 195 | Source 196 | ====== 197 | 198 | https://github.com/kti/python-netfilterqueue 199 | 200 | License 201 | ======= 202 | 203 | Copyright (c) 2011, Kerkhoff Technologies, Inc. 204 | 205 | `MIT licensed `_ 206 | 207 | -------------------------------------------------------------------------------- /netfilterqueue.pxd: -------------------------------------------------------------------------------- 1 | cdef extern from "sys/types.h": 2 | ctypedef unsigned char u_int8_t 3 | ctypedef unsigned short int u_int16_t 4 | ctypedef unsigned int u_int32_t 5 | 6 | cdef extern from "netinet/ip.h": 7 | struct iphdr: 8 | u_int8_t tos 9 | u_int16_t tot_len 10 | u_int16_t id 11 | u_int16_t frag_off 12 | u_int8_t ttl 13 | u_int8_t protocol 14 | u_int16_t check 15 | u_int32_t saddr 16 | u_int32_t daddr 17 | 18 | # Dummy defines from netinet/in.h: 19 | cdef enum: 20 | IPPROTO_IP = 0 # Dummy protocol for TCP. 21 | IPPROTO_HOPOPTS = 0 # IPv6 Hop-by-Hop options. 22 | IPPROTO_ICMP = 1 # Internet Control Message Protocol. 23 | IPPROTO_IGMP = 2 # Internet Group Management Protocol. */ 24 | IPPROTO_IPIP = 4 # IPIP tunnels (older KA9Q tunnels use 94). 25 | IPPROTO_TCP = 6 # Transmission Control Protocol. 26 | IPPROTO_EGP = 8 # Exterior Gateway Protocol. 27 | IPPROTO_PUP = 12 # PUP protocol. 28 | IPPROTO_UDP = 17 # User Datagram Protocol. 29 | IPPROTO_IDP = 22 # XNS IDP protocol. 30 | IPPROTO_TP = 29 # SO Transport Protocol Class 4. 31 | IPPROTO_IPV6 = 41 # IPv6 header. 32 | IPPROTO_ROUTING = 43 # IPv6 routing header. 33 | IPPROTO_FRAGMENT = 44 # IPv6 fragmentation header. 34 | IPPROTO_RSVP = 46 # Reservation Protocol. 35 | IPPROTO_GRE = 47 # General Routing Encapsulation. 36 | IPPROTO_ESP = 50 # encapsulating security payload. 37 | IPPROTO_AH = 51 # authentication header. 38 | IPPROTO_ICMPV6 = 58 # ICMPv6. 39 | IPPROTO_NONE = 59 # IPv6 no next header. 40 | IPPROTO_DSTOPTS = 60 # IPv6 destination options. 41 | IPPROTO_MTP = 92 # Multicast Transport Protocol. 42 | IPPROTO_ENCAP = 98 # Encapsulation Header. 43 | IPPROTO_PIM = 103 # Protocol Independent Multicast. 44 | IPPROTO_COMP = 108 # Compression Header Protocol. 45 | IPPROTO_SCTP = 132 # Stream Control Transmission Protocol. 46 | IPPROTO_RAW = 255 # Raw IP packets. 47 | IPPROTO_MAX 48 | 49 | cdef extern from "Python.h": 50 | object PyString_FromStringAndSize(char *s, Py_ssize_t len) 51 | 52 | cdef extern from "sys/time.h": 53 | ctypedef long time_t 54 | struct timeval: 55 | time_t tv_sec 56 | time_t tv_usec 57 | struct timezone: 58 | pass 59 | 60 | cdef extern from "netinet/in.h": 61 | u_int32_t ntohl (u_int32_t __netlong) nogil 62 | u_int16_t ntohs (u_int16_t __netshort) nogil 63 | u_int32_t htonl (u_int32_t __hostlong) nogil 64 | u_int16_t htons (u_int16_t __hostshort) nogil 65 | 66 | cdef extern from "libnfnetlink/linux_nfnetlink.h": 67 | struct nfgenmsg: 68 | u_int8_t nfgen_family 69 | u_int8_t version 70 | u_int16_t res_id 71 | 72 | cdef extern from "libnetfilter_queue/linux_nfnetlink_queue.h": 73 | enum nfqnl_config_mode: 74 | NFQNL_COPY_NONE 75 | NFQNL_COPY_META 76 | NFQNL_COPY_PACKET 77 | struct nfqnl_msg_packet_hdr: 78 | u_int32_t packet_id 79 | u_int16_t hw_protocol 80 | u_int8_t hook 81 | 82 | cdef extern from "libnetfilter_queue/libnetfilter_queue.h": 83 | struct nfq_handle: 84 | pass 85 | struct nfq_q_handle: 86 | pass 87 | struct nfq_data: 88 | pass 89 | struct nfqnl_msg_packet_hw: 90 | u_int8_t hw_addr[8] 91 | 92 | nfq_handle *nfq_open() 93 | int nfq_close(nfq_handle *h) 94 | 95 | int nfq_bind_pf(nfq_handle *h, u_int16_t pf) 96 | int nfq_unbind_pf(nfq_handle *h, u_int16_t pf) 97 | ctypedef int *nfq_callback(nfq_q_handle *gh, nfgenmsg *nfmsg, 98 | nfq_data *nfad, void *data) 99 | nfq_q_handle *nfq_create_queue(nfq_handle *h, 100 | u_int16_t num, 101 | nfq_callback *cb, 102 | void *data) 103 | int nfq_destroy_queue(nfq_q_handle *qh) 104 | 105 | int nfq_handle_packet(nfq_handle *h, char *buf, int len) 106 | 107 | int nfq_set_mode(nfq_q_handle *qh, 108 | u_int8_t mode, unsigned int len) 109 | 110 | q_set_queue_maxlen(nfq_q_handle *qh, 111 | u_int32_t queuelen) 112 | 113 | int nfq_set_verdict(nfq_q_handle *qh, 114 | u_int32_t id, 115 | u_int32_t verdict, 116 | u_int32_t data_len, 117 | unsigned char *buf) nogil 118 | 119 | int nfq_set_verdict_mark(nfq_q_handle *qh, 120 | u_int32_t id, 121 | u_int32_t verdict, 122 | u_int32_t mark, 123 | u_int32_t datalen, 124 | unsigned char *buf) nogil 125 | int nfq_set_queue_maxlen(nfq_q_handle *qh, u_int32_t queuelen) 126 | 127 | int nfq_fd(nfq_handle *h) 128 | nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(nfq_data *nfad) 129 | int nfq_get_payload(nfq_data *nfad, char **data) 130 | int nfq_get_timestamp(nfq_data *nfad, timeval *tv) 131 | nfqnl_msg_packet_hw *nfq_get_packet_hw(nfq_data *nfad) 132 | int nfq_get_nfmark (nfq_data *nfad) 133 | 134 | # Dummy defines from linux/socket.h: 135 | cdef enum: # Protocol families, same as address families. 136 | PF_INET = 2 137 | PF_INET6 = 10 138 | 139 | cdef extern from "sys/socket.h": 140 | ssize_t recv(int __fd, void *__buf, size_t __n, int __flags) nogil 141 | 142 | # Dummy defines from linux/netfilter.h 143 | cdef enum: 144 | NF_DROP 145 | NF_ACCEPT 146 | NF_STOLEN 147 | NF_QUEUE 148 | NF_REPEAT 149 | NF_STOP 150 | NF_MAX_VERDICT = NF_STOP 151 | 152 | cdef class Packet: 153 | cdef nfq_q_handle *_qh 154 | cdef nfq_data *_nfa 155 | cdef nfqnl_msg_packet_hdr *_hdr 156 | cdef bint _verdict_is_set # True if verdict has been issued, 157 | # false otherwise 158 | cdef bint _mark_is_set # True if a mark has been given, false otherwise 159 | cdef u_int32_t _given_mark # Mark given to packet 160 | cdef bytes _given_payload # New payload of packet, or null 161 | 162 | # From NFQ packet header: 163 | cdef readonly u_int32_t id 164 | cdef readonly u_int16_t hw_protocol 165 | cdef readonly u_int8_t hook 166 | cdef readonly u_int32_t mark 167 | 168 | # Packet details: 169 | cdef Py_ssize_t payload_len 170 | cdef readonly char *payload 171 | cdef timeval timestamp 172 | # TODO: implement these 173 | #cdef u_int8_t hw_addr[8] # A eui64-formatted address? 174 | #cdef readonly u_int32_t nfmark 175 | #cdef readonly u_int32_t indev 176 | #cdef readonly u_int32_t physindev 177 | #cdef readonly u_int32_t outdev 178 | #cdef readonly u_int32_t physoutdev 179 | 180 | cdef set_nfq_data(self, nfq_q_handle *qh, nfq_data *nfa) 181 | cdef void verdict(self, u_int8_t verdict) 182 | cpdef Py_ssize_t get_payload_len(self) 183 | cpdef double get_timestamp(self) 184 | cpdef set_payload(self, bytes payload) 185 | cpdef set_mark(self, u_int32_t mark) 186 | cpdef get_mark(self) 187 | cpdef accept(self) 188 | cpdef drop(self) 189 | cpdef repeat(self) 190 | 191 | cdef class NetfilterQueue: 192 | cdef object user_callback # User callback 193 | cdef nfq_handle *h # Handle to NFQueue library 194 | cdef nfq_q_handle *qh # A handle to the queue 195 | cdef u_int16_t af # Address family 196 | cdef packet_copy_size # Amount of packet metadata + data copied to buffer 197 | 198 | -------------------------------------------------------------------------------- /netfilterqueue.pyx: -------------------------------------------------------------------------------- 1 | """ 2 | Bind to a Linux netfilter queue. Send packets to a user-specified callback 3 | function. 4 | 5 | Copyright: (c) 2011, Kerkhoff Technologies Inc. 6 | License: MIT; see LICENSE.txt 7 | """ 8 | VERSION = (0, 6, 0) 9 | 10 | # Constants for module users 11 | COPY_NONE = 1 12 | COPY_META = 2 13 | COPY_PACKET = 3 14 | 15 | DEFAULT_MAX_QUEUELEN = 1024 16 | 17 | # Packet copying defaults 18 | DEF MaxPacketSize = 0xFFFF 19 | DEF BufferSize = 4096 20 | DEF MetadataSize = 80 21 | DEF MaxCopySize = BufferSize - MetadataSize 22 | 23 | cdef int global_callback(nfq_q_handle *qh, nfgenmsg *nfmsg, 24 | nfq_data *nfa, void *data) with gil: 25 | """Create a Packet and pass it to appropriate callback.""" 26 | cdef NetfilterQueue nfqueue = data 27 | cdef object user_callback = nfqueue.user_callback 28 | 29 | packet = Packet() 30 | packet.set_nfq_data(qh, nfa) 31 | user_callback(packet) 32 | return 1 33 | 34 | cdef class Packet: 35 | """A packet received from NetfilterQueue.""" 36 | def __cinit__(self): 37 | self._verdict_is_set = False 38 | self._mark_is_set = False 39 | self._given_payload = None 40 | 41 | def __str__(self): 42 | cdef iphdr *hdr = self.payload 43 | protocol = PROTOCOLS.get(hdr.protocol, "Unknown protocol") 44 | return "%s packet, %s bytes" % (protocol, self.payload_len) 45 | 46 | cdef set_nfq_data(self, nfq_q_handle *qh, nfq_data *nfa): 47 | """ 48 | Assign a packet from NFQ to this object. Parse the header and load 49 | local values. 50 | """ 51 | self._qh = qh 52 | self._nfa = nfa 53 | self._hdr = nfq_get_msg_packet_hdr(nfa) 54 | 55 | self.id = ntohl(self._hdr.packet_id) 56 | self.hw_protocol = ntohs(self._hdr.hw_protocol) 57 | self.hook = self._hdr.hook 58 | 59 | self.payload_len = nfq_get_payload(self._nfa, &self.payload) 60 | if self.payload_len < 0: 61 | raise OSError("Failed to get payload of packet.") 62 | 63 | nfq_get_timestamp(self._nfa, &self.timestamp) 64 | self.mark = nfq_get_nfmark(nfa) 65 | 66 | cdef void verdict(self, u_int8_t verdict): 67 | """Call appropriate set_verdict... function on packet.""" 68 | if self._verdict_is_set: 69 | raise RuntimeWarning("Verdict already given for this packet.") 70 | 71 | cdef u_int32_t modified_payload_len = 0 72 | cdef unsigned char *modified_payload = NULL 73 | if self._given_payload: 74 | modified_payload_len = len(self._given_payload) 75 | modified_payload = self._given_payload 76 | if self._mark_is_set: 77 | nfq_set_verdict_mark( 78 | self._qh, 79 | self.id, 80 | verdict, 81 | htonl(self._given_mark), 82 | modified_payload_len, 83 | modified_payload) 84 | else: 85 | nfq_set_verdict( 86 | self._qh, 87 | self.id, 88 | verdict, 89 | modified_payload_len, 90 | modified_payload) 91 | 92 | self._verdict_is_set = True 93 | 94 | def get_payload(self): 95 | """Return payload as Python string.""" 96 | cdef object py_string = PyString_FromStringAndSize(self.payload, 97 | self.payload_len) 98 | return py_string 99 | 100 | cpdef Py_ssize_t get_payload_len(self): 101 | return self.payload_len 102 | 103 | cpdef double get_timestamp(self): 104 | return self.timestamp.tv_sec + (self.timestamp.tv_usec/1000000.0) 105 | 106 | cpdef set_payload(self, bytes payload): 107 | """Set the new payload of this packet.""" 108 | self._given_payload = payload 109 | 110 | cpdef set_mark(self, u_int32_t mark): 111 | self._given_mark = mark 112 | self._mark_is_set = True 113 | 114 | cpdef get_mark(self): 115 | if self._mark_is_set: 116 | return self._given_mark 117 | return self.mark 118 | 119 | cpdef accept(self): 120 | """Accept the packet.""" 121 | self.verdict(NF_ACCEPT) 122 | 123 | cpdef drop(self): 124 | """Drop the packet.""" 125 | self.verdict(NF_DROP) 126 | 127 | cpdef repeat(self): 128 | """Repeat the packet.""" 129 | self.verdict(NF_REPEAT) 130 | 131 | cdef class NetfilterQueue: 132 | """Handle a single numbered queue.""" 133 | def __cinit__(self, *args, **kwargs): 134 | self.af = kwargs.get("af", PF_INET) 135 | 136 | self.h = nfq_open() 137 | if self.h == NULL: 138 | raise OSError("Failed to open NFQueue.") 139 | nfq_unbind_pf(self.h, self.af) # This does NOT kick out previous 140 | # running queues 141 | if nfq_bind_pf(self.h, self.af) < 0: 142 | raise OSError("Failed to bind family %s. Are you root?" % self.af) 143 | 144 | def __dealloc__(self): 145 | if self.qh != NULL: 146 | nfq_destroy_queue(self.qh) 147 | # Don't call nfq_unbind_pf unless you want to disconnect any other 148 | # processes using this libnetfilter_queue on this protocol family! 149 | nfq_close(self.h) 150 | 151 | def bind(self, int queue_num, object user_callback, 152 | u_int32_t max_len=DEFAULT_MAX_QUEUELEN, 153 | u_int8_t mode=NFQNL_COPY_PACKET, 154 | u_int32_t range=MaxPacketSize): 155 | """Create and bind to a new queue.""" 156 | self.user_callback = user_callback 157 | self.qh = nfq_create_queue(self.h, queue_num, 158 | global_callback, self) 159 | if self.qh == NULL: 160 | raise OSError("Failed to create queue %s." % queue_num) 161 | 162 | if range > MaxCopySize: 163 | range = MaxCopySize 164 | if nfq_set_mode(self.qh, mode, range) < 0: 165 | raise OSError("Failed to set packet copy mode.") 166 | 167 | nfq_set_queue_maxlen(self.qh, max_len) 168 | 169 | def unbind(self): 170 | """Destroy the queue.""" 171 | if self.qh != NULL: 172 | nfq_destroy_queue(self.qh) 173 | # See warning about nfq_unbind_pf in __dealloc__ above. 174 | 175 | def run(self): 176 | """Begin accepting packets.""" 177 | cdef int fd = nfq_fd(self.h) 178 | cdef char buf[BufferSize] 179 | cdef int rv 180 | with nogil: 181 | rv = recv(fd, buf, sizeof(buf), 0) 182 | while rv >= 0: 183 | nfq_handle_packet(self.h, buf, rv) 184 | with nogil: 185 | rv = recv(fd, buf, sizeof(buf), 0) 186 | 187 | PROTOCOLS = { 188 | 0: "HOPOPT", 189 | 1: "ICMP", 190 | 2: "IGMP", 191 | 3: "GGP", 192 | 4: "IP", 193 | 5: "ST", 194 | 6: "TCP", 195 | 7: "CBT", 196 | 8: "EGP", 197 | 9: "IGP", 198 | 10: "BBN-RCC-MON", 199 | 11: "NVP-II", 200 | 12: "PUP", 201 | 13: "ARGUS", 202 | 14: "EMCON", 203 | 15: "XNET", 204 | 16: "CHAOS", 205 | 17: "UDP", 206 | 18: "MUX", 207 | 19: "DCN-MEAS", 208 | 20: "HMP", 209 | 21: "PRM", 210 | 22: "XNS-IDP", 211 | 23: "TRUNK-1", 212 | 24: "TRUNK-2", 213 | 25: "LEAF-1", 214 | 26: "LEAF-2", 215 | 27: "RDP", 216 | 28: "IRTP", 217 | 29: "ISO-TP4", 218 | 30: "NETBLT", 219 | 31: "MFE-NSP", 220 | 32: "MERIT-INP", 221 | 33: "DCCP", 222 | 34: "3PC", 223 | 35: "IDPR", 224 | 36: "XTP", 225 | 37: "DDP", 226 | 38: "IDPR-CMTP", 227 | 39: "TP++", 228 | 40: "IL", 229 | 41: "IPv6", 230 | 42: "SDRP", 231 | 43: "IPv6-Route", 232 | 44: "IPv6-Frag", 233 | 45: "IDRP", 234 | 46: "RSVP", 235 | 47: "GRE", 236 | 48: "DSR", 237 | 49: "BNA", 238 | 50: "ESP", 239 | 51: "AH", 240 | 52: "I-NLSP", 241 | 53: "SWIPE", 242 | 54: "NARP", 243 | 55: "MOBILE", 244 | 56: "TLSP", 245 | 57: "SKIP", 246 | 58: "IPv6-ICMP", 247 | 59: "IPv6-NoNxt", 248 | 60: "IPv6-Opts", 249 | 61: "any host internal protocol", 250 | 62: "CFTP", 251 | 63: "any local network", 252 | 64: "SAT-EXPAK", 253 | 65: "KRYPTOLAN", 254 | 66: "RVD", 255 | 67: "IPPC", 256 | 68: "any distributed file system", 257 | 69: "SAT-MON", 258 | 70: "VISA", 259 | 71: "IPCV", 260 | 72: "CPNX", 261 | 73: "CPHB", 262 | 74: "WSN", 263 | 75: "PVP", 264 | 76: "BR-SAT-MON", 265 | 77: "SUN-ND", 266 | 78: "WB-MON", 267 | 79: "WB-EXPAK", 268 | 80: "ISO-IP", 269 | 81: "VMTP", 270 | 82: "SECURE-VMTP", 271 | 83: "VINES", 272 | 84: "TTP", 273 | 85: "NSFNET-IGP", 274 | 86: "DGP", 275 | 87: "TCF", 276 | 88: "EIGRP", 277 | 89: "OSPFIGP", 278 | 90: "Sprite-RPC", 279 | 91: "LARP", 280 | 92: "MTP", 281 | 93: "AX.25", 282 | 94: "IPIP", 283 | 95: "MICP", 284 | 96: "SCC-SP", 285 | 97: "ETHERIP", 286 | 98: "ENCAP", 287 | 99: "any private encryption scheme", 288 | 100: "GMTP", 289 | 101: "IFMP", 290 | 102: "PNNI", 291 | 103: "PIM", 292 | 104: "ARIS", 293 | 105: "SCPS", 294 | 106: "QNX", 295 | 107: "A/N", 296 | 108: "IPComp", 297 | 109: "SNP", 298 | 110: "Compaq-Peer", 299 | 111: "IPX-in-IP", 300 | 112: "VRRP", 301 | 113: "PGM", 302 | 114: "any 0-hop protocol", 303 | 115: "L2TP", 304 | 116: "DDX", 305 | 117: "IATP", 306 | 118: "STP", 307 | 119: "SRP", 308 | 120: "UTI", 309 | 121: "SMP", 310 | 122: "SM", 311 | 123: "PTP", 312 | 124: "ISIS", 313 | 125: "FIRE", 314 | 126: "CRTP", 315 | 127: "CRUDP", 316 | 128: "SSCOPMCE", 317 | 129: "IPLT", 318 | 130: "SPS", 319 | 131: "PIPE", 320 | 132: "SCTP", 321 | 133: "FC", 322 | 134: "RSVP-E2E-IGNORE", 323 | 135: "Mobility", 324 | 136: "UDPLite", 325 | 137: "MPLS-in-IP", 326 | 138: "manet", 327 | 139: "HIP", 328 | 140: "Shim6", 329 | 255: "Reserved", 330 | } 331 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | VERSION = "0.6" # Remember to change README.rst when version changes. 4 | 5 | try: 6 | # Use Cython 7 | from Cython.Distutils import build_ext 8 | cmd = {"build_ext": build_ext} 9 | ext = Extension( 10 | "netfilterqueue", 11 | sources=["netfilterqueue.pyx",], 12 | libraries=["netfilter_queue"], 13 | ) 14 | except ImportError: 15 | # No Cython 16 | cmd = {} 17 | ext = Extension( 18 | "netfilterqueue", 19 | sources = ["netfilterqueue.c"], 20 | libraries=["netfilter_queue"], 21 | ) 22 | 23 | setup( 24 | cmdclass = cmd, 25 | ext_modules = [ext], 26 | name="NetfilterQueue", 27 | version=VERSION, 28 | license="BSD", 29 | author="Matthew Fox", 30 | author_email="matthew@kerkhofftech.ca", 31 | url="https://github.com/kti/python-netfilterqueue", 32 | description="Python bindings for libnetfilter_queue", 33 | long_description=open("README.rst").read(), 34 | download_url="http://pypi.python.org/packages/source/N/NetfilterQueue/NetfilterQueue-%s.tar.gz" % VERSION, 35 | classifiers = [ 36 | "Development Status :: 4 - Beta", 37 | "License :: OSI Approved :: BSD License", 38 | "Operating System :: POSIX :: Linux", 39 | "Topic :: System :: Networking", 40 | "Topic :: Security", 41 | "Intended Audience :: Developers", 42 | "Intended Audience :: Telecommunications Industry", 43 | "Programming Language :: Cython", 44 | "Programming Language :: Python :: 2", 45 | ] 46 | ) 47 | --------------------------------------------------------------------------------