Skip to content

Add Packet accessors for interface indices #93

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ jobs:
fail-fast: false
matrix:
python:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- 'pypy-3.7'
- 'pypy-3.8'
- 'pypy-3.9'
check_lint: ['0']
extra_name: ['']
include:
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v1.1.0, unreleased
Add Packet accessors for {indev, outdev, physindev, physoutdev} interface indices

v1.0.0, 14 Jan 2022
Propagate exceptions raised by the user's packet callback
Avoid calls to the packet callback during queue unbinding
Expand Down
12 changes: 12 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ Objects of this type are passed to your callback.
into our queue. Values 0 through 4 correspond to PREROUTING, INPUT,
FORWARD, OUTPUT, and POSTROUTING respectively.

``Packet.indev``, ``Packet.outdev``, ``Packet.physindev``, ``Packet.physoutdev``
The interface indices on which the packet arrived (``indev``) or is slated
to depart (``outdev``). These are integers, which can be converted to
names like "eth0" by using ``socket.if_indextoname()``. Zero means
no interface is applicable, either because the packet was locally generated
or locally received, or because the interface information wasn't available
when the packet was queued (for example, ``PREROUTING`` rules don't yet
know the ``outdev``). If the ``indev`` or ``outdev`` refers to a bridge
device, then the corresponding ``physindev`` or ``physoutdev`` will name
the bridge member on which the actual traffic occurred; otherwise
``physindev`` and ``physoutdev`` will be zero.

``Packet.retain()``
Allocate a copy of the packet payload for use after the callback
has returned. ``get_payload()`` will raise an exception at that
Expand Down
20 changes: 10 additions & 10 deletions netfilterqueue/_impl.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,11 @@ cdef extern from "libnetfilter_queue/libnetfilter_queue.h":
int nfq_get_payload(nfq_data *nfad, unsigned char **data)
int nfq_get_timestamp(nfq_data *nfad, timeval *tv)
nfqnl_msg_packet_hw *nfq_get_packet_hw(nfq_data *nfad)
int nfq_get_nfmark (nfq_data *nfad)
int nfq_get_nfmark(nfq_data *nfad)
u_int32_t nfq_get_indev(nfq_data *nfad)
u_int32_t nfq_get_outdev(nfq_data *nfad)
u_int32_t nfq_get_physindev(nfq_data *nfad)
u_int32_t nfq_get_physoutdev(nfq_data *nfad)
nfnl_handle *nfq_nfnlh(nfq_handle *h)

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

cdef class Packet:
cdef NetfilterQueue _queue
cdef bint _verdict_is_set # True if verdict has been issued,
# false otherwise
cdef bint _verdict_is_set # True if verdict has been issued, false otherwise
cdef bint _mark_is_set # True if a mark has been given, false otherwise
cdef bint _hwaddr_is_set
cdef bint _timestamp_is_set
Expand All @@ -204,13 +207,10 @@ cdef class Packet:
cdef unsigned char *payload
cdef timeval timestamp
cdef u_int8_t hw_addr[8]

# TODO: implement these
#cdef readonly u_int32_t nfmark
#cdef readonly u_int32_t indev
#cdef readonly u_int32_t physindev
#cdef readonly u_int32_t outdev
#cdef readonly u_int32_t physoutdev
cdef readonly u_int32_t indev
cdef readonly u_int32_t physindev
cdef readonly u_int32_t outdev
cdef readonly u_int32_t physoutdev

cdef set_nfq_data(self, NetfilterQueue queue, nfq_data *nfa)
cdef drop_refs(self)
Expand Down
5 changes: 5 additions & 0 deletions netfilterqueue/_impl.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ class Packet:
hw_protocol: int
id: int
mark: int
# These are ifindexes, pass to socket.if_indextoname() to get names:
indev: int
outdev: int
physindev: int
physoutdev: int
def get_hw(self) -> Optional[bytes]: ...
def get_payload(self) -> bytes: ...
def get_payload_len(self) -> int: ...
Expand Down
4 changes: 4 additions & 0 deletions netfilterqueue/_impl.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ cdef class Packet:

nfq_get_timestamp(nfa, &self.timestamp)
self.mark = nfq_get_nfmark(nfa)
self.indev = nfq_get_indev(nfa)
self.outdev = nfq_get_outdev(nfa)
self.physindev = nfq_get_physindev(nfa)
self.physoutdev = nfq_get_physoutdev(nfa)

cdef drop_refs(self):
"""
Expand Down
18 changes: 17 additions & 1 deletion tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,13 @@ def cb(chan, pkt):
assert t0 < timestamps[0] < t1


async def test_hwaddr(harness):
async def test_hwaddr_and_inoutdev(harness):
hwaddrs = []
inoutdevs = []

def cb(pkt):
hwaddrs.append((pkt.get_hw(), pkt.hook, pkt.get_payload()[28:]))
inoutdevs.append((pkt.indev, pkt.outdev))
pkt.accept()

queue_num, nfq = harness.bind_queue(cb)
Expand Down Expand Up @@ -162,6 +164,20 @@ async def listen_for_packets():
(None, OUTPUT, b"four"),
]

if sys.implementation.name != "pypy":
# pypy doesn't appear to provide if_nametoindex()
iface1 = socket.if_nametoindex("veth1")
iface2 = socket.if_nametoindex("veth2")
else:
iface1, iface2 = inoutdevs[0]
assert 0 != iface1 != iface2 != 0
assert inoutdevs == [
(iface1, iface2),
(iface1, iface2),
(0, iface2),
(0, iface2),
]


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