Skip to content

Commit 2b6849b

Browse files
authored
Merge pull request #93 from oremanj/inoutdev
Add Packet accessors for interface indices
2 parents 0bb948d + 49e1681 commit 2b6849b

File tree

7 files changed

+53
-12
lines changed

7 files changed

+53
-12
lines changed

.github/workflows/ci.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ jobs:
1515
fail-fast: false
1616
matrix:
1717
python:
18-
- '3.6'
1918
- '3.7'
2019
- '3.8'
2120
- '3.9'
2221
- '3.10'
22+
- '3.11'
2323
- 'pypy-3.7'
2424
- 'pypy-3.8'
25+
- 'pypy-3.9'
2526
check_lint: ['0']
2627
extra_name: ['']
2728
include:

CHANGES.txt

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
v1.1.0, unreleased
2+
Add Packet accessors for {indev, outdev, physindev, physoutdev} interface indices
3+
14
v1.0.0, 14 Jan 2022
25
Propagate exceptions raised by the user's packet callback
36
Avoid calls to the packet callback during queue unbinding

README.rst

+12
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,18 @@ Objects of this type are passed to your callback.
217217
into our queue. Values 0 through 4 correspond to PREROUTING, INPUT,
218218
FORWARD, OUTPUT, and POSTROUTING respectively.
219219

220+
``Packet.indev``, ``Packet.outdev``, ``Packet.physindev``, ``Packet.physoutdev``
221+
The interface indices on which the packet arrived (``indev``) or is slated
222+
to depart (``outdev``). These are integers, which can be converted to
223+
names like "eth0" by using ``socket.if_indextoname()``. Zero means
224+
no interface is applicable, either because the packet was locally generated
225+
or locally received, or because the interface information wasn't available
226+
when the packet was queued (for example, ``PREROUTING`` rules don't yet
227+
know the ``outdev``). If the ``indev`` or ``outdev`` refers to a bridge
228+
device, then the corresponding ``physindev`` or ``physoutdev`` will name
229+
the bridge member on which the actual traffic occurred; otherwise
230+
``physindev`` and ``physoutdev`` will be zero.
231+
220232
``Packet.retain()``
221233
Allocate a copy of the packet payload for use after the callback
222234
has returned. ``get_payload()`` will raise an exception at that

netfilterqueue/_impl.pxd

+10-10
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ cdef extern from "libnetfilter_queue/libnetfilter_queue.h":
153153
int nfq_get_payload(nfq_data *nfad, unsigned char **data)
154154
int nfq_get_timestamp(nfq_data *nfad, timeval *tv)
155155
nfqnl_msg_packet_hw *nfq_get_packet_hw(nfq_data *nfad)
156-
int nfq_get_nfmark (nfq_data *nfad)
156+
int nfq_get_nfmark(nfq_data *nfad)
157+
u_int32_t nfq_get_indev(nfq_data *nfad)
158+
u_int32_t nfq_get_outdev(nfq_data *nfad)
159+
u_int32_t nfq_get_physindev(nfq_data *nfad)
160+
u_int32_t nfq_get_physoutdev(nfq_data *nfad)
157161
nfnl_handle *nfq_nfnlh(nfq_handle *h)
158162

159163
# Dummy defines from linux/socket.h:
@@ -184,8 +188,7 @@ cdef class NetfilterQueue:
184188

185189
cdef class Packet:
186190
cdef NetfilterQueue _queue
187-
cdef bint _verdict_is_set # True if verdict has been issued,
188-
# false otherwise
191+
cdef bint _verdict_is_set # True if verdict has been issued, false otherwise
189192
cdef bint _mark_is_set # True if a mark has been given, false otherwise
190193
cdef bint _hwaddr_is_set
191194
cdef bint _timestamp_is_set
@@ -204,13 +207,10 @@ cdef class Packet:
204207
cdef unsigned char *payload
205208
cdef timeval timestamp
206209
cdef u_int8_t hw_addr[8]
207-
208-
# TODO: implement these
209-
#cdef readonly u_int32_t nfmark
210-
#cdef readonly u_int32_t indev
211-
#cdef readonly u_int32_t physindev
212-
#cdef readonly u_int32_t outdev
213-
#cdef readonly u_int32_t physoutdev
210+
cdef readonly u_int32_t indev
211+
cdef readonly u_int32_t physindev
212+
cdef readonly u_int32_t outdev
213+
cdef readonly u_int32_t physoutdev
214214

215215
cdef set_nfq_data(self, NetfilterQueue queue, nfq_data *nfa)
216216
cdef drop_refs(self)

netfilterqueue/_impl.pyi

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ class Packet:
1111
hw_protocol: int
1212
id: int
1313
mark: int
14+
# These are ifindexes, pass to socket.if_indextoname() to get names:
15+
indev: int
16+
outdev: int
17+
physindev: int
18+
physoutdev: int
1419
def get_hw(self) -> Optional[bytes]: ...
1520
def get_payload(self) -> bytes: ...
1621
def get_payload_len(self) -> int: ...

netfilterqueue/_impl.pyx

+4
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ cdef class Packet:
9999

100100
nfq_get_timestamp(nfa, &self.timestamp)
101101
self.mark = nfq_get_nfmark(nfa)
102+
self.indev = nfq_get_indev(nfa)
103+
self.outdev = nfq_get_outdev(nfa)
104+
self.physindev = nfq_get_physindev(nfa)
105+
self.physoutdev = nfq_get_physoutdev(nfa)
102106

103107
cdef drop_refs(self):
104108
"""

tests/test_basic.py

+17-1
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,13 @@ def cb(chan, pkt):
119119
assert t0 < timestamps[0] < t1
120120

121121

122-
async def test_hwaddr(harness):
122+
async def test_hwaddr_and_inoutdev(harness):
123123
hwaddrs = []
124+
inoutdevs = []
124125

125126
def cb(pkt):
126127
hwaddrs.append((pkt.get_hw(), pkt.hook, pkt.get_payload()[28:]))
128+
inoutdevs.append((pkt.indev, pkt.outdev))
127129
pkt.accept()
128130

129131
queue_num, nfq = harness.bind_queue(cb)
@@ -162,6 +164,20 @@ async def listen_for_packets():
162164
(None, OUTPUT, b"four"),
163165
]
164166

167+
if sys.implementation.name != "pypy":
168+
# pypy doesn't appear to provide if_nametoindex()
169+
iface1 = socket.if_nametoindex("veth1")
170+
iface2 = socket.if_nametoindex("veth2")
171+
else:
172+
iface1, iface2 = inoutdevs[0]
173+
assert 0 != iface1 != iface2 != 0
174+
assert inoutdevs == [
175+
(iface1, iface2),
176+
(iface1, iface2),
177+
(0, iface2),
178+
(0, iface2),
179+
]
180+
165181

166182
async def test_errors(harness):
167183
with pytest.warns(RuntimeWarning, match="rcvbuf limit is") as record:

0 commit comments

Comments
 (0)