* [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink
@ 2024-05-24 5:37 Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 01/15] src: Convert nfq_open() to use libmnl Duncan Roe
` (14 more replies)
0 siblings, 15 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
The general method is to make the opaque struct nfq_handle contain fully
populated libnfnetlink-style and libmnl-style handles.
Patch 1 (nfq_open()) and patch 2 (nfq_open_nfnl()) sets this up.
Patch 3 (nfq_close()) cleans it away.
Patches 3-10 convert the other nfq_* functions that used to use
libnfnetlink, except for the nfq_get_*_name functions that need nlif.
Patches 11-13 provide all the nlif_* functions that libnfnetlink used to
offer, converted to use libmnl.
Patch 14 removes all use of and reference to header files provided by
libnfnetlink. It provides prototypes as required.
Patch 15 removes libnfnetlink as a private library.
There is a tester for this patchset at
https://github.com/duncan-roe/nfqnltester
Some of the tests require checking out different branches,
e.g. for testing the effect of loading libraries in a diffrernt order.
There is more info in the README. In particular I checked that nlif still
works with -lnfnetlink coming first
(app will use libnfnetlink's functions).
The nlif functions sit a little uneasily in libnetfilter_queue.
ulogd2 and conntrack-tools both use them so perhaps they would
be better placed in libmnl.
---
Changes in v2:
- 11/32 (Fix checkpatch whitespace and block comment warnings) is
subsumed into previous patches
- 22/32 becomes 14
- 21/32 becomes 15
- 12/32 & 17/32 become 11, but rtnl.c is not copied
- 14/32 & 16/32 become 12
- 19/32 & (some of) 32/32 become 13
- The only changes to linux_list.h are to fix or suppress checkpatch errors.
There is no attempt to document the circular linked list functions
and macros, so no changes to build_man.sh. That is how the rest of the
patches disappear.
- Other changes are documented in the individual patches
Duncan Roe (15):
src: Convert nfq_open() to use libmnl
src: Convert nfq_open_nfnl() to use libmnl
src: Convert nfq_close() to use libmnl
src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() to
use libmnl
src: Convert nfq_set_queue_flags(), nfq_set_queue_maxlen() &
nfq_set_mode() to use libmnl
src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload()
and all the nfq_get_ functions to use libmnl
src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if
there is no data
src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue
src: Convert nfq_fd() to use libmnl
src: Convert remaining nfq_* functions to use libmnl
src: Copy nlif-related files from libnfnetlink
doc: Add iftable.c to the doxygen system
src: Convert all nlif_* functions to use libmnl
include: Use libmnl.h instead of libnfnetlink.h
build: Remove libnfnetlink from the build
Make_global.am | 2 +-
configure.ac | 1 -
doxygen/Makefile.am | 1 +
doxygen/doxygen.cfg.in | 6 +
.../libnetfilter_queue/libnetfilter_queue.h | 38 +-
include/libnetfilter_queue/linux_list.h | 730 ++++++++++++++++++
.../linux_nfnetlink_queue.h | 3 +-
libnetfilter_queue.pc.in | 2 -
src/Makefile.am | 3 +-
src/iftable.c | 373 +++++++++
src/libnetfilter_queue.c | 543 ++++++++-----
11 files changed, 1512 insertions(+), 190 deletions(-)
create mode 100644 include/libnetfilter_queue/linux_list.h
create mode 100644 src/iftable.c
--
2.35.8
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 01/15] src: Convert nfq_open() to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 02/15] src: Convert nfq_open_nfnl() " Duncan Roe
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
Add copies of nfnl_handle, nfnl_subsys_handle & mnl_socket to
libnetfilter_queue.c. After calling mnl_socket_open() & mnl_socket_bind(),
fill in the libnfnetlink structs as if nfnl_open() had been called.
Call a static extended version of nfq_open_nfnl(), __nfq_open_nfnl() which
can tell how it was called via an extra argument: struct nfq_handle *qh.
nfq_open() passes the qh returned by mnl_open(). nfq_open_nfnl() passes
NULL.
__nfq_open_nfnl() creates and returns a qh if it wasn't given one.
Otherwise it returns the qh it was given or NULL on error (but the
passed-in qh is not freed).
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- Rather than inline nfnl subsys code, minimally modify nfq_open_nfnl()
as per updated commit message
- Replace NFNL_BUFFSIZE with MNL_SOCKET_BUFFER_SIZE
- Use calloc instead of malloc + memset in new code
- Don't rename struct nfq_handle *qh to *h
- Fix checkpatch space before tab warnings in lines 143,147,159,165
- Keep nfq_errno
doxygen/doxygen.cfg.in | 3 ++
src/libnetfilter_queue.c | 86 ++++++++++++++++++++++++++++++++++------
2 files changed, 77 insertions(+), 12 deletions(-)
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index 97174ff..6dd7017 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -13,6 +13,9 @@ EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
nfq_handle \
nfq_data \
nfq_q_handle \
+ nfnl_handle \
+ nfnl_subsys_handle \
+ mnl_socket \
tcp_flag_word
EXAMPLE_PATTERNS =
INPUT_FILTER = "sed 's/EXPORT_SYMBOL//g'"
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index bf67a19..f366198 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -31,6 +31,7 @@
#include <sys/socket.h>
#include <linux/netfilter/nfnetlink_queue.h>
+#include <libmnl/libmnl.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
@@ -134,11 +135,43 @@ gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
* burst
*/
+/* Copy of private libnfnetlink structures */
+
+#define NFNL_MAX_SUBSYS 16
+
+struct nfnl_subsys_handle {
+ struct nfnl_handle *nfnlh;
+ uint32_t subscriptions;
+ uint8_t subsys_id;
+ uint8_t cb_count;
+ struct nfnl_callback *cb; /* array of callbacks */
+};
+
+struct nfnl_handle {
+ int fd;
+ struct sockaddr_nl local;
+ struct sockaddr_nl peer;
+ uint32_t subscriptions;
+ uint32_t seq;
+ uint32_t dump;
+ uint32_t rcv_buffer_size; /* for nfnl_catch */
+ uint32_t flags;
+ struct nlmsghdr *last_nlhdr;
+ struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1];
+};
+
+/* Copy of private libmnl structure */
+struct mnl_socket {
+ int fd;
+ struct sockaddr_nl addr;
+};
+
struct nfq_handle
{
struct nfnl_handle *nfnlh;
struct nfnl_subsys_handle *nfnlssh;
struct nfq_q_handle *qh_list;
+ struct mnl_socket *nl;
};
struct nfq_q_handle
@@ -157,6 +190,9 @@ struct nfq_data {
EXPORT_SYMBOL int nfq_errno;
+static struct nfq_handle *__nfq_open_nfnl(struct nfnl_handle *nfnlh,
+ struct nfq_handle *qh);
+
/***********************************************************************
* low level stuff
***********************************************************************/
@@ -383,20 +419,41 @@ int nfq_fd(struct nfq_handle *h)
EXPORT_SYMBOL
struct nfq_handle *nfq_open(void)
{
- struct nfnl_handle *nfnlh = nfnl_open();
struct nfq_handle *qh;
+ struct nfq_handle *h;
- if (!nfnlh)
- return NULL;
-
- /* unset netlink sequence tracking by default */
- nfnl_unset_sequence_tracking(nfnlh);
-
- qh = nfq_open_nfnl(nfnlh);
+ qh = calloc(1, sizeof(*qh));
if (!qh)
- nfnl_close(nfnlh);
+ return NULL;
+ qh->nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (!qh->nl)
+ goto err_free;
+
+ if (mnl_socket_bind(qh->nl, 0, MNL_SOCKET_AUTOPID) < 0)
+ goto err_close;
+
+ /* Manufacture an nfnl handle */
+ qh->nfnlh = calloc(1, sizeof(*qh->nfnlh));
+ if (!qh->nfnlh)
+ goto err_close;
+ qh->nfnlh->fd = qh->nl->fd;
+ qh->nfnlh->local = qh->nl->addr;
+ qh->nfnlh->peer.nl_family = AF_NETLINK;
+ qh->nfnlh->rcv_buffer_size = MNL_SOCKET_BUFFER_SIZE;
+
+ h = __nfq_open_nfnl(qh->nfnlh, qh); /* Will return qh or NULL */
+ if (!h)
+ goto err_free2;
return qh;
+
+err_free2:
+ free(qh->nfnlh);
+err_close:
+ mnl_socket_close(qh->nl);
+err_free:
+ free(qh);
+ return NULL;
}
/**
@@ -415,6 +472,11 @@ struct nfq_handle *nfq_open(void)
*/
EXPORT_SYMBOL
struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
+{
+ return __nfq_open_nfnl(nfnlh, NULL);
+}
+static struct nfq_handle *__nfq_open_nfnl(struct nfnl_handle *nfnlh,
+ struct nfq_handle *qh)
{
struct nfnl_callback pkt_cb = {
.call = __nfq_rcv_pkt,
@@ -423,11 +485,10 @@ struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
struct nfq_handle *h;
int err;
- h = malloc(sizeof(*h));
+ h = qh ? qh : calloc(1, sizeof(*h));
if (!h)
return NULL;
- memset(h, 0, sizeof(*h));
h->nfnlh = nfnlh;
h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE,
@@ -448,7 +509,8 @@ struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
out_close:
nfnl_subsys_close(h->nfnlssh);
out_free:
- free(h);
+ if (!qh)
+ free(h);
return NULL;
}
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 02/15] src: Convert nfq_open_nfnl() to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 01/15] src: Convert nfq_open() to use libmnl Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 03/15] src: Convert nfq_close() " Duncan Roe
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
__nfq_open_nfnl() manufactures a libmnl handle if called by
nfq_open_nfnl().
Replace calls to nfnl_subsys_open() and nfnl_callback_register() with
inline code.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- Pretty much re-written as per updated commit message. In particular:
- Don't clear message sequencing - original didn't do that.
- Don't close the socket in any error path since it was open on entry.
src/libnetfilter_queue.c | 56 ++++++++++++++++++++++++++++++++--------
1 file changed, 45 insertions(+), 11 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index f366198..bfb6482 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -484,33 +484,67 @@ static struct nfq_handle *__nfq_open_nfnl(struct nfnl_handle *nfnlh,
};
struct nfq_handle *h;
int err;
+ int i;
+ uint32_t new_subscriptions;
h = qh ? qh : calloc(1, sizeof(*h));
if (!h)
return NULL;
+ if (!qh) {
+ /* Manufacture the libmnl handle */
+ h->nl = calloc(1, sizeof(*h->nl));
+ if (!h->nl)
+ goto out_free;
+ h->nl->fd = nfnlh->fd;
+ h->nl->addr = nfnlh->local;
+ }
h->nfnlh = nfnlh;
- h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE,
- NFQNL_MSG_MAX, 0);
- if (!h->nfnlssh) {
+ /* Replace nfnl_subsys_open() with code adapted from libnfnetlink */
+ h->nfnlssh = &h->nfnlh->subsys[NFNL_SUBSYS_QUEUE];
+ if (h->nfnlssh->cb) {
+ errno = EBUSY;
+ goto out_free;
+ }
+ h->nfnlssh->cb = calloc(NFQNL_MSG_MAX, sizeof(*(h->nfnlssh->cb)));
+ if (!h->nfnlssh->cb) {
/* FIXME: nfq_errno */
goto out_free;
}
+ h->nfnlssh->nfnlh = h->nfnlh;
+ h->nfnlssh->cb_count = NFQNL_MSG_MAX;
+ h->nfnlssh->subsys_id = NFNL_SUBSYS_QUEUE;
+
+ /* Replacement code for recalc_rebind_subscriptions() */
+ new_subscriptions = nfnlh->subscriptions;
+ for (i = 0; i < NFNL_MAX_SUBSYS; i++)
+ new_subscriptions |= nfnlh->subsys[i].subscriptions;
+ nfnlh->local.nl_groups = new_subscriptions;
+ err = bind(nfnlh->fd, (struct sockaddr *)&nfnlh->local,
+ sizeof(nfnlh->local));
+ if (err == -1) {
+ free(h->nfnlssh->cb);
+ h->nfnlssh->cb = NULL;
+ goto out_free;
+ }
+ h->nfnlssh->subscriptions = new_subscriptions;
pkt_cb.data = h;
- err = nfnl_callback_register(h->nfnlssh, NFQNL_MSG_PACKET, &pkt_cb);
- if (err < 0) {
- nfq_errno = err;
- goto out_close;
- }
+ /* Replacement code for nfnl_callback_register()
+ * The only error return from nfnl_callback_register() is not possible
+ * here: NFQNL_MSG_PACKET (= 0) will be less than h->nfnlssh->cb_count
+ * (set to NFQNL_MSG_MAX (= 4) a few lines back).
+ */
+ memcpy(&h->nfnlssh->cb[NFQNL_MSG_PACKET], &pkt_cb, sizeof(pkt_cb));
return h;
-out_close:
- nfnl_subsys_close(h->nfnlssh);
out_free:
- if (!qh)
+ if (!qh) {
+ if (h->nl)
+ free(h->nl);
free(h);
+ }
return NULL;
}
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 03/15] src: Convert nfq_close() to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 01/15] src: Convert nfq_open() to use libmnl Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 02/15] src: Convert nfq_open_nfnl() " Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 04/15] src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() " Duncan Roe
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
Use mnl_close() and clean up the NFNL_SUBSYS_QUEUE subsystem as
nfnl_close() would have done
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- Propogate return from mnl_socket_close()
- Don't free callbacks in the qh_list since nfq_close() didn't
(reported as a bug)
- Do a complete emulation of nfnl_close()
- Add explanatory comments
src/libnetfilter_queue.c | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index bfb6482..0483780 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -577,8 +577,30 @@ EXPORT_SYMBOL
int nfq_close(struct nfq_handle *h)
{
int ret;
+ int i;
+
+ ret = mnl_socket_close(h->nl);
+ h->nl = NULL; /* mnl_socket_close() always frees it */
+
+ /* Replacement code for nfnl_close().
+ * It seems unlikely that we need to go through all 16 subsystems
+ * instead of only subsys[NFNL_SUBSYS_QUEUE] which h->nfnlssh
+ * conveniently points to, but better safe than sorry.
+ */
+ for (i = 0; i < NFNL_MAX_SUBSYS; i++) {
+ h->nfnlh->subsys[i].subscriptions = 0;
+ h->nfnlh->subsys[i].cb_count = 0;
+ if (h->nfnlh->subsys[i].cb) {
+ free(h->nfnlh->subsys[i].cb);
+ h->nfnlh->subsys[i].cb = NULL;
+ }
+ }
+ if (ret == 0)
+ free(h->nfnlh);
- ret = nfnl_close(h->nfnlh);
+ /* nfnl_close() didn't free nfnlh if close() returned an error.
+ * Presumably that's why nfq_close() doesn't free h in that case.
+ */
if (ret == 0)
free(h);
return ret;
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 04/15] src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (2 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 03/15] src: Convert nfq_close() " Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 05/15] src: Convert nfq_set_queue_flags(), nfq_set_queue_maxlen() & nfq_set_mode() " Duncan Roe
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
Convert static function __build_send_cfg_msg() to use libmnl.
This by itself converts the 3 public functions.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- Rename nfq_query to __nfq_query so as not to pollute Posix namespace
- rebase to account for updated patches 1 - 3
src/libnetfilter_queue.c | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 0483780..b64f14a 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -230,27 +230,33 @@ static struct nfq_q_handle *find_qh(struct nfq_handle *h, uint16_t id)
return NULL;
}
+static int __nfq_query(struct nfq_handle *h, struct nlmsghdr *nlh, char *buf,
+ size_t bufsiz)
+{
+ int ret;
+
+ ret = mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len);
+ if (ret != -1)
+ ret = mnl_socket_recvfrom(h->nl, buf, bufsiz);
+ if (ret != -1)
+ ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(h->nl),
+ NULL, NULL);
+ return ret;
+}
+
/* build a NFQNL_MSG_CONFIG message */
static int
__build_send_cfg_msg(struct nfq_handle *h, uint8_t command,
uint16_t queuenum, uint16_t pf)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(struct nfqnl_msg_config_cmd))];
- struct nlmsghdr nmh;
- } u;
- struct nfqnl_msg_config_cmd cmd;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
- nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, AF_UNSPEC, queuenum,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, queuenum, NLM_F_ACK);
- cmd._pad = 0;
- cmd.command = command;
- cmd.pf = htons(pf);
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_CMD, &cmd, sizeof(cmd));
+ nfq_nlmsg_cfg_put_cmd(nlh, AF_UNSPEC, command);
- return nfnl_query(h->nfnlh, &u.nmh);
+ return __nfq_query(h, nlh, buf, sizeof(buf));
}
static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 05/15] src: Convert nfq_set_queue_flags(), nfq_set_queue_maxlen() & nfq_set_mode() to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (3 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 04/15] src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() " Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 06/15] src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload() and all the nfq_get_ functions " Duncan Roe
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
Use a buffer of MNL_SOCKET_BUFFER_SIZE; no union required.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- Rename nfq_query to __nfq_query so as not to pollute Posix namespace
- Also convert nfq_set_mode() here because of using the same strategy
- rebase to account for updated patches 1 - 3
src/libnetfilter_queue.c | 58 ++++++++++++++++------------------------
1 file changed, 23 insertions(+), 35 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index b64f14a..0ef3bd3 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -782,22 +782,21 @@ int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)
EXPORT_SYMBOL
int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
- struct nlmsghdr nmh;
- } u;
- struct nfqnl_msg_config_params params;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ int ret;
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, qh->id, NLM_F_ACK);
- params.copy_range = htonl(range);
- params.copy_mode = mode;
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_PARAMS, ¶ms,
- sizeof(params));
+ nfq_nlmsg_cfg_put_params(nlh, mode, range);
- return nfnl_query(qh->h->nfnlh, &u.nmh);
+ ret = mnl_socket_sendto(qh->h->nl, nlh, nlh->nlmsg_len);
+ if (ret != -1)
+ ret = mnl_socket_recvfrom(qh->h->nl, buf, sizeof(buf));
+ if (ret != -1)
+ ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(qh->h->nl),
+ NULL, NULL);
+ return ret;
}
/**
@@ -871,23 +870,18 @@ int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range)
EXPORT_SYMBOL
int nfq_set_queue_flags(struct nfq_q_handle *qh, uint32_t mask, uint32_t flags)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(mask)
- +NFA_LENGTH(sizeof(flags)))];
- struct nlmsghdr nmh;
- } u;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
mask = htonl(mask);
flags = htonl(flags);
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, qh->id, NLM_F_ACK);
- nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_FLAGS, flags);
- nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_MASK, mask);
+ mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, flags);
+ mnl_attr_put_u32(nlh, NFQA_CFG_MASK, mask);
- return nfnl_query(qh->h->nfnlh, &u.nmh);
+ return __nfq_query(qh->h, nlh, buf, sizeof(buf));
}
/**
@@ -904,20 +898,14 @@ int nfq_set_queue_flags(struct nfq_q_handle *qh, uint32_t mask, uint32_t flags)
EXPORT_SYMBOL
int nfq_set_queue_maxlen(struct nfq_q_handle *qh, uint32_t queuelen)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
- struct nlmsghdr nmh;
- } u;
- uint32_t queue_maxlen = htonl(queuelen);
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, qh->id, NLM_F_ACK);
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_QUEUE_MAXLEN, &queue_maxlen,
- sizeof(queue_maxlen));
+ mnl_attr_put_u32(nlh, NFQA_CFG_QUEUE_MAXLEN, htonl(queuelen));
- return nfnl_query(qh->h->nfnlh, &u.nmh);
+ return __nfq_query(qh->h, nlh, buf, sizeof(buf));
}
/**
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 06/15] src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload() and all the nfq_get_ functions to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (4 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 05/15] src: Convert nfq_set_queue_flags(), nfq_set_queue_maxlen() & nfq_set_mode() " Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 07/15] src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if there is no data Duncan Roe
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
The opaque struct nfq_data is now an array of struct nlattr instead of
struct nfattr.
Because of using mnl_attr_parse(), the first array element is for
attribute 0 instead of attribute 1 as previously. Because of this,
all the nfq_get_ functions have to be converted for this commit.
Functions now using libmnl exclusively: nfq_get_msg_packet_hdr(),
nfq_get_nfmark(), nfq_get_timestamp(), nfq_get_indev(),
nfq_get_physindev(), nfq_get_outdev(), nfq_get_physoutdev(),
nfqnl_msg_packet_hw(), nfq_get_uid() & nfq_get_gid().
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- Fix spelling error in commit message
- Fix checkpatch warning re space before __nfq_handle_msg declaration
- rebase to account for updated patches
doxygen/doxygen.cfg.in | 1 +
src/libnetfilter_queue.c | 124 ++++++++++++++++++++++++++++-----------
2 files changed, 92 insertions(+), 33 deletions(-)
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index 6dd7017..fcfc045 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -16,6 +16,7 @@ EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
nfnl_handle \
nfnl_subsys_handle \
mnl_socket \
+ nfnl_callback2 \
tcp_flag_word
EXAMPLE_PATTERNS =
INPUT_FILTER = "sed 's/EXPORT_SYMBOL//g'"
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 0ef3bd3..6500fec 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -32,6 +32,13 @@
#include <linux/netfilter/nfnetlink_queue.h>
#include <libmnl/libmnl.h>
+
+/* Use the real header since libnfnetlink is going away. */
+/* nfq_pkt_parse_attr_cb only knows attribates up to NFQA_SECCTX */
+/* so won't try to validate higher-numbered attrs but will store them. */
+/* mnl API programs will then be able to access them. */
+#include <linux/netfilter/nfnetlink.h>
+
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
@@ -144,7 +151,7 @@ struct nfnl_subsys_handle {
uint32_t subscriptions;
uint8_t subsys_id;
uint8_t cb_count;
- struct nfnl_callback *cb; /* array of callbacks */
+ struct nfnl_callback2 *cb; /* array of callbacks with struct nlattr* */
};
struct nfnl_handle {
@@ -166,6 +173,13 @@ struct mnl_socket {
struct sockaddr_nl addr;
};
+/* Amended callback prototype */
+struct nfnl_callback2 {
+ int (*call)(struct nlmsghdr *nlh, struct nlattr *nfa[], void *data);
+ void *data;
+ uint16_t attr_count;
+};
+
struct nfq_handle
{
struct nfnl_handle *nfnlh;
@@ -185,7 +199,7 @@ struct nfq_q_handle
};
struct nfq_data {
- struct nfattr **data;
+ struct nlattr **data;
};
EXPORT_SYMBOL int nfq_errno;
@@ -259,7 +273,7 @@ __build_send_cfg_msg(struct nfq_handle *h, uint8_t command,
return __nfq_query(h, nlh, buf, sizeof(buf));
}
-static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
+static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nlattr *nfa[],
void *data)
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
@@ -484,7 +498,7 @@ struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
static struct nfq_handle *__nfq_open_nfnl(struct nfnl_handle *nfnlh,
struct nfq_handle *qh)
{
- struct nfnl_callback pkt_cb = {
+ struct nfnl_callback2 pkt_cb = {
.call = __nfq_rcv_pkt,
.attr_count = NFQA_MAX,
};
@@ -650,6 +664,25 @@ int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf)
* @}
*/
+static int __nfq_handle_msg(const struct nlmsghdr *nlh, void *data)
+{
+ struct nfq_handle *h = data;
+ struct nfq_q_handle *qh;
+ struct nlattr *nfa[NFQA_MAX + 1] = {};
+ struct nfq_data nfad = {nfa};
+ struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+
+ if (nfq_nlmsg_parse(nlh, nfa) < 0)
+ return MNL_CB_ERROR;
+
+ /* Find our queue handler (to get CB fn) */
+ qh = find_qh(h, ntohs(nfmsg->res_id));
+ if (!qh)
+ return MNL_CB_ERROR;
+
+ return qh->cb(qh, nfmsg, &nfad, qh->data);
+}
+
/**
* \addtogroup Queue
* @{
@@ -761,7 +794,8 @@ int nfq_destroy_queue(struct nfq_q_handle *qh)
EXPORT_SYMBOL
int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)
{
- return nfnl_handle_packet(h->nfnlh, buf, len);
+ return mnl_cb_run(buf, len, 0, mnl_socket_get_portid(h->nl),
+ __nfq_handle_msg, h);
}
/**
@@ -930,7 +964,7 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
/* This must be declared here (and not inside the data
* handling block) because the iovec points to this. */
- struct nfattr data_attr;
+ struct nlattr data_attr;
memset(iov, 0, sizeof(iov));
@@ -951,15 +985,17 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
nvecs = 1;
if (data_len) {
- /* The typecast here is to cast away data's const-ness: */
- nfnl_build_nfa_iovec(&iov[1], &data_attr, NFQA_PAYLOAD,
- data_len, (unsigned char *) data);
+ /* Temporary cast until we get rid of nfnl_build_nfa_iovec() */
+ nfnl_build_nfa_iovec(&iov[1], (struct nfattr *)&data_attr,
+ //nfnl_build_nfa_iovec(&iov[1], &data_attr,
+ NFQA_PAYLOAD, data_len,
+ (unsigned char *) data);
nvecs += 2;
/* Add the length of the appended data to the message
* header. The size of the attribute is given in the
- * nfa_len field and is set in the nfnl_build_nfa_iovec()
+ * nla_len field and is set in the nfnl_build_nfa_iovec()
* function. */
- u.nmh.nlmsg_len += data_attr.nfa_len;
+ u.nmh.nlmsg_len += data_attr.nla_len;
}
return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0);
@@ -1123,8 +1159,10 @@ int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id,
EXPORT_SYMBOL
struct nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(struct nfq_data *nfad)
{
- return nfnl_get_pointer_to_data(nfad->data, NFQA_PACKET_HDR,
- struct nfqnl_msg_packet_hdr);
+ if (!nfad->data[NFQA_PACKET_HDR])
+ return NULL;
+
+ return mnl_attr_get_payload(nfad->data[NFQA_PACKET_HDR]);
}
/**
@@ -1136,6 +1174,10 @@ struct nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_nfmark(struct nfq_data *nfad)
{
+ if (!nfad->data[NFQA_MARK])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_MARK]));
return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, uint32_t));
}
@@ -1152,11 +1194,12 @@ EXPORT_SYMBOL
int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv)
{
struct nfqnl_msg_packet_timestamp *qpt;
- qpt = nfnl_get_pointer_to_data(nfad->data, NFQA_TIMESTAMP,
- struct nfqnl_msg_packet_timestamp);
- if (!qpt)
+
+ if (!nfad->data[NFQA_TIMESTAMP])
return -1;
+ qpt = mnl_attr_get_payload(nfad->data[NFQA_TIMESTAMP]);
+
tv->tv_sec = __be64_to_cpu(qpt->sec);
tv->tv_usec = __be64_to_cpu(qpt->usec);
@@ -1177,7 +1220,10 @@ int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv)
EXPORT_SYMBOL
uint32_t nfq_get_indev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_INDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_INDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_INDEV]));
}
/**
@@ -1191,7 +1237,10 @@ uint32_t nfq_get_indev(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_physindev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSINDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_PHYSINDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_PHYSINDEV]));
}
/**
@@ -1205,7 +1254,10 @@ uint32_t nfq_get_physindev(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_outdev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_OUTDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_OUTDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_OUTDEV]));
}
/**
@@ -1221,7 +1273,10 @@ uint32_t nfq_get_outdev(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_physoutdev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSOUTDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_PHYSOUTDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_PHYSOUTDEV]));
}
/**
@@ -1356,8 +1411,10 @@ int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle,
EXPORT_SYMBOL
struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad)
{
- return nfnl_get_pointer_to_data(nfad->data, NFQA_HWADDR,
- struct nfqnl_msg_packet_hw);
+ if (!nfad->data[NFQA_HWADDR])
+ return NULL;
+
+ return mnl_attr_get_payload(nfad->data[NFQA_HWADDR]);
}
/**
@@ -1405,10 +1462,10 @@ uint32_t nfq_get_skbinfo(struct nfq_data *nfad)
EXPORT_SYMBOL
int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid)
{
- if (!nfnl_attr_present(nfad->data, NFQA_UID))
+ if (!nfad->data[NFQA_UID])
return 0;
- *uid = ntohl(nfnl_get_data(nfad->data, NFQA_UID, uint32_t));
+ *uid = ntohl(mnl_attr_get_u32(nfad->data[NFQA_UID]));
return 1;
}
@@ -1426,10 +1483,10 @@ int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid)
EXPORT_SYMBOL
int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid)
{
- if (!nfnl_attr_present(nfad->data, NFQA_GID))
+ if (!nfad->data[NFQA_GID])
return 0;
- *gid = ntohl(nfnl_get_data(nfad->data, NFQA_GID, uint32_t));
+ *gid = ntohl(mnl_attr_get_u32(nfad->data[NFQA_GID]));
return 1;
}
@@ -1447,14 +1504,13 @@ int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid)
EXPORT_SYMBOL
int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata)
{
- if (!nfnl_attr_present(nfad->data, NFQA_SECCTX))
+ if (!nfad->data[NFQA_SECCTX])
return -1;
- *secdata = (unsigned char *)nfnl_get_pointer_to_data(nfad->data,
- NFQA_SECCTX, char);
+ *secdata = mnl_attr_get_payload(nfad->data[NFQA_SECCTX]);
if (*secdata)
- return NFA_PAYLOAD(nfad->data[NFQA_SECCTX-1]);
+ return mnl_attr_get_payload_len(nfad->data[NFQA_SECCTX]);
return 0;
}
@@ -1473,10 +1529,12 @@ int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata)
EXPORT_SYMBOL
int nfq_get_payload(struct nfq_data *nfad, unsigned char **data)
{
- *data = (unsigned char *)
- nfnl_get_pointer_to_data(nfad->data, NFQA_PAYLOAD, char);
+ if (!nfad->data[NFQA_PAYLOAD])
+ return -1;
+
+ *data = mnl_attr_get_payload(nfad->data[NFQA_PAYLOAD]);
if (*data)
- return NFA_PAYLOAD(nfad->data[NFQA_PAYLOAD-1]);
+ return mnl_attr_get_payload_len(nfad->data[NFQA_PAYLOAD]);
return -1;
}
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 07/15] src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if there is no data
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (5 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 06/15] src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload() and all the nfq_get_ functions " Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 08/15] src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue Duncan Roe
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
static __set_verdict() uses mnl-API calls in enough places that the path
for no (mangled) data doesn't use any nfnl-API functions.
With no data, __set_verdict() uses sendto() (faster than sendmsg()).
nfq_set_verdict2() must not use htonl() on the packet mark.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
v2:
- rebase to account for updated patches 1 - 3
- fix checkpatch warning re block comment termination
src/libnetfilter_queue.c | 36 +++++++++++++++++-------------------
1 file changed, 17 insertions(+), 19 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 6500fec..3fa8d2d 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -38,8 +38,8 @@
/* so won't try to validate higher-numbered attrs but will store them. */
/* mnl API programs will then be able to access them. */
#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_compat.h>
-#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
@@ -951,13 +951,8 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
uint32_t data_len, const unsigned char *data,
enum nfqnl_msg_types type)
{
- struct nfqnl_msg_verdict_hdr vh;
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(mark))
- +NFA_LENGTH(sizeof(vh))];
- struct nlmsghdr nmh;
- } u;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
struct iovec iov[3];
int nvecs;
@@ -968,20 +963,23 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
memset(iov, 0, sizeof(iov));
- vh.verdict = htonl(verdict);
- vh.id = htonl(id);
-
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- type, NLM_F_REQUEST);
+ nlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qh->id);
/* add verdict header */
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_VERDICT_HDR, &vh, sizeof(vh));
+ nfq_nlmsg_verdict_put(nlh, id, verdict);
if (set_mark)
- nfnl_addattr32(&u.nmh, sizeof(u), NFQA_MARK, mark);
+ nfq_nlmsg_verdict_put_mark(nlh, mark);
+
+ /* Efficiency gain: when there is only 1 iov,
+ * sendto() is faster than sendmsg() because the kernel only has
+ * 1 userspace address to validate instead of 2.
+ */
+ if (!data_len)
+ return mnl_socket_sendto(qh->h->nl, nlh, nlh->nlmsg_len);
- iov[0].iov_base = &u.nmh;
- iov[0].iov_len = NLMSG_TAIL(&u.nmh) - (void *)&u.nmh;
+ iov[0].iov_base = nlh;
+ iov[0].iov_len = NLMSG_TAIL(nlh) - (void *)nlh;
nvecs = 1;
if (data_len) {
@@ -995,7 +993,7 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
* header. The size of the attribute is given in the
* nla_len field and is set in the nfnl_build_nfa_iovec()
* function. */
- u.nmh.nlmsg_len += data_attr.nla_len;
+ nlh->nlmsg_len += data_attr.nla_len;
}
return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0);
@@ -1052,7 +1050,7 @@ int nfq_set_verdict2(struct nfq_q_handle *qh, uint32_t id,
uint32_t verdict, uint32_t mark,
uint32_t data_len, const unsigned char *buf)
{
- return __set_verdict(qh, id, verdict, htonl(mark), 1, data_len,
+ return __set_verdict(qh, id, verdict, mark, 1, data_len,
buf, NFQNL_MSG_VERDICT);
}
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 08/15] src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (6 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 07/15] src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if there is no data Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 09/15] src: Convert nfq_fd() to use libmnl Duncan Roe
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
nfnl_rcvbufsiz() is the first bullet point in the Performance section
of the libnetfilter_queue HTML main page.
We have to assume people have used it,
so supply a version that uses libmnl.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
v2: rebase to account for updated patches
.../libnetfilter_queue/libnetfilter_queue.h | 2 ++
src/libnetfilter_queue.c | 36 +++++++++++++++++++
2 files changed, 38 insertions(+)
diff --git a/include/libnetfilter_queue/libnetfilter_queue.h b/include/libnetfilter_queue/libnetfilter_queue.h
index f7e68d8..9327f8c 100644
--- a/include/libnetfilter_queue/libnetfilter_queue.h
+++ b/include/libnetfilter_queue/libnetfilter_queue.h
@@ -35,6 +35,8 @@ typedef int nfq_callback(struct nfq_q_handle *gh, struct nfgenmsg *nfmsg,
struct nfq_data *nfad, void *data);
+extern unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h,
+ unsigned int size);
extern struct nfq_handle *nfq_open(void);
extern struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh);
extern int nfq_close(struct nfq_handle *h);
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 3fa8d2d..f26b65f 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -585,6 +585,42 @@ out_free:
* @{
*/
+/**
+ * nfnl_rcvbufsiz - set the socket buffer size
+ * \param h nfnetlink connection handle obtained via call to \b nfq_nfnlh()
+ * \param size size of the buffer we want to set
+ *
+ * This nfnl-API function sets the new size of the socket buffer.
+ * Use this setting
+ * to increase the socket buffer size if your system is reporting ENOBUFS
+ * errors.
+ *
+ * \return new size of kernel socket buffer
+ */
+
+EXPORT_SYMBOL
+unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, unsigned int size)
+{
+ int status;
+ socklen_t socklen = sizeof(size);
+ unsigned int read_size = 0;
+
+ /* first we try the FORCE option, which is introduced in kernel
+ * 2.6.14 to give "root" the ability to override the system wide
+ * maximum
+ */
+ status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, socklen);
+ if (status < 0) {
+ /* if this didn't work, we try at least to get the system
+ * wide maximum (or whatever the user requested)
+ */
+ setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &size, socklen);
+ }
+ getsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &read_size, &socklen);
+
+ return read_size;
+}
+
/**
* nfq_close - close a nfqueue handler
* \param h Netfilter queue connection handle obtained via call to nfq_open()
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 09/15] src: Convert nfq_fd() to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (7 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 08/15] src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 10/15] src: Convert remaining nfq_* functions " Duncan Roe
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
struct nfq_handle has a struct mnl_socket * now, use that.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
v2: rebase to account for updated patches
src/libnetfilter_queue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index f26b65f..8a11f41 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -384,7 +384,7 @@ struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h)
EXPORT_SYMBOL
int nfq_fd(struct nfq_handle *h)
{
- return nfnl_fd(nfq_nfnlh(h));
+ return mnl_socket_get_fd(h->nl);
}
/**
* @}
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 10/15] src: Convert remaining nfq_* functions to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (8 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 09/15] src: Convert nfq_fd() to use libmnl Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 11/15] src: Copy nlif-related files from libnfnetlink Duncan Roe
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
Converted: nfq_set_verdict2(), nfq_set_verdict_batch2(),
nfq_set_verdict_mark(), nfq_get_nfmark() [again] &
nfq_get_skbinfo()
We only use 2 iovecs instead of 3
by tacking the data attribute onto the end of the first iovec buffer.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- Move nfq_set_mode() conversion to patch 5
- Rebase to account for updated patches
src/libnetfilter_queue.c | 67 +++++++++++++++++++++-------------------
1 file changed, 35 insertions(+), 32 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 8a11f41..ecdd144 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -989,17 +989,9 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
+ static struct sockaddr_nl snl = {.nl_family = AF_NETLINK };
- struct iovec iov[3];
- int nvecs;
-
- /* This must be declared here (and not inside the data
- * handling block) because the iovec points to this. */
- struct nlattr data_attr;
-
- memset(iov, 0, sizeof(iov));
-
- nlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qh->id);
+ nlh = nfq_nlmsg_put(buf, type, qh->id);
/* add verdict header */
nfq_nlmsg_verdict_put(nlh, id, verdict);
@@ -1013,26 +1005,38 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
*/
if (!data_len)
return mnl_socket_sendto(qh->h->nl, nlh, nlh->nlmsg_len);
+ {
+ struct iovec iov[2];
+ struct nlattr *data_attr = mnl_nlmsg_get_payload_tail(nlh);
+ const struct msghdr msg = {
+ .msg_name = &snl,
+ .msg_namelen = sizeof(snl),
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ mnl_attr_put(nlh, NFQA_PAYLOAD, 0, NULL);
+
+ iov[0].iov_base = nlh;
+ iov[0].iov_len = nlh->nlmsg_len;
+ /* The typecast here is to cast away data's const-ness: */
+ iov[1].iov_base = (unsigned char *)data;
+ iov[1].iov_len = data_len;
- iov[0].iov_base = nlh;
- iov[0].iov_len = NLMSG_TAIL(nlh) - (void *)nlh;
- nvecs = 1;
-
- if (data_len) {
- /* Temporary cast until we get rid of nfnl_build_nfa_iovec() */
- nfnl_build_nfa_iovec(&iov[1], (struct nfattr *)&data_attr,
- //nfnl_build_nfa_iovec(&iov[1], &data_attr,
- NFQA_PAYLOAD, data_len,
- (unsigned char *) data);
- nvecs += 2;
/* Add the length of the appended data to the message
- * header. The size of the attribute is given in the
- * nla_len field and is set in the nfnl_build_nfa_iovec()
- * function. */
- nlh->nlmsg_len += data_attr.nla_len;
- }
+ * header and attribute length.
+ * No padding is needed: this is the end of the message.
+ */
+
+ nlh->nlmsg_len += data_len;
- return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0);
+ data_attr->nla_len += data_len;
+
+ return sendmsg(qh->h->nfnlh->fd, &msg, 0);
+ }
}
/**
@@ -1121,7 +1125,7 @@ EXPORT_SYMBOL
int nfq_set_verdict_batch2(struct nfq_q_handle *qh, uint32_t id,
uint32_t verdict, uint32_t mark)
{
- return __set_verdict(qh, id, verdict, htonl(mark), 1, 0,
+ return __set_verdict(qh, id, verdict, mark, 1, 0,
NULL, NFQNL_MSG_VERDICT_BATCH);
}
@@ -1144,7 +1148,7 @@ int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id,
uint32_t verdict, uint32_t mark,
uint32_t data_len, const unsigned char *buf)
{
- return __set_verdict(qh, id, verdict, mark, 1, data_len, buf,
+ return __set_verdict(qh, id, verdict, ntohl(mark), 1, data_len, buf,
NFQNL_MSG_VERDICT);
}
@@ -1212,7 +1216,6 @@ uint32_t nfq_get_nfmark(struct nfq_data *nfad)
return 0;
return ntohl(mnl_attr_get_u32(nfad->data[NFQA_MARK]));
- return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, uint32_t));
}
/**
@@ -1476,10 +1479,10 @@ struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_skbinfo(struct nfq_data *nfad)
{
- if (!nfnl_attr_present(nfad->data, NFQA_SKB_INFO))
+ if (!nfad->data[NFQA_SKB_INFO])
return 0;
- return ntohl(nfnl_get_data(nfad->data, NFQA_SKB_INFO, uint32_t));
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_SKB_INFO]));
}
/**
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 11/15] src: Copy nlif-related files from libnfnetlink
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (9 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 10/15] src: Convert remaining nfq_* functions " Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 12/15] doc: Add iftable.c to the doxygen system Duncan Roe
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
Introduce include/libnetfilter_queue/linux_list.h and src/iftable.c.
These are not exact copies: all tractable checkpatch errors are fixed.
Also complete iftable.c kerneldoc to doxygen translation.
This commit doesn't actually do anything with the new files.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- This was originally patch 12 of 32
- Update commit message
- Don't copy src/rtnl.c since it's not kept
- Fix checkpatch errors on the fly.
- Finish kerneldoc xlation on the fly (was patch 16 of 32).
include/libnetfilter_queue/linux_list.h | 730 ++++++++++++++++++++++++
src/iftable.c | 355 ++++++++++++
2 files changed, 1085 insertions(+)
create mode 100644 include/libnetfilter_queue/linux_list.h
create mode 100644 src/iftable.c
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
new file mode 100644
index 0000000..68637c3
--- /dev/null
+++ b/include/libnetfilter_queue/linux_list.h
@@ -0,0 +1,730 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); })
+
+/*
+ * Check at compile time that something is of a particular type.
+ * Always evaluates to 1 so you may use it easily in comparisons.
+ */
+#define typecheck(type, x) \
+({ type __dummy; \
+ typeof(x) __dummy2; \
+ (void)(&__dummy == &__dummy2); \
+ 1; \
+})
+
+#define prefetch(x) ((void)0)
+
+/* empty define to make this work in userspace -HW */
+#ifndef smp_wmb
+#define smp_wmb() /* Comment to placate checkpatch */
+#endif
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add_rcu(struct list_head *new,
+ struct list_head *prev, struct list_head *next)
+{
+ new->next = next;
+ new->prev = prev;
+ smp_wmb(); /* Comment to placate checkpatch */
+ next->prev = new;
+ prev->next = new;
+}
+
+/**
+ * list_add_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
+{
+ __list_add_rcu(new, head, head->next);
+}
+
+/**
+ * list_add_tail_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_tail_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_tail_rcu(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add_rcu(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head *next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_rcu - deletes entry from list without re-initialization
+ * @entry: the element to delete from the list.
+ *
+ * Note: list_empty on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_del_rcu()
+ * or list_add_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ *
+ * Note that the caller is not permitted to immediately free
+ * the newly deleted entry. Instead, either synchronize_kernel()
+ * or call_rcu() must be used to defer freeing until an RCU
+ * grace period has elapsed.
+ */
+static inline void list_del_rcu(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ prefetch(pos->member.prev); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member), \
+ prefetch(pos->member.prev))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ * list_for_each_entry_continue
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - iterate over list of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_rcu - iterate over an rcu-protected list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_rcu(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0; }), prefetch(pos->next))
+
+#define __list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0; }))
+
+/**
+ * list_for_each_safe_rcu - iterate over an rcu-protected list safe
+ * against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_safe_rcu(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, ({ smp_read_barrier_depends(); 0; }), n = pos->next)
+
+/**
+ * list_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_entry_rcu(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ ({ smp_read_barrier_depends(); 0; }), \
+ prefetch(pos->member.next))
+
+
+/**
+ * list_for_each_continue_rcu - iterate over an rcu-protected list
+ * continuing after existing point.
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_continue_rcu(pos, head) \
+ for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
+ (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0; }), prefetch((pos)->next))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_del_rcu - deletes entry from hash list without re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: list_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry().
+ */
+static inline void hlist_del_rcu(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (n->pprev) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+#define hlist_del_rcu_init hlist_del_init
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+
+/**
+ * hlist_add_head_rcu - adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry(), but only if smp_read_barrier_depends()
+ * is used to prevent memory-consistency problems on Alpha CPUs.
+ * Regardless of the type of CPU, the list-traversal primitive
+ * must be guarded by rcu_read_lock().
+ *
+ * OK, so why don't we have an hlist_for_each_entry_rcu()???
+ */
+static inline void hlist_add_head_rcu(struct hlist_node *n,
+ struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+
+ n->next = first;
+ n->pprev = &h->first;
+ smp_wmb(); /* Comment to placate checkpatch */
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if (next->next)
+ next->next->pprev = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr, type, member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as hlist_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0; }))
+
+#endif
diff --git a/src/iftable.c b/src/iftable.c
new file mode 100644
index 0000000..4673001
--- /dev/null
+++ b/src/iftable.c
@@ -0,0 +1,355 @@
+/* iftable - table of network interfaces
+ *
+ * (C) 2004 by Astaro AG, written by Harald Welte <hwelte@astaro.com>
+ * (C) 2008 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2024 by Duncan Roe <duncan_roe@optusnet.com.au>
+ *
+ * This software is Free Software and licensed under GNU GPLv2+.
+ */
+
+/* IFINDEX handling */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <linux/netdevice.h>
+
+#include <libnfnetlink/libnfnetlink.h>
+#include "rtnl.h"
+#include "linux_list.h"
+
+/**
+ * \defgroup iftable Functions to manage a table of network interfaces
+ * These functions maintain a database of the name and flags of each
+ * network interface.
+ * @{
+ */
+
+struct ifindex_node {
+ struct list_head head;
+
+ uint32_t index;
+ uint32_t type;
+ uint32_t alen;
+ uint32_t flags;
+ char addr[8];
+ char name[16];
+};
+
+struct nlif_handle {
+ struct list_head ifindex_hash[16];
+ struct rtnl_handle *rtnl_handle;
+ struct rtnl_handler ifadd_handler;
+ struct rtnl_handler ifdel_handler;
+};
+
+/* iftable_add - Add/Update an entry to/in the interface table
+ * \param n: netlink message header of a RTM_NEWLINK message
+ * \param arg: not used
+ *
+ * This function adds/updates an entry in the intrface table.
+ * Returns -1 on error, 1 on success.
+ */
+static int iftable_add(struct nlmsghdr *n, void *arg)
+{
+ unsigned int hash, found = 0;
+ struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
+ struct ifindex_node *this;
+ struct rtattr *cb[IFLA_MAX+1];
+ struct nlif_handle *h = arg;
+
+ if (n->nlmsg_type != RTM_NEWLINK)
+ return -1;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
+ return -1;
+
+ rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
+
+ if (!cb[IFLA_IFNAME])
+ return -1;
+
+ hash = ifi_msg->ifi_index & 0xF;
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == ifi_msg->ifi_index) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ this = malloc(sizeof(*this));
+ if (!this)
+ return -1;
+
+ this->index = ifi_msg->ifi_index;
+ }
+
+ this->type = ifi_msg->ifi_type;
+ this->flags = ifi_msg->ifi_flags;
+ if (cb[IFLA_ADDRESS]) {
+ unsigned int alen;
+
+ this->alen = alen = RTA_PAYLOAD(cb[IFLA_ADDRESS]);
+ if (alen > sizeof(this->addr))
+ alen = sizeof(this->addr);
+ memcpy(this->addr, RTA_DATA(cb[IFLA_ADDRESS]), alen);
+ } else {
+ this->alen = 0;
+ memset(this->addr, 0, sizeof(this->addr));
+ }
+ strcpy(this->name, RTA_DATA(cb[IFLA_IFNAME]));
+
+ if (!found)
+ list_add(&this->head, &h->ifindex_hash[hash]);
+
+ return 1;
+}
+
+/* iftable_del - Delete an entry from the interface table
+ * \param n: netlink message header of a RTM_DELLINK nlmsg
+ * \param arg: not used
+ *
+ * Delete an entry from the interface table.
+ * Returns -1 on error, 0 if no matching entry was found or 1 on success.
+ */
+static int iftable_del(struct nlmsghdr *n, void *arg)
+{
+ struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
+ struct rtattr *cb[IFLA_MAX+1];
+ struct nlif_handle *h = arg;
+ struct ifindex_node *this, *tmp;
+ unsigned int hash;
+
+ if (n->nlmsg_type != RTM_DELLINK)
+ return -1;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
+ return -1;
+
+ rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
+
+ hash = ifi_msg->ifi_index & 0xF;
+ list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash], head) {
+ if (this->index == ifi_msg->ifi_index) {
+ list_del(&this->head);
+ free(this);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * nlif_index2name - get the name for an ifindex
+ *
+ * \param h pointer to nlif_handle created by nlif_open()
+ * \param index ifindex to be resolved
+ * \param name interface name, pass a buffer of IFNAMSIZ size
+ * \return -1 on error, 1 on success
+ */
+int nlif_index2name(struct nlif_handle *h,
+ unsigned int index,
+ char *name)
+{
+ unsigned int hash;
+ struct ifindex_node *this;
+
+ assert(h != NULL);
+ assert(name != NULL);
+
+ if (index == 0) {
+ strcpy(name, "*");
+ return 1;
+ }
+
+ hash = index & 0xF;
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == index) {
+ strcpy(name, this->name);
+ return 1;
+ }
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+/**
+ * nlif_get_ifflags - get the flags for an ifindex
+ *
+ * \param h pointer to nlif_handle created by nlif_open()
+ * \param index ifindex to be resolved
+ * \param flags pointer to variable used to store the interface flags
+ * \return -1 on error, 1 on success
+ */
+int nlif_get_ifflags(const struct nlif_handle *h,
+ unsigned int index,
+ unsigned int *flags)
+{
+ unsigned int hash;
+ struct ifindex_node *this;
+
+ assert(h != NULL);
+ assert(flags != NULL);
+
+ if (index == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ hash = index & 0xF;
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == index) {
+ *flags = this->flags;
+ return 1;
+ }
+ }
+ errno = ENOENT;
+ return -1;
+}
+
+/**
+ * nlif_open - initialize interface table
+ *
+ * Initialize rtnl interface and interface table
+ * Call this before any nlif_* function
+ *
+ * \return file descriptor to netlink socket
+ */
+struct nlif_handle *nlif_open(void)
+{
+ int i;
+ struct nlif_handle *h;
+
+ h = calloc(1, sizeof(struct nlif_handle));
+ if (h == NULL)
+ goto err;
+
+ for (i = 0; i < 16; i++)
+ INIT_LIST_HEAD(&h->ifindex_hash[i]);
+
+ h->ifadd_handler.nlmsg_type = RTM_NEWLINK;
+ h->ifadd_handler.handlefn = iftable_add;
+ h->ifadd_handler.arg = h;
+ h->ifdel_handler.nlmsg_type = RTM_DELLINK;
+ h->ifdel_handler.handlefn = iftable_del;
+ h->ifdel_handler.arg = h;
+
+ h->rtnl_handle = rtnl_open();
+ if (h->rtnl_handle == NULL)
+ goto err;
+
+ if (rtnl_handler_register(h->rtnl_handle, &h->ifadd_handler) < 0)
+ goto err_close;
+
+ if (rtnl_handler_register(h->rtnl_handle, &h->ifdel_handler) < 0)
+ goto err_unregister;
+
+ return h;
+
+err_unregister:
+ rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
+err_close:
+ rtnl_close(h->rtnl_handle);
+ free(h);
+err:
+ return NULL;
+}
+
+/**
+ * nlif_close - free all resources associated with the interface table
+ *
+ * \param h pointer to nlif_handle created by nlif_open()
+ */
+void nlif_close(struct nlif_handle *h)
+{
+ int i;
+ struct ifindex_node *this, *tmp;
+
+ assert(h != NULL);
+
+ rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
+ rtnl_handler_unregister(h->rtnl_handle, &h->ifdel_handler);
+ rtnl_close(h->rtnl_handle);
+
+ for (i = 0; i < 16; i++) {
+ list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) {
+ list_del(&this->head);
+ free(this);
+ }
+ }
+
+ free(h);
+ h = NULL; /* bugtrap */
+}
+
+/**
+ * nlif_catch - receive message from netlink and update interface table
+ *
+ * FIXME - elaborate a bit
+ *
+ * \param h pointer to nlif_handle created by nlif_open()
+ * \return 0 if OK
+ */
+int nlif_catch(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (h->rtnl_handle)
+ return rtnl_receive(h->rtnl_handle);
+
+ return -1;
+}
+
+static int nlif_catch_multi(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (h->rtnl_handle)
+ return rtnl_receive_multi(h->rtnl_handle);
+
+ return -1;
+}
+
+/**
+ * nlif_query - request a dump of interfaces available in the system
+ * \param h: pointer to a valid nlif_handler
+ */
+int nlif_query(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (rtnl_dump_type(h->rtnl_handle, RTM_GETLINK) < 0)
+ return -1;
+
+ return nlif_catch_multi(h);
+}
+
+/**
+ * nlif_fd - get file descriptor for the netlink socket
+ *
+ * \param h pointer to nlif_handle created by nlif_open()
+ * \return The fd or -1 if there's an error
+ */
+int nlif_fd(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (h->rtnl_handle)
+ return h->rtnl_handle->rtnl_fd;
+
+ return -1;
+}
+
+/**
+ * @}
+ */
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 12/15] doc: Add iftable.c to the doxygen system
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (10 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 11/15] src: Copy nlif-related files from libnfnetlink Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 13/15] src: Convert all nlif_* functions to use libmnl Duncan Roe
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
iftable.c has a usage description (moved from libnetfilter_queue.c),
but is not yet converted to use libmnl.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
v2: Created from patches 14/32 & 16/32
doxygen/Makefile.am | 1 +
doxygen/doxygen.cfg.in | 2 ++
src/iftable.c | 49 ++++++++++++++++++++++++++++++++++++++++
src/libnetfilter_queue.c | 38 ++++---------------------------
4 files changed, 56 insertions(+), 34 deletions(-)
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index 68be963..a6cd83a 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -2,6 +2,7 @@ if HAVE_DOXYGEN
doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c\
$(top_srcdir)/src/nlmsg.c\
+ $(top_srcdir)/src/iftable.c\
$(top_srcdir)/src/extra/checksum.c\
$(top_srcdir)/src/extra/ipv4.c\
$(top_srcdir)/src/extra/pktbuff.c\
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index fcfc045..bf6cba8 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -16,6 +16,8 @@ EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
nfnl_handle \
nfnl_subsys_handle \
mnl_socket \
+ ifindex_node \
+ nlif_handle \
nfnl_callback2 \
tcp_flag_word
EXAMPLE_PATTERNS =
diff --git a/src/iftable.c b/src/iftable.c
index 4673001..9884a52 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -29,6 +29,55 @@
* \defgroup iftable Functions to manage a table of network interfaces
* These functions maintain a database of the name and flags of each
* network interface.
+ *
+ * Programs access an nlif database through an opaque __struct nlif_handle__
+ * interface resolving handle. Call nlif_open() to get a handle:
+ * \verbatim
+ h = nlif_open();
+ if (h == NULL) {
+ perror("nlif_open");
+ exit(EXIT_FAILURE);
+ }
+\endverbatim
+ * Once the handler is open, you need to fetch the interface table at a
+ * whole via a call to nlif_query.
+ * \verbatim
+ nlif_query(h);
+\endverbatim
+ * libnetfilter_queue is able to update the interface mapping
+ * when a new interface appears.
+ * To do so, you need to call nlif_catch() on the handler after each
+ * interface related event. The simplest way to get and treat event is to run
+ * a **select()** or **poll()** against the nlif and netilter_queue
+ * file descriptors.
+ * E.g. use nlif_fd() to get the nlif file descriptor, then give this fd to
+ * **poll()** as in this code snippet (error-checking removed):
+ * \verbatim
+ if_fd = nlif_fd(h);
+ qfd = mnl_socket_get_fd(nl); // For mnl API or ...
+ qfd = nfq_fd(qh); // For nfnl API
+ . . .
+ fds[0].fd = ifd;
+ fds[0].events = POLLIN;
+ fds[1].fd = qfd;
+ fds[1].events = POLLIN;
+ for(;;)
+ {
+ poll((struct pollfd *)&fds, 2, -1);
+ if (fds[0].revents & POLLIN)
+ nlif_catch(h);
+\endverbatim
+ * Don't forget to close the handler when you don't need the feature anymore:
+ * \verbatim
+ nlif_close(h);
+\endverbatim
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
* @{
*/
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index ecdd144..970aea2 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -1324,34 +1324,7 @@ uint32_t nfq_get_physoutdev(struct nfq_data *nfad)
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
* \return -1 in case of error, >0 if it succeed.
- *
- * To use a nlif_handle, You need first to call nlif_open() and to open
- * an handler. Don't forget to store the result as it will be used
- * during all your program life:
- * \verbatim
- h = nlif_open();
- if (h == NULL) {
- perror("nlif_open");
- exit(EXIT_FAILURE);
- }
-\endverbatim
- * Once the handler is open, you need to fetch the interface table at a
- * whole via a call to nlif_query.
- * \verbatim
- nlif_query(h);
-\endverbatim
- * libnfnetlink is able to update the interface mapping when a new interface
- * appears. To do so, you need to call nlif_catch() on the handler after each
- * interface related event. The simplest way to get and treat event is to run
- * a select() or poll() against the nlif file descriptor. To get this file
- * descriptor, you need to use nlif_fd:
- * \verbatim
- if_fd = nlif_fd(h);
-\endverbatim
- * Don't forget to close the handler when you don't need the feature anymore:
- * \verbatim
- nlif_close(h);
-\endverbatim
+ * \sa __nlif_open__(3)
*
*/
EXPORT_SYMBOL
@@ -1370,9 +1343,8 @@ int nfq_get_indev_name(struct nlif_handle *nlif_handle,
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
*
- * See nfq_get_indev_name() documentation for nlif_handle usage.
- *
* \return -1 in case of error, > 0 if it succeed.
+ * \sa __nlif_open__(3)
*/
EXPORT_SYMBOL
int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
@@ -1390,9 +1362,8 @@ int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
*
- * See nfq_get_indev_name() documentation for nlif_handle usage.
- *
* \return -1 in case of error, > 0 if it succeed.
+ * \sa __nlif_open__(3)
*/
EXPORT_SYMBOL
int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
@@ -1410,9 +1381,8 @@ int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
*
- * See nfq_get_indev_name() documentation for nlif_handle usage.
- *
* \return -1 in case of error, > 0 if it succeed.
+ * \sa __nlif_open__(3)
*/
EXPORT_SYMBOL
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 13/15] src: Convert all nlif_* functions to use libmnl
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (11 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 12/15] doc: Add iftable.c to the doxygen system Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 14/15] include: Use libmnl.h instead of libnfnetlink.h Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 15/15] build: Remove libnfnetlink from the build Duncan Roe
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
In iftable.c, replace calls to functions in rtnetlink.c with inline code
(converted to use libmnl instead of libnfnetlink).
It is essential to offer *all* functions originally provided by
libnfnetlink so that a built program will either take its nlif_*()
functions from libnetfilter_queue or libnfnetlink (depending on the
build-time order in LIBS).
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
v2: created from patches 19/32 & (some of) 32/32
src/Makefile.am | 1 +
src/iftable.c | 311 ++++++++++++++++++++++--------------------------
2 files changed, 141 insertions(+), 171 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 079853e..a6813e8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,7 @@ libnetfilter_queue_la_LDFLAGS = -Wc,-nostartfiles \
-version-info $(LIBVERSION)
libnetfilter_queue_la_SOURCES = libnetfilter_queue.c \
nlmsg.c \
+ iftable.c \
extra/checksum.c \
extra/icmp.c \
extra/ipv6.c \
diff --git a/src/iftable.c b/src/iftable.c
index 9884a52..54364b3 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -11,19 +11,29 @@
#include <unistd.h>
#include <stdlib.h>
+#include <time.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
-#include <assert.h>
#include <linux/netdevice.h>
-#include <libnfnetlink/libnfnetlink.h>
-#include "rtnl.h"
-#include "linux_list.h"
+#include <libmnl/libmnl.h>
+#include <linux/rtnetlink.h>
+#include <libnetfilter_queue/linux_list.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+
+#include "internal.h"
+
+#define NUM_NLIF_BITS 4
+#define NUM_NLIF_ENTRIES (1 << NUM_NLIF_BITS)
+#define NLIF_ENTRY_MASK (NUM_NLIF_ENTRIES - 1)
+
+static int data_cb(const struct nlmsghdr *nlh, void *data);
/**
* \defgroup iftable Functions to manage a table of network interfaces
@@ -86,117 +96,15 @@ struct ifindex_node {
uint32_t index;
uint32_t type;
- uint32_t alen;
uint32_t flags;
- char addr[8];
- char name[16];
+ char name[IFNAMSIZ];
};
struct nlif_handle {
- struct list_head ifindex_hash[16];
- struct rtnl_handle *rtnl_handle;
- struct rtnl_handler ifadd_handler;
- struct rtnl_handler ifdel_handler;
+ struct list_head ifindex_hash[NUM_NLIF_ENTRIES];
+ struct mnl_socket *nl;
};
-/* iftable_add - Add/Update an entry to/in the interface table
- * \param n: netlink message header of a RTM_NEWLINK message
- * \param arg: not used
- *
- * This function adds/updates an entry in the intrface table.
- * Returns -1 on error, 1 on success.
- */
-static int iftable_add(struct nlmsghdr *n, void *arg)
-{
- unsigned int hash, found = 0;
- struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
- struct ifindex_node *this;
- struct rtattr *cb[IFLA_MAX+1];
- struct nlif_handle *h = arg;
-
- if (n->nlmsg_type != RTM_NEWLINK)
- return -1;
-
- if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
- return -1;
-
- rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
-
- if (!cb[IFLA_IFNAME])
- return -1;
-
- hash = ifi_msg->ifi_index & 0xF;
- list_for_each_entry(this, &h->ifindex_hash[hash], head) {
- if (this->index == ifi_msg->ifi_index) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- this = malloc(sizeof(*this));
- if (!this)
- return -1;
-
- this->index = ifi_msg->ifi_index;
- }
-
- this->type = ifi_msg->ifi_type;
- this->flags = ifi_msg->ifi_flags;
- if (cb[IFLA_ADDRESS]) {
- unsigned int alen;
-
- this->alen = alen = RTA_PAYLOAD(cb[IFLA_ADDRESS]);
- if (alen > sizeof(this->addr))
- alen = sizeof(this->addr);
- memcpy(this->addr, RTA_DATA(cb[IFLA_ADDRESS]), alen);
- } else {
- this->alen = 0;
- memset(this->addr, 0, sizeof(this->addr));
- }
- strcpy(this->name, RTA_DATA(cb[IFLA_IFNAME]));
-
- if (!found)
- list_add(&this->head, &h->ifindex_hash[hash]);
-
- return 1;
-}
-
-/* iftable_del - Delete an entry from the interface table
- * \param n: netlink message header of a RTM_DELLINK nlmsg
- * \param arg: not used
- *
- * Delete an entry from the interface table.
- * Returns -1 on error, 0 if no matching entry was found or 1 on success.
- */
-static int iftable_del(struct nlmsghdr *n, void *arg)
-{
- struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
- struct rtattr *cb[IFLA_MAX+1];
- struct nlif_handle *h = arg;
- struct ifindex_node *this, *tmp;
- unsigned int hash;
-
- if (n->nlmsg_type != RTM_DELLINK)
- return -1;
-
- if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
- return -1;
-
- rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
-
- hash = ifi_msg->ifi_index & 0xF;
- list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash], head) {
- if (this->index == ifi_msg->ifi_index) {
- list_del(&this->head);
- free(this);
- return 1;
- }
- }
-
- return 0;
-}
-
/**
* nlif_index2name - get the name for an ifindex
*
@@ -205,6 +113,7 @@ static int iftable_del(struct nlmsghdr *n, void *arg)
* \param name interface name, pass a buffer of IFNAMSIZ size
* \return -1 on error, 1 on success
*/
+EXPORT_SYMBOL
int nlif_index2name(struct nlif_handle *h,
unsigned int index,
char *name)
@@ -212,9 +121,6 @@ int nlif_index2name(struct nlif_handle *h,
unsigned int hash;
struct ifindex_node *this;
- assert(h != NULL);
- assert(name != NULL);
-
if (index == 0) {
strcpy(name, "*");
return 1;
@@ -240,6 +146,7 @@ int nlif_index2name(struct nlif_handle *h,
* \param flags pointer to variable used to store the interface flags
* \return -1 on error, 1 on success
*/
+EXPORT_SYMBOL
int nlif_get_ifflags(const struct nlif_handle *h,
unsigned int index,
unsigned int *flags)
@@ -247,9 +154,6 @@ int nlif_get_ifflags(const struct nlif_handle *h,
unsigned int hash;
struct ifindex_node *this;
- assert(h != NULL);
- assert(flags != NULL);
-
if (index == 0) {
errno = ENOENT;
return -1;
@@ -269,11 +173,12 @@ int nlif_get_ifflags(const struct nlif_handle *h,
/**
* nlif_open - initialize interface table
*
- * Initialize rtnl interface and interface table
- * Call this before any nlif_* function
+ * Open a netlink socket and initialize interface table
+ * Call this before any other nlif_* function
*
- * \return file descriptor to netlink socket
+ * \return NULL on error, else valid pointer to an nlif_handle structure
*/
+EXPORT_SYMBOL
struct nlif_handle *nlif_open(void)
{
int i;
@@ -283,32 +188,21 @@ struct nlif_handle *nlif_open(void)
if (h == NULL)
goto err;
- for (i = 0; i < 16; i++)
+ for (i = 0; i < NUM_NLIF_ENTRIES; i++)
INIT_LIST_HEAD(&h->ifindex_hash[i]);
- h->ifadd_handler.nlmsg_type = RTM_NEWLINK;
- h->ifadd_handler.handlefn = iftable_add;
- h->ifadd_handler.arg = h;
- h->ifdel_handler.nlmsg_type = RTM_DELLINK;
- h->ifdel_handler.handlefn = iftable_del;
- h->ifdel_handler.arg = h;
+ h->nl = mnl_socket_open(NETLINK_ROUTE);
+ if (!h->nl)
+ goto err_free;
- h->rtnl_handle = rtnl_open();
- if (h->rtnl_handle == NULL)
- goto err;
-
- if (rtnl_handler_register(h->rtnl_handle, &h->ifadd_handler) < 0)
+ if (mnl_socket_bind(h->nl, RTMGRP_LINK, MNL_SOCKET_AUTOPID) < 0)
goto err_close;
- if (rtnl_handler_register(h->rtnl_handle, &h->ifdel_handler) < 0)
- goto err_unregister;
-
return h;
-err_unregister:
- rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
err_close:
- rtnl_close(h->rtnl_handle);
+ mnl_socket_close(h->nl);
+err_free:
free(h);
err:
return NULL;
@@ -319,18 +213,15 @@ err:
*
* \param h pointer to nlif_handle created by nlif_open()
*/
+EXPORT_SYMBOL
void nlif_close(struct nlif_handle *h)
{
int i;
struct ifindex_node *this, *tmp;
- assert(h != NULL);
+ mnl_socket_close(h->nl);
- rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
- rtnl_handler_unregister(h->rtnl_handle, &h->ifdel_handler);
- rtnl_close(h->rtnl_handle);
-
- for (i = 0; i < 16; i++) {
+ for (i = 0; i < NUM_NLIF_ENTRIES; i++) {
list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) {
list_del(&this->head);
free(this);
@@ -344,61 +235,139 @@ void nlif_close(struct nlif_handle *h)
/**
* nlif_catch - receive message from netlink and update interface table
*
- * FIXME - elaborate a bit
- *
* \param h pointer to nlif_handle created by nlif_open()
* \return 0 if OK
*/
+EXPORT_SYMBOL
int nlif_catch(struct nlif_handle *h)
{
- assert(h != NULL);
-
- if (h->rtnl_handle)
- return rtnl_receive(h->rtnl_handle);
-
- return -1;
-}
-
-static int nlif_catch_multi(struct nlif_handle *h)
-{
- assert(h != NULL);
-
- if (h->rtnl_handle)
- return rtnl_receive_multi(h->rtnl_handle);
+ /*
+ * Use MNL_SOCKET_BUFFER_SIZE instead of MNL_SOCKET_DUMP_SIZE
+ * to keep memory footprint same as it was.
+ */
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret;
+
+ if (!h->nl) /* The old library had this test */
+ return -1;
- return -1;
+ ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
+ if (ret == -1)
+ return -1;
+ return mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(h->nl),
+ data_cb, h) == -1 ? -1 : 0;
}
/**
* nlif_query - request a dump of interfaces available in the system
* \param h: pointer to a valid nlif_handler
+ * \return -1 on error with errno set, else >=0
*/
+EXPORT_SYMBOL
int nlif_query(struct nlif_handle *h)
{
- assert(h != NULL);
-
- if (rtnl_dump_type(h->rtnl_handle, RTM_GETLINK) < 0)
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t seq;
+ int ret;
+ struct rtgenmsg *rt;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = RTM_GETLINK;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_seq = seq = time(NULL);
+ rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
+ rt->rtgen_family = AF_PACKET;
+ if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
return -1;
-
- return nlif_catch_multi(h);
+ ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, seq, mnl_socket_get_portid(h->nl),
+ data_cb, h);
+ if (ret <= MNL_CB_STOP)
+ break;
+ ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
+ }
+ return ret;
}
/**
* nlif_fd - get file descriptor for the netlink socket
*
* \param h pointer to nlif_handle created by nlif_open()
- * \return The fd or -1 if there's an error
+ * \return socket fd or -1 on error
*/
+EXPORT_SYMBOL
int nlif_fd(struct nlif_handle *h)
{
- assert(h != NULL);
-
- if (h->rtnl_handle)
- return h->rtnl_handle->rtnl_fd;
-
- return -1;
+ return h->nl ? mnl_socket_get_fd(h->nl) : -1;
}
/**
* @}
*/
+
+/*
+ * data_cb - callback for rtnetlink messages
+ * caller will put nlif_handle in data
+ */
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct ifinfomsg *ifi_msg = mnl_nlmsg_get_payload(nlh);
+ struct nlif_handle *h = data;
+ struct nlattr *attr;
+ uint32_t hash;
+ struct ifindex_node *this, *tmp;
+
+ if (nlh->nlmsg_type != RTM_NEWLINK && nlh->nlmsg_type != RTM_DELLINK) {
+ errno = EPROTO;
+ return MNL_CB_ERROR;
+ }
+ hash = ifi_msg->ifi_index & NLIF_ENTRY_MASK;
+
+ /* RTM_DELLINK is simple, do it first for less indenting */
+ if (nlh->nlmsg_type == RTM_DELLINK) {
+ /*
+ * The original code used list_for_each_entry_safe when deleting
+ * and list_for_each_entry when adding.
+ * The code is only ever going to delete one entry
+ * so what does the safe variant achieve?
+ * In a multi-threaded app,
+ * I'd suggest a pthread rwlock on all nlif accesses.
+ */
+ list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash],
+ head) {
+ if (this->index == ifi_msg->ifi_index) {
+ list_del(&this->head);
+ free(this);
+ }
+ }
+ return MNL_CB_OK;
+ }
+
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == ifi_msg->ifi_index)
+ goto found;
+ }
+ this = calloc(1, sizeof(*this));
+ if (!this)
+ return MNL_CB_ERROR;
+ this->index = ifi_msg->ifi_index;
+ this->type = ifi_msg->ifi_type;
+ this->flags = ifi_msg->ifi_flags;
+ list_add(&this->head, &h->ifindex_hash[hash]);
+found:
+ mnl_attr_for_each(attr, nlh, sizeof(*ifi_msg)) {
+ /* All we want is the interface name */
+ if (mnl_attr_get_type(attr) == IFLA_IFNAME) {
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ strcpy(this->name, mnl_attr_get_str(attr));
+ break;
+ }
+ }
+ return MNL_CB_OK;
+}
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 14/15] include: Use libmnl.h instead of libnfnetlink.h
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (12 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 13/15] src: Convert all nlif_* functions to use libmnl Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 15/15] build: Remove libnfnetlink from the build Duncan Roe
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
Add nlif_* prototypes and 64-bit converters to libnetfilter_queue.h.
Update (deprecated) include/libnetfilter_queue/linux_nfnetlink_queue.h
to use /usr/include/linux/nfnetlink.h
instead of libnfnetlink/linux_nfnetlink.h
As an aside, everything compiles fine with this line removed
(i.e library, utils and examples all compile),
so maybe we can do without it.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Changes in v2:
- This was patch 18 v1
- Update commit message:
- libnetfilter_queue.c has no libnfnetlink.h references
(removed in patch 6 v2).
- Incorporate patch 22 v1
.../libnetfilter_queue/libnetfilter_queue.h | 36 ++++++++++++++++++-
.../linux_nfnetlink_queue.h | 3 +-
2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/include/libnetfilter_queue/libnetfilter_queue.h b/include/libnetfilter_queue/libnetfilter_queue.h
index 9327f8c..46289f2 100644
--- a/include/libnetfilter_queue/libnetfilter_queue.h
+++ b/include/libnetfilter_queue/libnetfilter_queue.h
@@ -14,7 +14,7 @@
#define __LIBCTNETLINK_H
#include <sys/time.h>
-#include <libnfnetlink/libnfnetlink.h>
+#include <libmnl/libmnl.h>
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
@@ -25,6 +25,7 @@ extern "C" {
struct nfq_handle;
struct nfq_q_handle;
struct nfq_data;
+struct nlif_handle;
extern int nfq_errno;
@@ -155,8 +156,41 @@ int nfq_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr **attr);
struct nlmsghdr *nfq_nlmsg_put(char *buf, int type, uint32_t queue_num);
struct nlmsghdr *nfq_nlmsg_put2(char *buf, int type, uint32_t queue_num, uint16_t flags);
+/*
+ * Network Interface Table API
+ */
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+struct nlif_handle *nlif_open(void);
+void nlif_close(struct nlif_handle *orig);
+int nlif_fd(struct nlif_handle *nlif_handle);
+int nlif_query(struct nlif_handle *nlif_handle);
+int nlif_catch(struct nlif_handle *nlif_handle);
+int nlif_index2name(struct nlif_handle *nlif_handle, unsigned int if_index, char *name);
+int nlif_get_ifflags(const struct nlif_handle *h, unsigned int index, unsigned int *flags);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
+/*
+ * __be46 stuff - should be in libmnl.h maybe?
+ */
+
+#include <byteswap.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+# ifndef __be64_to_cpu
+# define __be64_to_cpu(x) (x)
+# endif
+# else
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+# ifndef __be64_to_cpu
+# define __be64_to_cpu(x) __bswap_64(x)
+# endif
+# endif
+#endif
+
#endif /* __LIBNFQNETLINK_H */
diff --git a/include/libnetfilter_queue/linux_nfnetlink_queue.h b/include/libnetfilter_queue/linux_nfnetlink_queue.h
index 6844270..82d8ece 100644
--- a/include/libnetfilter_queue/linux_nfnetlink_queue.h
+++ b/include/libnetfilter_queue/linux_nfnetlink_queue.h
@@ -8,7 +8,8 @@
#endif
#include <linux/types.h>
-#include <libnfnetlink/linux_nfnetlink.h>
+/* Use the real header since libnfnetlink is going away. */
+#include <linux/nfnetlink.h>
enum nfqnl_msg_types {
NFQNL_MSG_PACKET, /* packet from kernel to userspace */
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH libnetfilter_queue v2 15/15] build: Remove libnfnetlink from the build
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
` (13 preceding siblings ...)
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 14/15] include: Use libmnl.h instead of libnfnetlink.h Duncan Roe
@ 2024-05-24 5:37 ` Duncan Roe
14 siblings, 0 replies; 16+ messages in thread
From: Duncan Roe @ 2024-05-24 5:37 UTC (permalink / raw)
To: netfilter-devel; +Cc: pablo
libnfnetlink was a "private library" - always loaded whether user apps
used it or not. Remove it now it is no longer needed.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
v2: This was patch 21/32. No changes.
Make_global.am | 2 +-
configure.ac | 1 -
libnetfilter_queue.pc.in | 2 --
src/Makefile.am | 2 +-
4 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/Make_global.am b/Make_global.am
index 91da5da..4d8a58e 100644
--- a/Make_global.am
+++ b/Make_global.am
@@ -1,2 +1,2 @@
-AM_CPPFLAGS = -I${top_srcdir}/include ${LIBNFNETLINK_CFLAGS} ${LIBMNL_CFLAGS}
+AM_CPPFLAGS = -I${top_srcdir}/include ${LIBMNL_CFLAGS}
AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN}
diff --git a/configure.ac b/configure.ac
index 7359fba..ba7b15f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,7 +42,6 @@ case "$host" in
esac
dnl Dependencies
-PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 0.0.41])
PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
AS_IF([test "$enable_man_pages" = no -a "$enable_html_doc" = no],
diff --git a/libnetfilter_queue.pc.in b/libnetfilter_queue.pc.in
index 9c6c2c4..1927a8a 100644
--- a/libnetfilter_queue.pc.in
+++ b/libnetfilter_queue.pc.in
@@ -9,8 +9,6 @@ Name: libnetfilter_queue
Description: netfilter userspace packet queueing library
URL: http://netfilter.org/projects/libnetfilter_queue/
Version: @VERSION@
-Requires: libnfnetlink
Conflicts:
Libs: -L${libdir} -lnetfilter_queue
-Libs.private: @LIBNFNETLINK_LIBS@
Cflags: -I${includedir}
diff --git a/src/Makefile.am b/src/Makefile.am
index a6813e8..e5e1d66 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,4 +39,4 @@ libnetfilter_queue_la_SOURCES = libnetfilter_queue.c \
extra/pktbuff.c \
extra/udp.c
-libnetfilter_queue_la_LIBADD = ${LIBNFNETLINK_LIBS} ${LIBMNL_LIBS}
+libnetfilter_queue_la_LIBADD = ${LIBMNL_LIBS}
--
2.35.8
^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2024-05-24 5:38 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-24 5:37 [PATCH libnetfilter_queue v2 00/15] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 01/15] src: Convert nfq_open() to use libmnl Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 02/15] src: Convert nfq_open_nfnl() " Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 03/15] src: Convert nfq_close() " Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 04/15] src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() " Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 05/15] src: Convert nfq_set_queue_flags(), nfq_set_queue_maxlen() & nfq_set_mode() " Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 06/15] src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload() and all the nfq_get_ functions " Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 07/15] src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if there is no data Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 08/15] src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 09/15] src: Convert nfq_fd() to use libmnl Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 10/15] src: Convert remaining nfq_* functions " Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 11/15] src: Copy nlif-related files from libnfnetlink Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 12/15] doc: Add iftable.c to the doxygen system Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 13/15] src: Convert all nlif_* functions to use libmnl Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 14/15] include: Use libmnl.h instead of libnfnetlink.h Duncan Roe
2024-05-24 5:37 ` [PATCH libnetfilter_queue v2 15/15] build: Remove libnfnetlink from the build Duncan Roe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).