From c530f1bd9422637835a29d63ff07ddf3e4c5e9db Mon Sep 17 00:00:00 2001
From: DOWRIGHT <dowright@nationofnobodies.com>
Date: Sat, 16 Apr 2022 12:17:40 -0700
Subject: [PATCH] added in/outdev getters and performance improvements.

---
 netfilterqueue/_impl.pxd |  6 +++++
 netfilterqueue/_impl.pyi |  2 ++
 netfilterqueue/_impl.pyx | 55 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/netfilterqueue/_impl.pxd b/netfilterqueue/_impl.pxd
index 54c2fa3..8a9eba6 100644
--- a/netfilterqueue/_impl.pxd
+++ b/netfilterqueue/_impl.pxd
@@ -154,6 +154,8 @@ cdef extern from "libnetfilter_queue/libnetfilter_queue.h":
     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)
+    u_int8_t nfq_get_indev(nfq_data *nfad)
+    u_int8_t nfq_get_outdev(nfq_data *nfad)
     nfnl_handle *nfq_nfnlh(nfq_handle *h)
 
 # Dummy defines from linux/socket.h:
@@ -193,6 +195,8 @@ cdef class Packet:
     cdef bytes _given_payload # New payload of packet, or null
     cdef bytes _owned_payload
 
+    cdef nfq_data *_nfa
+
     # From NFQ packet header:
     cdef readonly u_int32_t id
     cdef readonly u_int16_t hw_protocol
@@ -215,6 +219,8 @@ cdef class Packet:
     cdef set_nfq_data(self, NetfilterQueue queue, nfq_data *nfa)
     cdef drop_refs(self)
     cdef int verdict(self, u_int8_t verdict) except -1
+    cpdef get_indev(self, bint name=*)
+    cpdef get_outdev(self, bint name=*)
     cpdef Py_ssize_t get_payload_len(self)
     cpdef double get_timestamp(self)
     cpdef bytes get_payload(self)
diff --git a/netfilterqueue/_impl.pyi b/netfilterqueue/_impl.pyi
index 3cba8fc..f8e4628 100644
--- a/netfilterqueue/_impl.pyi
+++ b/netfilterqueue/_impl.pyi
@@ -12,6 +12,8 @@ class Packet:
     id: int
     mark: int
     def get_hw(self) -> Optional[bytes]: ...
+    def get_indev(self, name: bool = False): ...
+    def get_outdev(self, name: bool = False): ...
     def get_payload(self) -> bytes: ...
     def get_payload_len(self) -> int: ...
     def get_timestamp(self) -> float: ...
diff --git a/netfilterqueue/_impl.pyx b/netfilterqueue/_impl.pyx
index d656d5b..94fcb52 100644
--- a/netfilterqueue/_impl.pyx
+++ b/netfilterqueue/_impl.pyx
@@ -4,9 +4,16 @@ function.
 
 Copyright: (c) 2011, Kerkhoff Technologies Inc.
 License: MIT; see LICENSE.txt
+
+Expanded features and performance improvements from downstream development
+of DNXFIREWALL.
+ - DOWRIGHT @ Wright Network Solutions, LLC.
 """
 
 # Constants for module users
+import Cython
+import socket
+
 COPY_NONE = 0
 COPY_META = 1
 COPY_PACKET = 2
@@ -41,7 +48,9 @@ cdef int global_callback(nfq_q_handle *qh, nfgenmsg *nfmsg,
         # so just ignore the packet. The kernel will drop it once we
         # unbind.
         return 1
-    packet = Packet()
+
+    # skipping call to __init__.
+    packet = Packet.__new__(Packet)
     packet.set_nfq_data(nfqueue, nfa)
     try:
         user_callback(packet)
@@ -49,6 +58,8 @@ cdef int global_callback(nfq_q_handle *qh, nfgenmsg *nfmsg,
         packet.drop_refs()
     return 1
 
+# pre allocated memory for Packet object.
+@Cython.freelist(8)
 cdef class Packet:
     """A packet received from NetfilterQueue."""
     def __cinit__(self):
@@ -69,6 +80,8 @@ cdef class Packet:
         cdef nfqnl_msg_packet_hw *hw
         cdef nfqnl_msg_packet_hdr *hdr
 
+        self._nfa = nfa
+
         hdr = nfq_get_msg_packet_hdr(nfa)
         self._queue = queue
         self.id = ntohl(hdr.packet_id)
@@ -129,6 +142,46 @@ cdef class Packet:
 
         self._verdict_is_set = True
 
+    cpdef get_indev(self, bint name=False):
+        """Returns the index of the inbound interface of the packet. If the packet 
+        sourced from localhost or the input interface is not known, 0/unknown will
+        be returned respectively.
+
+        if name=True, socket.if_indextoname() will be returned.
+        """
+        cdef object in_interface_name
+
+        in_interface = nfq_get_indev(self._nfa)
+        if not name:
+            return in_interface
+
+        try:
+            in_interface_name = socket.if_indextoname(in_interface)
+        except OSError:
+            in_interface_name = 'unknown'
+
+        return in_interface_name
+
+    cpdef get_outdev(self, bint name=False):
+        """Returns the index of the outbound interface of the packet. If the packet 
+        sourced from localhost or the input interface is not known, 0/unknown will
+        be returned respectively.
+
+        if name=True, socket.if_indextoname() will be returned.
+        """
+        cdef object out_interface_name
+
+        out_interface = nfq_get_outdev(self._nfa)
+        if not name:
+            return out_interface
+
+        try:
+            out_interface_name = socket.if_indextoname(out_interface)
+        except OSError:
+            out_interface_name = 'unknown'
+
+        return out_interface_name
+
     def get_hw(self):
         """Return the packet's source MAC address as a Python bytestring, or
         None if it's not available.