├── .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 =