From de8dafc90e335cbb06252a087d25a7589b607ad2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 17 Feb 2009 20:40:36 +0100 Subject: nfnl: allow disabling and enabling sequence tracking This patch adds a couple of functions to enable and disable netlink sequence tracking. Since nfqueue goes over a unicast socket, the same channel to receive control messages and packets is used. This leads to race conditions that may trigger sporious out-of-sequence errors while creating queues and receiving high load of packets at the same time. Reported-by: Anton Vazir Signed-off-by: Pablo Neira Ayuso --- configure.in | 2 +- include/libnfnetlink/libnfnetlink.h | 4 ++++ src/libnfnetlink.c | 37 +++++++++++++++++++++++++++++++++---- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/configure.in b/configure.in index 27b00c2..f760cd0 100644 --- a/configure.in +++ b/configure.in @@ -1,6 +1,6 @@ dnl Process this file with autoconf to create configure. -AC_INIT(libnfnetlink, 0.0.40) +AC_INIT(libnfnetlink, 0.0.41) AC_CANONICAL_SYSTEM diff --git a/include/libnfnetlink/libnfnetlink.h b/include/libnfnetlink/libnfnetlink.h index b2f3652..10b6478 100644 --- a/include/libnfnetlink/libnfnetlink.h +++ b/include/libnfnetlink/libnfnetlink.h @@ -60,6 +60,10 @@ extern struct nfnl_subsys_handle *nfnl_subsys_open(struct nfnl_handle *, unsigned int); extern void nfnl_subsys_close(struct nfnl_subsys_handle *); +/* set and unset sequence tracking */ +void nfnl_set_sequence_tracking(struct nfnl_handle *h); +void nfnl_unset_sequence_tracking(struct nfnl_handle *h); + /* set receive buffer size (for nfnl_catch) */ extern void nfnl_set_rcv_buffer_size(struct nfnl_handle *h, unsigned int size); diff --git a/src/libnfnetlink.c b/src/libnfnetlink.c index d4212f9..a836de1 100644 --- a/src/libnfnetlink.c +++ b/src/libnfnetlink.c @@ -78,6 +78,9 @@ struct nfnl_subsys_handle { }; #define NFNL_MAX_SUBSYS 16 /* enough for now */ + +#define NFNL_F_SEQTRACK_ENABLED (1 << 0) + struct nfnl_handle { int fd; struct sockaddr_nl local; @@ -86,6 +89,7 @@ struct nfnl_handle { u_int32_t seq; u_int32_t dump; u_int32_t rcv_buffer_size; /* for nfnl_catch */ + u_int32_t flags; struct nlmsghdr *last_nlhdr; struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1]; }; @@ -202,6 +206,8 @@ struct nfnl_handle *nfnl_open(void) errno = EINVAL; goto err_close; } + /* sequence tracking enabled by default */ + nfnlh->flags |= NFNL_F_SEQTRACK_ENABLED; return nfnlh; @@ -212,6 +218,24 @@ err_free: return NULL; } +/** + * nfnl_set_sequence_tracking - set netlink sequence tracking + * @h: nfnetlink handler + */ +void nfnl_set_sequence_tracking(struct nfnl_handle *h) +{ + h->flags |= NFNL_F_SEQTRACK_ENABLED; +} + +/** + * nfnl_unset_sequence_tracking - set netlink sequence tracking + * @h: nfnetlink handler + */ +void nfnl_unset_sequence_tracking(struct nfnl_handle *h) +{ + h->flags &= ~NFNL_F_SEQTRACK_ENABLED; +} + /** * nfnl_set_rcv_buffer_size - set the size of the receive buffer * @h: libnfnetlink handler @@ -418,11 +442,16 @@ void nfnl_fill_hdr(struct nfnl_subsys_handle *ssh, nlh->nlmsg_type = (ssh->subsys_id<<8)|msg_type; nlh->nlmsg_flags = msg_flags; nlh->nlmsg_pid = 0; - nlh->nlmsg_seq = ++ssh->nfnlh->seq; - /* check for wraparounds: assume that seqnum 0 is only used by events */ - if (!ssh->nfnlh->seq) - nlh->nlmsg_seq = ssh->nfnlh->seq = time(NULL); + if (ssh->nfnlh->flags & NFNL_F_SEQTRACK_ENABLED) { + nlh->nlmsg_seq = ++ssh->nfnlh->seq; + /* kernel uses sequence number zero for events */ + if (!ssh->nfnlh->seq) + nlh->nlmsg_seq = ssh->nfnlh->seq = time(NULL); + } else { + /* unset sequence number, ignore it */ + nlh->nlmsg_seq = 0; + } nfg->nfgen_family = family; nfg->version = NFNETLINK_V0; -- cgit v1.2.3