Skip to content
This repository was archived by the owner on Feb 18, 2025. It is now read-only.
Open
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
35 changes: 34 additions & 1 deletion handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@ import (
"unsafe"
)

// Main distribs still use libnetfilter_queue 1.0.2, which does not contain UID and GID stuff
// To work on most systems, I disable them for now

//export handle
func handle(id uint32, buffer *C.uchar, len C.int, queueID int) int {
func handle(
id uint32, buffer *C.uchar, len C.int,
inDev, outDev, physInDev, physOutDev, nfMark uint32, hwAddrlen, hwPad uint16,
// hasUID, hasGID int, uid, gid, inDev, outDev, physInDev, physOutDev, nfMark uint32, hwAddrlen, hwPad uint16,
hwAddress0, hwAddress1, hwAddress2, hwAddress3, hwAddress4, hwAddress5, hwAddress6, hwAddress7 uint8,
queueID int) int {
q := queueRegistry.Get(uint16(queueID))
if q == nil {
return 0
Expand All @@ -32,6 +40,31 @@ func handle(id uint32, buffer *C.uchar, len C.int, queueID int) int {
id: id,
Buffer: C.GoBytes(unsafe.Pointer(buffer), len),
q: q,
Meta: &PacketMeta{
HasUID: false,
UID: 0,
HasGID: false,
GID: 0,
// HasUID: hasUID == 1,
// UID: uid,
// HasGID: hasGID == 1,
// GID: gid,
InDev: inDev,
OutDev: outDev,
PhysInDev: physInDev,
PhysOutDev: physOutDev,
NFMark: nfMark,
HWAddr: []byte{
hwAddress0,
hwAddress1,
hwAddress2,
hwAddress3,
hwAddress4,
hwAddress5,
hwAddress6,
hwAddress7,
},
},
}
q.handler.Handle(packet)
return 0
Expand Down
60 changes: 60 additions & 0 deletions nfqueue.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import "C"
import (
"errors"
"fmt"
"net"
"unsafe"
)

Expand All @@ -37,9 +38,68 @@ type PacketHandler interface {
Handle(p *Packet)
}

// PacketMeta contains metadata about a packet
type PacketMeta struct {
HasUID bool
HasGID bool
UID uint32
GID uint32
InDev uint32
OutDev uint32
PhysInDev uint32
PhysOutDev uint32
NFMark uint32
HWAddr []byte
}

// InDevName returns the name of the input interface
func (m *PacketMeta) InDevName() string {
iface, err := net.InterfaceByIndex(int(m.InDev))
if err != nil {
return ""
}
return iface.Name
}

// OutDevName returns the name of the output interface
func (m *PacketMeta) OutDevName() string {
iface, err := net.InterfaceByIndex(int(m.OutDev))
if err != nil {
return ""
}
return iface.Name
}

// PhysInDevName returns the name of the physical input interface
func (m *PacketMeta) PhysInDevName() string {
iface, err := net.InterfaceByIndex(int(m.PhysInDev))
if err != nil {
return ""
}
return iface.Name
}

// PhysOutDevName returns the name of the physical output interface
func (m *PacketMeta) PhysOutDevName() string {
iface, err := net.InterfaceByIndex(int(m.PhysOutDev))
if err != nil {
return ""
}
return iface.Name
}

// MACAddr returns the human-readable value of the MAC address for the packet source
func (m *PacketMeta) MACAddr() string {
return fmt.Sprintf(
"%02X:%02X:%02X:%02X:%02X:%02X",
m.HWAddr[0], m.HWAddr[1], m.HWAddr[2], m.HWAddr[3], m.HWAddr[4], m.HWAddr[5],
)
}

// Packet struct provides the packet data and methods to accept, drop or modify the packet.
type Packet struct {
Buffer []byte
Meta *PacketMeta
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of passing PacketMeta by pointer, when Packet itself is passed as pointer to the callback?

id uint32
q *Queue
}
Expand Down
55 changes: 53 additions & 2 deletions nfqueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,72 @@
// Maximum packet size of a TCP packet
const uint MAX_PACKET_SIZE = 65535;

// Main distribs still use libnetfilter_queue 1.0.2, which does not contain UID and GID stuff
// To work on most systems, I disable them for now

// handle is the packet handler function implemented in go.
// The arguments are:
// - id (packet identifier)
// - buffer (pointer to the packet data starting from IP layer)
// - len (buffer length)
// - had_uid (1 if the packet has an assigned UID)
// - had_gid (1 if the packet has an assigned GID)
// - uid (the UID assigned to the packet)
// - gid (the GID assigned to the packet)
// - indev (input device index)
// - outdev (output device index)
// - physindev (physical input device index)
// - physoutdev (physical output device index)
// - nfmark (NF mark for the packet)
// - hw_addrlen (length of the HW address)
// - hw_pad (padding of the HW address)
// - hw_addr (HW address)
// - queue_id (queue identifier)
extern int handle(uint32_t id, unsigned char* buffer, int len, int queue_id);
extern int handle(uint32_t id, unsigned char* buffer, int len, u_int32_t indev, u_int32_t outdev, u_int32_t physindev, u_int32_t physoutdev, u_int32_t nfmark, u_int16_t hw_addrlen, u_int16_t hw_pad, u_int8_t hw_addr0, u_int8_t hw_addr1, u_int8_t hw_addr2, u_int8_t hw_addr3, u_int8_t hw_addr4, u_int8_t hw_addr5, u_int8_t hw_addr6, u_int8_t hw_addr7, int queue_id);
// extern int handle(uint32_t id, unsigned char* buffer, int len, int has_uid, int has_gid, u_int32_t uid, u_int32_t gid, u_int32_t indev, u_int32_t outdev, u_int32_t physindev, u_int32_t physoutdev, u_int32_t nfmark, u_int16_t hw_addrlen, u_int16_t hw_pad, u_int8_t hw_addr0, u_int8_t hw_addr1, u_int8_t hw_addr2, u_int8_t hw_addr3, u_int8_t hw_addr4, u_int8_t hw_addr5, u_int8_t hw_addr6, u_int8_t hw_addr7, int queue_id);

int nfqueue_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa, void *cb_data)
{
unsigned char *buffer = NULL;
struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(nfa);
uint32_t id = ntohl(ph->packet_id);
int ret = nfq_get_payload(nfa, &buffer);
return handle(id, buffer, ret, (intptr_t)cb_data);
// Main distribs still use libnetfilter_queue 1.0.2, which does not contain UID and GID stuff
// To work on most systems, I disable them for now
// u_int32_t uid = 0;
// u_int32_t gid = 0;
// int has_uid = nfq_get_uid(nfa, &uid);
// int has_gid = nfq_get_gid(nfa, &gid);
u_int32_t indev = nfq_get_indev(nfa);
u_int32_t outdev = nfq_get_outdev(nfa);
u_int32_t physindev = nfq_get_physindev(nfa);
u_int32_t physoutdev = nfq_get_physoutdev(nfa);
u_int32_t nfmark = nfq_get_nfmark(nfa);
struct nfqnl_msg_packet_hw *packet_hw = nfq_get_packet_hw(nfa);
u_int16_t hw_addrlen = 0;
u_int16_t hw_pad = 0;
u_int8_t hw_addr0 = 0;
u_int8_t hw_addr1 = 0;
u_int8_t hw_addr2 = 0;
u_int8_t hw_addr3 = 0;
u_int8_t hw_addr4 = 0;
u_int8_t hw_addr5 = 0;
u_int8_t hw_addr6 = 0;
u_int8_t hw_addr7 = 0;
if (packet_hw != NULL) {
hw_addrlen = packet_hw->hw_addrlen;
hw_pad = packet_hw->_pad;
hw_addr0 = packet_hw->hw_addr[0];
hw_addr1 = packet_hw->hw_addr[1];
hw_addr2 = packet_hw->hw_addr[2];
hw_addr3 = packet_hw->hw_addr[3];
hw_addr4 = packet_hw->hw_addr[4];
hw_addr5 = packet_hw->hw_addr[5];
hw_addr6 = packet_hw->hw_addr[6];
hw_addr7 = packet_hw->hw_addr[7];
}
return handle(id, buffer, ret, indev, outdev, physindev, physoutdev, nfmark, hw_addrlen, hw_pad, hw_addr0, hw_addr1, hw_addr2, hw_addr3, hw_addr4, hw_addr5, hw_addr6, hw_addr7, (intptr_t)cb_data);
// return handle(id, buffer, ret, has_uid, has_gid, uid, gid, indev, outdev, physindev, physoutdev, nfmark, hw_addrlen, hw_pad, hw_addr0, hw_addr1, hw_addr2, hw_addr3, hw_addr4, hw_addr5, hw_addr6, hw_addr7, (intptr_t)cb_data);
}

static struct nfq_q_handle *nfqueue_create_queue(struct nfq_handle *h, u_int16_t queue_id) {
Expand Down