diff mbox series

[libnetfilter_queue,v2,02/15] src: Convert nfq_open_nfnl() to use libmnl

Message ID 20240524053742.27294-3-duncan_roe@optusnet.com.au
State New
Headers show
Series Convert libnetfilter_queue to not need libnfnetlink | expand

Commit Message

Duncan Roe May 24, 2024, 5:37 a.m. UTC
__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 mbox series

Patch

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;
 }