summaryrefslogtreecommitdiffstats
path: root/examples/nf-queue.c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/nf-queue.c')
-rw-r--r--examples/nf-queue.c75
1 files changed, 56 insertions, 19 deletions
diff --git a/examples/nf-queue.c b/examples/nf-queue.c
index 960e244..1ae52e4 100644
--- a/examples/nf-queue.c
+++ b/examples/nf-queue.c
@@ -15,26 +15,11 @@
#include <libnetfilter_queue/libnetfilter_queue.h>
-/* only for NFQA_CT, not needed otherwise: */
+/* NFQA_CT requires CTA_* attributes defined in nfnetlink_conntrack.h */
#include <linux/netfilter/nfnetlink_conntrack.h>
static struct mnl_socket *nl;
-static struct nlmsghdr *
-nfq_hdr_put(char *buf, int type, uint32_t queue_num)
-{
- struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
- nlh->nlmsg_type = (NFNL_SUBSYS_QUEUE << 8) | type;
- nlh->nlmsg_flags = NLM_F_REQUEST;
-
- struct nfgenmsg *nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
- nfg->nfgen_family = AF_UNSPEC;
- nfg->version = NFNETLINK_V0;
- nfg->res_id = htons(queue_num);
-
- return nlh;
-}
-
static void
nfq_send_verdict(int queue_num, uint32_t id)
{
@@ -42,7 +27,7 @@ nfq_send_verdict(int queue_num, uint32_t id)
struct nlmsghdr *nlh;
struct nlattr *nest;
- nlh = nfq_hdr_put(buf, NFQNL_MSG_VERDICT, queue_num);
+ nlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, queue_num);
nfq_nlmsg_verdict_put(nlh, id, NF_ACCEPT);
/* example to set the connmark. First, start NFQA_CT section: */
@@ -69,6 +54,9 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data)
struct nfgenmsg *nfg;
uint16_t plen;
+ /* Parse netlink message received from the kernel, the array of
+ * attributes is set up to store metadata and the actual packet.
+ */
if (nfq_nlmsg_parse(nlh, attr) < 0) {
perror("problems parsing");
return MNL_CB_ERROR;
@@ -81,13 +69,30 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_ERROR;
}
+ /* Access packet metadata, which provides unique packet ID, hook number
+ * and ethertype. See struct nfqnl_msg_packet_hdr for details.
+ */
ph = mnl_attr_get_payload(attr[NFQA_PACKET_HDR]);
+ /* Access actual packet data length. */
plen = mnl_attr_get_payload_len(attr[NFQA_PAYLOAD]);
+
+ /* Access actual packet data */
/* void *payload = mnl_attr_get_payload(attr[NFQA_PAYLOAD]); */
+ /* Fetch metadata flags, possible flags values are:
+ *
+ * - NFQA_SKB_CSUMNOTREADY:
+ * Kernel performed partial checksum validation, see CHECKSUM_PARTIAL.
+ * - NFQA_SKB_CSUM_NOTVERIFIED:
+ * Kernel already verified checksum.
+ * - NFQA_SKB_GSO:
+ * Not the original packet received from the wire. Kernel has
+ * aggregated several packets into one single packet via GSO.
+ */
skbinfo = attr[NFQA_SKB_INFO] ? ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])) : 0;
+ /* Kernel has truncated the packet, fetch original packet length. */
if (attr[NFQA_CAP_LEN]) {
uint32_t orig_len = ntohl(mnl_attr_get_u32(attr[NFQA_CAP_LEN]));
if (orig_len != plen)
@@ -101,6 +106,25 @@ static int queue_cb(const struct nlmsghdr *nlh, void *data)
printf("packet received (id=%u hw=0x%04x hook=%u, payload len %u",
id, ntohs(ph->hw_protocol), ph->hook, plen);
+ /* Fetch ethernet destination address. */
+ if (attr[NFQA_HWADDR]) {
+ struct nfqnl_msg_packet_hw *hw = mnl_attr_get_payload(attr[NFQA_HWADDR]);
+ unsigned int hwlen = ntohs(hw->hw_addrlen);
+ const unsigned char *addr = hw->hw_addr;
+ unsigned int i;
+
+ printf(", hwaddr %02x", addr[0]);
+ for (i = 1; i < hwlen; i++) {
+ if (i >= sizeof(hw->hw_addr)) {
+ printf("[truncated]");
+ break;
+ }
+ printf(":%02x", (unsigned char)addr[i]);
+ }
+
+ printf(" len %u", hwlen);
+ }
+
/*
* ip/tcp checksums are not yet valid, e.g. due to GRO/GSO.
* The application should behave as if the checksums are correct.
@@ -132,6 +156,9 @@ int main(int argc, char *argv[])
}
queue_num = atoi(argv[1]);
+ /*
+ * Set up netlink socket to communicate with the netfilter subsystem.
+ */
nl = mnl_socket_open(NETLINK_NETFILTER);
if (nl == NULL) {
perror("mnl_socket_open");
@@ -150,7 +177,11 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num);
+ /* Configure the pipeline between kernel and userspace, build and send
+ * a netlink message to specify queue number to bind to. Your ruleset
+ * has to use this queue number to deliver packets to userspace.
+ */
+ nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_cmd(nlh, AF_INET, NFQNL_CFG_CMD_BIND);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
@@ -158,7 +189,10 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- nlh = nfq_hdr_put(buf, NFQNL_MSG_CONFIG, queue_num);
+ /* Build and send a netlink message to specify how many bytes are
+ * copied from kernel to userspace for this queue.
+ */
+ nlh = nfq_nlmsg_put(buf, NFQNL_MSG_CONFIG, queue_num);
nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff);
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(NFQA_CFG_F_GSO));
@@ -176,6 +210,9 @@ int main(int argc, char *argv[])
ret = 1;
mnl_socket_setsockopt(nl, NETLINK_NO_ENOBUFS, &ret, sizeof(int));
+ /* Loop forever on packets received from the kernel and run the
+ * callback handler.
+ */
for (;;) {
ret = mnl_socket_recvfrom(nl, buf, sizeof_buf);
if (ret == -1) {