__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@xxxxxxxxxxxxxxx> --- 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