aboutsummaryrefslogtreecommitdiffstats
path: root/main/fprobe-ulog
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2015-07-10 11:26:44 +0300
committerTimo Teräs <timo.teras@iki.fi>2015-07-10 11:28:20 +0300
commit6c9d9325fe81174d7e1de61f3f49c88c2a7d194a (patch)
tree1a725c8df498af68546a8c938d947ae6fb62a3f5 /main/fprobe-ulog
parent88840d407c2603116e2d2b79a1f419c450830ea0 (diff)
downloadaports-6c9d9325fe81174d7e1de61f3f49c88c2a7d194a.tar.bz2
aports-6c9d9325fe81174d7e1de61f3f49c88c2a7d194a.tar.xz
main/fprobe-ulog: migrate to nflog api
ULOG is no longer present in kernels we use. The compat library is deficient and does not support e.g. mapping of interface names or timestamps. This patch updates the code to use nflog natively and removes the ifindex to name mappings using syscalls so this improves performance too.
Diffstat (limited to 'main/fprobe-ulog')
-rw-r--r--main/fprobe-ulog/APKBUILD12
-rw-r--r--main/fprobe-ulog/fprobe-nflog.patch617
2 files changed, 625 insertions, 4 deletions
diff --git a/main/fprobe-ulog/APKBUILD b/main/fprobe-ulog/APKBUILD
index a97e014cd7..2d8124eb38 100644
--- a/main/fprobe-ulog/APKBUILD
+++ b/main/fprobe-ulog/APKBUILD
@@ -1,7 +1,7 @@
# Maintainer: Leonardo Arena <rnalrd@alpinelinux.org>
pkgname=fprobe-ulog
pkgver=1.2
-pkgrel=1
+pkgrel=2
pkgdesc="netfilter-based tool that collect network traffic"
url="https://github.com/opoplawski/fprobe-ulog"
arch="all"
@@ -15,6 +15,7 @@ source="https://github.com/opoplawski/fprobe-ulog/releases/download/v$pkgver/fpr
fprobe-ulog.initd
fprobe-1.1-pidfile-sanity.patch
fix-setuser.patch
+ fprobe-nflog.patch
"
_builddir="$srcdir"/$pkgname-$pkgver
@@ -55,14 +56,17 @@ md5sums="05408501ac17a664fda269a208efa087 fprobe-ulog-1.2.tar.gz
8aabfe548f2fb197a10c8ccfaa4d0a23 fprobe-ulog.confd
d791e5d15be8fb59b22f7fa235b9f041 fprobe-ulog.initd
f1316ad835c1a2b6565b4dc448b022df fprobe-1.1-pidfile-sanity.patch
-27bfeb6c6cd7089240173a2829054d87 fix-setuser.patch"
+27bfeb6c6cd7089240173a2829054d87 fix-setuser.patch
+daeeac4f76b19e7ec7a579bcbb9b103c fprobe-nflog.patch"
sha256sums="72a8c13001dd512acff9b85594dd29a435947072e20abefe85c29468a3967121 fprobe-ulog-1.2.tar.gz
7101091e238f5b0719a66f525f5bdc000ad593f492dd51896e2bd077fcada8f4 fprobe-ulog.confd
3dfaa0a8e995ac2c3caa49a01ed570f83348fb3348d1a5106af5a80a1fc1f3d0 fprobe-ulog.initd
660531f8ba574f80835bb26390e47c2541a3c75985656d46a334c38bfaa4e362 fprobe-1.1-pidfile-sanity.patch
-aa4b237750555323de29f6ddbc3f807dc507bd72564043e9dab6316dc3424123 fix-setuser.patch"
+aa4b237750555323de29f6ddbc3f807dc507bd72564043e9dab6316dc3424123 fix-setuser.patch
+5e9dae31daabdc9916ccd3d50c95f41dbd58439b233e445e3accd161d0d29fbb fprobe-nflog.patch"
sha512sums="c393c0705bd6c7cee998fccc48dede3568063b5130971f36c08f580c7678cf52fdf446c02cc4df3d5a2ead68cb2d14434e0847bfff27b6a0c5ef5ec7d6f61145 fprobe-ulog-1.2.tar.gz
388522863b5c77a334ee11bd771717d829448c85755b58088e22558b99a98514ac95ec3122cf3cb1ce7376f40ac0bae6bf1488dbd4ef60170c3ff83824988195 fprobe-ulog.confd
2c81ab715eea71beac21d4e4261464ed763464398e3fa4979eb8bd1f671d22916dffb64f051714b6460bb422924517979a3630139b478ddd258b2c28b3d73a14 fprobe-ulog.initd
e8d5103d2c12fffb913b327badf07e6ac3a0ad8b6e39e942c50dc7e472391b345006b7ee7b7d12a4613c351db2b4e88a6fbd17cfa0907c7c9010faeced3ff557 fprobe-1.1-pidfile-sanity.patch
-981f8bf359f7f338a742eb605a09ff95a960231b98b80552d70f1637aea0ec061fddfd8fa004eef971143af52c88e3a8c7dd45605693f9035cb2c63ccfadb1ed fix-setuser.patch"
+981f8bf359f7f338a742eb605a09ff95a960231b98b80552d70f1637aea0ec061fddfd8fa004eef971143af52c88e3a8c7dd45605693f9035cb2c63ccfadb1ed fix-setuser.patch
+dbf186246b25f60a54a822d28e8463f1f4b17812e99ed9e4a76519506b6046ed41494e669ab70f8449923d0e7d43428b9417dc67642059b16fc9457b3dc70d3b fprobe-nflog.patch"
diff --git a/main/fprobe-ulog/fprobe-nflog.patch b/main/fprobe-ulog/fprobe-nflog.patch
new file mode 100644
index 0000000000..8b66a23433
--- /dev/null
+++ b/main/fprobe-ulog/fprobe-nflog.patch
@@ -0,0 +1,617 @@
+diff -ru fprobe-ulog-1.2.orig/src/Makefile.am fprobe-ulog-1.2/src/Makefile.am
+--- fprobe-ulog-1.2.orig/src/Makefile.am 2014-12-23 19:26:37.000000000 -0200
++++ fprobe-ulog-1.2/src/Makefile.am 2015-07-10 11:23:21.839152998 -0300
+@@ -11,4 +11,4 @@
+
+ EXTRA_DIST = ${man_MANS}
+
+-fprobe_ulog_LDADD = -lnetfilter_log_libipulog
++fprobe_ulog_LDADD = -lnetfilter_log -lnfnetlink
+diff -ru fprobe-ulog-1.2.orig/src/Makefile.in fprobe-ulog-1.2/src/Makefile.in
+--- fprobe-ulog-1.2.orig/src/Makefile.in 2014-12-23 20:02:22.000000000 -0200
++++ fprobe-ulog-1.2/src/Makefile.in 2015-07-10 11:23:32.279250285 -0300
+@@ -293,7 +293,7 @@
+
+ man_MANS = fprobe-ulog.8
+ EXTRA_DIST = ${man_MANS}
+-fprobe_ulog_LDADD = -lnetfilter_log_libipulog
++fprobe_ulog_LDADD = -lnetfilter_log -lnfnetlink
+ all: all-am
+
+ .SUFFIXES:
+diff -ru fprobe-ulog-1.2.orig/src/fprobe-ulog.c fprobe-ulog-1.2/src/fprobe-ulog.c
+--- fprobe-ulog-1.2.orig/src/fprobe-ulog.c 2015-07-10 11:22:29.668666836 -0300
++++ fprobe-ulog-1.2/src/fprobe-ulog.c 2015-07-10 11:23:06.479009860 -0300
+@@ -27,14 +27,8 @@
+ #include <asm/types.h>
+ #include <sys/socket.h>
+ #include <linux/netlink.h>
+-#include <libnetfilter_log/libipulog.h>
+-struct ipulog_handle {
+- int fd;
+- u_int8_t blocking;
+- struct sockaddr_nl local;
+- struct sockaddr_nl peer;
+- struct nlmsghdr* last_nlhdr;
+-};
++#include <libnfnetlink/libnfnetlink.h>
++#include <libnetfilter_log/libnetfilter_log.h>
+
+ /* inet_*() (Linux, FreeBSD, Solaris), getpid() */
+ #include <sys/types.h>
+@@ -106,7 +100,6 @@
+ Uflag,
+ uflag,
+ vflag,
+- Xflag,
+ };
+
+ static struct getopt_parms parms[] = {
+@@ -129,7 +122,6 @@
+ {'U', MY_GETOPT_ARG_REQUIRED, 0, 0},
+ {'u', MY_GETOPT_ARG_REQUIRED, 0, 0},
+ {'v', MY_GETOPT_ARG_REQUIRED, 0, 0},
+- {'X', MY_GETOPT_ARG_REQUIRED, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+@@ -208,21 +200,19 @@
+ static pid_t pid;
+ static int killed;
+ static int emit_timeout = EMIT_TIMEOUT, unpending_timeout = UNPENDING_TIMEOUT;
+-static struct ipulog_handle *ulog_handle;
+-static uint32_t ulog_gmask = 1;
++static struct nflog_handle *nflog_handle;
++static uint32_t nflog_gmask = 1;
+ static unsigned char *cap_buf;
+-static int nsnmp_rules;
+-static struct snmp_rule *snmp_rules;
+ static struct passwd *pw = 0;
+
+ void usage()
+ {
+ fprintf(stdout,
+- "fprobe-ulog: a NetFlow probe. Version %s\n"
+- "Usage: fprobe-ulog [options] remote:port[/[local][/type]] ...\n"
++ "fprobe-nflog: a NetFlow probe. Version %s\n"
++ "Usage: fprobe-nflog [options] remote:port[/[local][/type]] ...\n"
+ "\n"
+ "-h\t\tDisplay this help\n"
+- "-U <mask>\tULOG group bitwise mask [1]\n"
++ "-U <mask>\tNFLOG group bitwise mask [1]\n"
+ "-s <seconds>\tHow often scan for expired flows [5]\n"
+ "-g <seconds>\tFragmented flow lifetime [30]\n"
+ "-d <seconds>\tIdle flow lifetime (inactive timer) [60]\n"
+@@ -275,13 +265,18 @@
+ }
+ }
+
++static void timeval2time(struct timeval *tv, struct Time *t)
++{
++ t->sec = tv->tv_sec;
++ t->usec = tv->tv_usec;
++}
++
+ void gettime(struct Time *now)
+ {
+ struct timeval t;
+
+ gettimeofday(&t, 0);
+- now->sec = t.tv_sec;
+- now->usec = t.tv_usec;
++ timeval2time(&t, now);
+ }
+
+ inline time_t cmpmtime(struct Time *t1, struct Time *t2)
+@@ -302,21 +297,6 @@
+ else return hash(flow, sizeof(struct Flow_TL));
+ }
+
+-uint16_t snmp_index(char *name) {
+- uint32_t i;
+-
+- if (!*name) return 0;
+-
+- for (i = 0; (int) i < nsnmp_rules; i++) {
+- if (strncmp(snmp_rules[i].basename, name, snmp_rules[i].len)) continue;
+- return atoi(&name[snmp_rules[i].len]) + snmp_rules[i].base;
+- }
+-
+- if ((i = if_nametoindex(name))) return i;
+-
+- return -1;
+-}
+-
+ inline void copy_flow(struct Flow *src, struct Flow *dst)
+ {
+ dst->iif = src->iif;
+@@ -845,226 +825,230 @@
+ }
+ }
+
+-void *cap_thread()
++static int fprobe_cb(struct nflog_g_handle *gh, struct nfgenmsg *nfmsg,
++ struct nflog_data *nfd, void *data)
+ {
+- struct ulog_packet_msg *ulog_msg;
++ struct timeval tv;
++ char *payload;
+ struct ip *nl;
+ void *tl;
+ struct Flow *flow;
+ int off_frag, psize;
+- ssize_t len;
+ #if ((DEBUG) & DEBUG_C)
+ char buf[64];
+ char logbuf[256];
+ #endif
+
+- while (!killed) {
+- len = ipulog_read(ulog_handle, cap_buf, CAPTURE_SIZE, 1);
+- if (len <= 0) {
+- my_log(LOG_ERR, "ipulog_read(): %s", ipulog_strerror(ipulog_errno));
+- continue;
+- }
+- while ((ulog_msg = ipulog_get_packet(ulog_handle, cap_buf, len))) {
++ if (killed)
++ return NFNL_CB_STOP;
+
++ psize = nflog_get_payload(nfd, &payload);
++ nl = (struct ip*) payload;
+ #if ((DEBUG) & DEBUG_C)
+- sprintf(logbuf, "C: %d", ulog_msg->data_len);
++ sprintf(logbuf, "C: %d", psize);
+ #endif
+
+- nl = (void *) &ulog_msg->payload;
+- psize = ulog_msg->data_len;
+-
+- /* Sanity check */
+- if (psize < (signed) sizeof(struct ip) || nl->ip_v != 4) {
++ /* Sanity check */
++ if (psize < (signed) sizeof(struct ip) || nl->ip_v != 4) {
+ #if ((DEBUG) & DEBUG_C)
+- strcat(logbuf, " U");
+- my_log(LOG_DEBUG, "%s", logbuf);
++ strcat(logbuf, " U");
++ my_log(LOG_DEBUG, "%s", logbuf);
+ #endif
+ #if ((DEBUG) & DEBUG_I)
+- pkts_ignored++;
++ pkts_ignored++;
+ #endif
+- continue;
+- }
++ return NFNL_CB_CONTINUE;
++ }
+
+- if (pending_head->flags) {
++ if (pending_head->flags) {
+ #if ((DEBUG) & DEBUG_C) || defined MESSAGES
+- my_log(LOG_ERR,
++ my_log(LOG_ERR,
+ # if ((DEBUG) & DEBUG_C)
+- "%s %s %s", logbuf,
++ "%s %s %s", logbuf,
+ # else
+- "%s %s",
++ "%s %s",
+ # endif
+- "pending queue full:", "packet lost");
++ "pending queue full:", "packet lost");
+ #endif
+ #if ((DEBUG) & DEBUG_I)
+- pkts_lost_capture++;
++ pkts_lost_capture++;
+ #endif
+- goto done;
+- }
++ goto done;
++ }
+
+ #if ((DEBUG) & DEBUG_I)
+- pkts_total++;
++ pkts_total++;
+ #endif
+
+- flow = pending_head;
++ flow = pending_head;
+
+- /* ?FIXME? Add sanity check for ip_len? */
+- flow->size = ntohs(nl->ip_len);
++ /* ?FIXME? Add sanity check for ip_len? */
++ flow->size = ntohs(nl->ip_len);
+ #if ((DEBUG) & DEBUG_I)
+- size_total += flow->size;
++ size_total += flow->size;
+ #endif
+
+- flow->sip = nl->ip_src;
+- flow->dip = nl->ip_dst;
+- flow->iif = snmp_index(ulog_msg->indev_name);
+- flow->oif = snmp_index(ulog_msg->outdev_name);
+- flow->tos = mark_is_tos ? ulog_msg->mark : nl->ip_tos;
+- flow->proto = nl->ip_p;
+- flow->id = 0;
+- flow->tcp_flags = 0;
+- flow->pkts = 1;
+- flow->sizeF = 0;
+- flow->sizeP = 0;
+- /* Packets captured from OUTPUT table didn't contains valid timestamp */
+- if (ulog_msg->timestamp_sec) {
+- flow->ctime.sec = ulog_msg->timestamp_sec;
+- flow->ctime.usec = ulog_msg->timestamp_usec;
+- } else gettime(&flow->ctime);
+- flow->mtime = flow->ctime;
+-
+- off_frag = (ntohs(nl->ip_off) & IP_OFFMASK) << 3;
+-
+- /*
+- Offset (from network layer) to transport layer header/IP data
+- IOW IP header size ;-)
+-
+- ?FIXME?
+- Check ip_hl for valid value (>=5)? Maybe check CRC? No, thanks...
+- */
+- off_tl = nl->ip_hl << 2;
+- tl = (void *) nl + off_tl;
+-
+- /* THIS packet data size: data_size = total_size - ip_header_size*4 */
+- flow->sizeF = ntohs(nl->ip_len) - off_tl;
+- psize -= off_tl;
+- if ((signed) flow->sizeF < 0) flow->sizeF = 0;
+- if (psize > (signed) flow->sizeF) psize = flow->sizeF;
++ flow->sip = nl->ip_src;
++ flow->dip = nl->ip_dst;
++ flow->iif = nflog_get_indev(nfd);
++ flow->oif = nflog_get_outdev(nfd);
++ flow->tos = mark_is_tos ? nflog_get_nfmark(nfd) : nl->ip_tos;
++ flow->proto = nl->ip_p;
++ flow->id = 0;
++ flow->tcp_flags = 0;
++ flow->pkts = 1;
++ flow->sizeF = 0;
++ flow->sizeP = 0;
++ /* Packets captured from OUTPUT table didn't contains valid timestamp */
++ if (nflog_get_timestamp(nfd, &tv) >= 0)
++ timeval2time(&tv, &flow->ctime);
++ else
++ gettime(&flow->ctime);
++ flow->mtime = flow->ctime;
++
++ off_frag = (ntohs(nl->ip_off) & IP_OFFMASK) << 3;
++
++ /*
++ Offset (from network layer) to transport layer header/IP data
++ IOW IP header size ;-)
++
++ ?FIXME?
++ Check ip_hl for valid value (>=5)? Maybe check CRC? No, thanks...
++ */
++ off_tl = nl->ip_hl << 2;
++ tl = (void *) nl + off_tl;
++
++ /* THIS packet data size: data_size = total_size - ip_header_size*4 */
++ flow->sizeF = ntohs(nl->ip_len) - off_tl;
++ psize -= off_tl;
++ if ((signed) flow->sizeF < 0) flow->sizeF = 0;
++ if (psize > (signed) flow->sizeF) psize = flow->sizeF;
+
+- if (ntohs(nl->ip_off) & (IP_MF | IP_OFFMASK)) {
+- /* Fragmented packet (IP_MF flag == 1 or fragment offset != 0) */
++ if (ntohs(nl->ip_off) & (IP_MF | IP_OFFMASK)) {
++ /* Fragmented packet (IP_MF flag == 1 or fragment offset != 0) */
+ #if ((DEBUG) & DEBUG_C)
+- strcat(logbuf, " F");
++ strcat(logbuf, " F");
+ #endif
+ #if ((DEBUG) & DEBUG_I)
+- pkts_total_fragmented++;
++ pkts_total_fragmented++;
+ #endif
+- flow->flags |= FLOW_FRAG;
+- flow->id = nl->ip_id;
++ flow->flags |= FLOW_FRAG;
++ flow->id = nl->ip_id;
+
+- if (!(ntohs(nl->ip_off) & IP_MF)) {
+- /* Packet whith IP_MF contains information about whole datagram size */
+- flow->flags |= FLOW_LASTFRAG;
+- /* size = frag_offset*8 + data_size */
+- flow->sizeP = off_frag + flow->sizeF;
+- }
+- }
++ if (!(ntohs(nl->ip_off) & IP_MF)) {
++ /* Packet whith IP_MF contains information about whole datagram size */
++ flow->flags |= FLOW_LASTFRAG;
++ /* size = frag_offset*8 + data_size */
++ flow->sizeP = off_frag + flow->sizeF;
++ }
++ }
+
+ #if ((DEBUG) & DEBUG_C)
+- sprintf(buf, " %s@%u>", inet_ntoa(flow->sip), flow->iif);
+- strcat(logbuf, buf);
+- sprintf(buf, "%s@%u P:%x", inet_ntoa(flow->dip), flow->oif, flow->proto);
+- strcat(logbuf, buf);
++ sprintf(buf, " %s@%u>", inet_ntoa(flow->sip), flow->iif);
++ strcat(logbuf, buf);
++ sprintf(buf, "%s@%u P:%x", inet_ntoa(flow->dip), flow->oif, flow->proto);
++ strcat(logbuf, buf);
+ #endif
+
+- /*
+- Fortunately most interesting transport layer information fit
+- into first 8 bytes of IP data field (minimal nonzero size).
+- Thus we don't need actual packet reassembling to build whole
+- transport layer data. We only check the fragment offset for
+- zero value to find packet with this information.
+- */
+- if (!off_frag && psize >= 8) {
+- switch (flow->proto) {
+- case IPPROTO_TCP:
+- case IPPROTO_UDP:
+- flow->sp = ((struct udphdr *)tl)->uh_sport;
+- flow->dp = ((struct udphdr *)tl)->uh_dport;
+- goto tl_known;
++ /*
++ Fortunately most interesting transport layer information fit
++ into first 8 bytes of IP data field (minimal nonzero size).
++ Thus we don't need actual packet reassembling to build whole
++ transport layer data. We only check the fragment offset for
++ zero value to find packet with this information.
++ */
++ if (!off_frag && psize >= 8) {
++ switch (flow->proto) {
++ case IPPROTO_TCP:
++ case IPPROTO_UDP:
++ flow->sp = ((struct udphdr *)tl)->uh_sport;
++ flow->dp = ((struct udphdr *)tl)->uh_dport;
++ goto tl_known;
+
+ #ifdef ICMP_TRICK
+- case IPPROTO_ICMP:
+- flow->sp = htons(((struct icmp *)tl)->icmp_type);
+- flow->dp = htons(((struct icmp *)tl)->icmp_code);
+- goto tl_known;
++ case IPPROTO_ICMP:
++ flow->sp = htons(((struct icmp *)tl)->icmp_type);
++ flow->dp = htons(((struct icmp *)tl)->icmp_code);
++ goto tl_known;
+ #endif
+ #ifdef ICMP_TRICK_CISCO
+- case IPPROTO_ICMP:
+- flow->dp = *((int32_t *) tl);
+- goto tl_known;
++ case IPPROTO_ICMP:
++ flow->dp = *((int32_t *) tl);
++ goto tl_known;
+ #endif
+
+- default:
+- /* Unknown transport layer */
++ default:
++ /* Unknown transport layer */
+ #if ((DEBUG) & DEBUG_C)
+- strcat(logbuf, " U");
++ strcat(logbuf, " U");
+ #endif
+- flow->sp = 0;
+- flow->dp = 0;
+- break;
++ flow->sp = 0;
++ flow->dp = 0;
++ break;
+
+- tl_known:
++ tl_known:
+ #if ((DEBUG) & DEBUG_C)
+- sprintf(buf, " %d>%d", ntohs(flow->sp), ntohs(flow->dp));
+- strcat(logbuf, buf);
++ sprintf(buf, " %d>%d", ntohs(flow->sp), ntohs(flow->dp));
++ strcat(logbuf, buf);
+ #endif
+- flow->flags |= FLOW_TL;
+- }
+- }
++ flow->flags |= FLOW_TL;
++ }
++ }
+
+- /* Check for tcp flags presence (including CWR and ECE). */
+- if (flow->proto == IPPROTO_TCP
+- && off_frag < 16
+- && psize >= 16 - off_frag) {
+- flow->tcp_flags = *((uint8_t *)(tl + 13 - off_frag));
++ /* Check for tcp flags presence (including CWR and ECE). */
++ if (flow->proto == IPPROTO_TCP
++ && off_frag < 16
++ && psize >= 16 - off_frag) {
++ flow->tcp_flags = *((uint8_t *)(tl + 13 - off_frag));
+ #if ((DEBUG) & DEBUG_C)
+- sprintf(buf, " TCP:%x", flow->tcp_flags);
+- strcat(logbuf, buf);
++ sprintf(buf, " TCP:%x", flow->tcp_flags);
++ strcat(logbuf, buf);
+ #endif
+- }
++ }
+
+ #if ((DEBUG) & DEBUG_C)
+- sprintf(buf, " => %x", (unsigned) flow);
+- strcat(logbuf, buf);
+- my_log(LOG_DEBUG, "%s", logbuf);
++ sprintf(buf, " => %x", (unsigned) flow);
++ strcat(logbuf, buf);
++ my_log(LOG_DEBUG, "%s", logbuf);
+ #endif
+
+ #if ((DEBUG) & DEBUG_I)
+- pkts_pending++;
+- pending_queue_trace_candidate = pkts_pending - pkts_pending_done;
+- if (pending_queue_trace < pending_queue_trace_candidate)
+- pending_queue_trace = pending_queue_trace_candidate;
++ pkts_pending++;
++ pending_queue_trace_candidate = pkts_pending - pkts_pending_done;
++ if (pending_queue_trace < pending_queue_trace_candidate)
++ pending_queue_trace = pending_queue_trace_candidate;
+ #endif
+
+- /* Flow complete - inform unpending_thread() about it */
+- pending_head->flags |= FLOW_PENDING;
+- pending_head = pending_head->next;
+- done:
+- pthread_cond_signal(&unpending_cond);
+- }
+- }
++ /* Flow complete - inform unpending_thread() about it */
++ pending_head->flags |= FLOW_PENDING;
++ pending_head = pending_head->next;
++done:
++ pthread_cond_signal(&unpending_cond);
++
++ return NFNL_CB_CONTINUE;
++}
++
++void *cap_thread()
++{
++ while (nfnl_catch(nflog_nfnlh(nflog_handle)) != NFNL_CB_STOP)
++ ;
++
+ return 0;
+ }
+
+ int main(int argc, char **argv)
+ {
+ char errpbuf[512];
+- char *dhost, *dport, *lhost, *type = 0, *log_suffix = 0, *rule;
++ char *dhost, *dport, *lhost, *type = 0, *log_suffix = 0;
+ int c, i, sock, memory_limit = 0;
++ struct nflog_g_handle *gh;
+ struct addrinfo hints, *res;
+ struct sockaddr_in saddr;
+ pthread_attr_t tattr;
+ struct sigaction sigact;
+ static void *threads[THREADS - 1] = {&emit_thread, &scan_thread, &unpending_thread, &cap_thread};
+ struct timeval timeout;
++ size_t s;
+
+ sched_min = sched_get_priority_min(SCHED);
+ sched_max = sched_get_priority_max(SCHED);
+@@ -1088,7 +1072,7 @@
+ }
+ }
+
+- if (parms[Uflag].count) ulog_gmask = atoi(parms[Uflag].arg);
++ if (parms[Uflag].count) nflog_gmask = atoi(parms[Uflag].arg);
+ if (parms[sflag].count) scan_interval = atoi(parms[sflag].arg);
+ if (parms[gflag].count) frag_lifetime = atoi(parms[gflag].arg);
+ if (parms[dflag].count) inactive_lifetime = atoi(parms[dflag].arg);
+@@ -1156,31 +1140,6 @@
+ }
+ }
+ if (parms[mflag].count) memory_limit = atoi(parms[mflag].arg) << 10;
+- if (parms[Xflag].count) {
+- for(i = 0; parms[Xflag].arg[i]; i++)
+- if (parms[Xflag].arg[i] == ':') nsnmp_rules++;
+- if (!(snmp_rules = malloc(nsnmp_rules * sizeof(struct snmp_rule))))
+- goto err_malloc;
+- rule = strtok(parms[Xflag].arg, ":");
+- for (i = 0; rule; i++) {
+- snmp_rules[i].len = strlen(rule);
+- if (snmp_rules[i].len > IFNAMSIZ) {
+- fprintf(stderr, "Illegal %s\n", "interface basename");
+- exit(1);
+- }
+- strncpy(snmp_rules[i].basename, rule, snmp_rules[i].len);
+- if (!*(rule - 1)) *(rule - 1) = ',';
+- rule = strtok(NULL, ",");
+- if (!rule) {
+- fprintf(stderr, "Illegal %s\n", "SNMP rule");
+- exit(1);
+- }
+- snmp_rules[i].base = atoi(rule);
+- *(rule - 1) = ':';
+- rule = strtok(NULL, ":");
+- }
+- nsnmp_rules = i;
+- }
+ if (parms[tflag].count)
+ sscanf(parms[tflag].arg, "%d:%d", &emit_rate_bytes, &emit_rate_delay);
+ if (parms[aflag].count) {
+@@ -1266,16 +1225,34 @@
+ }
+
+ if (!(cap_buf = malloc(CAPTURE_SIZE))) goto err_malloc;
+- ulog_handle = ipulog_create_handle(ulog_gmask, CAPTURE_SIZE);
+- if (!ulog_handle) {
+- fprintf(stderr, "libipulog initialization error: %s",
+- ipulog_strerror(ipulog_errno));
++ nflog_handle = nflog_open();
++ if (!nflog_handle) {
++ fprintf(stderr, "libnflog initialization error: %s",
++ strerror(nflog_errno));
+ exit(1);
+ }
+- if (sockbufsize)
+- if (setsockopt(ulog_handle->fd, SOL_SOCKET, SO_RCVBUF,
+- &sockbufsize, sizeof(sockbufsize)) < 0)
+- fprintf(stderr, "setsockopt(): %s", strerror(errno));
++
++ if (sockbufsize &&
++ nfnl_rcvbufsiz(nflog_nfnlh(nflog_handle), sockbufsize) == 0)
++ fprintf(stderr, "nfnl_rcvbufsiz(): %s", strerror(errno));
++
++ if (nflog_bind_pf(nflog_handle, PF_INET) < 0) {
++ fprintf(stderr, "libnflog failed to bind PF_INET %d: %s",
++ i, strerror(nflog_errno));
++ exit(1);
++ }
++
++ for (s = 0; s < sizeof(nflog_gmask) * 8; s++) {
++ if (!(nflog_gmask & (1UL << s)))
++ continue;
++ gh = nflog_bind_group(nflog_handle, s + 1);
++ if (!gh) {
++ fprintf(stderr, "libnflog failed to bind group %d: %s",
++ i, strerror(nflog_errno));
++ exit(1);
++ }
++ nflog_callback_register(gh, fprobe_cb, NULL);
++ }
+
+ /* Daemonize (if log destination stdout-free) */
+
+@@ -1402,15 +1379,11 @@
+ my_log(LOG_INFO, "pid: %d", pid);
+ my_log(LOG_INFO, "options: u=%u s=%u g=%u d=%u e=%u n=%u a=%s "
+ "M=%d b=%u m=%u q=%u B=%u r=%u t=%u:%u c=%s u=%s v=%u l=%u%s",
+- ulog_gmask, scan_interval, frag_lifetime, inactive_lifetime, active_lifetime,
++ nflog_gmask, scan_interval, frag_lifetime, inactive_lifetime, active_lifetime,
+ netflow->Version, inet_ntoa(saddr.sin_addr), mark_is_tos, bulk_quantity,
+ memory_limit >> 10, pending_queue_length, sockbufsize >> 10, schedp.sched_priority - 1,
+ emit_rate_bytes, emit_rate_delay, parms[cflag].count ? parms[cflag].arg : "",
+ parms[uflag].count ? parms[uflag].arg : "", verbosity, log_dest, log_suffix ? log_suffix : "");
+- for (i = 0; i < nsnmp_rules; i++) {
+- my_log(LOG_INFO, "SNMP rule #%d %s:%d",
+- i + 1, snmp_rules[i].basename, snmp_rules[i].base);
+- }
+ for (i = 0; i < npeers; i++) {
+ switch (peers[i].type) {
+ case PEER_MIRROR:
+diff -ru fprobe-ulog-1.2.orig/src/fprobe-ulog.h fprobe-ulog-1.2/src/fprobe-ulog.h
+--- fprobe-ulog-1.2.orig/src/fprobe-ulog.h 2005-01-29 21:30:41.000000000 -0200
++++ fprobe-ulog-1.2/src/fprobe-ulog.h 2015-07-10 11:23:06.479009860 -0300
+@@ -117,12 +117,6 @@
+ uint32_t seq;
+ };
+
+-struct snmp_rule {
+- char basename[IFNAMSIZ];
+- int len;
+- int base;
+-} snmp_rule_t;
+-
+ #define PEER_MIRROR 0
+ #define PEER_ROTATE 1
+