diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2017-02-14 18:36:19 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2017-02-14 18:50:10 +0000 |
commit | 2b49e4cba6b4430543020f099a37c97a596e3533 (patch) | |
tree | ace835ec5d84de0cfb9565a98d1e259b6e66413d /testing/ipt-netflow-grsec | |
parent | 24733a94a24b056f175e65c0f4cb4903ee53e85c (diff) | |
download | aports-2b49e4cba6b4430543020f099a37c97a596e3533.tar.bz2 aports-2b49e4cba6b4430543020f099a37c97a596e3533.tar.xz |
testing/ipt-netflow-grsec: upgrade to 2.2 and 4.9.9 kernel
Diffstat (limited to 'testing/ipt-netflow-grsec')
-rw-r--r-- | testing/ipt-netflow-grsec/APKBUILD | 14 | ||||
-rw-r--r-- | testing/ipt-netflow-grsec/git.patch | 3143 | ||||
-rw-r--r-- | testing/ipt-netflow-grsec/kernel-4.6.patch | 63 |
3 files changed, 68 insertions, 3152 deletions
diff --git a/testing/ipt-netflow-grsec/APKBUILD b/testing/ipt-netflow-grsec/APKBUILD index a7586dbc69..830eaff6e5 100644 --- a/testing/ipt-netflow-grsec/APKBUILD +++ b/testing/ipt-netflow-grsec/APKBUILD @@ -2,11 +2,11 @@ _flavor=grsec _kpkg=linux-$_flavor -_kver=4.4.47 +_kver=4.9.9 _kpkgrel=0 # when chaning _ver we *must* bump _mypkgrel -_ver=2.1 +_ver=2.2 _mypkgrel=0 @@ -30,7 +30,7 @@ url="http://ipt-netflow.sourceforge.net/" arch="all !aarch64" license=GPL3+ source="ipt-netflow-$_ver.tar.gz::https://github.com/aabc/ipt-netflow/archive/v$_ver.tar.gz - git.patch + kernel-4.6.patch " depends="$_kpkg-dev=$_kpkgver" makedepends="linux-${_flavor}-dev=$_kpkgver iptables-dev bash" @@ -65,9 +65,5 @@ dev() { default_dev } -md5sums="bd8fc7d609c12832f5052f342640a839 ipt-netflow-2.1.tar.gz -98c5286c6471e47d3bb25026ac406b30 git.patch" -sha256sums="a3eafe7a09f09e15d330539fab983b88c887db56e5614bc820619e8462bc7749 ipt-netflow-2.1.tar.gz -4d45daecb82ca29a513ebaed7c9bab91f0d16fa7834b52a7ff06dc0d1cd4cd3a git.patch" -sha512sums="4ec48cb4612bd99d06ed2832d165fcddaf265f0c9555c7c49e012375c38c72cd57d5ee194a6b11e32eecfd2750e710a2bd167f3f2b2597b2e880a3f9b13ba27e ipt-netflow-2.1.tar.gz -3714c78ae8e8ca432a3216c2067ec00f64f1e25985b39996907f4638835509ab587605937c81d823a9dc95cf3b963a0119eade75a3f2286d425aa0d333a44bc9 git.patch" +sha512sums="e5d9039c079abfb2ef3656d96228616514ac57d87a9c71181f132ecac51e51407bcdc62aa6e1eb43d16f98be5b22d3801c58578317ea21aaa5433ed143daabe2 ipt-netflow-2.2.tar.gz +96a250b87f8fb7d6240850dd0721aa0e1dcc7647b689abb15b07fb8758aea4338e5d169b3d0dca19e45279b38166d791cd0d412a9f4b44caf028cee2e782b72b kernel-4.6.patch" diff --git a/testing/ipt-netflow-grsec/git.patch b/testing/ipt-netflow-grsec/git.patch deleted file mode 100644 index 643da202c6..0000000000 --- a/testing/ipt-netflow-grsec/git.patch +++ /dev/null @@ -1,3143 +0,0 @@ -diff --git a/CREDITS b/CREDITS -index 51e736e..e3fb344 100644 ---- a/CREDITS -+++ b/CREDITS -@@ -48,6 +48,12 @@ Principal author and project maintainer: - ABC <abc@telekom.ru> [2008-2015] - - -+Compatibility layer is using code from Linux Kernel and should be -+attributed to respective Linux developers. -+ -+MurmurHash3 is based on smhasher (2012) of Austin Appleby. -+ -+ - Patch authors and submitters: - - Ilya Evseev [2010] -@@ -82,6 +88,7 @@ Extensive testing and other help: - Andrew Savin @ Starlink [2014] - Alexander Zakharov @ WAW Technologies [2015] - Ivanov Eduard [2015] -+ Maciej Zdeb [2015] - - - (Send your names, emails, or nicks to add to the list.) -diff --git a/Makefile.in b/Makefile.in -index e96d50b..d72cb90 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -20,15 +20,18 @@ ccflags-y = @KOPTS@ - - all: ipt_NETFLOW.ko libipt_NETFLOW.so libip6t_NETFLOW.so @SNMPTARGET@ - --ipt_NETFLOW.ko: version.h ipt_NETFLOW.c ipt_NETFLOW.h Makefile -+ipt_NETFLOW.ko: version.h ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile - @echo Compiling for kernel $(KVERSION) - make -C $(KDIR) M=$(CURDIR) modules CONFIG_DEBUG_INFO=y - @touch $@ --sparse: | version.h ipt_NETFLOW.c ipt_NETFLOW.h Makefile -+sparse: | version.h ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile - @rm -f ipt_NETFLOW.ko ipt_NETFLOW.o - @echo Compiling for kernel $(KVERSION) - make -C $(KDIR) M=$(CURDIR) modules C=1 - @touch ipt_NETFLOW.ko -+coverity: -+ coverity-submit -v -+ - minstall: | ipt_NETFLOW.ko - @echo " *" - make -C $(KDIR) M=$(CURDIR) modules_install INSTALL_MOD_PATH=$(DESTDIR) -@@ -66,7 +69,7 @@ sinstall: | snmp_NETFLOW.so IPT-NETFLOW-MIB.my - %.so: %_sh.o - gcc -shared -o $@ $< - --version.h: ipt_NETFLOW.c ipt_NETFLOW.h Makefile -+version.h: ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile - @./version.sh --define > version.h - - linstall: | libipt_NETFLOW.so libip6t_NETFLOW.so -@@ -113,3 +116,8 @@ unload: - -rmmod ipt_NETFLOW.ko - - reload: unload load -+ -+ChangeLog: -+ gitlog-to-changelog > ChangeLog -+.PHONY: ChangeLog -+ -diff --git a/README b/README -index d524b17..c82cdf7 100644 ---- a/README -+++ b/README -@@ -1,4 +1,4 @@ --ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. -+ipt_NETFLOW linux 2.6.x-4.x kernel module by <abc@telekom.ru> -- 2008-2015. - - High performance NetFlow v5, v9, IPFIX flow data export module for Linux - kernel. Created to be useful for highly loaded linux router. It should be -@@ -39,9 +39,9 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - Such as metering, exporting, sampling stat and reliability stat, sampling - configuration, network devices ifName, ifDescr list. - -- * Tested to compile and work out of the box on Centos 5, 6, 7, and Debian. -- Many vanilla Linux kernels since 2.6.18 up to the latest (as of writing -- is 3.16) are supported and tested. -+ * Tested to compile and work out of the box on Centos 5, 6, 7, Debian and -+ * Ubuntu. Many vanilla Linux kernels since 2.6.18 up to the latest (as of -+ * writing is 3.19) are supported and tested. - - * Module load time and run-time (via sysctl) configuration. - -@@ -52,14 +52,15 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - * SNMP-index translation rules, let convert meaningless and unstable - interface indexes (ifIndex) to more meaningful numbering scheme. - -- * Easy support for catching mirrored traffic with promisc option. -+ * Easy support for catching mirrored traffic with promisc option. Which is -+ also supporting optional MPLS decapsulation and MPLS-aware NetFlow. - - - ============================ - = OBTAINING LATEST VERSION = - ============================ - -- $ git clone git://git.code.sf.net/p/ipt-netflow/code ipt-netflow -+ $ git clone git://github.com/aabc/ipt-netflow.git ipt-netflow - $ cd ipt-netflow - - -@@ -79,7 +80,7 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - - ~# yum install kernel-devel - -- b) What to do for Debian: -+ b) What to do for Debian and Ubuntu: - - ~# apt-get install module-assistant - ~# m-a prepare -@@ -118,7 +119,7 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - - # yum install iptables-devel - -- b) What to do for Debian: -+ b) What to do for Debian or Ubuntu: - - # apt-get install iptables-dev pkg-config - -@@ -134,7 +135,7 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - - # yum install net-snmp net-snmp-devel - -- b) For Debian: -+ b) For Debian or Ubuntu: - - # apt-get install snmpd libsnmp-dev - -@@ -161,6 +162,14 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - c) If you have sources in non-standard places or configure isn't able to - find something run ./configure --help to see how to specify paths manually. - -+ d) To run irqtop on Debian 8 you may need to install: -+ -+ # apt-get install ruby ruby-dev ncurses-dev -+ # gem install curses -+ -+ z) If all fails create ticket at -+ https://github.com/aabc/ipt-netflow/issues -+ - ** 5. After this point you should be able to load module and - use -j NETFLOW target in your iptables. See next section. - -@@ -227,6 +236,25 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - only disable auto-install into DKMS, but still create dkms.conf, in - case you will want to install it manually. - -+ --enable-physdev -+ Export ingressPhysicalInterface(252) and egressPhysicalInterface(253) -+ (relevant for bridges) in V9 and IPFIX. If your collector does not -+ support these Elements but you still need physdevs then use -+ --enable-physdev-override, in that case physdevs will override normal -+ interface numbers ingressInterface(10) and egressInterface(14). -+ -+ --enable-promisc -+ Enables capturing of promiscuous packets into raw/PREROUTING chain. -+ See README.promisc Solution 1 for usage details and example. -+ -+ --promisc-mpls -+ Enables MPLS label stack decapsulation for promiscuous packets. (For -+ IPv4 and IPv6 packets only). This also enables MPLS-aware NetFlow (v9 -+ and IPFIX), you may wish to specify with --promisc-mpls=n how much MPLS -+ labels you want to be recorded and exported (default is 3, maximum is -+ 10, set to 0 to not report anything). -+ -+ - =========== - = RUNNING = - =========== -@@ -381,10 +409,15 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - because NetFlow v5 isn't compatible with IPv6. - - destination=127.0.0.1:2055 -- - where to export netflow, to this ip address -- You will see this connection in netstat like this: -+ - where to export netflow, to this ip address. Port is optional, default -+ is 2055. You will see this connection in netstat like this: -+ - udp 0 0 127.0.0.1:32772 127.0.0.1:2055 ESTABLISHED - -+ destination=[2001:db8::1]:2055 -+ - export target using IPv6 address. Brackets are optional, but otherwise -+ you should delimit port with 'p' or '#' character. -+ - destination=127.0.0.1:2055,192.0.0.1:2055 - - mirror flows to two (can be more) addresses, separate addresses - with comma. -@@ -523,13 +556,25 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - snmp-rules are compilation disabled by default, to enable you will need - to add --enable-snmp option to ./configure script. - -- scan-min = 1 -+ scan-min=1 - - Minimal interval between flow export scans. Sometimes could be useful - to reduce load on exporting CPU by increasing this interval. Value are - in kernel jiffies units (which is x/HZ seconds). - -- promisc = 1 -- - Enable promisc hack. See README.promisc Solution.1 for details. -+ promisc=1 -+ - Enables promisc hack. See README.promisc Solution 1 for details. -+ -+ exportcpu=number -+ - Lock exporter to single CPU. This may be useful to fine control CPU -+ load. Common use case: with smp_affinity and RSS you spread packet -+ processing to all CPUs except one, and lock it to the exporter. While -+ exporter CPU load generally is not high, for someone it may be not -+ desirable to combine it with packet processing on very highly loaded -+ routers. -+ -+ This option also could be changed at runtime with: -+ -+ # echo number > /sys/module/ipt_NETFLOW/parameters/exportcpu - - - ==================== -@@ -722,17 +767,26 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015. - IP TOS: ipClassOfService(5), - and address family (IP or IPv6). - -- If VLAN exporting is enabled: -+ Additional Flow Keys if VLAN exporting is enabled: -+ - First (outer) dot1q VLAN tag: dot1qVlanId(243) and - dot1qPriority(244) for IPFIX, - or vlanId(243) for NetFlow v9. - Second (customer) dot1q VLAN tag: dot1qCustomerVlanId(245) - and dot1qCustomerPriority(246). - -- If MAC address exporting is enabled: -+ Additional Flow Keys if MAC address exporting is enabled: -+ - Destination MAC address: destinationMacAddress(80), - Source MAC address: sourceMacAddress(56). - -+ Additional Flow Keys if MPLS-aware NetFlow is enabled: -+ -+ Captured MPLS stack is fully treated as flow key (including TTL values), -+ which is Elements from mplsTopLabelStackSection(70) to -+ mplsLabelStackSection10(79), and, if present, mplsTopLabelTTL(200). -+ -+ - Other Elements are not Flow Keys. Note that outer interface, which is - egressInterface(14), is not regarded as Flow Key. Quoting RFC 7012: "For - Information Elements ... for which the value may change from packet to packet -diff --git a/compat.h b/compat.h -new file mode 100644 -index 0000000..2b05994 ---- /dev/null -+++ b/compat.h -@@ -0,0 +1,598 @@ -+/* This code is derived from the Linux Kernel sources intended -+ * to maintain compatibility with different Kernel versions. -+ * Copyright of original source is of respective Linux Kernel authors. -+ * License is GPLv2. -+ */ -+ -+#ifndef COMPAT_NETFLOW_H -+#define COMPAT_NETFLOW_H -+ -+ -+#ifndef NIPQUAD -+# define NIPQUAD(addr) \ -+ ((unsigned char *)&addr)[0], \ -+ ((unsigned char *)&addr)[1], \ -+ ((unsigned char *)&addr)[2], \ -+ ((unsigned char *)&addr)[3] -+#endif -+#ifndef HIPQUAD -+# if defined(__LITTLE_ENDIAN) -+# define HIPQUAD(addr) \ -+ ((unsigned char *)&addr)[3], \ -+ ((unsigned char *)&addr)[2], \ -+ ((unsigned char *)&addr)[1], \ -+ ((unsigned char *)&addr)[0] -+# elif defined(__BIG_ENDIAN) -+# define HIPQUAD NIPQUAD -+# else -+# error "Please fix asm/byteorder.h" -+# endif /* __LITTLE_ENDIAN */ -+#endif -+ -+#ifndef IPT_CONTINUE -+# define IPT_CONTINUE XT_CONTINUE -+# define ipt_target xt_target -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) -+union nf_inet_addr { -+ __be32 ip; -+ __be32 ip6[4]; -+ struct in_addr in; -+ struct in6_addr in6; -+}; -+#endif -+ -+#ifndef list_first_entry -+#define list_first_entry(ptr, type, member) \ -+ list_entry((ptr)->next, type, member) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) -+# define INIT_NET(x) x -+#else -+# define INIT_NET(x) init_net.x -+#endif -+ -+#ifndef ETH_P_8021AD -+# define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ -+#endif -+ -+#ifndef ETH_P_QINQ1 -+# define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN */ -+# define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN */ -+# define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN */ -+#endif -+ -+#ifndef IPPROTO_MH -+# define IPPROTO_MH 135 -+#endif -+ -+#ifdef CONFIG_SYSCTL -+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) -+# define BEFORE2632(x,y) x,y -+# else /* since 2.6.32 */ -+# define BEFORE2632(x,y) -+# endif -+ -+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) -+# define ctl_table struct ctl_table -+# endif -+ -+# ifndef HAVE_GRSECURITY_H -+# define ctl_table_no_const ctl_table -+# endif -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) -+# define compat_hlist_for_each_entry hlist_for_each_entry -+# define compat_hlist_for_each_entry_safe hlist_for_each_entry_safe -+#else /* since 3.9.0 */ -+# define compat_hlist_for_each_entry(a,pos,c,d) hlist_for_each_entry(a,c,d) -+# define compat_hlist_for_each_entry_safe(a,pos,c,d,e) hlist_for_each_entry_safe(a,c,d,e) -+#endif -+ -+#ifndef WARN_ONCE -+#define WARN_ONCE(x,fmt...) ({ if (x) printk(KERN_WARNING fmt); }) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -+# define IPPROTO_UDPLITE 136 -+#endif -+ -+#ifndef time_is_before_jiffies -+# define time_is_before_jiffies(a) time_after(jiffies, a) -+#endif -+#ifndef time_is_after_jiffies -+# define time_is_after_jiffies(a) time_before(jiffies, a) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) -+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -+# define prandom_u32 get_random_int -+# elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) -+# define prandom_u32 random32 -+#endif -+#define prandom_u32_max compat_prandom_u32_max -+static inline u32 prandom_u32_max(u32 ep_ro) -+{ -+ return (u32)(((u64) prandom_u32() * ep_ro) >> 32); -+} -+#endif -+ -+#ifndef min_not_zero -+# define min_not_zero(x, y) ({ \ -+ typeof(x) __x = (x); \ -+ typeof(y) __y = (y); \ -+ __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); }) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) -+static int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -+{ -+ ASSERT_RTNL(); -+ -+ if (!dev->ethtool_ops->get_settings) -+ return -EOPNOTSUPP; -+ -+ memset(cmd, 0, sizeof(struct ethtool_cmd)); -+ cmd->cmd = ETHTOOL_GSET; -+ return dev->ethtool_ops->get_settings(dev, cmd); -+} -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) -+# define ethtool_cmd_speed(x) (x)->speed -+#endif -+ -+#ifndef ARPHRD_PHONET -+# define ARPHRD_PHONET 820 -+# define ARPHRD_PHONET_PIPE 821 -+#endif -+#ifndef ARPHRD_IEEE802154 -+# define ARPHRD_IEEE802154 804 -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -+# define for_each_netdev_ns(net, dev) for (dev = dev_base; dev; dev = dev->next) -+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) -+# define for_each_netdev_ns(net, d) for_each_netdev(d) -+#else -+# define for_each_netdev_ns(net, d) for_each_netdev(net, d) -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) -+# define CHECK_FAIL 0 -+# define CHECK_OK 1 -+#else -+# define CHECK_FAIL -EINVAL -+# define CHECK_OK 0 -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) -+# define use_module ref_module -+#endif -+ -+#ifndef NF_IP_LOCAL_IN /* 2.6.25 */ -+# define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING -+# define NF_IP_LOCAL_IN NF_INET_LOCAL_IN -+# define NF_IP_FORWARD NF_INET_FORWARD -+# define NF_IP_LOCAL_OUT NF_INET_LOCAL_OUT -+# define NF_IP_POST_ROUTING NF_INET_POST_ROUTING -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -+/* net/netfilter/x_tables.c */ -+static void xt_unregister_targets(struct xt_target *target, unsigned int n) -+{ -+ unsigned int i; -+ -+ for (i = 0; i < n; i++) -+ xt_unregister_target(&target[i]); -+} -+static int xt_register_targets(struct xt_target *target, unsigned int n) -+{ -+ unsigned int i; -+ -+ int err = 0; -+ for (i = 0; i < n; i++) -+ if ((err = xt_register_target(&target[i]))) -+ goto err; -+ return err; -+err: -+ if (i > 0) -+ xt_unregister_targets(target, i); -+ return err; -+} -+#endif -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) -+#define num_physpages totalram_pages -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) -+# ifdef ktime_to_timeval -+/* ktime_to_timeval is defined on 64bit and inline on 32bit cpu */ -+/* when it's defined it calls ns_to_timeval, which is not exported */ -+struct timeval portable_ns_to_timeval(const s64 nsec) -+{ -+ struct timespec ts = ns_to_timespec(nsec); -+ struct timeval tv; -+ -+ tv.tv_sec = ts.tv_sec; -+ tv.tv_usec = (suseconds_t) ts.tv_nsec / 1000; -+ -+ return tv; -+} -+# define ns_to_timeval portable_ns_to_timeval -+# endif -+ -+static inline s64 portable_ktime_to_ms(const ktime_t kt) -+{ -+ struct timeval tv = ktime_to_timeval(kt); -+ return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC; -+} -+# define ktime_to_ms portable_ktime_to_ms -+#endif /* before 2.6.35 */ -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) -+static inline s64 portable_ktime_to_us(const ktime_t kt) -+{ -+ struct timeval tv = ktime_to_timeval(kt); -+ return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec; -+} -+#define ktime_to_us portable_ktime_to_us -+#endif -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) -+static inline void put_unaligned_be16(u16 val, void *p) -+{ -+ put_unaligned(cpu_to_be16(val), (__be16 *)p); -+} -+static inline void put_unaligned_be32(u32 val, void *p) -+{ -+ put_unaligned(cpu_to_be32(val), (__be32 *)p); -+} -+static inline void put_unaligned_be64(u64 val, void *p) -+{ -+ put_unaligned(cpu_to_be64(val), (__be64 *)p); -+} -+#endif -+ -+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) && !defined(RHEL_MAJOR) -+static void *__seq_open_private(struct file *f, struct seq_operations *ops, -+ int psize) -+{ -+ int rc; -+ void *private; -+ struct seq_file *seq; -+ -+ private = kzalloc(psize, GFP_KERNEL); -+ if (private == NULL) -+ goto out; -+ -+ rc = seq_open(f, ops); -+ if (rc < 0) -+ goto out_free; -+ -+ seq = f->private_data; -+ seq->private = private; -+ return private; -+ -+out_free: -+ kfree(private); -+out: -+ return NULL; -+} -+#endif -+ -+/* disappeared in v3.19 */ -+#ifndef __get_cpu_var -+#define __get_cpu_var(var) (*this_cpu_ptr(&(var))) -+#endif -+ -+#ifndef MPLS_HLEN -+#define MPLS_HLEN 4 -+static inline int eth_p_mpls(__be16 eth_type) -+{ -+ return eth_type == htons(ETH_P_MPLS_UC) || -+ eth_type == htons(ETH_P_MPLS_MC); -+} -+#endif -+#ifndef MPLS_LS_S_MASK -+struct mpls_label { -+ __be32 entry; -+}; -+#define MPLS_LS_S_MASK 0x00000100 -+ -+#endif -+ -+/* sockaddr comparison functions is from fs/nfs/client.c */ -+static int sockaddr_match_ipaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2) -+{ -+ const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; -+ const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; -+ -+ if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr)) -+ return 0; -+#if 0 -+ else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL) -+ return sin1->sin6_scope_id == sin2->sin6_scope_id; -+#endif -+ return 1; -+} -+ -+static int sockaddr_match_ipaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2) -+{ -+ const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; -+ const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; -+ -+ return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; -+} -+ -+static int sockaddr_cmp_ip6(const struct sockaddr *sa1, const struct sockaddr *sa2) -+{ -+ const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; -+ const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; -+ -+ return sockaddr_match_ipaddr6(sa1, sa2) && -+ (sin1->sin6_port == sin2->sin6_port); -+} -+ -+static int sockaddr_cmp_ip4(const struct sockaddr *sa1, const struct sockaddr *sa2) -+{ -+ const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; -+ const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; -+ -+ return sockaddr_match_ipaddr4(sa1, sa2) && -+ (sin1->sin_port == sin2->sin_port); -+} -+ -+static int sockaddr_cmp(const struct sockaddr_storage *sa1, const struct sockaddr_storage *sa2) -+{ -+ const struct sockaddr *s1 = (const struct sockaddr *)sa1; -+ const struct sockaddr *s2 = (const struct sockaddr *)sa2; -+ -+ if (sa1->ss_family != sa2->ss_family) -+ return 0; -+ -+ switch (sa1->ss_family) { -+ case AF_INET: -+ return sockaddr_cmp_ip4(s1, s2); -+ case AF_INET6: -+ return sockaddr_cmp_ip6(s1, s2); -+ } -+ return 0; -+} -+ -+#ifndef IN6PTON_XDIGIT -+#define hex_to_bin compat_hex_to_bin -+/* lib/hexdump.c */ -+int hex_to_bin(char ch) -+{ -+ if ((ch >= '0') && (ch <= '9')) -+ return ch - '0'; -+ ch = tolower(ch); -+ if ((ch >= 'a') && (ch <= 'f')) -+ return ch - 'a' + 10; -+ return -1; -+} -+ -+/* net/core/utils.c */ -+#define IN6PTON_XDIGIT 0x00010000 -+#define IN6PTON_DIGIT 0x00020000 -+#define IN6PTON_COLON_MASK 0x00700000 -+#define IN6PTON_COLON_1 0x00100000 /* single : requested */ -+#define IN6PTON_COLON_2 0x00200000 /* second : requested */ -+#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */ -+#define IN6PTON_DOT 0x00800000 /* . */ -+#define IN6PTON_DELIM 0x10000000 -+#define IN6PTON_NULL 0x20000000 /* first/tail */ -+#define IN6PTON_UNKNOWN 0x40000000 -+ -+static inline int xdigit2bin(char c, int delim) -+{ -+ int val; -+ -+ if (c == delim || c == '\0') -+ return IN6PTON_DELIM; -+ if (c == ':') -+ return IN6PTON_COLON_MASK; -+ if (c == '.') -+ return IN6PTON_DOT; -+ -+ val = hex_to_bin(c); -+ if (val >= 0) -+ return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0); -+ -+ if (delim == -1) -+ return IN6PTON_DELIM; -+ return IN6PTON_UNKNOWN; -+} -+ -+int in4_pton(const char *src, int srclen, -+ u8 *dst, -+ int delim, const char **end) -+{ -+ const char *s; -+ u8 *d; -+ u8 dbuf[4]; -+ int ret = 0; -+ int i; -+ int w = 0; -+ -+ if (srclen < 0) -+ srclen = strlen(src); -+ s = src; -+ d = dbuf; -+ i = 0; -+ while(1) { -+ int c; -+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim); -+ if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) { -+ goto out; -+ } -+ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) { -+ if (w == 0) -+ goto out; -+ *d++ = w & 0xff; -+ w = 0; -+ i++; -+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { -+ if (i != 4) -+ goto out; -+ break; -+ } -+ goto cont; -+ } -+ w = (w * 10) + c; -+ if ((w & 0xffff) > 255) { -+ goto out; -+ } -+cont: -+ if (i >= 4) -+ goto out; -+ s++; -+ srclen--; -+ } -+ ret = 1; -+ memcpy(dst, dbuf, sizeof(dbuf)); -+out: -+ if (end) -+ *end = s; -+ return ret; -+} -+ -+int in6_pton(const char *src, int srclen, -+ u8 *dst, -+ int delim, const char **end) -+{ -+ const char *s, *tok = NULL; -+ u8 *d, *dc = NULL; -+ u8 dbuf[16]; -+ int ret = 0; -+ int i; -+ int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL; -+ int w = 0; -+ -+ memset(dbuf, 0, sizeof(dbuf)); -+ -+ s = src; -+ d = dbuf; -+ if (srclen < 0) -+ srclen = strlen(src); -+ -+ while (1) { -+ int c; -+ -+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim); -+ if (!(c & state)) -+ goto out; -+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { -+ /* process one 16-bit word */ -+ if (!(state & IN6PTON_NULL)) { -+ *d++ = (w >> 8) & 0xff; -+ *d++ = w & 0xff; -+ } -+ w = 0; -+ if (c & IN6PTON_DELIM) { -+ /* We've processed last word */ -+ break; -+ } -+ /* -+ * COLON_1 => XDIGIT -+ * COLON_2 => XDIGIT|DELIM -+ * COLON_1_2 => COLON_2 -+ */ -+ switch (state & IN6PTON_COLON_MASK) { -+ case IN6PTON_COLON_2: -+ dc = d; -+ state = IN6PTON_XDIGIT | IN6PTON_DELIM; -+ if (dc - dbuf >= sizeof(dbuf)) -+ state |= IN6PTON_NULL; -+ break; -+ case IN6PTON_COLON_1|IN6PTON_COLON_1_2: -+ state = IN6PTON_XDIGIT | IN6PTON_COLON_2; -+ break; -+ case IN6PTON_COLON_1: -+ state = IN6PTON_XDIGIT; -+ break; -+ case IN6PTON_COLON_1_2: -+ state = IN6PTON_COLON_2; -+ break; -+ default: -+ state = 0; -+ } -+ tok = s + 1; -+ goto cont; -+ } -+ -+ if (c & IN6PTON_DOT) { -+ ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s); -+ if (ret > 0) { -+ d += 4; -+ break; -+ } -+ goto out; -+ } -+ -+ w = (w << 4) | (0xff & c); -+ state = IN6PTON_COLON_1 | IN6PTON_DELIM; -+ if (!(w & 0xf000)) { -+ state |= IN6PTON_XDIGIT; -+ } -+ if (!dc && d + 2 < dbuf + sizeof(dbuf)) { -+ state |= IN6PTON_COLON_1_2; -+ state &= ~IN6PTON_DELIM; -+ } -+ if (d + 2 >= dbuf + sizeof(dbuf)) { -+ state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2); -+ } -+cont: -+ if ((dc && d + 4 < dbuf + sizeof(dbuf)) || -+ d + 4 == dbuf + sizeof(dbuf)) { -+ state |= IN6PTON_DOT; -+ } -+ if (d >= dbuf + sizeof(dbuf)) { -+ state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK); -+ } -+ s++; -+ srclen--; -+ } -+ -+ i = 15; d--; -+ -+ if (dc) { -+ while(d >= dc) -+ dst[i--] = *d--; -+ while(i >= dc - dbuf) -+ dst[i--] = 0; -+ while(i >= 0) -+ dst[i--] = *d--; -+ } else -+ memcpy(dst, dbuf, sizeof(dbuf)); -+ -+ ret = 1; -+out: -+ if (end) -+ *end = s; -+ return ret; -+} -+#endif /* IN6PTON_XDIGIT */ -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0) -+# define sock_create_kern(f, t, p, s) sock_create_kern(&init_net, f, t, p, s) -+#endif -+ -+#if !defined(vlan_tx_tag_get) && defined(skb_vlan_tag_get) -+# define vlan_tx_tag_get skb_vlan_tag_get -+# define vlan_tx_tag_present skb_vlan_tag_present -+#endif -+ -+#ifndef NF_HOOK -+# define NF_HOOK_COMPAT NF_HOOK -+#else -+# define NF_HOOK_COMPAT(a,b,c,d,e,f,g) NF_HOOK(a,b,d,e,f,g) -+#endif -+ -+#endif /* COMPAT_NETFLOW_H */ -diff --git a/configure b/configure -index 30a928c..1278c61 100755 ---- a/configure -+++ b/configure -@@ -263,7 +263,6 @@ show_help() { - echo " --kver=.. kernel version (ex.: 2.6.30-std-def-alt15)" - echo " --kdir=.. directory for kernel source (ex.: /usr/src/kernel)" - echo " --enable-natevents enables natevents support" -- echo " --enable-debugfs enables debugfs support for flow lists" - echo " --enable-snmp-rules enables SNMP-index conversion rules" - echo " --enable-macaddress enables MAC address for v9/IPFIX" - echo " --enable-vlan enables VLAN Ids for v9/IPFIX" -@@ -271,7 +270,11 @@ show_help() { - echo " --enable-sampler enables Flow Sampling" - echo " --enable-sampler=hash enables Hash sampler" - echo " --enable-aggregation enables aggregation rules" -- echo " --enable-promisc enables promisc hack" -+ echo " --enable-promisc enables promisc hack mode" -+ echo " --promisc-mpls decapsulate MPLS in promisc mode" -+ echo " --promisc-mpls=N -- and record N labels (default 3)" -+ echo " --enable-physdev enables physdev reporting" -+ echo " --enable-physdev-override to override interfaces" - echo " --disable-snmp-agent disables net-snmp agent" - echo " --disable-dkms disables DKMS support completely" - echo " --disable-dkms-install no DKMS install but still create dkms.conf" -@@ -295,15 +298,17 @@ do - --kver=*) KVERSION="$ac_optarg" ;; - --kdir=*) KDIR="$ac_optarg" ;; - --enable-nat*) KOPTS="$KOPTS -DENABLE_NAT" ;; -- --enable-debug*) KOPTS="$KOPTS -DENABLE_DEBUGFS" ;; - --enable-mac*) KOPTS="$KOPTS -DENABLE_MAC" ;; - --enable-vlan*) KOPTS="$KOPTS -DENABLE_VLAN" ;; - --enable-direc*) KOPTS="$KOPTS -DENABLE_DIRECTION" ;; - --enable-sampl*hash) KOPTS="$KOPTS -DENABLE_SAMPLER -DSAMPLING_HASH" ;; - --enable-sampl*) KOPTS="$KOPTS -DENABLE_SAMPLER" ;; - --enable-aggr*) KOPTS="$KOPTS -DENABLE_AGGR" ;; -- --enable-promi*) KOPTS="$KOPTS -DENABLE_PROMISC" ;; -+ --enable-promi*) ENABLE_PROMISC=1 ;; -+ --promisc-mpls*) ENABLE_PROMISC=1; PROMISC_MPLS=1; MPLS_DEPTH="$ac_optarg" ;; - --enable-snmp-r*) KOPTS="$KOPTS -DENABLE_SNMP" ;; -+ --enable-physdev) KOPTS="$KOPTS -DENABLE_PHYSDEV" ;; -+ --enable-physdev-over*) KOPTS="$KOPTS -DENABLE_PHYSDEV_OVER" ;; - --disable-snmp-a*) SKIPSNMP=1 ;; - --disable-net-snmp*) SKIPSNMP=1 ;; - --disable-dkms*) SKIPDKMS=1 ;; -@@ -316,6 +321,18 @@ do - esac - done - -+if [ "$ENABLE_PROMISC" = 1 ]; then KOPTS="$KOPTS -DENABLE_PROMISC"; fi -+if [ "$PROMISC_MPLS" = 1 ]; then -+ KOPTS="$KOPTS -DPROMISC_MPLS" -+ if [ "$MPLS_DEPTH" -gt 10 ]; then -+ echo "! Requested MPLS stack depth is too big, limiting to 10." -+ MPLS_DEPTH=10; -+ elif [ ! "$MPLS_DEPTH" ]; then -+ MPLS_DEPTH=3 -+ fi -+ if [ "$MPLS_DEPTH" -ge 1 ]; then KOPTS="$KOPTS -DMPLS_DEPTH=$MPLS_DEPTH"; fi -+fi -+ - kernel_find_version() { - KHOW=requested - test "$KVERSION" && return 0 -@@ -436,6 +453,7 @@ kernel_check_include() { - - kernel_check_features() { - kernel_check_include include/linux/llist.h -DHAVE_LLIST -+ kernel_check_include include/linux/grsecurity.h -DHAVE_GRSECURITY_H - } - - snmp_check() { -diff --git a/ipt_NETFLOW.c b/ipt_NETFLOW.c -index f6bd7a8..2d5e95b 100644 ---- a/ipt_NETFLOW.c -+++ b/ipt_NETFLOW.c -@@ -26,6 +26,8 @@ - #include <linux/seq_file.h> - #include <linux/random.h> - #include <linux/in6.h> -+#include <linux/inet.h> -+#include <linux/kernel.h> - #include <linux/ip.h> - #include <linux/udp.h> - #include <linux/icmp.h> -@@ -51,69 +53,37 @@ - #ifndef ENABLE_NAT - # undef CONFIG_NF_NAT_NEEDED - #endif --#ifdef ENABLE_VLAN --#include <linux/if_vlan.h> -+#if defined(ENABLE_VLAN) || defined(ENABLE_PROMISC) -+# include <linux/if_vlan.h> - #endif - #ifdef ENABLE_MAC --#include <linux/if_ether.h> --#include <linux/etherdevice.h> -+# include <linux/if_ether.h> -+# include <linux/etherdevice.h> - #endif - #if defined(CONFIG_NF_NAT_NEEDED) --#include <linux/notifier.h> --#include <net/netfilter/nf_conntrack.h> --#include <net/netfilter/nf_conntrack_core.h> -+# include <linux/notifier.h> -+# include <net/netfilter/nf_conntrack.h> -+# include <net/netfilter/nf_conntrack_core.h> - #endif - #include <linux/version.h> - #include <asm/unaligned.h> - #ifdef HAVE_LLIST - /* llist.h is officially defined since linux 3.1, - * but centos6 have it backported on its 2.6.32.el6 */ --#include <linux/llist.h> -+# include <linux/llist.h> - #endif -+#include "compat.h" - #include "ipt_NETFLOW.h" - #include "murmur3.h" - #ifdef CONFIG_BRIDGE_NETFILTER --#include <linux/netfilter_bridge.h> -+# include <linux/netfilter_bridge.h> - #endif - #ifdef CONFIG_SYSCTL --#include <linux/sysctl.h> --#endif --#ifdef ENABLE_DEBUGFS --# ifdef CONFIG_DEBUG_FS --# include <linux/debugfs.h> --# else --# undef ENABLE_DEBUGFS --# endif -+# include <linux/sysctl.h> - #endif - #ifndef CONFIG_NF_CONNTRACK_EVENTS - /* No conntrack events in the kernel imply no natevents. */ --#undef CONFIG_NF_NAT_NEEDED --#endif -- --#ifndef NIPQUAD --#define NIPQUAD(addr) \ -- ((unsigned char *)&addr)[0], \ -- ((unsigned char *)&addr)[1], \ -- ((unsigned char *)&addr)[2], \ -- ((unsigned char *)&addr)[3] --#endif --#ifndef HIPQUAD --#if defined(__LITTLE_ENDIAN) --#define HIPQUAD(addr) \ -- ((unsigned char *)&addr)[3], \ -- ((unsigned char *)&addr)[2], \ -- ((unsigned char *)&addr)[1], \ -- ((unsigned char *)&addr)[0] --#elif defined(__BIG_ENDIAN) --#define HIPQUAD NIPQUAD --#else --#error "Please fix asm/byteorder.h" --#endif /* __LITTLE_ENDIAN */ --#endif -- --#ifndef IPT_CONTINUE --#define IPT_CONTINUE XT_CONTINUE --#define ipt_target xt_target -+# undef CONFIG_NF_NAT_NEEDED - #endif - - #define IPT_NETFLOW_VERSION "2.1" /* Note that if you are using git, you -@@ -339,7 +309,7 @@ static int metric = METRIC_DFL, - - static int set_hashsize(int new_size); - static void destination_removeall(void); --static int add_destinations(char *ptr); -+static int add_destinations(const char *ptr); - static int netflow_scan_and_export(int flush); - enum { - DONT_FLUSH, AND_FLUSH -@@ -351,10 +321,6 @@ static int tpl_count = 0; /* how much active templates */ - static unsigned long ts_stat_last = 0; /* (jiffies) */ - static unsigned long ts_sysinf_last = 0; /* (jiffies) */ - static unsigned long ts_ifnames_last = 0; /* (jiffies) */ --#ifdef ENABLE_DEBUGFS --static atomic_t freeze = ATOMIC_INIT(0); --static struct dentry *flows_dump_d; --#endif - - static inline __be32 bits2mask(int bits) { - return (bits? 0xffffffff << (32 - bits) : 0); -@@ -424,12 +390,6 @@ static inline void pause_scan_worker(void) - _unschedule_scan_worker(); - } - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) --#define INIT_NET(x) x --#else --#define INIT_NET(x) init_net.x --#endif -- - #ifdef ENABLE_SAMPLER - static inline unsigned char get_sampler_mode(void) - { -@@ -457,6 +417,55 @@ static inline unsigned short sampler_nf_v5(void) - } - #endif - -+/* return value is different from usual snprintf */ -+static char *snprintf_sockaddr(char *buf, size_t len, const struct sockaddr_storage *ss) -+{ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) -+ if (ss->ss_family == AF_INET) { -+ const struct sockaddr_in *sin = (struct sockaddr_in *)ss; -+ -+ snprintf(buf, len, "%u.%u.%u.%u:%u", -+ NIPQUAD(sin->sin_addr.s_addr), -+ ntohs(sin->sin_port)); -+ } else if (ss->ss_family == AF_INET6) { -+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss; -+ -+ snprintf(buf, len, "[%x:%x:%x:%x:%x:%x:%x:%x]:%u", -+ ntohs(sin6->sin6_addr.s6_addr16[0]), -+ ntohs(sin6->sin6_addr.s6_addr16[1]), -+ ntohs(sin6->sin6_addr.s6_addr16[2]), -+ ntohs(sin6->sin6_addr.s6_addr16[3]), -+ ntohs(sin6->sin6_addr.s6_addr16[4]), -+ ntohs(sin6->sin6_addr.s6_addr16[5]), -+ ntohs(sin6->sin6_addr.s6_addr16[6]), -+ ntohs(sin6->sin6_addr.s6_addr16[7]), -+ ntohs(sin6->sin6_port)); -+ } else -+ snprintf(buf, len, "(invalid address)"); -+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0) -+ if (ss->ss_family == AF_INET) -+ snprintf(buf, len, "%pI4:%u", -+ &((const struct sockaddr_in *)ss)->sin_addr, -+ ntohs(((const struct sockaddr_in *)ss)->sin_port)); -+ else if (ss->ss_family == AF_INET6) -+ snprintf(buf, len, "[%pI6c]:%u", -+ &((const struct sockaddr_in6 *)ss)->sin6_addr, -+ ntohs(((const struct sockaddr_in6 *)ss)->sin6_port)); -+ else -+ snprintf(buf, len, "(invalid address)"); -+#else -+ snprintf(buf, len, "%pISpc", ss); -+#endif -+ return buf; -+} -+ -+static char *print_sockaddr(const struct sockaddr_storage *ss) -+{ -+ static char buf[64]; -+ -+ return snprintf_sockaddr(buf, sizeof(buf), ss); -+} -+ - #ifdef CONFIG_PROC_FS - static inline int ABS(int x) { return x >= 0 ? x : -x; } - #define SAFEDIV(x,y) ((y)? ({ u64 __tmp = x; do_div(__tmp, y); (int)__tmp; }) : 0) -@@ -561,10 +570,9 @@ static int snmp_seq_show(struct seq_file *seq, void *v) - - if (sndbuf_peak < wmem_peak) - sndbuf_peak = wmem_peak; -- seq_printf(seq, "sock%d %u.%u.%u.%u:%u %d %u %u %u %u", -+ seq_printf(seq, "sock%d %s %d %u %u %u %u", - snum, -- HIPQUAD(usock->ipaddr), -- usock->port, -+ print_sockaddr(&usock->addr), - !!usock->sock, - usock->err_connect, - usock->err_full, -@@ -606,9 +614,6 @@ static int nf_seq_show(struct seq_file *seq, void *v) - #ifdef ENABLE_AGGR - " aggr" - #endif --#ifdef ENABLE_DEBUGFS -- " debugfs" --#endif - #ifdef ENABLE_DIRECTION - " dir" - #endif -@@ -623,6 +628,9 @@ static int nf_seq_show(struct seq_file *seq, void *v) - #endif - #ifdef ENABLE_PROMISC - " promisc" -+# ifdef PROMISC_MPLS -+ "+mpls" -+# endif - #endif - #ifdef ENABLE_SAMPLER - " samp" -@@ -808,10 +816,9 @@ static int nf_seq_show(struct seq_file *seq, void *v) - - mutex_lock(&sock_lock); - list_for_each_entry(usock, &usock_list, list) { -- seq_printf(seq, "sock%d: %u.%u.%u.%u:%u", -+ seq_printf(seq, "sock%d: %s", - snum, -- HIPQUAD(usock->ipaddr), -- usock->port); -+ print_sockaddr(&usock->addr)); - if (usock->sock) { - struct sock *sk = usock->sock->sk; - -@@ -902,110 +909,171 @@ static struct file_operations snmp_seq_fops = { - .llseek = seq_lseek, - .release = single_release, - }; --#endif /* CONFIG_PROC_FS */ - --#ifdef ENABLE_DEBUGFS --static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout, const unsigned long jiff); -+static inline int inactive_needs_export(const struct ipt_netflow *nf, const long i_timeout, -+ const unsigned long jiff); -+static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout, -+ const unsigned long jiff); - static inline u_int32_t hash_netflow(const struct ipt_netflow_tuple *tuple); - --static int seq_stripe = -1; -+struct flows_dump_private { -+ int pcache; /* pos */ -+ void *vcache; /* corresponding pointer for pos */ -+ int stripe; /* current stripe */ -+ struct list_head list; /* copy of stripe */ -+ int alloc_errors; -+}; -+ -+/* deallocate copied stripe */ -+static void nf_free_stripe(struct list_head *list) -+{ -+ struct ipt_netflow *cf, *tmp; -+ -+ list_for_each_entry_safe(cf, tmp, list, flows_list) { -+ kmem_cache_free(ipt_netflow_cachep, cf); -+ } -+ INIT_LIST_HEAD(list); -+} -+ -+/* quickly clone stripe into flows_dump_private then it can be walked slowly -+ * and lockless */ -+static void __nf_copy_stripe(struct flows_dump_private *st, const struct list_head *list) -+{ -+ const struct ipt_netflow *nf; -+ struct ipt_netflow *cf; -+ -+ nf_free_stripe(&st->list); -+ list_for_each_entry(nf, list, flows_list) { -+ cf = kmem_cache_alloc(ipt_netflow_cachep, GFP_ATOMIC); -+ if (!cf) { -+ st->alloc_errors++; -+ continue; -+ } -+ memcpy(cf, nf, sizeof(*cf)); -+ list_add(&cf->flows_list, &st->list); -+ } -+} - --/* get first & next ipt_netflow list entry and lock it */ --static struct list_head *nf_get_first(int nstripe) -+/* nstripe is desired stripe, in st->stripe will be recorded actual stripe used -+ * (with empty stripes skipped), -1 is there is no valid stripes anymore, -+ * return first element in stripe list or NULL */ -+static struct list_head *nf_get_stripe(struct flows_dump_private *st, int nstripe) - { -- /* no locking here since it's under global rwlock */ -+ read_lock_bh(&htable_rwlock); - for (; nstripe < LOCK_COUNT; nstripe++) { - struct stripe_entry *stripe = &htable_stripes[nstripe]; - -+ spin_lock(&stripe->lock); - if (!list_empty(&stripe->list)) { -- seq_stripe = nstripe; -- return stripe->list.next; -+ st->stripe = nstripe; -+ __nf_copy_stripe(st, &stripe->list); -+ spin_unlock(&stripe->lock); -+ read_unlock_bh(&htable_rwlock); -+ return st->list.next; - } -+ spin_unlock(&stripe->lock); - } -- seq_stripe = -1; -+ read_unlock_bh(&htable_rwlock); -+ st->stripe = -1; - return NULL; - } - --static struct list_head *nf_get_next(struct list_head *head) -+/* simply next element in flows list or NULL */ -+static struct list_head *nf_get_next(struct flows_dump_private *st, struct list_head *head) - { -- struct stripe_entry *stripe; -- -- if (seq_stripe < 0) -+ if (head == SEQ_START_TOKEN) -+ return nf_get_stripe(st, 0); -+ if (st->stripe < 0) - return NULL; -- stripe = &htable_stripes[seq_stripe]; -- head = head->next; -- if (head != &stripe->list) -- return head; -- return nf_get_first(seq_stripe + 1); -+ /* next element */ -+ if (!list_is_last(head, &st->list)) -+ return head->next; -+ /* next bucket */ -+ return nf_get_stripe(st, st->stripe + 1); - } - --static int seq_pcache; --static void *seq_vcache; -+/* seq_file could arbitrarily start/stop iteration as it feels need, -+ * so, I try to cache things to (significantly) speed it up. */ - static void *flows_dump_seq_start(struct seq_file *seq, loff_t *pos) - { -+ struct flows_dump_private *st = seq->private; - int ppos = *pos; - struct list_head *lh; - - if (!ppos) { -- seq_pcache = 0; -- seq_vcache = nf_get_first(0); -- return seq_vcache; -- } -- if (ppos >= seq_pcache) { -- ppos -= seq_pcache; -- lh = seq_vcache; -- } else -- lh = nf_get_first(0); -+ /* first */ -+ st->pcache = 0; -+ st->vcache = SEQ_START_TOKEN; -+ return st->vcache; -+ } -+ if (ppos >= st->pcache) { -+ /* can iterate forward */ -+ ppos -= st->pcache; -+ lh = st->vcache; -+ } else /* can't, start from 0 */ -+ lh = SEQ_START_TOKEN; -+ /* iterate forward */ - while (ppos--) -- lh = nf_get_next(lh); -- seq_pcache = *pos; -- seq_vcache = lh; -- return seq_vcache; -+ lh = nf_get_next(st, lh); -+ st->pcache = *pos; -+ st->vcache = lh; -+ return st->vcache; - } - - static void *flows_dump_seq_next(struct seq_file *seq, void *v, loff_t *pos) - { -- seq_pcache = ++*pos; -- seq_vcache = nf_get_next((struct list_head *)v); -- return seq_vcache; -+ struct flows_dump_private *st = seq->private; -+ -+ st->pcache = ++*pos; -+ st->vcache = nf_get_next(st, (struct list_head *)v); -+ return st->vcache; - } - - static void flows_dump_seq_stop(struct seq_file *seq, void *v) - { - } - --static unsigned long dump_start; /* jiffies */ --static unsigned int dump_err; - /* To view this: cat /sys/kernel/debug/netflow_dump */ - static int flows_dump_seq_show(struct seq_file *seq, void *v) - { -- struct ipt_netflow *nf = list_entry(v, struct ipt_netflow, flows_list); -- long i_timeout = inactive_timeout * HZ; -- long a_timeout = active_timeout * HZ; -- int inactive = (jiffies - nf->nf_ts_last) >= i_timeout; -- int active = active_needs_export(nf, a_timeout, dump_start); -- u_int32_t hash = hash_netflow(&nf->tuple); -+ struct flows_dump_private *st = seq->private; -+ const long i_timeout = inactive_timeout * HZ; -+ const long a_timeout = active_timeout * HZ; -+ const struct ipt_netflow *nf; - -- if (seq_pcache == 0) { -- unsigned int nr_flows = atomic_read(&ipt_netflow_count); -- -- seq_printf(seq, "# Attention: netflow processing is disabled while dumping. (~%u flows)\n", nr_flows); -+ if (v == SEQ_START_TOKEN) { -+ seq_printf(seq, "# hash a dev:i,o" -+#ifdef SNMP_RULES -+ " snmp:i,o" -+#endif -+#ifdef ENABLE_MAC -+ " mac:src,dst" -+#endif -+#ifdef ENABLE_VLAN -+ " vlan" -+#endif -+#if defined(ENABLE_MAC) || defined(ENABLE_VLAN) -+ " type" -+#endif -+ " proto src:ip,port dst:ip,port nexthop" -+ " tos,tcpflags,options,tcpoptions" -+ " packets bytes ts:first,last\n"); - return 0; - } - -- seq_printf(seq, "%d %02x,%04x %02d", -- seq_pcache, -- seq_stripe, -- hash, -- inactive * 10 + active); --#ifdef SNMP_RULES -- seq_printf(seq, " %hd,%hd(%hd,%hd)", -- nf->i_ifcr, -- nf->o_ifcr, -+ nf = list_entry(v, struct ipt_netflow, flows_list); -+ seq_printf(seq, "%d %04x %x", -+ st->pcache, -+ hash_netflow(&nf->tuple), -+ (!!inactive_needs_export(nf, i_timeout, jiffies)) | -+ (active_needs_export(nf, a_timeout, jiffies) << 1)); -+ seq_printf(seq, " %hd,%hd", - nf->tuple.i_ifc, - nf->o_ifc); --#else -+#ifdef SNMP_RULES - seq_printf(seq, " %hd,%hd", -+ nf->i_ifcr, -+ nf->o_ifcr, - nf->tuple.i_ifc, - nf->o_ifc); - #endif -@@ -1013,55 +1081,44 @@ static int flows_dump_seq_show(struct seq_file *seq, void *v) - seq_printf(seq, " %pM,%pM", &nf->tuple.h_src, &nf->tuple.h_dst); - #endif - #ifdef ENABLE_VLAN -- if (nf->tuple.tag1 || nf->tuple.tag2) { -- seq_printf(seq, ",%d", ntohs(nf->tuple.tag1)); -- if (nf->tuple.tag2) -- seq_printf(seq, ",%d", ntohs(nf->tuple.tag2)); -+ if (nf->tuple.tag[0]) { -+ seq_printf(seq, " %d", ntohs(nf->tuple.tag[0])); -+ if (nf->tuple.tag[1]) -+ seq_printf(seq, ",%d", ntohs(nf->tuple.tag[1])); - } - #endif - #if defined(ENABLE_MAC) || defined(ENABLE_VLAN) -- seq_printf(seq, " [%04x]", ntohs(nf->ethernetType)); -+ seq_printf(seq, " %04x", ntohs(nf->ethernetType)); - #endif -- seq_printf(seq, " %u,%u ", -- nf->tuple.l3proto, -+ seq_printf(seq, " %u ", - nf->tuple.protocol); - if (nf->tuple.l3proto == AF_INET) { -- seq_printf(seq, "%pI4n:%u,%pI4n:%u %pI4n", -+ seq_printf(seq, "%pI4n,%u %pI4n,%u %pI4n", - &nf->tuple.src, - ntohs(nf->tuple.s_port), - &nf->tuple.dst, - ntohs(nf->tuple.d_port), - &nf->nh); -- /* sanity check */ -- if (nf->tuple.src.ip6[1] || -- nf->tuple.src.ip6[2] || -- nf->tuple.src.ip6[3]) -- seq_puts(seq, "error:src:garbage"); -- if (nf->tuple.dst.ip6[1] || -- nf->tuple.dst.ip6[2] || -- nf->tuple.dst.ip6[3]) -- seq_puts(seq, "error:dst:garbage"); - } else if (nf->tuple.l3proto == AF_INET6) { -- seq_printf(seq, "%pI6c#%u,%pI6c#%u %pI6c", -+ seq_printf(seq, "%pI6c,%u %pI6c,%u %pI6c", - &nf->tuple.src, - ntohs(nf->tuple.s_port), - &nf->tuple.dst, - ntohs(nf->tuple.d_port), - &nf->nh); - } else { -- seq_puts(seq, "error:l3proto:unknown"); -+ seq_puts(seq, "?,? ?,? ?"); - } - seq_printf(seq, " %x,%x,%x,%x", - nf->tuple.tos, - nf->tcp_flags, - nf->options, - nf->tcpoptions); -- seq_printf(seq, " %d,%d %lu,%lu\n", -+ seq_printf(seq, " %u %u %lu,%lu\n", - nf->nr_packets, - nf->nr_bytes, - jiffies - nf->nf_ts_first, -- jiffies - nf->nf_ts_last -- ); -+ jiffies - nf->nf_ts_last); - - return 0; - } -@@ -1073,67 +1130,54 @@ static struct seq_operations flows_dump_seq_ops = { - .stop = flows_dump_seq_stop, - }; - --static int flows_dump_open(struct inode *inode, struct file *file) -+static int flows_seq_open(struct inode *inode, struct file *file) - { -- int ret; -+ struct flows_dump_private *st; - char *buf; -+ const size_t size = 4 * PAGE_SIZE; - -- if (atomic_inc_return(&freeze) > 1) { -- /* do not let concurrent dumps. */ -- atomic_dec(&freeze); -- return -EAGAIN; -- } -- buf = kmalloc(KMALLOC_MAX_SIZE, GFP_KERNEL); -- if (!buf) { -- atomic_dec(&freeze); -+ buf = kmalloc(size, GFP_KERNEL); -+ if (!buf) - return -ENOMEM; -- } -- pause_scan_worker(); -- synchronize_sched(); -- /* write_lock to be sure that softirq is finished */ -- write_lock(&htable_rwlock); -- -- dump_start = jiffies; -- dump_err = NETFLOW_STAT_READ(freeze_err); - -- ret = seq_open(file, &flows_dump_seq_ops); -- if (ret) { -- write_unlock(&htable_rwlock); -- cont_scan_worker(); -+ st = __seq_open_private(file, &flows_dump_seq_ops, sizeof(struct flows_dump_private)); -+ if (!st) { - kfree(buf); -- atomic_dec(&freeze); -- return ret; -+ return -ENOMEM; - } -+ INIT_LIST_HEAD(&st->list); -+ /* speed up seq interface with bigger buffer */ - ((struct seq_file *)file->private_data)->buf = buf; -- ((struct seq_file *)file->private_data)->size = KMALLOC_MAX_SIZE; -+ ((struct seq_file *)file->private_data)->size = size; - return 0; - - } --static int flows_dump_release(struct inode *inode, struct file *file) -+static int flows_seq_release(struct inode *inode, struct file *file) - { -- seq_stripe = -1; -- write_unlock(&htable_rwlock); -- cont_scan_worker(); -- atomic_dec(&freeze); -+ struct seq_file *seq = file->private_data; -+ struct flows_dump_private *st = seq->private; - -- printk(KERN_INFO "ipt_NETFLOW: dump finished in %lu/%lu sec, dropped %u packets.\n", -- jiffies - dump_start, -- msecs_to_jiffies(1000), -- NETFLOW_STAT_READ(freeze_err) - dump_err); -- return seq_release(inode, file); -+ nf_free_stripe(&st->list); -+ if (st->alloc_errors) -+ printk(KERN_INFO "ipt_NETFLOW: alloc_errors %d\n", st->alloc_errors); -+ return seq_release_private(inode, file); - } - --static const struct file_operations flows_dump_fops = { -+static struct file_operations flows_seq_fops = { - .owner = THIS_MODULE, -- .open = flows_dump_open, -+ .open = flows_seq_open, - .read = seq_read, - .llseek = seq_lseek, -- .release = flows_dump_release, -+ .release = flows_seq_release, - }; --#endif /* ENABLE_DEBUGFS */ -+#endif /* CONFIG_PROC_FS */ - - #ifdef ENABLE_PROMISC --static int promisc_finish(struct sk_buff *skb) -+static int promisc_finish( -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) -+ struct sock *sk, -+#endif -+ struct sk_buff *skb) - { - /* don't pass to the routing */ - kfree_skb(skb); -@@ -1145,16 +1189,8 @@ static int promisc4_rcv(struct sk_buff *skb, struct net_device *dev, struct pack - const struct iphdr *iph; - u32 len; - -- /* what is not PACKET_OTHERHOST will be parsed at ip_rcv() */ -- if (skb->pkt_type != PACKET_OTHERHOST) -- goto out; -- -- NETFLOW_STAT_INC(pkt_promisc); -- - /* clone skb and do basic IPv4 sanity checking and preparations - * for L3, this is quick and dirty version of ip_rcv() */ -- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) -- goto drop; - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto drop; - iph = ip_hdr(skb); -@@ -1176,10 +1212,10 @@ static int promisc4_rcv(struct sk_buff *skb, struct net_device *dev, struct pack - memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); - skb_orphan(skb); - -- return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL, promisc_finish); -+ return NF_HOOK_COMPAT(NFPROTO_IPV4, NF_INET_PRE_ROUTING, NULL, -+ skb, dev, NULL, promisc_finish); - drop: - NETFLOW_STAT_INC(pkt_promisc_drop); --out: - kfree_skb(skb); - return NET_RX_DROP; - } -@@ -1190,18 +1226,11 @@ static int promisc6_rcv(struct sk_buff *skb, struct net_device *dev, struct pack - u32 pkt_len; - struct inet6_dev *idev; - -- /* what is not PACKET_OTHERHOST will be parsed at ipv6_rcv() */ -- if (skb->pkt_type != PACKET_OTHERHOST) -- goto out; -- -- NETFLOW_STAT_INC(pkt_promisc); -- - /* quick and dirty version of ipv6_rcv(), basic sanity checking - * and preparation of skb for later processing */ - rcu_read_lock(); - idev = __in6_dev_get(skb->dev); -- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || -- !idev || unlikely(idev->cnf.disable_ipv6)) -+ if (!idev || unlikely(idev->cnf.disable_ipv6)) - goto drop; - memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); - IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; -@@ -1252,22 +1281,127 @@ static int promisc6_rcv(struct sk_buff *skb, struct net_device *dev, struct pack - rcu_read_unlock(); - skb_orphan(skb); - -- return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL, promisc_finish); -+ return NF_HOOK_COMPAT(NFPROTO_IPV6, NF_INET_PRE_ROUTING, NULL, -+ skb, dev, NULL, promisc_finish); - drop: - rcu_read_unlock(); - NETFLOW_STAT_INC(pkt_promisc_drop); --out: - kfree_skb(skb); - return NET_RX_DROP; - } - --static struct packet_type promisc4_packet_type __read_mostly = { -- .type = htons(ETH_P_IP), -- .func = promisc4_rcv, --}; --static struct packet_type promisc6_packet_type __read_mostly = { -- .type = htons(ETH_P_IPV6), -- .func = promisc6_rcv, -+/* source is skb_network_protocol() and __vlan_get_protocol() */ -+static __be16 __skb_network_protocol(struct sk_buff *skb, int *depth) -+{ -+ __be16 type = skb->protocol; -+ unsigned int vlan_depth; -+ -+ if (type == htons(ETH_P_TEB)) { -+ struct ethhdr *eth; -+ -+ if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) -+ return 0; -+ -+ eth = (struct ethhdr *)skb_mac_header(skb); -+ type = eth->h_proto; -+ } -+ -+ vlan_depth = skb->mac_len; -+ if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { -+ if (vlan_depth) { -+ if (WARN_ON(vlan_depth < VLAN_HLEN)) -+ return 0; -+ vlan_depth -= VLAN_HLEN; -+ } else { -+ vlan_depth = ETH_HLEN; -+ } -+ do { -+ struct vlan_hdr *vh; -+ -+ if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) -+ return 0; -+ -+ vh = (struct vlan_hdr *)(skb->data + vlan_depth); -+ type = vh->h_vlan_encapsulated_proto; -+ vlan_depth += VLAN_HLEN; -+ } while (type == htons(ETH_P_8021Q) || -+ type == htons(ETH_P_8021AD)); -+ } -+ -+ *depth = vlan_depth; -+ -+ return type; -+} -+ -+static int promisc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) -+{ -+ /* what is not PACKET_OTHERHOST will be processed normally */ -+ if (skb->pkt_type != PACKET_OTHERHOST) -+ goto out; -+ -+ NETFLOW_STAT_INC(pkt_promisc); -+ -+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) -+ goto drop; -+ -+ /* Note about vlans: -+ * - older kernels will pass raw packet; -+ * - newer kernes (since 3.0) will have one vlan tag -+ * physically stripped out of the packet, and it will -+ * be saved into skb->vlan_tci. skb->protocol will be -+ * untagged etherType. */ -+ -+ if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || -+ skb->protocol == cpu_to_be16(ETH_P_8021AD)) { -+ int vlan_depth = skb->mac_len; -+ -+ skb_push(skb, skb->data - skb_mac_header(skb)); -+ skb->protocol = __skb_network_protocol(skb, &vlan_depth); -+ skb_pull(skb, vlan_depth); -+ -+ skb_reset_network_header(skb); -+ skb_reset_mac_len(skb); -+ } -+# ifdef PROMISC_MPLS -+ if (eth_p_mpls(skb->protocol)) { -+ size_t stack_len = 0; -+ const struct mpls_label *mpls; -+ -+ do { -+ stack_len += MPLS_HLEN; -+ if (unlikely(!pskb_may_pull(skb, stack_len))) -+ goto drop; -+ mpls = (struct mpls_label *)(skb->data + stack_len - MPLS_HLEN); -+ } while (!(mpls->entry & htonl(MPLS_LS_S_MASK))); -+ -+ skb_pull(skb, stack_len); -+ skb_reset_network_header(skb); -+ -+ if (!pskb_may_pull(skb, 1)) -+ goto drop; -+ switch (ip_hdr(skb)->version) { -+ case 4: skb->protocol = htons(ETH_P_IP); break; -+ case 6: skb->protocol = htons(ETH_P_IPV6); break; -+ default: goto drop; -+ } -+ } -+# endif -+ switch (skb->protocol) { -+ case htons(ETH_P_IP): -+ return promisc4_rcv(skb, dev, pt, orig_dev); -+ case htons(ETH_P_IPV6): -+ return promisc6_rcv(skb, dev, pt, orig_dev); -+ } -+drop: -+ NETFLOW_STAT_INC(pkt_promisc_drop); -+out: -+ kfree_skb(skb); -+ return 0; -+} -+ -+static struct packet_type promisc_packet_type __read_mostly = { -+ .type = htons(ETH_P_ALL), -+ .func = promisc_rcv, - }; - - /* should not have promisc passed as parameter */ -@@ -1277,13 +1411,10 @@ static int switch_promisc(int newpromisc) - mutex_lock(&promisc_lock); - if (newpromisc == promisc) - goto unlock; -- if (newpromisc) { -- dev_add_pack(&promisc4_packet_type); -- dev_add_pack(&promisc6_packet_type); -- } else { -- dev_remove_pack(&promisc4_packet_type); -- dev_remove_pack(&promisc6_packet_type); -- } -+ if (newpromisc) -+ dev_add_pack(&promisc_packet_type); -+ else -+ dev_remove_pack(&promisc_packet_type); - printk(KERN_INFO "ipt_NETFLOW: promisc hack is %s\n", - newpromisc? "enabled" : "disabled"); - promisc = newpromisc; -@@ -1294,21 +1425,6 @@ unlock: - #endif - - #ifdef CONFIG_SYSCTL -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) --#define BEFORE2632(x,y) x,y --#else /* since 2.6.32 */ --#define BEFORE2632(x,y) --#endif -- --#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0) --#define ctl_table struct ctl_table --#endif -- --#ifndef CONFIG_GRKERNSEC --#define ctl_table_no_const ctl_table --#endif -- - /* sysctl /proc/sys/net/netflow */ - static int hsize_procctl(ctl_table *ctl, int write, BEFORE2632(struct file *filp,) - void __user *buffer, size_t *lenp, loff_t *fpos) -@@ -1753,30 +1869,25 @@ static void sk_error_report(struct sock *sk) - return; - } - --static struct socket *usock_open_sock(const __be32 ipaddr, const unsigned short port, void *u) -+static struct socket *usock_open_sock(const struct sockaddr_storage *addr, void *user_data) - { -- struct sockaddr_in sin; - struct socket *sock; - int error; - -- if ((error = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { -+ if ((error = sock_create_kern(addr->ss_family, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) { - printk(KERN_ERR "ipt_NETFLOW: sock_create_kern error %d\n", -error); - return NULL; - } - sock->sk->sk_allocation = GFP_ATOMIC; - sock->sk->sk_prot->unhash(sock->sk); /* hidden from input */ - sock->sk->sk_error_report = &sk_error_report; /* clear ECONNREFUSED */ -- sock->sk->sk_user_data = u; -+ sock->sk->sk_user_data = user_data; /* usock */ - if (sndbuf) - sock->sk->sk_sndbuf = sndbuf; - else - sndbuf = sock->sk->sk_sndbuf; -- memset(&sin, 0, sizeof(sin)); -- sin.sin_family = AF_INET; -- sin.sin_addr.s_addr = htonl(ipaddr); -- sin.sin_port = htons(port); -- if ((error = sock->ops->connect(sock, (struct sockaddr *)&sin, -- sizeof(sin), 0)) < 0) { -+ error = sock->ops->connect(sock, (struct sockaddr *)addr, sizeof(*addr), 0); -+ if (error < 0) { - printk(KERN_ERR "ipt_NETFLOW: error connecting UDP socket %d," - " don't worry, will try reconnect later.\n", -error); - /* ENETUNREACH when no interfaces */ -@@ -1788,18 +1899,16 @@ static struct socket *usock_open_sock(const __be32 ipaddr, const unsigned short - - static void usock_connect(struct ipt_netflow_sock *usock, const int sendmsg) - { -- usock->sock = usock_open_sock(usock->ipaddr, usock->port, usock); -+ usock->sock = usock_open_sock(&usock->addr, usock); - if (usock->sock) { - if (sendmsg || debug) -- printk(KERN_INFO "ipt_NETFLOW: connected %u.%u.%u.%u:%u\n", -- HIPQUAD(usock->ipaddr), -- usock->port); -+ printk(KERN_INFO "ipt_NETFLOW: connected %s\n", -+ print_sockaddr(&usock->addr)); - } else { - usock->err_connect++; - if (debug) -- printk(KERN_INFO "ipt_NETFLOW: connect to %u.%u.%u.%u:%u failed%s.\n", -- HIPQUAD(usock->ipaddr), -- usock->port, -+ printk(KERN_INFO "ipt_NETFLOW: connect to %s failed%s.\n", -+ print_sockaddr(&usock->addr), - (sendmsg)? " (pdu lost)" : ""); - } - atomic_set(&usock->wmem_peak, 0); -@@ -1888,9 +1997,8 @@ static void netflow_sendmsg(void *buffer, const int len) - - static void usock_close_free(struct ipt_netflow_sock *usock) - { -- printk(KERN_INFO "ipt_NETFLOW: removed destination %u.%u.%u.%u:%u\n", -- HIPQUAD(usock->ipaddr), -- usock->port); -+ printk(KERN_INFO "ipt_NETFLOW: removed destination %s\n", -+ print_sockaddr(&usock->addr)); - usock_close(usock); - vfree(usock); - } -@@ -1917,17 +2025,15 @@ static void add_usock(struct ipt_netflow_sock *usock) - mutex_lock(&sock_lock); - /* don't need duplicated sockets */ - list_for_each_entry(sk, &usock_list, list) { -- if (sk->ipaddr == usock->ipaddr && -- sk->port == usock->port) { -+ if (sockaddr_cmp(&sk->addr, &usock->addr)) { - mutex_unlock(&sock_lock); - usock_close_free(usock); - return; - } - } - list_add_tail(&usock->list, &usock_list); -- printk(KERN_INFO "ipt_NETFLOW: added destination %u.%u.%u.%u:%u%s\n", -- HIPQUAD(usock->ipaddr), -- usock->port, -+ printk(KERN_INFO "ipt_NETFLOW: added destination %s%s\n", -+ print_sockaddr(&usock->addr), - (!usock->sock)? " (unconnected)" : ""); - mutex_unlock(&sock_lock); - } -@@ -2105,33 +2211,76 @@ static inline int resolve_snmp(const struct net_device *ifc) - } - #endif /* SNMP_RULES */ - -+/* count how much character c is in the string */ -+static size_t strncount(const char *s, size_t count, int c) -+{ -+ size_t amount = 0; -+ -+ for (; count-- && *s != '\0'; ++s) -+ if (*s == (char)c) -+ ++amount; -+ return amount; -+} -+ - #define SEPARATORS " ,;\t\n" --static int add_destinations(char *ptr) -+static int add_destinations(const char *ptr) - { -- while (ptr) { -- unsigned char ip[4]; -- unsigned short port; -+ int len; - -- ptr += strspn(ptr, SEPARATORS); -+ for (; ptr; ptr += len) { -+ struct sockaddr_storage ss; -+ struct ipt_netflow_sock *usock; -+ const char *end; -+ int succ = 0; - -- if (sscanf(ptr, "%hhu.%hhu.%hhu.%hhu:%hu", -- ip, ip + 1, ip + 2, ip + 3, &port) == 5) { -- struct ipt_netflow_sock *usock; -+ /* skip initial separators */ -+ ptr += strspn(ptr, SEPARATORS); - -- if (!(usock = vmalloc(sizeof(*usock)))) { -- printk(KERN_ERR "ipt_NETFLOW: can't vmalloc socket\n"); -- return -ENOMEM; -+ len = strcspn(ptr, SEPARATORS); -+ if (!len) -+ break; -+ memset(&ss, 0, sizeof(ss)); -+ -+ if (strncount(ptr, len, ':') >= 2) { -+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; -+ const char *c = ptr; -+ int clen = len; -+ -+ sin6->sin6_family = AF_INET6; -+ sin6->sin6_port = htons(2055); -+ if (*c == '[') { -+ ++c; -+ --clen; - } -+ succ = in6_pton(c, clen, (u8 *)&sin6->sin6_addr, -1, &end); -+ if (succ && *ptr == '[' && *end == ']') -+ ++end; -+ if (succ && -+ (*end == ':' || *end == '.' || *end == 'p' || *end == '#')) -+ sin6->sin6_port = htons(simple_strtoul(++end, NULL, 0)); -+ } else { -+ struct sockaddr_in *sin = (struct sockaddr_in *)&ss; - -- memset(usock, 0, sizeof(*usock)); -- usock->ipaddr = ntohl(*(__be32 *)ip); -- usock->port = port; -- usock_connect(usock, 0); -- add_usock(usock); -- } else -- break; -+ sin->sin_family = AF_INET; -+ sin->sin_port = htons(2055); -+ succ = in4_pton(ptr, len, (u8 *)&sin->sin_addr, -1, &end); -+ if (succ && *end == ':') -+ sin->sin_port = htons(simple_strtoul(++end, NULL, 0)); -+ } -+ if (!succ) { -+ printk(KERN_ERR "ipt_NETFLOW: can't parse destination: %.*s\n", -+ len, ptr); -+ continue; -+ } - -- ptr = strpbrk(ptr, SEPARATORS); -+ if (!(usock = vmalloc(sizeof(*usock)))) { -+ printk(KERN_ERR "ipt_NETFLOW: can't vmalloc socket\n"); -+ return -ENOMEM; -+ } -+ memset(usock, 0, sizeof(*usock)); -+ usock->addr = ss; -+ usock_connect(usock, 0); -+ add_usock(usock); - } - return 0; - } -@@ -2246,12 +2395,7 @@ ipt_netflow_find(const struct ipt_netflow_tuple *tuple, const unsigned int hash) - { - struct ipt_netflow *nf; - #if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) --#define compat_hlist_for_each_entry hlist_for_each_entry --#define compat_hlist_for_each_entry_safe hlist_for_each_entry_safe - struct hlist_node *pos; --#else /* since 3.9.0 */ --#define compat_hlist_for_each_entry(a,pos,c,d) hlist_for_each_entry(a,c,d) --#define compat_hlist_for_each_entry_safe(a,pos,c,d,e) hlist_for_each_entry_safe(a,c,d,e) - #endif - - compat_hlist_for_each_entry(nf, pos, &htable[hash], hlist) { -@@ -2529,7 +2673,7 @@ static inline void pdu_rewind_space(const size_t size) - /* allocate data space in pdu, or export (reallocate) and fail. */ - static inline unsigned char *pdu_alloc_fail_export(const size_t size) - { -- if (!pdu_have_space(size)) { -+ if (unlikely(!pdu_have_space(size))) { - netflow_export_pdu(); - return NULL; - } -@@ -2585,6 +2729,7 @@ struct base_template { - #define BTPL_DIRECTION 0x00200000 /* flowDirection */ - #define BTPL_SAMPLERID 0x00400000 /* samplerId (v9) */ - #define BTPL_SELECTORID 0x00800000 /* selectorId (IPFIX) */ -+#define BTPL_MPLS 0x01000000 /* MPLS stack */ - #define BTPL_OPTION 0x80000000 /* Options Template */ - #define BTPL_MAX 32 - /* Options Templates */ -@@ -2604,6 +2749,10 @@ static struct base_template template_base_9 = { - .types = { - INPUT_SNMP, - OUTPUT_SNMP, -+#ifdef ENABLE_PHYSDEV -+ ingressPhysicalInterface, -+ egressPhysicalInterface, -+#endif - IN_PKTS, - IN_BYTES, - FIRST_SWITCHED, -@@ -2617,12 +2766,17 @@ static struct base_template template_base_ipfix = { - .types = { - ingressInterface, - egressInterface, -+#ifdef ENABLE_PHYSDEV -+ ingressPhysicalInterface, -+ egressPhysicalInterface, -+#endif - packetDeltaCount, - octetDeltaCount, - flowStartMilliseconds, - flowEndMilliseconds, - protocolIdentifier, - ipClassOfService, -+ flowEndReason, - 0 - } - }; -@@ -2660,6 +2814,27 @@ static struct base_template template_vlan_inner = { - } - }; - #endif -+#ifdef MPLS_DEPTH -+static struct base_template template_mpls = { -+ .types = { -+ mplsTopLabelTTL, -+ /* do not just add element here, becasue this array -+ * is truncated in ipt_netflow_init() */ -+#define MPLS_LABELS_BASE_INDEX 1 -+ MPLS_LABEL_1, -+ MPLS_LABEL_2, -+ MPLS_LABEL_3, -+ MPLS_LABEL_4, -+ MPLS_LABEL_5, -+ MPLS_LABEL_6, -+ MPLS_LABEL_7, -+ MPLS_LABEL_8, -+ MPLS_LABEL_9, -+ MPLS_LABEL_10, -+ 0 -+ } -+}; -+#endif - #ifdef ENABLE_DIRECTION - static struct base_template template_direction = { - .types = { DIRECTION, 0 } -@@ -3026,6 +3201,10 @@ static struct data_template *get_template(const unsigned int tmask) - if (tmask & BTPL_ETHERTYPE) - tlist[tnum++] = &template_ethertype; - #endif -+#ifdef MPLS_DEPTH -+ if (tmask & BTPL_MPLS) -+ tlist[tnum++] = &template_mpls; -+#endif - #ifdef ENABLE_DIRECTION - if (tmask & BTPL_DIRECTION) - tlist[tnum++] = &template_direction; -@@ -3176,23 +3355,6 @@ static void pdu_add_template(struct data_template *tpl) - pdu_tpl_records++; - } - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) --static inline s64 portable_ktime_to_ms(const ktime_t kt) --{ -- struct timeval tv = ktime_to_timeval(kt); -- return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC; --} --#define ktime_to_ms portable_ktime_to_ms --#endif --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) --static inline s64 portable_ktime_to_us(const ktime_t kt) --{ -- struct timeval tv = ktime_to_timeval(kt); -- return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec; --} --#define ktime_to_us portable_ktime_to_us --#endif -- - #ifdef ENABLE_DIRECTION - static inline __u8 hook2dir(const __u8 hooknum) - { -@@ -3209,21 +3371,6 @@ static inline __u8 hook2dir(const __u8 hooknum) - } - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) --static inline void put_unaligned_be16(u16 val, void *p) --{ -- put_unaligned(cpu_to_be16(val), (__be16 *)p); --} --static inline void put_unaligned_be32(u32 val, void *p) --{ -- put_unaligned(cpu_to_be32(val), (__be32 *)p); --} --static inline void put_unaligned_be64(u64 val, void *p) --{ -- put_unaligned(cpu_to_be64(val), (__be64 *)p); --} --#endif -- - static inline void put_unaligned_be24(u32 val, unsigned char *p) - { - *p++ = val >> 16; -@@ -3260,9 +3407,6 @@ static inline s64 jiffies_to_ms_abs(unsigned long j) - return jiffies_base.ms + (s64)jiffies_to_msecs(-jdiff); - } - --#ifndef WARN_ONCE --#define WARN_ONCE(x,fmt...) ({ if (x) printk(KERN_WARNING fmt); }) --#endif - typedef struct in6_addr in6_t; - /* encode one field (data records only) */ - static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_netflow *nf) -@@ -3286,14 +3430,20 @@ static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_net - case INPUT_SNMP: put_unaligned_be16(nf->tuple.i_ifc, ptr); break; - case OUTPUT_SNMP: put_unaligned_be16(nf->o_ifc, ptr); break; - #endif -+#ifdef ENABLE_PHYSDEV -+ case ingressPhysicalInterface: -+ put_unaligned_be16(nf->i_ifphys, ptr); break; -+ case egressPhysicalInterface: -+ put_unaligned_be16(nf->o_ifphys, ptr); break; -+#endif - #ifdef ENABLE_VLAN - #define EXTRACT_VLAN_PRIO(tag) ((ntohs(tag) & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT) - case SRC_VLAN: -- case dot1qVlanId: put_unaligned(nf->tuple.tag1 & htons(VLAN_VID_MASK), (__be16 *)ptr); break; -- case dot1qPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag1); break; -+ case dot1qVlanId: put_unaligned(nf->tuple.tag[0] & htons(VLAN_VID_MASK), (__be16 *)ptr); break; -+ case dot1qPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag[0]); break; - case dot1qCustomerVlanId: -- put_unaligned(nf->tuple.tag2 & htons(VLAN_VID_MASK), (__be16 *)ptr); break; -- case dot1qCustomerPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag2); break; -+ put_unaligned(nf->tuple.tag[1] & htons(VLAN_VID_MASK), (__be16 *)ptr); break; -+ case dot1qCustomerPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag[1]); break; - #endif - #if defined(ENABLE_MAC) || defined(ENABLE_VLAN) - case ethernetType: put_unaligned(nf->ethernetType, (__be16 *)ptr); break; -@@ -3302,6 +3452,21 @@ static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_net - case destinationMacAddress: memcpy(ptr, &nf->tuple.h_dst, ETH_ALEN); break; - case sourceMacAddress: memcpy(ptr, &nf->tuple.h_src, ETH_ALEN); break; - #endif -+#ifdef MPLS_DEPTH -+ case MPLS_LABEL_1: memcpy(ptr, &nf->tuple.mpls[0], 3); break; -+ case MPLS_LABEL_2: memcpy(ptr, &nf->tuple.mpls[1], 3); break; -+ case MPLS_LABEL_3: memcpy(ptr, &nf->tuple.mpls[2], 3); break; -+# if MPLS_DEPTH > 3 -+ case MPLS_LABEL_4: memcpy(ptr, &nf->tuple.mpls[3], 3); break; -+ case MPLS_LABEL_5: memcpy(ptr, &nf->tuple.mpls[4], 3); break; -+ case MPLS_LABEL_6: memcpy(ptr, &nf->tuple.mpls[5], 3); break; -+ case MPLS_LABEL_7: memcpy(ptr, &nf->tuple.mpls[6], 3); break; -+ case MPLS_LABEL_8: memcpy(ptr, &nf->tuple.mpls[7], 3); break; -+ case MPLS_LABEL_9: memcpy(ptr, &nf->tuple.mpls[8], 3); break; -+ case MPLS_LABEL_10: memcpy(ptr, &nf->tuple.mpls[9], 3); break; -+# endif -+ case mplsTopLabelTTL: *ptr = ntohl(nf->tuple.mpls[0]); break; -+#endif - #ifdef ENABLE_DIRECTION - case DIRECTION: *ptr = hook2dir(nf->hooknumx - 1); break; - #endif -@@ -3321,6 +3486,7 @@ static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_net - case icmpTypeCodeIPv4: /*FALLTHROUGH*/ - case icmpTypeCodeIPv6: put_unaligned(nf->tuple.d_port, (__be16 *)ptr); break; - case MUL_IGMP_TYPE: *ptr = nf->tuple.d_port; break; -+ case flowEndReason: *ptr = nf->flowEndReason; break; - #ifdef CONFIG_NF_NAT_NEEDED - case postNATSourceIPv4Address: put_unaligned(nf->nat->post.s_addr, (__be32 *)ptr); break; - case postNATDestinationIPv4Address: put_unaligned(nf->nat->post.d_addr, (__be32 *)ptr); break; -@@ -3363,18 +3529,6 @@ static inline unsigned long timeout_rate_j(void) - return t_rate_j; - } - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) --#define IPPROTO_UDPLITE 136 --#endif -- --#ifndef time_is_before_jiffies --#define time_is_before_jiffies(a) time_after(jiffies, a) --#endif --#ifndef time_is_after_jiffies --#define time_is_after_jiffies(a) time_before(jiffies, a) --#endif -- -- - /* return buffer where to write records data */ - static unsigned char *alloc_record_tpl(struct data_template *tpl) - { -@@ -3382,9 +3536,9 @@ static unsigned char *alloc_record_tpl(struct data_template *tpl) - - /* If previous write was to the same template and there is room, then we just add new record, - * otherwise we (re)allocate flowset (and/or whole pdu). */ -- if (unlikely(!pdu_flowset || -+ if (!pdu_flowset || - pdu_flowset->flowset_id != tpl->template_id_n || -- !(ptr = pdu_alloc_fail_export(tpl->rec_size)))) { -+ !(ptr = pdu_alloc_fail_export(tpl->rec_size))) { - - /* if there was previous data template we should pad it to 4 bytes */ - if (pdu_flowset) { -@@ -3427,18 +3581,6 @@ static unsigned char *alloc_record_key(const unsigned int t_key, struct data_tem - return alloc_record_tpl(tpl); - } - --#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) --#define prandom_u32 get_random_int --#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) --#define prandom_u32 random32 --#endif --static inline u32 prandom_u32_max(u32 ep_ro) --{ -- return (u32)(((u64) prandom_u32() * ep_ro) >> 32); --} --#endif -- - static void netflow_export_flow_tpl(struct ipt_netflow *nf) - { - unsigned char *ptr; -@@ -3497,12 +3639,12 @@ static void netflow_export_flow_tpl(struct ipt_netflow *nf) - tpl_mask |= BTPL_MAC; - #endif - #ifdef ENABLE_VLAN -- if (nf->tuple.tag1) { -+ if (nf->tuple.tag[0]) { - if (protocol == 9) - tpl_mask |= BTPL_VLAN9; - else { - tpl_mask |= BTPL_VLANX; -- if (nf->tuple.tag2) -+ if (nf->tuple.tag[1]) - tpl_mask |= BTPL_VLANI; - } - } -@@ -3511,6 +3653,10 @@ static void netflow_export_flow_tpl(struct ipt_netflow *nf) - if (nf->ethernetType) - tpl_mask |= BTPL_ETHERTYPE; - #endif -+#ifdef MPLS_DEPTH -+ if (nf->tuple.mpls[0]) -+ tpl_mask |= BTPL_MPLS; -+#endif - #ifdef ENABLE_DIRECTION - if (nf->hooknumx) - tpl_mask |= BTPL_DIRECTION; -@@ -3657,13 +3803,6 @@ static inline void export_stat(const unsigned int tpl_mask) - export_stat_st(tpl_mask, NULL); - } - --#ifndef min_not_zero --#define min_not_zero(x, y) ({ \ -- typeof(x) __x = (x); \ -- typeof(y) __y = (y); \ -- __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); }) --#endif -- - static void netflow_export_stats(void) - { - struct ipt_netflow_stat t = { 0 }; -@@ -3748,20 +3887,6 @@ static void export_sampler_parameters(void) - } - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) --int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) --{ -- ASSERT_RTNL(); -- -- if (!dev->ethtool_ops->get_settings) -- return -EOPNOTSUPP; -- -- memset(cmd, 0, sizeof(struct ethtool_cmd)); -- cmd->cmd = ETHTOOL_GSET; -- return dev->ethtool_ops->get_settings(dev, cmd); --} --#endif -- - static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *dev) - { - struct ethtool_drvinfo info = { 0 }; -@@ -3774,8 +3899,8 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d - return 0; - if (ops->begin) { - /* was not called before __ethtool_get_settings() though */ -- if (ops->begin(dev) < 0); -- return 0; -+ if (ops->begin(dev) < 0) -+ return 0; - } - - /* driver name */ -@@ -3792,13 +3917,13 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d - if (!n || len <= 1) /* have room for separator too */ - goto ret; - -- /* append basic parameters: speed and port */ -- if (!__ethtool_get_settings(dev, &ecmd)) { -+ /* only get_settings for running devices to not trigger link negotiation */ -+ if (dev->flags & IFF_UP && -+ dev->flags & IFF_RUNNING && -+ !__ethtool_get_settings(dev, &ecmd)) { - char *s, *p; - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) --#define ethtool_cmd_speed(x) (x)->speed --#endif -+ /* append basic parameters: speed and port */ - switch (ethtool_cmd_speed(&ecmd)) { - case SPEED_10000: s = "10Gb"; break; - case SPEED_2500: s = "2.5Gb"; break; -@@ -3827,14 +3952,6 @@ ret: - return size - len; - } - --#ifndef ARPHRD_PHONET --#define ARPHRD_PHONET 820 --#define ARPHRD_PHONET_PIPE 821 --#endif --#ifndef ARPHRD_IEEE802154 --#define ARPHRD_IEEE802154 804 --#endif -- - static const unsigned short netdev_type[] = - {ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_AX25, - ARPHRD_IEEE802, ARPHRD_ARCNET, -@@ -3939,13 +4056,6 @@ static void export_dev(struct net_device *dev) - pdu_ts_mod = jiffies; - } - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) --#define for_each_netdev_ns(net, dev) for (dev = dev_base; dev; dev = dev->next) --#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) --#define for_each_netdev_ns(net, d) for_each_netdev(d) --#else --#define for_each_netdev_ns(net, d) for_each_netdev(net, d) --#endif - static void export_ifnames(void) - { - struct net_device *dev; -@@ -4041,14 +4151,40 @@ static void export_nat_event(struct nat_event *nel) - } - #endif /* CONFIG_NF_NAT_NEEDED */ - --static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout, const unsigned long jiff) -+static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout, -+ const unsigned long j) -+{ -+ return ((j - nf->nf_ts_first) > a_timeout) || -+ nf->nr_bytes >= FLOW_FULL_WATERMARK; -+} -+ -+/* return flowEndReason (rfc5102) */ -+/* i_timeout == 0 is flush */ -+static inline int inactive_needs_export(const struct ipt_netflow *nf, const long i_timeout, -+ const unsigned long j) - { -- /* active too long, finishing, or having too much bytes */ -- return ((jiff - nf->nf_ts_first) > a_timeout) || -- (nf->tuple.protocol == IPPROTO_TCP && -- (nf->tcp_flags & TCP_FIN_RST) && -- (jiff - nf->nf_ts_last) > (1 * HZ)) || -- nf->nr_bytes >= FLOW_FULL_WATERMARK; -+ if (likely(i_timeout)) { -+ if (unlikely((j - nf->nf_ts_last) > i_timeout)) { -+ if (nf->tuple.protocol == IPPROTO_TCP && -+ (nf->tcp_flags & TCP_FIN_RST)) -+ return 0x03; /* end of Flow detected */ -+ else -+ return 0x01; /* idle timeout */ -+ } else -+ return 0; -+ } else -+ return 0x04; /* forced end */ -+} -+ -+/* helper which also record to nf->flowEndReason */ -+static inline int needs_export_rec(struct ipt_netflow *nf, const long i_timeout, -+ const long a_timeout, const unsigned long j) -+{ -+ int reason = inactive_needs_export(nf, i_timeout, j); -+ -+ if (!reason && active_needs_export(nf, a_timeout, j)) -+ reason = 0x02; /* active timeout or just active flow */ -+ return (nf->flowEndReason = reason); - } - - /* could be called with zero to flush cache and pdu */ -@@ -4056,13 +4192,12 @@ static inline int active_needs_export(const struct ipt_netflow *nf, const long a - /* return number of pdus sent */ - static int netflow_scan_and_export(const int flush) - { -- long i_timeout = inactive_timeout * HZ; -+ const long i_timeout = flush? 0 : inactive_timeout * HZ; -+ const long a_timeout = active_timeout * HZ; - #ifdef HAVE_LLIST - struct llist_node *node; --#else -- long a_timeout = active_timeout * HZ; - #endif -- int pdu_c = pdu_count; -+ const int pdu_c = pdu_count; - LIST_HEAD(export_list); - struct ipt_netflow *nf, *tmp; - int i; -@@ -4070,9 +4205,6 @@ static int netflow_scan_and_export(const int flush) - unsigned char mode; - #endif - -- if (flush) -- i_timeout = 0; -- - if (protocol >= 9) { - netflow_export_stats(); - #ifdef ENABLE_SAMPLER -@@ -4091,14 +4223,7 @@ static int netflow_scan_and_export(const int flush) - } - list_for_each_entry_safe_reverse(nf, tmp, &stripe->list, flows_list) { - ++wk_count; -- if (((jiffies - nf->nf_ts_last) >= i_timeout) --#ifdef HAVE_LLIST -- /* exportable actives already go into export_llist, -- * thus this check is redundant. */ --#else -- || active_needs_export(nf, a_timeout, jiffies) --#endif -- ) { -+ if (needs_export_rec(nf, i_timeout, a_timeout, jiffies)) { - hlist_del(&nf->hlist); - list_del(&nf->flows_list); - list_add(&nf->flows_list, &export_list); -@@ -4387,13 +4512,6 @@ netflow_target_check(const struct xt_tgchk_param *par) - if (strcmp("nat", tablename) == 0) { - /* In the nat table we only see single packet per flow, which is useless. */ - printk(KERN_ERR "%s target: is not valid in %s table\n", target->name, tablename); --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) --#define CHECK_FAIL 0 --#define CHECK_OK 1 --#else --#define CHECK_FAIL -EINVAL --#define CHECK_OK 0 --#endif - return CHECK_FAIL; - } - if (target->family == AF_INET6 && protocol == 5) { -@@ -4404,9 +4522,6 @@ netflow_target_check(const struct xt_tgchk_param *par) - } - - #define SetXBit(x) (0x8000 >> (x)) /* Proper bit for htons later. */ --#ifndef IPPROTO_MH --#define IPPROTO_MH 135 --#endif - static inline __u16 observed_hdrs(const __u8 currenthdr) - { - switch (currenthdr) { -@@ -4537,69 +4652,80 @@ static inline __u32 tcp_options(const struct sk_buff *skb, const unsigned int pt - return ret; - } - --#ifdef ENABLE_VLAN --/* double tagged header */ --struct vlan_ethhdr2 { -- unsigned char h_dest[ETH_ALEN]; -- unsigned char h_source[ETH_ALEN]; -- __be16 h_vlan_proto; -- __be16 h_vlan_TCI; -- __be16 h2_vlan_proto; -- __be16 h2_vlan_TCI; -- __be16 h2_vlan_encapsulated_proto; --}; --static inline struct vlan_ethhdr2 *vlan_eth_hdr2(const struct sk_buff *skb) -+/* check if data region is in header boundary */ -+inline static int skb_in_header(const struct sk_buff *skb, const void *ptr, size_t off) - { -- return (struct vlan_ethhdr2 *)skb_mac_header(skb); -+ return ((unsigned char *)ptr + off) <= skb->data; - } --#define VLAN_ETH_H2LEN (VLAN_ETH_HLEN + 4) --#ifndef ETH_P_8021AD --#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ --#endif --#ifndef ETH_P_QINQ1 --#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN */ --#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN */ --#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN */ --#endif --/* http://tools.ietf.org/html/rfc7133 */ --static inline __u16 parse_vlan_tags(const struct sk_buff *skb, struct ipt_netflow_tuple *tuple) --{ -- /* no even untagged ethernet header */ -- if (skb_mac_header(skb) < skb->head || -- skb_mac_header(skb) + ETH_HLEN > skb->data) -- return 0; -- -- switch (eth_hdr(skb)->h_proto) { -- case htons(ETH_P_QINQ1): -- case htons(ETH_P_QINQ2): -- case htons(ETH_P_QINQ3): -- case htons(ETH_P_8021AD): /* S-TAG or B-TAG */ -- case htons(ETH_P_8021Q): /* C-TAG */ -- /* tagged and have full vlan header */ -- if (skb_mac_header(skb) + VLAN_ETH_HLEN <= skb->data) -- break; -- /* FALLTHROUGH */ -- default: -- return eth_hdr(skb)->h_proto; -- } - -- /* outer tag */ -- tuple->tag1 = vlan_eth_hdr(skb)->h_vlan_TCI; -+static inline int eth_p_vlan(__be16 eth_type) -+{ -+ return eth_type == htons(ETH_P_8021Q) || -+ eth_type == htons(ETH_P_8021AD); -+} - -- switch (vlan_eth_hdr(skb)->h_vlan_encapsulated_proto) { -- case htons(ETH_P_8021Q): /* C-TAG */ -- if (skb_mac_header(skb) + VLAN_ETH_H2LEN <= skb->data) -- break; -- /* FALLTHROUGH */ -- default: -- return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; -- } -+/* Extract all L2 header data, currently (in iptables) skb->data is -+ * pointing to network_header, so we use mac_header instead. */ -+/* Parse eth header, then vlans, then mpls. */ -+static void parse_l2_header(const struct sk_buff *skb, struct ipt_netflow_tuple *tuple) -+{ -+#if defined(ENABLE_MAC) || defined(ENABLE_VLAN) || defined(MPLS_DEPTH) -+#define ENABLE_L2 -+ unsigned char *mac_header = skb_mac_header(skb); -+# if defined(ENABLE_VLAN) || defined(MPLS_DEPTH) -+ unsigned int hdr_depth; -+ __be16 proto; -+# endif -+# ifdef ENABLE_VLAN -+ int tag_num = 0; - -- /* second tag */ -- tuple->tag2 = vlan_eth_hdr2(skb)->h2_vlan_TCI; -- return vlan_eth_hdr2(skb)->h2_vlan_encapsulated_proto; -+ /* get vlan tag that is saved in skb->vlan_tci */ -+ if (vlan_tx_tag_present(skb)) -+ tuple->tag[tag_num++] = htons(vlan_tx_tag_get(skb)); -+# endif -+ if (mac_header < skb->head || -+ mac_header + ETH_HLEN > skb->data) -+ return; -+# ifdef ENABLE_MAC -+ memcpy(&tuple->h_dst, eth_hdr(skb)->h_dest, ETH_ALEN); -+ memcpy(&tuple->h_src, eth_hdr(skb)->h_source, ETH_ALEN); -+# endif -+# if defined(ENABLE_VLAN) || defined(MPLS_DEPTH) -+ hdr_depth = ETH_HLEN; -+ proto = eth_hdr(skb)->h_proto; -+ if (eth_p_vlan(proto)) { -+ do { -+ const struct vlan_hdr *vh; -+ -+ vh = (struct vlan_hdr *)(mac_header + hdr_depth); -+ if (!skb_in_header(skb, vh, VLAN_HLEN)) -+ return; -+ proto = vh->h_vlan_encapsulated_proto; -+# ifdef ENABLE_VLAN -+ if (tag_num < MAX_VLAN_TAGS) -+ tuple->tag[tag_num++] = vh->h_vlan_TCI; -+# endif -+ hdr_depth += VLAN_HLEN; -+ } while (eth_p_vlan(proto)); -+ } -+# ifdef MPLS_DEPTH -+ if (eth_p_mpls(proto)) { -+ const struct mpls_label *mpls; -+ int label_num = 0; -+ -+ do { -+ mpls = (struct mpls_label *)(mac_header + hdr_depth); -+ if (!skb_in_header(skb, mpls, MPLS_HLEN)) -+ return; -+ if (label_num < MPLS_DEPTH) -+ tuple->mpls[label_num++] = mpls->entry; -+ hdr_depth += MPLS_HLEN; -+ } while (!(mpls->entry & htonl(MPLS_LS_S_MASK))); -+ } -+# endif -+# endif /* defined(ENABLE_VLAN) || defined(MPLS_DEPTH) */ -+#endif /* defined(ENABLE_MAC) || defined(ENABLE_VLAN) || defined(MPLS_DEPTH) */ - } --#endif /* ENABLE_VLAN */ - - /* packet receiver */ - static unsigned int netflow_target( -@@ -4622,6 +4748,8 @@ static unsigned int netflow_target( - const void *targinfo - # endif - #else /* since 2.6.28 */ -+# define if_in par->in -+# define if_out par->out - # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) - const struct xt_target_param *par - # else -@@ -4631,7 +4759,11 @@ static unsigned int netflow_target( - ) - { - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) -- const struct sk_buff *skb = *pskb; -+# ifndef ENABLE_L2 -+ /* pskb_may_pull() may modify skb */ -+ const -+# endif -+ struct sk_buff *skb = *pskb; - #endif - union { - struct iphdr ip; -@@ -4660,12 +4792,15 @@ static unsigned int netflow_target( - int options = 0; - int tcpoptions = 0; - struct stripe_entry *stripe; --#if defined(ENABLE_MAC) || defined(ENABLE_VLAN) -- __be16 ethernetType = 0; --#endif - -- iph = skb_header_pointer(skb, 0, (likely(family == AF_INET))? sizeof(_iph.ip) : sizeof(_iph.ip6), &iph); -- if (unlikely(iph == NULL)) { -+ if (unlikely( -+#ifdef ENABLE_L2 -+ /* to ensure that full L2 headers are present */ -+ unlikely(!pskb_may_pull(skb, 0)) || -+#endif -+ !(iph = skb_header_pointer(skb, 0, -+ (likely(family == AF_INET))? sizeof(_iph.ip) : sizeof(_iph.ip6), -+ &iph)))) { - NETFLOW_STAT_INC(truncated); - NETFLOW_STAT_INC(pkt_drop); - NETFLOW_STAT_ADD(traf_drop, skb->len); -@@ -4673,46 +4808,18 @@ static unsigned int netflow_target( - return IPT_CONTINUE; - } - --#ifdef ENABLE_DEBUGFS -- if (atomic_read(&freeze)) { -- NETFLOW_STAT_INC(freeze_err); -- NETFLOW_STAT_INC(pkt_drop); -- NETFLOW_STAT_ADD(traf_drop, skb->len); -- NETFLOW_STAT_TS(drop); -- return IPT_CONTINUE; -- } -+ memset(&tuple, 0, sizeof(tuple)); -+ tuple.l3proto = family; -+#ifdef ENABLE_PHYSDEV_OVER -+ if (skb->nf_bridge && skb->nf_bridge->physindev) -+ tuple.i_ifc = skb->nf_bridge->physindev->ifindex; -+ else /* FALLTHROUGH */ - #endif -- -- tuple.l3proto = family; -- tuple.s_port = 0; -- tuple.d_port = 0; --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - tuple.i_ifc = if_in? if_in->ifindex : -1; --#else -- tuple.i_ifc = par->in? par->in->ifindex : -1; --#endif -- tcp_flags = 0; /* Cisco sometimes have TCP ACK for non TCP packets, don't get it */ -+ tcp_flags = 0; - s_mask = 0; - d_mask = 0; --#ifdef ENABLE_MAC -- if (skb_mac_header(skb) >= skb->head && -- skb_mac_header(skb) + ETH_HLEN <= skb->data) { -- memcpy(&tuple.h_dst, eth_hdr(skb)->h_dest, ETH_ALEN); -- memcpy(&tuple.h_src, eth_hdr(skb)->h_source, ETH_ALEN); --#ifndef ENABLE_VLAN -- ethernetType = eth_hdr(skb)->h_proto; --#endif -- } else { -- memset(&tuple.h_dst, 0, ETH_ALEN); -- memset(&tuple.h_src, 0, ETH_ALEN); -- } --#endif --#ifdef ENABLE_VLAN -- tuple.tag2 = tuple.tag1 = 0; -- if (vlan_tx_tag_present(skb)) -- tuple.tag1 = htons(vlan_tx_tag_get(skb)); -- ethernetType = parse_vlan_tags(skb, &tuple); --#endif -+ parse_l2_header(skb, &tuple); - - if (likely(family == AF_INET)) { - tuple.src = (union nf_inet_addr){ .ip = iph->ip.saddr }; -@@ -4832,16 +4939,16 @@ do_protocols: - case IPPROTO_ICMP: { - struct icmphdr _hdr, *hp; - -- if (likely(family == AF_INET && -- (hp = skb_header_pointer(skb, ptr, 2, &_hdr)))) -+ if (likely(family == AF_INET) && -+ likely(hp = skb_header_pointer(skb, ptr, 2, &_hdr))) - tuple.d_port = htons((hp->type << 8) | hp->code); - break; - } - case IPPROTO_ICMPV6: { - struct icmp6hdr _icmp6h, *ic; - -- if (likely(family == AF_INET6 && -- (ic = skb_header_pointer(skb, ptr, 2, &_icmp6h)))) -+ if (likely(family == AF_INET6) && -+ likely(ic = skb_header_pointer(skb, ptr, 2, &_icmp6h))) - tuple.d_port = htons((ic->icmp6_type << 8) | ic->icmp6_code); - break; - } -@@ -4856,8 +4963,8 @@ do_protocols: - struct ip_auth_hdr _hdr, *hp; - - /* This is for IPv4 only. IPv6 it's parsed above. */ -- if (likely(family == AF_INET && -- (hp = skb_header_pointer(skb, ptr, 8, &_hdr)))) -+ if (likely(family == AF_INET) && -+ likely(hp = skb_header_pointer(skb, ptr, 8, &_hdr))) - SAVE_SPI(tuple, hp->spi); - break; - } -@@ -4967,27 +5074,43 @@ do_protocols: - #endif - nf->nf_ts_first = jiffies; - nf->tcp_flags = tcp_flags; --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) - nf->o_ifc = if_out? if_out->ifindex : -1; --#else -- nf->o_ifc = par->out? par->out->ifindex : -1; -+#ifdef ENABLE_PHYSDEV_OVER -+ if (skb->nf_bridge && skb->nf_bridge->physoutdev) -+ nf->o_ifc = skb->nf_bridge->physoutdev->ifindex; - #endif -+ - #ifdef SNMP_RULES - rcu_read_lock(); --# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -+#else -+# define resolve_snmp(dev) ((dev)? (dev)->ifindex : -1) -+#endif -+/* copy and snmp-resolve device with physdev overriding normal dev */ -+#define copy_dev(out, physdev, dev) \ -+ if (skb->nf_bridge && skb->nf_bridge->physdev) \ -+ out = resolve_snmp(skb->nf_bridge->physdev); \ -+ else \ -+ out = resolve_snmp(dev); -+#ifdef ENABLE_PHYSDEV -+ copy_dev(nf->o_ifphys, physoutdev, if_out); -+ copy_dev(nf->i_ifphys, physindev, if_in); -+#endif -+#ifdef SNMP_RULES -+# ifdef ENABLE_PHYSDEV_OVER -+ copy_dev(nf->o_ifcr, physoutdev, if_out); -+ copy_dev(nf->i_ifcr, physindev, if_in); -+# else - nf->o_ifcr = resolve_snmp(if_out); - nf->i_ifcr = resolve_snmp(if_in); --# else -- nf->o_ifcr = resolve_snmp(par->out); -- nf->i_ifcr = resolve_snmp(par->in); - # endif - rcu_read_unlock(); -+ - #endif - nf->s_mask = s_mask; - nf->d_mask = d_mask; - - #if defined(ENABLE_MAC) || defined(ENABLE_VLAN) -- nf->ethernetType = ethernetType; -+ nf->ethernetType = skb->protocol; - #endif - - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) -@@ -5034,7 +5157,7 @@ do_protocols: - - #define LIST_IS_NULL(name) (!(name)->next) - -- if (likely(active_needs_export(nf, active_timeout * HZ, jiffies))) { -+ if (unlikely(active_needs_export(nf, active_timeout * HZ, jiffies))) { - /* ok, if this is active flow to be exported */ - #ifdef HAVE_LLIST - /* delete from hash and add to the export llist */ -@@ -5150,9 +5273,6 @@ static void register_ct_events(void) - /* Reference netlink module to prevent it's unsafe unload before us. */ - if (!referenced && (netlink_m = find_module(NETLINK_M))) { - referenced++; --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) --#define use_module ref_module --#endif - use_module(THIS_MODULE, netlink_m); - } - -@@ -5190,39 +5310,6 @@ static void unregister_ct_events(void) - } - #endif /* CONFIG_NF_NAT_NEEDED */ - --#ifndef NF_IP_LOCAL_IN /* 2.6.25 */ --#define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING --#define NF_IP_LOCAL_IN NF_INET_LOCAL_IN --#define NF_IP_FORWARD NF_INET_FORWARD --#define NF_IP_LOCAL_OUT NF_INET_LOCAL_OUT --#define NF_IP_POST_ROUTING NF_INET_POST_ROUTING --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) --/* net/netfilter/x_tables.c */ --static void xt_unregister_targets(struct xt_target *target, unsigned int n) --{ -- unsigned int i; -- -- for (i = 0; i < n; i++) -- xt_unregister_target(&target[i]); --} --static int xt_register_targets(struct xt_target *target, unsigned int n) --{ -- unsigned int i; -- -- int err = 0; -- for (i = 0; i < n; i++) -- if ((err = xt_register_target(&target[i]))) -- goto err; -- return err; --err: -- if (i > 0) -- xt_unregister_targets(target, i); -- return err; --} --#endif -- - static struct ipt_target ipt_netflow_reg[] __read_mostly = { - { - .name = "NETFLOW", -@@ -5296,9 +5383,6 @@ static int __init ipt_netflow_init(void) - clear_ipt_netflow_stat(); - - if (!hashsize) { --#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0) --#define num_physpages totalram_pages --#endif - /* use 1/1024 of memory, 1M for hash table on 1G box */ - unsigned long memksize = (num_physpages << PAGE_SHIFT) / 1024; - -@@ -5318,6 +5402,11 @@ static int __init ipt_netflow_init(void) - goto err; - } - -+#ifdef MPLS_DEPTH -+ if (MPLS_DEPTH >= 0 && MPLS_DEPTH < 10) -+ template_mpls.types[MPLS_LABELS_BASE_INDEX + MPLS_DEPTH] = 0; -+#endif -+ - for (i = 0; i < LOCK_COUNT; i++) { - spin_lock_init(&htable_stripes[i].lock); - INIT_LIST_HEAD(&htable_stripes[i].list); -@@ -5339,10 +5428,8 @@ static int __init ipt_netflow_init(void) - goto err_free_netflow_slab; - if (!register_stat("ipt_netflow_snmp", &snmp_seq_fops)) - goto err_free_proc_stat1; -- --#ifdef ENABLE_DEBUGFS -- flows_dump_d = debugfs_create_file("netflow_dump", S_IRUGO, NULL, NULL, &flows_dump_fops); --#endif -+ if (!register_stat("ipt_netflow_flows", &flows_seq_fops)) -+ goto err_free_proc_stat2; - - #ifdef CONFIG_SYSCTL - ctl_table_renumber(netflow_sysctl_table); -@@ -5357,7 +5444,7 @@ static int __init ipt_netflow_init(void) - #endif - if (!netflow_sysctl_header) { - printk(KERN_ERR "netflow: can't register to sysctl\n"); -- goto err_free_proc_stat2; -+ goto err_free_proc_stat3; - } else - printk(KERN_INFO "netflow: registered: sysctl net.netflow\n"); - #endif -@@ -5443,12 +5530,11 @@ err_stop_timer: - err_free_sysctl: - #ifdef CONFIG_SYSCTL - unregister_sysctl_table(netflow_sysctl_header); --err_free_proc_stat2: --#endif --#ifdef ENABLE_DEBUGFS -- debugfs_remove(flows_dump_d); - #endif -+err_free_proc_stat3: - #ifdef CONFIG_PROC_FS -+ remove_proc_entry("ipt_netflow_flows", INIT_NET(proc_net_stat)); -+err_free_proc_stat2: - remove_proc_entry("ipt_netflow_snmp", INIT_NET(proc_net_stat)); - err_free_proc_stat1: - remove_proc_entry("ipt_netflow", INIT_NET(proc_net_stat)); -@@ -5469,10 +5555,8 @@ static void __exit ipt_netflow_fini(void) - #ifdef CONFIG_SYSCTL - unregister_sysctl_table(netflow_sysctl_header); - #endif --#ifdef ENABLE_DEBUGFS -- debugfs_remove(flows_dump_d); --#endif - #ifdef CONFIG_PROC_FS -+ remove_proc_entry("ipt_netflow_flows", INIT_NET(proc_net_stat)); - remove_proc_entry("ipt_netflow_snmp", INIT_NET(proc_net_stat)); - remove_proc_entry("ipt_netflow", INIT_NET(proc_net_stat)); - #endif -diff --git a/ipt_NETFLOW.h b/ipt_NETFLOW.h -index 59512f0..eb00e94 100644 ---- a/ipt_NETFLOW.h -+++ b/ipt_NETFLOW.h -@@ -16,8 +16,8 @@ - * - */ - --#ifndef _IP_NETFLOW_H --#define _IP_NETFLOW_H -+#ifndef _IPT_NETFLOW_H -+#define _IPT_NETFLOW_H - - /* - * Some tech info: -@@ -113,9 +113,20 @@ struct netflow5_pdu { - two(61, DIRECTION, flowDirection, 1) \ - two(62, IPV6_NEXT_HOP, ipNextHopIPv6Address, 16) \ - two(64, IPV6_OPTION_HEADERS, ipv6ExtensionHeaders, 2) \ -+ two(70, MPLS_LABEL_1, mplsTopLabelStackSection, 3) \ -+ two(71, MPLS_LABEL_2, mplsLabelStackSection2, 3) \ -+ two(72, MPLS_LABEL_3, mplsLabelStackSection3, 3) \ -+ two(73, MPLS_LABEL_4, mplsLabelStackSection4, 3) \ -+ two(74, MPLS_LABEL_5, mplsLabelStackSection5, 3) \ -+ two(75, MPLS_LABEL_6, mplsLabelStackSection6, 3) \ -+ two(76, MPLS_LABEL_7, mplsLabelStackSection7, 3) \ -+ two(77, MPLS_LABEL_8, mplsLabelStackSection8, 3) \ -+ two(78, MPLS_LABEL_9, mplsLabelStackSection9, 3) \ -+ two(79, MPLS_LABEL_10, mplsLabelStackSection10, 3) \ - one(80, destinationMacAddress, 6) \ - two(82, IF_NAME, interfaceName, IF_NAME_SZ) \ - two(83, IF_DESC, interfaceDescription, IF_DESC_SZ) \ -+ one(136, flowEndReason, 1) \ - one(138, observationPointId, 4) \ - one(139, icmpTypeCodeIPv6, 2) \ - one(141, LineCardId, 4) \ -@@ -135,6 +146,9 @@ struct netflow5_pdu { - one(166, notSentFlowTotalCount, 8) \ - one(167, notSentPacketTotalCount, 8) \ - one(168, notSentOctetTotalCount, 8) \ -+ one(200, mplsTopLabelTTL, 1) \ -+ one(201, mplsLabelStackLength, 1) \ -+ one(202, mplsLabelStackDepth, 1) \ - one(208, ipv4Options, 4) \ - one(209, tcpOptions, 4) \ - one(225, postNATSourceIPv4Address, 4) \ -@@ -146,6 +160,8 @@ struct netflow5_pdu { - one(244, dot1qPriority, 1) \ - one(245, dot1qCustomerVlanId, 2) \ - one(246, dot1qCustomerPriority, 1) \ -+ one(252, ingressPhysicalInterface, 2) \ -+ one(253, egressPhysicalInterface, 2) \ - one(256, ethernetType, 2) \ - one(295, IPSecSPI, 4) \ - one(300, observationDomainName, 128) \ -@@ -240,18 +256,10 @@ struct ipfix_pdu { - * not searchable and will be exported soon. */ - #define FLOW_FULL_WATERMARK 0xffefffff - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) --union nf_inet_addr { -- __be32 ip; -- __be32 ip6[4]; -- struct in_addr in; -- struct in6_addr in6; --}; --#endif -- - #define EXTRACT_SPI(tuple) ((tuple.s_port << 16) | tuple.d_port) - #define SAVE_SPI(tuple, spi) { tuple.s_port = spi >> 16; \ - tuple.d_port = spi; } -+#define MAX_VLAN_TAGS 2 - - /* hashed data which identify unique flow */ - /* 16+16 + 2+2 + 2+1+1+1 = 41 */ -@@ -260,10 +268,12 @@ struct ipt_netflow_tuple { - union nf_inet_addr dst; - __be16 s_port; // Network byte order - __be16 d_port; // -"- -+#ifdef MPLS_DEPTH -+ __be32 mpls[MPLS_DEPTH]; /* Network byte order */ -+#endif - __u16 i_ifc; // Host byte order - #ifdef ENABLE_VLAN -- __be16 tag1; // Network byte order (outer tag) -- __be16 tag2; // -"- -+ __be16 tag[MAX_VLAN_TAGS]; // Network byte order (outer tag first) - #endif - __u8 protocol; - __u8 tos; -@@ -287,13 +297,18 @@ struct ipt_netflow { - __be16 ethernetType; /* Network byte order */ - #endif - __u16 o_ifc; -+#ifdef ENABLE_PHYSDEV -+ __u16 i_ifphys; -+ __u16 o_ifphys; -+#endif - #ifdef SNMP_RULES -- __u16 i_ifcr; -+ __u16 i_ifcr; /* translated interface numbers*/ - __u16 o_ifcr; - #endif - __u8 s_mask; - __u8 d_mask; - __u8 tcp_flags; /* `OR' of all tcp flags */ -+ __u8 flowEndReason; - #ifdef ENABLE_DIRECTION - __u8 hooknumx; /* hooknum + 1 */ - #endif -@@ -362,8 +377,7 @@ static inline int ipt_netflow_tuple_equal(const struct ipt_netflow_tuple *t1, - struct ipt_netflow_sock { - struct list_head list; - struct socket *sock; -- __be32 ipaddr; // destination -- unsigned short port; -+ struct sockaddr_storage addr; // destination - atomic_t wmem_peak; // sk_wmem_alloc peak value - unsigned int err_connect; // connect errors - unsigned int err_full; // socket filled error -@@ -446,9 +460,6 @@ struct ipt_netflow_stat { - unsigned int frags; // packets stat (drop) - unsigned int maxflows_err; // maxflows reached (drop) - unsigned int alloc_err; // failed to allocate memory (drop & lost) --#ifdef ENABLE_DEBUGFS -- unsigned int freeze_err; // freeze errors (drop) --#endif - struct duration drop; - unsigned int send_success; // sendmsg() ok - unsigned int send_failed; // sendmsg() failed -@@ -478,10 +489,5 @@ struct ipt_netflow_stat { - int metric; // one minute ewma of hash efficiency - }; - --#ifndef list_first_entry --#define list_first_entry(ptr, type, member) \ -- list_entry((ptr)->next, type, member) --#endif -- - #endif - /* vim: set sw=8: */ -diff --git a/snmp_NETFLOW.c b/snmp_NETFLOW.c -index cf1d743..62457db 100644 ---- a/snmp_NETFLOW.c -+++ b/snmp_NETFLOW.c -@@ -368,10 +368,10 @@ static int iptNetflowSysctl_handler( - return sysctl_read(request, obj); - case MODE_SET_RESERVE1: - sys = find_varinfo(sysctls, obj); -- if (request->requestvb->type != sys->type) -- netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE); -- if (!sysctl_access_ok(sys->name)) -+ if (!sys || !sysctl_access_ok(sys->name)) - netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME); -+ if (sys && request->requestvb->type != sys->type) -+ netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE); - break; - case MODE_SET_RESERVE2: - case MODE_SET_FREE: -diff --git a/testing.sh b/testing.sh -index b465c8d..45a0619 100755 ---- a/testing.sh -+++ b/testing.sh -@@ -6,7 +6,7 @@ if [ "$1" = "" ]; then - echo Maintainer only tool. - exit 1 - elif [ "$1" = all ]; then -- exec bash $0 linux-2.6.18 centos5 linux-3.11.2 centos6 linux-3.4.66 linux-3.9.11 centos7 linux-3.14 linux-3.17 -+ exec bash $0 linux-2.6.18 centos5 linux-3.11.2 centos6 linux-3.4.66 linux-3.9.11 centos7 linux-3.14 linux-3.17 linux-3.19 - exit 1 - fi - -@@ -28,11 +28,17 @@ readarray -t opts <<EOF - --enable-snmp-rules - --enable-macaddress - --enable-vlan -+ --promisc-mpls - --enable-direction - --enable-sampler - --enable-sampler=hash -- --enable-promisc -+ --enable-promisc --promisc-mpls -+ --enable-physdev -+ --enable-physdev-override - EOF -+if [ "$SHORT" ]; then -+ opts=("$SHORT") -+fi - - colorecho() { - echo -e "\033[1;32m$@\033[m" -diff --git a/version.sh b/version.sh -index e39433b..2509149 100755 ---- a/version.sh -+++ b/version.sh -@@ -7,25 +7,29 @@ PATH=$PATH:/usr/local/bin:/usr/bin:/bin - MVERSION=`sed -n 's/^#define.*IPT_NETFLOW_VERSION.*"\(.*\)".*/\1/p' ipt_NETFLOW.c` - - # GITVERSION overrides base version. --if [ -e version.h ]; then -+if [ -e version.h ] && grep -q GITVERSION version.h; then - MVERSION=`sed -n 's/#define GITVERSION "\(.*\)".*/\1/p' version.h` - fi - - # git describe overrides version from the source. - if [ -d .git ] && which git >/dev/null 2>&1; then \ -- GVERSION=`git describe --dirty` -- MVERSION=${GVERSION#v} -+ GVERSION=`git describe --dirty 2>/dev/null` -+ if [ "$GVERSION" ]; then -+ MVERSION=${GVERSION#v} -+ fi - else - GVERSION= - fi - - if [ "$1" = --define ]; then -- # output version.h which is GITVERSION or empty. -+ # called from Makefile to create version.h -+ # which should contain GITVERSION or be empty. - if [ "$GVERSION" ]; then - echo "#define GITVERSION \"$MVERSION\"" - else -- echo "/* kernel doesn't like empty files */" -+ echo "/* placeholder, because kernel doesn't like empty files */" - fi - else -+ # normal run - echo $MVERSION - fi diff --git a/testing/ipt-netflow-grsec/kernel-4.6.patch b/testing/ipt-netflow-grsec/kernel-4.6.patch new file mode 100644 index 0000000000..79fba3c5bf --- /dev/null +++ b/testing/ipt-netflow-grsec/kernel-4.6.patch @@ -0,0 +1,63 @@ +From c16ffc6cb679b3377a0d4a30a6bbcf5e2f3d0214 Mon Sep 17 00:00:00 2001 +From: ABC <abc@telekom.ru> +Date: Sun, 22 May 2016 22:07:14 +0300 +Subject: [PATCH] Support ETHTOOL_xLINKSETTINGS API (new in linux 4.6). + +Thus, making support for 4.6 kernels. +Reference to linux commit: + https://github.com/torvalds/linux/commit/3f1ac7a700d + +Fixes #56, thanks karel-un. +--- + ipt_NETFLOW.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/ipt_NETFLOW.c b/ipt_NETFLOW.c +index 067fd50..d27eea2 100644 +--- a/ipt_NETFLOW.c ++++ b/ipt_NETFLOW.c +@@ -3904,7 +3904,13 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d + { + struct ethtool_drvinfo info = { 0 }; + const struct ethtool_ops *ops = dev->ethtool_ops; ++#ifndef ETHTOOL_GLINKSETTINGS + struct ethtool_cmd ecmd; ++#define _KSETTINGS(x, y) (x) ++#else ++ struct ethtool_link_ksettings ekmd; ++#define _KSETTINGS(x, y) (y) ++#endif + int len = size; + int n; + +@@ -3933,11 +3939,11 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d + /* only get_settings for running devices to not trigger link negotiation */ + if (dev->flags & IFF_UP && + dev->flags & IFF_RUNNING && +- !__ethtool_get_settings(dev, &ecmd)) { ++ !_KSETTINGS(__ethtool_get_settings(dev, &ecmd), __ethtool_get_link_ksettings(dev, &ekmd))) { + char *s, *p; + + /* append basic parameters: speed and port */ +- switch (ethtool_cmd_speed(&ecmd)) { ++ switch (_KSETTINGS(ethtool_cmd_speed(&ecmd), ekmd.base.speed)) { + case SPEED_10000: s = "10Gb"; break; + case SPEED_2500: s = "2.5Gb"; break; + case SPEED_1000: s = "1Gb"; break; +@@ -3945,7 +3951,7 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d + case SPEED_10: s = "10Mb"; break; + default: s = ""; + } +- switch (ecmd.port) { ++ switch (_KSETTINGS(ecmd.port, ekmd.base.port)) { + case PORT_TP: p = "tp"; break; + case PORT_AUI: p = "aui"; break; + case PORT_MII: p = "mii"; break; +@@ -3964,6 +3970,7 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d + ops->complete(dev); + return size - len; + } ++#undef _KSETTINGS + + static const unsigned short netdev_type[] = + {ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_AX25, |