summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/helper/conntrackd.conf8
-rw-r--r--doc/misc/README187
-rw-r--r--doc/misc/clusterip.sh254
-rw-r--r--src/cache-ct.c10
-rw-r--r--src/conntrack.c78
-rw-r--r--src/helpers/amanda.c1
-rw-r--r--src/helpers/dhcpv6.c1
-rw-r--r--src/helpers/ftp.c1
-rw-r--r--src/helpers/rpc.c1
-rw-r--r--src/helpers/sane.c1
-rw-r--r--src/helpers/slp.c1
-rw-r--r--src/helpers/ssdp.c1
-rw-r--r--src/helpers/tftp.c1
-rw-r--r--src/helpers/tns.c1
-rwxr-xr-xtests/conntrack/bulk-load-stress.sh163
15 files changed, 694 insertions, 15 deletions
diff --git a/doc/helper/conntrackd.conf b/doc/helper/conntrackd.conf
index cbcb284..efa318a 100644
--- a/doc/helper/conntrackd.conf
+++ b/doc/helper/conntrackd.conf
@@ -83,7 +83,7 @@ Helper {
}
}
Type mdns inet udp {
- QueueNum 6
+ QueueNum 5
QueueLen 10240
Policy mdns {
ExpectMax 8
@@ -91,7 +91,7 @@ Helper {
}
}
Type ssdp inet udp {
- QueueNum 5
+ QueueNum 6
QueueLen 10240
Policy ssdp {
ExpectMax 8
@@ -99,7 +99,7 @@ Helper {
}
}
Type ssdp inet tcp {
- QueueNum 5
+ QueueNum 7
QueueLen 10240
Policy ssdp {
ExpectMax 8
@@ -107,7 +107,7 @@ Helper {
}
}
Type slp inet udp {
- QueueNum 7
+ QueueNum 8
QueueLen 10240
Policy slp {
ExpectMax 8
diff --git a/doc/misc/README b/doc/misc/README
new file mode 100644
index 0000000..7d0a1ae
--- /dev/null
+++ b/doc/misc/README
@@ -0,0 +1,187 @@
+= Setting up active-active load-sharing hash-based stateful firewall =
+ by Pablo Neira Ayuso <pablo@netfilter.org> in 2010
+
+If you want to know more about this configuration and other firewall
+architectures, please read:
+
+* Demystifying cluster-based fault-tolerant firewalls.
+ IEEE Internet Computing, 13(6):31-38, December 2009.
+ Available at: https://perso.ens-lyon.fr/laurent.lefevre/pdf/IC2009_Neira_Gasca_Lefevre.pdf
+
+== 0x0 intro ==
+
+Under this directory you can find a script that allows you to setup a simple
+active-active hash-based load-sharing firewall cluster based on the iptables'
+cluster match.
+
+== 0x1 testbed ==
+
+My testbed looks like the following:
+
+ ---------- eth1 eth2 ----------
+ client A ------| |--- firewall 1 ----| |
+ (192.168.0.2) | switch | (.0.5) (.1.5) | switch |--- server
+ | | | | (192.168.1.2)
+ client B ------| |--- firewall 2 ----| |
+ (192.168.0.11) ---------- (.0.5) (.1.5) ----------
+ eth1 eth2
+
+The firewalls perform SNAT to masquerade clients. Note that both cluster
+firewall have the same IP addresses. For administrative purposes, it is
+a good idea that each firewall has its one IP address to SSH them, make
+sure you add the appropriate rule to skip the cluster match rule-set!
+More comments: although the picture shows two switches, I'm actually
+using one and I separated the clients and the server in two different
+VLANs.
+
+The script also sets a multicast MAC address that is the same for both
+firewalls so that the switch floods the same packets to both firewalls.
+Using a multicast MAC address is a RFC violation [1], since network node
+must not include multicast MAC address in ARP replies, but:
+
+ a) it is the only way I found so far to obtain the behaviour from my
+ HP procurve switches.
+
+ b) the VRRP MAC address range is not supported appropritely by switch
+ vendors, at least by my HP procurve switches. If switch vendors
+ support this MAC address range appropriately, they will handle them
+ as multicast MAC address. As of 2011 I did not find any switch handling
+ VRRP MAC address range as multicast ports (they still handle them as
+ normal unicast MAC addresses, therefore my solution does not work with
+ two nodes with the same VRRP MAC address).
+
+The cluster match relies upon the Connection Tracking System (conntrack).
+Thus, traffic coming in the reply direction which does not belong this node
+is labeled as INVALID for TCP and ICMP protocols. The scripts add a rule to
+drop this traffic to avoid possible packet duplication. For UDP traffic,
+you will have to add a rule to drop NEW traffic in the reply direction
+because conntrack considers it valid. If you don't do this, both nodes
+may accept reply traffic, thus, sending duplicated packets to the client,
+which is not what you want.
+
+During my last experiments, I was using the Linux kernel 2.6.37 in the
+firewalls and the server. Everything you need to setup this configuration
+is available in stock Linux kernels. No external patches with new features
+are required.
+
+== 0x2 running scripts ==
+
+Copy the script to each node, then adjust the script variables to your
+configuration.
+
+On firewall 1:
+firewall1# ./clusterip-node1.sh start
+
+On firewall 2:
+firewall2# ./clusterip-node2.sh start
+
+== 0x3 trouble-shooting ==
+
+Some troubleshooting may help to understand how this setup works. Check
+the following if you experience problems:
+
+1) Check that Multicast MAC address are assigned to the NICs:
+
+firewall1$ ip maddr
+[...]
+2: eth1
+[...]
+ link 01:00:5e:00:01:01 static
+3: eth2
+[...]
+ link 01:00:5e:00:01:02 static
+
+The scripts add the multicast MAC addresses to the NICs, if this
+is not done the traffic will be discarded by the firewalls'
+networking stack.
+
+2) ICMP ping the server from one the clients:
+
+client$ ping -c 1 192.168.1.2
+PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
+64 bytes from 192.168.1.2: icmp_seq=1 ttl=63 time=0.220 ms
+
+--- 192.168.1.2 ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+rtt min/avg/max/mdev = 0.220/0.220/0.220/0.000 ms
+
+If this does not work, make sure the firewalls are including the
+multicast MAC address in their ARP replies, you can check this
+by looking at the neigbour cache:
+
+client$ ip neighbour
+[...]
+192.168.0.5 dev eth1 lladdr 01:00:5e:00:01:01 REACHABLE
+
+server$ ip neighbour
+[...]
+192.168.1.5 dev eth1 lladdr 01:00:5e:00:01:02 REACHABLE
+
+firewall$ ip neighbour
+[...]
+192.168.0.5 dev eth1 lladdr 01:00:5e:00:01:01 REACHABLE
+192.168.1.5 dev eth2 lladdr 01:00:5e:00:01:02 REACHABLE
+
+3) Test TCP connections: you can use netcat to start simple connections
+between the client and the server.
+
+You can also use intensive HTTP traffic generation to test performance
+like injectX.c and httpterm from Willy Tarreau:
+
+http://1wt.eu/tools/inject/
+http://1wt.eu/tools/httpterm/
+
+clientA:~/http-client-benchmark# ./client -t 60 -u 200 -G 192.168.1.2:8000
+# hits hits/s ^h/s ^bytes kB/s errs rst tout mhtime
+ 266926 26692 26766 3881270 3779 0 0 0 0.237
+ 294067 26733 27141 3935621 3785 0 0 0 0.176
+
+clientB~/http-client-benchmark# ./client -t 30 -u 40 -G 192.168.1.2:8020
+# hits hits/s ^h/s ^bytes kB/s errs rst tout mhtime
+ 53250 17750 17368 2518448 2513 0 0 0 0.240
+ 70766 17691 17516 2539907 2505 0 0 0 0.297
+
+^h/s is the current number of HTTP petitions per second. This means
+that you get ~45000 HTTP petitions per second. In my setup, with only
+one firewall active I get ~27000 HTTP petitions per second. We obtain
+extra performance of ~66%, not that bad 8-).
+
+I have configured httpterm to send object of 0 bytes over HTTP
+to obtain the maximum number of HTTP flows. This is the worst case
+scenario in firewall load.
+
+I forgot to mention that I set CPU affinity for NICs IRQs. I've got
+two cores, one for each firewall NIC.
+
+== 0x4 report sucessful setups ==
+
+My testbed is composed of low-cost basic five years old HP proliant
+systems, you can see that the numbers are not great. I like knowing
+about numbers, I'd appreciate if you drop me a line to tell me the
+numbers that you get and your experience.
+
+== 0x5 conclusions and future works ==
+
+The cluster match allows to setup load-sharing hash-based stateful
+firewalls that is a way to avoid having a spare backup firewall as
+it happens in classical Primary-Backup setups.
+
+Still, there is some pending work to fully integrate conntrackd and HA
+managers with it (in case that you want high availability, of course).
+
+-o-
+
+[1] More specifically, it's a RFC 1812 (section 3.3.2) violation.
+It's been reported that this is a problem for CISCO routers:
+http://marc.info/?l=netfilter&m=128810399113170&w=2
+
+Michele Codutti: "The problem is the multicast MAC address that these
+routers doesn't "like". They discard any incoming packet with MAC
+multicast address to be compliant with RFC1812. The only documented
+(by Cisco) workaround is to put a fixed arp entry with the multicast
+address that maps the clustered IP in the router."
+
+If you keep reading the mailing thread, the reported problem affected
+Cisco 7200 VXR.
+
+--02/02/2010
diff --git a/doc/misc/clusterip.sh b/doc/misc/clusterip.sh
new file mode 100644
index 0000000..911f676
--- /dev/null
+++ b/doc/misc/clusterip.sh
@@ -0,0 +1,254 @@
+#!/bin/sh
+
+#
+# (C) 2009-2011 by Pablo Neira Ayuso <pneira@us.es>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+
+#
+# Here, you can find the variables that you have to change.
+#
+
+# enable this for debugging
+LOG_DEBUG=0
+
+# number of cluster node (must be unique, from 1 to N cluster nodes)
+NODE=1
+
+# this is the real MAC address of eth1
+REAL_HWADDR1=00:18:71:68:f2:34
+
+# this is the real MAC address of eth2
+REAL_HWADDR2=00:11:0a:60:e7:32
+
+#
+# These variables MUST have the same values in both cluster nodes
+#
+
+# number of nodes that belong this cluster
+TOTAL_NODES=2
+
+# this is the cluster multicast MAC address of eth1
+MC_HWADDR1=01:00:5e:00:01:01
+
+# this is the cluster multicast MAC address of eth2
+MC_HWADDR2=01:00:5e:00:01:02
+
+# cluster IP address of eth1
+ADDR1=192.168.0.5/24
+
+# cluster IP address of eth2
+ADDR2=192.168.1.5/24
+
+# random seed for hashing
+SEED=0xdeadbeef
+
+start_cluster_address()
+{
+ # set cluster IP addresses
+ ip a a $ADDR1 dev eth1
+ ip a a $ADDR2 dev eth2
+ # set cluster multicast MAC addresses
+ ip maddr add $MC_HWADDR1 dev eth1
+ ip maddr add $MC_HWADDR2 dev eth2
+ # mangle ARP replies to include the cluster multicast MAC addresses
+ arptables -I OUTPUT -o eth1 --h-length 6 \
+ -j mangle --mangle-mac-s $MC_HWADDR1
+ # mangle ARP request to use the original MAC address (otherwise the
+ # stack drops this packet).
+ arptables -I INPUT -i eth1 --h-length 6 --destination-mac \
+ $MC_HWADDR1 -j mangle --mangle-mac-d $REAL_HWADDR1
+ arptables -I OUTPUT -o eth2 --h-length 6 \
+ -j mangle --mangle-mac-s $MC_HWADDR2
+ arptables -I INPUT -i eth2 --h-length 6 --destination-mac \
+ $MC_HWADDR2 -j mangle --mangle-mac-d $REAL_HWADDR2
+}
+
+stop_cluster_address()
+{
+ # delete cluster IP addresses
+ ip a d $ADDR1 dev eth1
+ ip a d $ADDR2 dev eth2
+ # delete cluster multicast MAC addresses
+ ip maddr del $MC_HWADDR1 dev eth1
+ ip maddr del $MC_HWADDR2 dev eth2
+ # delete ARP replies mangling
+ arptables -D OUTPUT -o eth1 --h-length 6 \
+ -j mangle --mangle-mac-s $MC_HWADDR1
+ # delete ARP requests mangling
+ arptables -D INPUT -i eth1 --h-length 6 --destination-mac \
+ $MC_HWADDR1 -j mangle --mangle-mac-d $REAL_HWADDR1
+ arptables -D OUTPUT -o eth2 --h-length 6 \
+ -j mangle --mangle-mac-s $MC_HWADDR2
+ arptables -D INPUT -i eth2 --h-length 6 --destination-mac \
+ $MC_HWADDR2 -j mangle --mangle-mac-d $REAL_HWADDR2
+}
+
+start_nat()
+{
+ iptables -A POSTROUTING -t nat -s 192.168.0.11 \
+ -j SNAT --to-source 192.168.1.5
+ iptables -A POSTROUTING -t nat -s 192.168.0.2 \
+ -j SNAT --to-source 192.168.1.5
+}
+
+stop_nat()
+{
+ iptables -D POSTROUTING -t nat -s 192.168.0.11 \
+ -j SNAT --to-source 192.168.1.5
+ iptables -D POSTROUTING -t nat -s 192.168.0.2 \
+ -j SNAT --to-source 192.168.1.5
+}
+
+iptables_start_cluster_rules()
+{
+ # mark packets that belong to this node (go direction)
+ iptables -A CLUSTER-RULES -t mangle -i eth1 -m cluster \
+ --cluster-total-nodes $TOTAL_NODES --cluster-local-node $1 \
+ --cluster-hash-seed $SEED -j MARK --set-mark 0xffff
+
+ # mark packet that belong to this node (reply direction)
+ # note: we *do* need this to change the packet type to PACKET_HOST,
+ # otherwise the stack silently drops the packet.
+ iptables -A CLUSTER-RULES -t mangle -i eth2 -m cluster \
+ --cluster-total-nodes $TOTAL_NODES --cluster-local-node $1 \
+ --cluster-hash-seed $SEED -j MARK --set-mark 0xffff
+}
+
+iptables_stop_cluster_rules()
+{
+ iptables -D CLUSTER-RULES -t mangle -i eth1 -m cluster \
+ --cluster-total-nodes $TOTAL_NODES --cluster-local-node $1 \
+ --cluster-hash-seed $SEED -j MARK --set-mark 0xffff
+
+ iptables -D CLUSTER-RULES -t mangle -i eth2 -m cluster \
+ --cluster-total-nodes $TOTAL_NODES --cluster-local-node $1 \
+ --cluster-hash-seed $SEED -j MARK --set-mark 0xffff
+}
+
+start_cluster_ruleset() {
+ iptables -N CLUSTER-RULES -t mangle
+
+ iptables_start_cluster_rules $NODE
+
+ iptables -A PREROUTING -t mangle -j CLUSTER-RULES
+
+ if [ $LOG_DEBUG -eq 1 ]
+ then
+ iptables -A PREROUTING -t mangle -i eth1 -m mark \
+ --mark 0xffff -j LOG --log-prefix "cluster-accept: "
+ iptables -A PREROUTING -t mangle -i eth1 -m mark \
+ ! --mark 0xffff -j LOG --log-prefix "cluster-drop: "
+ iptables -A PREROUTING -t mangle -i eth2 -m mark \
+ --mark 0xffff \
+ -j LOG --log-prefix "cluster-reply-accept: "
+ iptables -A PREROUTING -t mangle -i eth2 -m mark \
+ ! --mark 0xffff \
+ -j LOG --log-prefix "cluster-reply-drop: "
+ fi
+
+ # drop packets that don't belong to us (go direction)
+ iptables -A PREROUTING -t mangle -i eth1 -m mark \
+ ! --mark 0xffff -j DROP
+
+ # drop packets that don't belong to us (reply direction)
+ iptables -A PREROUTING -t mangle -i eth2 -m mark \
+ ! --mark 0xffff -j DROP
+}
+
+stop_cluster_ruleset() {
+ iptables -D PREROUTING -t mangle -j CLUSTER-RULES
+
+ if [ $LOG_DEBUG -eq 1 ]
+ then
+ iptables -D PREROUTING -t mangle -i eth1 -m mark \
+ --mark 0xffff -j LOG --log-prefix "cluster-accept: "
+ iptables -D PREROUTING -t mangle -i eth1 -m mark \
+ ! --mark 0xffff -j LOG --log-prefix "cluster-drop: "
+ iptables -D PREROUTING -t mangle -i eth2 -m mark \
+ --mark 0xffff \
+ -j LOG --log-prefix "cluster-reply-accept: "
+ iptables -D PREROUTING -t mangle -i eth2 -m mark \
+ ! --mark 0xffff \
+ -j LOG --log-prefix "cluster-reply-drop: "
+ fi
+
+ iptables -D PREROUTING -t mangle -i eth1 -m mark \
+ ! --mark 0xffff -j DROP
+
+ iptables -D PREROUTING -t mangle -i eth2 -m mark \
+ ! --mark 0xffff -j DROP
+
+ iptables_stop_cluster_rules $NODE
+
+ iptables -F CLUSTER-RULES -t mangle
+ iptables -X CLUSTER-RULES -t mangle
+}
+
+case "$1" in
+start)
+ echo "starting cluster configuration for node $NODE."
+
+ # just in case that you forget it
+ echo 1 > /proc/sys/net/ipv4/ip_forward
+
+ # disable TCP pickup
+ echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_be_liberal
+ echo 0 > /proc/sys/net/ipv4/netfilter/ip_conntrack_tcp_loose
+
+ start_cluster_address
+ start_nat
+
+ # drop invalid flows from eth2 (not allowed). This is mandatory
+ # because traffic which does not belong to this node is always
+ # labeled as INVALID by TCP and ICMP state tracking. For protocols like
+ # UDP, you will have to drop NEW traffic from eth2, otherwise reply
+ # traffic may be accepted by both nodes, thus duplicating the traffic.
+ iptables -A PREROUTING -t mangle -i eth2 \
+ -m state --state INVALID -j DROP
+
+ start_cluster_ruleset
+ ;;
+stop)
+ echo "stopping cluster configuration for node $NODE."
+
+ stop_cluster_address
+ stop_nat
+
+ iptables -D PREROUTING -t mangle -i eth2 \
+ -m state --state INVALID -j DROP
+
+ stop_cluster_ruleset
+ ;;
+primary)
+ logger "cluster-match-script: entering MASTER state for node $2"
+ if [ -x $CONNTRACKD_SCRIPT ]
+ then
+ sh $CONNTRACKD_SCRIPT primary $NODE $2
+ fi
+ iptables_start_cluster_rules $2
+ ;;
+backup)
+ logger "cluster-match-script: entering BACKUP state for node $2"
+ if [ -x $CONNTRACKD_SCRIPT ]
+ then
+ sh $CONNTRACKD_SCRIPT backup $NODE $2
+ fi
+ iptables_stop_cluster_rules $2
+ ;;
+fault)
+ logger "cluster-match-script: entering FAULT state for node $2"
+ if [ -x $CONNTRACKD_SCRIPT ]
+ then
+ sh $CONNTRACKD_SCRIPT fault $NODE $2
+ fi
+ iptables_stop_cluster_rules $2
+ ;;
+*)
+ echo "$0 start|stop|add|del [nodeid]"
+ ;;
+esac
diff --git a/src/cache-ct.c b/src/cache-ct.c
index abcfde4..fe01e16 100644
--- a/src/cache-ct.c
+++ b/src/cache-ct.c
@@ -34,13 +34,14 @@
static uint32_t
cache_hash4_ct(const struct nf_conntrack *ct, const struct hashtable *table)
{
- uint32_t a[4] = {
+ uint32_t a[5] = {
[0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC),
[1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST),
[2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 |
nfct_get_attr_u8(ct, ATTR_L4PROTO),
[3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 |
nfct_get_attr_u16(ct, ATTR_PORT_DST),
+ [4] = nfct_get_attr_u16(ct, ATTR_ZONE),
};
/*
@@ -50,13 +51,13 @@ cache_hash4_ct(const struct nf_conntrack *ct, const struct hashtable *table)
* but using a multiply, less expensive than a divide. See:
* http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html
*/
- return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32;
+ return ((uint64_t)jhash2(a, 5, 0) * table->hashsize) >> 32;
}
static uint32_t
cache_hash6_ct(const struct nf_conntrack *ct, const struct hashtable *table)
{
- uint32_t a[10];
+ uint32_t a[11];
memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4);
memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_DST), sizeof(uint32_t)*4);
@@ -64,8 +65,9 @@ cache_hash6_ct(const struct nf_conntrack *ct, const struct hashtable *table)
nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 |
nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+ a[10] = nfct_get_attr_u16(ct, ATTR_ZONE);
- return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32;
+ return ((uint64_t)jhash2(a, 11, 0) * table->hashsize) >> 32;
}
static uint32_t
diff --git a/src/conntrack.c b/src/conntrack.c
index 987a521..9e2fa25 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -92,6 +92,10 @@ struct ct_tmpl {
struct nfct_filter_dump_mark filter_mark_kernel;
bool filter_mark_kernel_set;
+ /* Allow to filter by status from kernel-space. */
+ struct nfct_filter_dump_mark filter_status_kernel;
+ bool filter_status_kernel_set;
+
/* Allows filtering by ctlabels */
struct nfct_bitmask *label;
@@ -1146,7 +1150,7 @@ static struct parse_parameter {
};
static int
-do_parse_parameter(const char *str, size_t str_length, unsigned int *value,
+do_parse_parameter(const char *str, size_t str_length, unsigned int *value,
int parse_type)
{
size_t i;
@@ -1171,7 +1175,7 @@ do_parse_parameter(const char *str, size_t str_length, unsigned int *value,
ret = 1;
break;
}
-
+
return ret;
}
@@ -1193,6 +1197,53 @@ parse_parameter(const char *arg, unsigned int *status, int parse_type)
}
static void
+parse_parameter_mask(const char *arg, unsigned int *status, unsigned int *mask, int parse_type)
+{
+ static const char unreplied[] = "UNREPLIED";
+ unsigned int *value;
+ const char *comma;
+ bool negated;
+
+ while ((comma = strchr(arg, ',')) != NULL) {
+ if (comma == arg)
+ exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+
+ negated = *arg == '!';
+ if (negated)
+ arg++;
+ if (comma == arg)
+ exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+
+ value = negated ? mask : status;
+
+ if (!negated && strncmp(arg, unreplied, strlen(unreplied)) == 0) {
+ *mask |= IPS_SEEN_REPLY;
+ arg = comma+1;
+ continue;
+ }
+
+ if (!do_parse_parameter(arg, comma-arg, value, parse_type))
+ exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+ arg = comma+1;
+ }
+
+ negated = *arg == '!';
+ if (negated)
+ arg++;
+ value = negated ? mask : status;
+
+ if (!negated && strncmp(arg, unreplied, strlen(unreplied)) == 0) {
+ *mask |= IPS_SEEN_REPLY;
+ return;
+ }
+
+ if (strlen(arg) == 0
+ || !do_parse_parameter(arg, strlen(arg),
+ value, parse_type))
+ exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg);
+}
+
+static void
parse_u32_mask(const char *arg, struct u32_mask *m)
{
char *end;
@@ -2435,12 +2486,14 @@ nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family)
return mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, cb, NULL);
}
+#define UNKNOWN_STATS_NUM 4
+
static int nfct_stats_attr_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
- if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
+ if (mnl_attr_type_valid(attr, CTA_STATS_MAX + UNKNOWN_STATS_NUM) < 0)
return MNL_CB_OK;
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
@@ -2452,8 +2505,6 @@ static int nfct_stats_attr_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
}
-#define UNKNOWN_STATS_NUM 4
-
static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[CTA_STATS_MAX + UNKNOWN_STATS_NUM + 1] = {};
@@ -2473,6 +2524,7 @@ static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data)
[CTA_STATS_ERROR] = "error",
[CTA_STATS_SEARCH_RESTART] = "search_restart",
[CTA_STATS_CLASH_RESOLVE] = "clash_resolve",
+ [CTA_STATS_CHAIN_TOOLONG] = "chaintoolong",
/* leave at end. Allows to show counters supported
* by newer kernel with older conntrack-tools release.
@@ -2914,8 +2966,16 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
break;
case 'u':
options |= CT_OPT_STATUS;
- parse_parameter(optarg, &status, PARSE_STATUS);
+ parse_parameter_mask(optarg, &status,
+ &tmpl->filter_status_kernel.mask,
+ PARSE_STATUS);
nfct_set_attr_u32(tmpl->ct, ATTR_STATUS, status);
+ if (tmpl->filter_status_kernel.mask == 0)
+ tmpl->filter_status_kernel.mask = status;
+
+ tmpl->mark.value = status;
+ tmpl->filter_status_kernel.val = tmpl->mark.value;
+ tmpl->filter_status_kernel_set = true;
break;
case 'e':
options |= CT_OPT_EVENT_MASK;
@@ -3171,7 +3231,11 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd)
nfct_filter_dump_set_attr_u8(filter_dump,
NFCT_FILTER_DUMP_L3NUM,
cmd->family);
-
+ if (cmd->tmpl.filter_status_kernel_set) {
+ nfct_filter_dump_set_attr(filter_dump,
+ NFCT_FILTER_DUMP_STATUS,
+ &cmd->tmpl.filter_status_kernel);
+ }
if (cmd->options & CT_OPT_ZERO)
res = nfct_query(cth, NFCT_Q_DUMP_FILTER_RESET,
filter_dump);
diff --git a/src/helpers/amanda.c b/src/helpers/amanda.c
index faee1cd..234d511 100644
--- a/src/helpers/amanda.c
+++ b/src/helpers/amanda.c
@@ -24,6 +24,7 @@
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/dhcpv6.c b/src/helpers/dhcpv6.c
index f87b6ce..4c5676d 100644
--- a/src/helpers/dhcpv6.c
+++ b/src/helpers/dhcpv6.c
@@ -25,6 +25,7 @@
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/ftp.c b/src/helpers/ftp.c
index c3aa284..2505c71 100644
--- a/src/helpers/ftp.c
+++ b/src/helpers/ftp.c
@@ -30,6 +30,7 @@
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/rpc.c b/src/helpers/rpc.c
index bd24dd3..3b3d0a7 100644
--- a/src/helpers/rpc.c
+++ b/src/helpers/rpc.c
@@ -35,6 +35,7 @@
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/sane.c b/src/helpers/sane.c
index c30f4ba..2c07099 100644
--- a/src/helpers/sane.c
+++ b/src/helpers/sane.c
@@ -34,6 +34,7 @@
#include <netinet/tcp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/slp.c b/src/helpers/slp.c
index b8339d6..a53485a 100644
--- a/src/helpers/slp.c
+++ b/src/helpers/slp.c
@@ -28,6 +28,7 @@
#include "myct.h"
#include "log.h"
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include <linux/netfilter.h>
diff --git a/src/helpers/ssdp.c b/src/helpers/ssdp.c
index 58658e3..56526f4 100644
--- a/src/helpers/ssdp.c
+++ b/src/helpers/ssdp.c
@@ -54,6 +54,7 @@
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/tftp.c b/src/helpers/tftp.c
index 70dd28a..e61195f 100644
--- a/src/helpers/tftp.c
+++ b/src/helpers/tftp.c
@@ -20,6 +20,7 @@
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/tns.c b/src/helpers/tns.c
index 2b4fed4..803f40a 100644
--- a/src/helpers/tns.c
+++ b/src/helpers/tns.c
@@ -23,6 +23,7 @@
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/tests/conntrack/bulk-load-stress.sh b/tests/conntrack/bulk-load-stress.sh
new file mode 100755
index 0000000..9250528
--- /dev/null
+++ b/tests/conntrack/bulk-load-stress.sh
@@ -0,0 +1,163 @@
+#!/bin/bash
+
+DEFAULT_CT="../../src/conntrack"
+DEFAULT_SPORT_COUNT=0xffff
+DEFAULT_DPORT_COUNT=0x2
+DEFAULT_TMP_FILE="./ct_data.txt"
+DEFAULT_CT_ZONE=123
+DEFAULT_GEN_ONLY=0
+DEFAULT_CLEANUP_INDIVIDUAL=0
+
+CT=$DEFAULT_CT
+SPORT_COUNT=$DEFAULT_SPORT_COUNT
+DPORT_COUNT=$DEFAULT_DPORT_COUNT
+TMP_FILE=$DEFAULT_TMP_FILE
+CT_ZONE=$DEFAULT_CT_ZONE
+GEN_ONLY=$DEFAULT_GEN_ONLY
+CLEANUP_INDIVIDUAL=$DEFAULT_CLEANUP_INDIVIDUAL
+
+print_help()
+{
+ me=$(basename "$0")
+
+ echo "Script for stress-testing bulk ct entries load (-R option)"
+ echo ""
+ echo "Usage: $me [options]"
+ echo ""
+ echo "Where options can be:"
+ echo ""
+ echo "-dpc <dst_port_count> - number of destination port values."
+ echo " Default is ${DEFAULT_DPORT_COUNT}."
+ echo ""
+ echo "-spc <src_port_count> - number of source port values."
+ echo " Default is ${DEFAULT_SPORT_COUNT}."
+ echo ""
+ echo "-ct <ct_tool_path> - path to the conntrack tool."
+ echo " Default is ${DEFAULT_CT}."
+ echo ""
+ echo "-z <ct_zone> - ct zone to be used."
+ echo " Default is ${DEFAULT_CT_ZONE}."
+ echo ""
+ echo "-f <tmp_file_name> - tmp file to be used to generate the ct data to."
+ echo " Default is ${DEFAULT_TMP_FILE}."
+ echo ""
+ echo "-g - Generate tmp file and exit."
+ echo ""
+ echo "-h - Print this help and exit."
+}
+
+function ct_data_gen()
+{
+ for (( d = 1; d <= $DPORT_COUNT; d++ )) do
+ for (( s = 1; s <= $SPORT_COUNT; s++ )) do
+ echo "-I -w $CT_ZONE -s 1.1.1.1 -d 2.2.2.2 -p tcp --sport ${s} --dport ${d} --state LISTEN -u SEEN_REPLY -t 50"
+ done
+ done
+}
+
+if [ $UID -ne 0 ]
+then
+ echo "Run this test as root"
+ exit 1
+fi
+
+while [ $# -gt 0 ]
+do
+ case "$1" in
+ -spc)
+ SPORT_COUNT=${2:-}
+ if [ -z "$SPORT_COUNT" ]
+ then
+ echo "Source port must be specified!"
+ print_help
+ exit 1
+ fi
+ shift
+ ;;
+ -dpc)
+ DPORT_COUNT=${2:-}
+ if [ -z "$DPORT_COUNT" ]
+ then
+ echo "Destination port must be specified!"
+ print_help
+ exit 1
+ fi
+ shift
+ ;;
+ -ct)
+ CT=${2:-}
+ if [ -z "$CT" ]
+ then
+ echo "conntrack path must be specified!"
+ print_help
+ exit 1
+ fi
+ shift
+ ;;
+ -z)
+ CT_ZONE=${2:-}
+ if [ -z "$CT_ZONE" ]
+ then
+ echo "ct zone must be specified!"
+ print_help
+ exit 1
+ fi
+ shift
+ ;;
+ -f)
+ TMP_FILE=${2:-}
+ if [ -z "$TMP_FILE" ]
+ then
+ echo "Tmp file must be specified!"
+ print_help
+ exit 1
+ fi
+ shift
+ ;;
+ -g)
+ GEN_ONLY=1
+ ;;
+ -ci)
+ CLEANUP_INDIVIDUAL=1
+ ;;
+ -h)
+ print_help
+ exit 1
+ ;;
+ *)
+ echo "Unknown paramerer \"$1\""
+ print_help
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+ct_data_gen > $TMP_FILE
+
+NUM_ENTRIES=$(cat ${TMP_FILE} | wc -l)
+
+echo "File ${TMP_FILE} is generated, number of entries: ${NUM_ENTRIES}."
+
+if [ "$GEN_ONLY" -eq "1" ]; then
+ exit 0
+fi
+
+echo "Loading ${NUM_ENTRIES} entries from ${TMP_FILE} .."
+time -p ${CT} -R $TMP_FILE
+
+if [ "$CLEANUP_INDIVIDUAL" -eq "1" ]; then
+ sed -i -e "s/-I/-D/g" -e "s/-t 50//g" $TMP_FILE
+
+ NUM_ENTRIES=$(cat ${TMP_FILE} | wc -l)
+
+ echo "File ${TMP_FILE} is updated, number of entries: ${NUM_ENTRIES}."
+
+ echo "Cleaning ${NUM_ENTRIES} entries from ${TMP_FILE} .."
+ time -p ${CT} -R $TMP_FILE
+fi
+
+
+echo "Cleaning up zone ${CT_ZONE}.."
+time -p ${CT} -D -w $CT_ZONE > /dev/null
+rm $TMP_FILE