diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-02-17 20:40:36 +0100 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-02-17 20:40:36 +0100 |
commit | de8dafc90e335cbb06252a087d25a7589b607ad2 (patch) | |
tree | d11a6a4c82569a466245181cb5a06995eabd4b32 | |
parent | b5194b353d27aa0c480691be44e2d4778759c9c0 (diff) |
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 <anton.vazir@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r-- | configure.in | 2 | ||||
-rw-r--r-- | include/libnfnetlink/libnfnetlink.h | 4 | ||||
-rw-r--r-- | 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; @@ -213,6 +219,24 @@ err_free: } /** + * 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 * @size: buffer size @@ -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; |