aboutsummaryrefslogtreecommitdiffstats
path: root/net/netfilter
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-03-24 16:24:36 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-24 16:24:36 -0400
commitb5bb14386eabcb4229ade2bc0a2b237ca166d37d (patch)
tree1966e65479f0d12cec0a204443a95b8eb57946db /net/netfilter
parentbb4f92b3a33bfc31f55098da85be44702bea2d16 (diff)
parent1d45209d89e647e9f27e4afa1f47338df73bc112 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
Diffstat (limited to 'net/netfilter')
-rw-r--r--net/netfilter/Kconfig63
-rw-r--r--net/netfilter/Makefile4
-rw-r--r--net/netfilter/core.c2
-rw-r--r--net/netfilter/nf_conntrack_core.c14
-rw-r--r--net/netfilter/nf_conntrack_expect.c3
-rw-r--r--net/netfilter/nf_conntrack_netlink.c161
-rw-r--r--net/netfilter/nf_conntrack_proto.c21
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c145
-rw-r--r--net/netfilter/nf_conntrack_proto_generic.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c2
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c2
-rw-r--r--net/netfilter/nf_log.c201
-rw-r--r--net/netfilter/nfnetlink.c6
-rw-r--r--net/netfilter/nfnetlink_log.c18
-rw-r--r--net/netfilter/x_tables.c26
-rw-r--r--net/netfilter/xt_HL.c171
-rw-r--r--net/netfilter/xt_LED.c161
-rw-r--r--net/netfilter/xt_cluster.c164
-rw-r--r--net/netfilter/xt_hashlimit.c7
-rw-r--r--net/netfilter/xt_hl.c108
-rw-r--r--net/netfilter/xt_limit.c40
-rw-r--r--net/netfilter/xt_physdev.c37
-rw-r--r--net/netfilter/xt_quota.c31
-rw-r--r--net/netfilter/xt_statistic.c28
24 files changed, 1177 insertions, 240 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index c2bac9cd0ca..2562d05dbaf 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -357,6 +357,45 @@ config NETFILTER_XT_TARGET_DSCP
357 357
358 To compile it as a module, choose M here. If unsure, say N. 358 To compile it as a module, choose M here. If unsure, say N.
359 359
360config NETFILTER_XT_TARGET_HL
361 tristate '"HL" hoplimit target support'
362 depends on IP_NF_MANGLE || IP6_NF_MANGLE
363 depends on NETFILTER_ADVANCED
364 ---help---
365 This option adds the "HL" (for IPv6) and "TTL" (for IPv4)
366 targets, which enable the user to change the
367 hoplimit/time-to-live value of the IP header.
368
369 While it is safe to decrement the hoplimit/TTL value, the
370 modules also allow to increment and set the hoplimit value of
371 the header to arbitrary values. This is EXTREMELY DANGEROUS
372 since you can easily create immortal packets that loop
373 forever on the network.
374
375config NETFILTER_XT_TARGET_LED
376 tristate '"LED" target support'
377 depends on LEDS_CLASS
378 depends on NETFILTER_ADVANCED
379 help
380 This option adds a `LED' target, which allows you to blink LEDs in
381 response to particular packets passing through your machine.
382
383 This can be used to turn a spare LED into a network activity LED,
384 which only flashes in response to FTP transfers, for example. Or
385 you could have an LED which lights up for a minute or two every time
386 somebody connects to your machine via SSH.
387
388 You will need support for the "led" class to make this work.
389
390 To create an LED trigger for incoming SSH traffic:
391 iptables -A INPUT -p tcp --dport 22 -j LED --led-trigger-id ssh --led-delay 1000
392
393 Then attach the new trigger to an LED on your system:
394 echo netfilter-ssh > /sys/class/leds/<ledname>/trigger
395
396 For more information on the LEDs available on your system, see
397 Documentation/leds-class.txt
398
360config NETFILTER_XT_TARGET_MARK 399config NETFILTER_XT_TARGET_MARK
361 tristate '"MARK" target support' 400 tristate '"MARK" target support'
362 default m if NETFILTER_ADVANCED=n 401 default m if NETFILTER_ADVANCED=n
@@ -488,6 +527,22 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP
488 This option adds a "TCPOPTSTRIP" target, which allows you to strip 527 This option adds a "TCPOPTSTRIP" target, which allows you to strip
489 TCP options from TCP packets. 528 TCP options from TCP packets.
490 529
530config NETFILTER_XT_MATCH_CLUSTER
531 tristate '"cluster" match support'
532 depends on NF_CONNTRACK
533 depends on NETFILTER_ADVANCED
534 ---help---
535 This option allows you to build work-load-sharing clusters of
536 network servers/stateful firewalls without having a dedicated
537 load-balancing router/server/switch. Basically, this match returns
538 true when the packet must be handled by this cluster node. Thus,
539 all nodes see all packets and this match decides which node handles
540 what packets. The work-load sharing algorithm is based on source
541 address hashing.
542
543 If you say Y or M here, try `iptables -m cluster --help` for
544 more information.
545
491config NETFILTER_XT_MATCH_COMMENT 546config NETFILTER_XT_MATCH_COMMENT
492 tristate '"comment" match support' 547 tristate '"comment" match support'
493 depends on NETFILTER_ADVANCED 548 depends on NETFILTER_ADVANCED
@@ -605,6 +660,14 @@ config NETFILTER_XT_MATCH_HELPER
605 660
606 To compile it as a module, choose M here. If unsure, say Y. 661 To compile it as a module, choose M here. If unsure, say Y.
607 662
663config NETFILTER_XT_MATCH_HL
664 tristate '"hl" hoplimit/TTL match support'
665 depends on NETFILTER_ADVANCED
666 ---help---
667 HL matching allows you to match packets based on the hoplimit
668 in the IPv6 header, or the time-to-live field in the IPv4
669 header of the packet.
670
608config NETFILTER_XT_MATCH_IPRANGE 671config NETFILTER_XT_MATCH_IPRANGE
609 tristate '"iprange" address range match support' 672 tristate '"iprange" address range match support'
610 depends on NETFILTER_ADVANCED 673 depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index da3d909e053..6282060fbda 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -45,6 +45,8 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
45obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o 45obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
46obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o 46obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
47obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o 47obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
48obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
49obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
48obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o 50obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
49obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o 51obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
50obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o 52obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
@@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
57obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o 59obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
58 60
59# matches 61# matches
62obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o
60obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o 63obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
61obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o 64obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o
62obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o 65obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o
@@ -67,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o
67obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o 70obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o
68obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o 71obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o
69obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o 72obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o
73obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o
70obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o 74obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o
71obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o 75obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o
72obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o 76obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index a90ac83c591..5bb34737501 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -174,7 +174,6 @@ next_hook:
174 outdev, &elem, okfn, hook_thresh); 174 outdev, &elem, okfn, hook_thresh);
175 if (verdict == NF_ACCEPT || verdict == NF_STOP) { 175 if (verdict == NF_ACCEPT || verdict == NF_STOP) {
176 ret = 1; 176 ret = 1;
177 goto unlock;
178 } else if (verdict == NF_DROP) { 177 } else if (verdict == NF_DROP) {
179 kfree_skb(skb); 178 kfree_skb(skb);
180 ret = -EPERM; 179 ret = -EPERM;
@@ -183,7 +182,6 @@ next_hook:
183 verdict >> NF_VERDICT_BITS)) 182 verdict >> NF_VERDICT_BITS))
184 goto next_hook; 183 goto next_hook;
185 } 184 }
186unlock:
187 rcu_read_unlock(); 185 rcu_read_unlock();
188 return ret; 186 return ret;
189} 187}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f4935e344b6..dfb447b584d 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_lock);
54unsigned int nf_conntrack_htable_size __read_mostly; 54unsigned int nf_conntrack_htable_size __read_mostly;
55EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); 55EXPORT_SYMBOL_GPL(nf_conntrack_htable_size);
56 56
57int nf_conntrack_max __read_mostly; 57unsigned int nf_conntrack_max __read_mostly;
58EXPORT_SYMBOL_GPL(nf_conntrack_max); 58EXPORT_SYMBOL_GPL(nf_conntrack_max);
59 59
60struct nf_conn nf_conntrack_untracked __read_mostly; 60struct nf_conn nf_conntrack_untracked __read_mostly;
@@ -472,7 +472,8 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
472 struct nf_conn *ct; 472 struct nf_conn *ct;
473 473
474 if (unlikely(!nf_conntrack_hash_rnd_initted)) { 474 if (unlikely(!nf_conntrack_hash_rnd_initted)) {
475 get_random_bytes(&nf_conntrack_hash_rnd, 4); 475 get_random_bytes(&nf_conntrack_hash_rnd,
476 sizeof(nf_conntrack_hash_rnd));
476 nf_conntrack_hash_rnd_initted = 1; 477 nf_conntrack_hash_rnd_initted = 1;
477 } 478 }
478 479
@@ -516,16 +517,17 @@ EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
516static void nf_conntrack_free_rcu(struct rcu_head *head) 517static void nf_conntrack_free_rcu(struct rcu_head *head)
517{ 518{
518 struct nf_conn *ct = container_of(head, struct nf_conn, rcu); 519 struct nf_conn *ct = container_of(head, struct nf_conn, rcu);
519 struct net *net = nf_ct_net(ct);
520 520
521 nf_ct_ext_free(ct); 521 nf_ct_ext_free(ct);
522 kmem_cache_free(nf_conntrack_cachep, ct); 522 kmem_cache_free(nf_conntrack_cachep, ct);
523 atomic_dec(&net->ct.count);
524} 523}
525 524
526void nf_conntrack_free(struct nf_conn *ct) 525void nf_conntrack_free(struct nf_conn *ct)
527{ 526{
527 struct net *net = nf_ct_net(ct);
528
528 nf_ct_ext_destroy(ct); 529 nf_ct_ext_destroy(ct);
530 atomic_dec(&net->ct.count);
529 call_rcu(&ct->rcu, nf_conntrack_free_rcu); 531 call_rcu(&ct->rcu, nf_conntrack_free_rcu);
530} 532}
531EXPORT_SYMBOL_GPL(nf_conntrack_free); 533EXPORT_SYMBOL_GPL(nf_conntrack_free);
@@ -733,6 +735,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
733 nf_conntrack_put(skb->nfct); 735 nf_conntrack_put(skb->nfct);
734 skb->nfct = NULL; 736 skb->nfct = NULL;
735 NF_CT_STAT_INC_ATOMIC(net, invalid); 737 NF_CT_STAT_INC_ATOMIC(net, invalid);
738 if (ret == -NF_DROP)
739 NF_CT_STAT_INC_ATOMIC(net, drop);
736 return -ret; 740 return -ret;
737 } 741 }
738 742
@@ -1103,7 +1107,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
1103 1107
1104 /* We have to rehahs for the new table anyway, so we also can 1108 /* We have to rehahs for the new table anyway, so we also can
1105 * use a newrandom seed */ 1109 * use a newrandom seed */
1106 get_random_bytes(&rnd, 4); 1110 get_random_bytes(&rnd, sizeof(rnd));
1107 1111
1108 /* Lookups in the old hash might happen in parallel, which means we 1112 /* Lookups in the old hash might happen in parallel, which means we
1109 * might get false negatives during connection lookup. New connections 1113 * might get false negatives during connection lookup. New connections
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 3a8a34a6d37..357ba39d4c8 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -72,7 +72,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple
72 unsigned int hash; 72 unsigned int hash;
73 73
74 if (unlikely(!nf_ct_expect_hash_rnd_initted)) { 74 if (unlikely(!nf_ct_expect_hash_rnd_initted)) {
75 get_random_bytes(&nf_ct_expect_hash_rnd, 4); 75 get_random_bytes(&nf_ct_expect_hash_rnd,
76 sizeof(nf_ct_expect_hash_rnd));
76 nf_ct_expect_hash_rnd_initted = 1; 77 nf_ct_expect_hash_rnd_initted = 1;
77 } 78 }
78 79
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index ed6d873ad38..7a16bd462f8 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -518,6 +518,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this,
518nla_put_failure: 518nla_put_failure:
519 rcu_read_unlock(); 519 rcu_read_unlock();
520nlmsg_failure: 520nlmsg_failure:
521 nfnetlink_set_err(0, group, -ENOBUFS);
521 kfree_skb(skb); 522 kfree_skb(skb);
522 return NOTIFY_DONE; 523 return NOTIFY_DONE;
523} 524}
@@ -599,7 +600,8 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple)
599 600
600 nla_parse_nested(tb, CTA_IP_MAX, attr, NULL); 601 nla_parse_nested(tb, CTA_IP_MAX, attr, NULL);
601 602
602 l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); 603 rcu_read_lock();
604 l3proto = __nf_ct_l3proto_find(tuple->src.l3num);
603 605
604 if (likely(l3proto->nlattr_to_tuple)) { 606 if (likely(l3proto->nlattr_to_tuple)) {
605 ret = nla_validate_nested(attr, CTA_IP_MAX, 607 ret = nla_validate_nested(attr, CTA_IP_MAX,
@@ -608,7 +610,7 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple)
608 ret = l3proto->nlattr_to_tuple(tb, tuple); 610 ret = l3proto->nlattr_to_tuple(tb, tuple);
609 } 611 }
610 612
611 nf_ct_l3proto_put(l3proto); 613 rcu_read_unlock();
612 614
613 return ret; 615 return ret;
614} 616}
@@ -633,7 +635,8 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
633 return -EINVAL; 635 return -EINVAL;
634 tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]); 636 tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]);
635 637
636 l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); 638 rcu_read_lock();
639 l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum);
637 640
638 if (likely(l4proto->nlattr_to_tuple)) { 641 if (likely(l4proto->nlattr_to_tuple)) {
639 ret = nla_validate_nested(attr, CTA_PROTO_MAX, 642 ret = nla_validate_nested(attr, CTA_PROTO_MAX,
@@ -642,7 +645,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr,
642 ret = l4proto->nlattr_to_tuple(tb, tuple); 645 ret = l4proto->nlattr_to_tuple(tb, tuple);
643 } 646 }
644 647
645 nf_ct_l4proto_put(l4proto); 648 rcu_read_unlock();
646 649
647 return ret; 650 return ret;
648} 651}
@@ -989,10 +992,11 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[])
989 992
990 nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL); 993 nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL);
991 994
992 l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct)); 995 rcu_read_lock();
996 l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct));
993 if (l4proto->from_nlattr) 997 if (l4proto->from_nlattr)
994 err = l4proto->from_nlattr(tb, ct); 998 err = l4proto->from_nlattr(tb, ct);
995 nf_ct_l4proto_put(l4proto); 999 rcu_read_unlock();
996 1000
997 return err; 1001 return err;
998} 1002}
@@ -1062,6 +1066,10 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[])
1062{ 1066{
1063 int err; 1067 int err;
1064 1068
1069 /* only allow NAT changes and master assignation for new conntracks */
1070 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST] || cda[CTA_TUPLE_MASTER])
1071 return -EOPNOTSUPP;
1072
1065 if (cda[CTA_HELP]) { 1073 if (cda[CTA_HELP]) {
1066 err = ctnetlink_change_helper(ct, cda); 1074 err = ctnetlink_change_helper(ct, cda);
1067 if (err < 0) 1075 if (err < 0)
@@ -1124,13 +1132,11 @@ ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report)
1124 report); 1132 report);
1125} 1133}
1126 1134
1127static int 1135static struct nf_conn *
1128ctnetlink_create_conntrack(struct nlattr *cda[], 1136ctnetlink_create_conntrack(struct nlattr *cda[],
1129 struct nf_conntrack_tuple *otuple, 1137 struct nf_conntrack_tuple *otuple,
1130 struct nf_conntrack_tuple *rtuple, 1138 struct nf_conntrack_tuple *rtuple,
1131 struct nf_conn *master_ct, 1139 u8 u3)
1132 u32 pid,
1133 int report)
1134{ 1140{
1135 struct nf_conn *ct; 1141 struct nf_conn *ct;
1136 int err = -EINVAL; 1142 int err = -EINVAL;
@@ -1138,10 +1144,10 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1138 1144
1139 ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC); 1145 ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC);
1140 if (IS_ERR(ct)) 1146 if (IS_ERR(ct))
1141 return -ENOMEM; 1147 return ERR_PTR(-ENOMEM);
1142 1148
1143 if (!cda[CTA_TIMEOUT]) 1149 if (!cda[CTA_TIMEOUT])
1144 goto err; 1150 goto err1;
1145 ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); 1151 ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT]));
1146 1152
1147 ct->timeout.expires = jiffies + ct->timeout.expires * HZ; 1153 ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
@@ -1152,10 +1158,8 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1152 char *helpname; 1158 char *helpname;
1153 1159
1154 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname); 1160 err = ctnetlink_parse_help(cda[CTA_HELP], &helpname);
1155 if (err < 0) { 1161 if (err < 0)
1156 rcu_read_unlock(); 1162 goto err2;
1157 goto err;
1158 }
1159 1163
1160 helper = __nf_conntrack_helper_find_byname(helpname); 1164 helper = __nf_conntrack_helper_find_byname(helpname);
1161 if (helper == NULL) { 1165 if (helper == NULL) {
@@ -1163,28 +1167,26 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1163#ifdef CONFIG_MODULES 1167#ifdef CONFIG_MODULES
1164 if (request_module("nfct-helper-%s", helpname) < 0) { 1168 if (request_module("nfct-helper-%s", helpname) < 0) {
1165 err = -EOPNOTSUPP; 1169 err = -EOPNOTSUPP;
1166 goto err; 1170 goto err1;
1167 } 1171 }
1168 1172
1169 rcu_read_lock(); 1173 rcu_read_lock();
1170 helper = __nf_conntrack_helper_find_byname(helpname); 1174 helper = __nf_conntrack_helper_find_byname(helpname);
1171 if (helper) { 1175 if (helper) {
1172 rcu_read_unlock();
1173 err = -EAGAIN; 1176 err = -EAGAIN;
1174 goto err; 1177 goto err2;
1175 } 1178 }
1176 rcu_read_unlock(); 1179 rcu_read_unlock();
1177#endif 1180#endif
1178 err = -EOPNOTSUPP; 1181 err = -EOPNOTSUPP;
1179 goto err; 1182 goto err1;
1180 } else { 1183 } else {
1181 struct nf_conn_help *help; 1184 struct nf_conn_help *help;
1182 1185
1183 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); 1186 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
1184 if (help == NULL) { 1187 if (help == NULL) {
1185 rcu_read_unlock();
1186 err = -ENOMEM; 1188 err = -ENOMEM;
1187 goto err; 1189 goto err2;
1188 } 1190 }
1189 1191
1190 /* not in hash table yet so not strictly necessary */ 1192 /* not in hash table yet so not strictly necessary */
@@ -1193,44 +1195,34 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1193 } else { 1195 } else {
1194 /* try an implicit helper assignation */ 1196 /* try an implicit helper assignation */
1195 err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC); 1197 err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC);
1196 if (err < 0) { 1198 if (err < 0)
1197 rcu_read_unlock(); 1199 goto err2;
1198 goto err;
1199 }
1200 } 1200 }
1201 1201
1202 if (cda[CTA_STATUS]) { 1202 if (cda[CTA_STATUS]) {
1203 err = ctnetlink_change_status(ct, cda); 1203 err = ctnetlink_change_status(ct, cda);
1204 if (err < 0) { 1204 if (err < 0)
1205 rcu_read_unlock(); 1205 goto err2;
1206 goto err;
1207 }
1208 } 1206 }
1209 1207
1210 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { 1208 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
1211 err = ctnetlink_change_nat(ct, cda); 1209 err = ctnetlink_change_nat(ct, cda);
1212 if (err < 0) { 1210 if (err < 0)
1213 rcu_read_unlock(); 1211 goto err2;
1214 goto err;
1215 }
1216 } 1212 }
1217 1213
1218#ifdef CONFIG_NF_NAT_NEEDED 1214#ifdef CONFIG_NF_NAT_NEEDED
1219 if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { 1215 if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) {
1220 err = ctnetlink_change_nat_seq_adj(ct, cda); 1216 err = ctnetlink_change_nat_seq_adj(ct, cda);
1221 if (err < 0) { 1217 if (err < 0)
1222 rcu_read_unlock(); 1218 goto err2;
1223 goto err;
1224 }
1225 } 1219 }
1226#endif 1220#endif
1227 1221
1228 if (cda[CTA_PROTOINFO]) { 1222 if (cda[CTA_PROTOINFO]) {
1229 err = ctnetlink_change_protoinfo(ct, cda); 1223 err = ctnetlink_change_protoinfo(ct, cda);
1230 if (err < 0) { 1224 if (err < 0)
1231 rcu_read_unlock(); 1225 goto err2;
1232 goto err;
1233 }
1234 } 1226 }
1235 1227
1236 nf_ct_acct_ext_add(ct, GFP_ATOMIC); 1228 nf_ct_acct_ext_add(ct, GFP_ATOMIC);
@@ -1241,23 +1233,37 @@ ctnetlink_create_conntrack(struct nlattr *cda[],
1241#endif 1233#endif
1242 1234
1243 /* setup master conntrack: this is a confirmed expectation */ 1235 /* setup master conntrack: this is a confirmed expectation */
1244 if (master_ct) { 1236 if (cda[CTA_TUPLE_MASTER]) {
1237 struct nf_conntrack_tuple master;
1238 struct nf_conntrack_tuple_hash *master_h;
1239 struct nf_conn *master_ct;
1240
1241 err = ctnetlink_parse_tuple(cda, &master, CTA_TUPLE_MASTER, u3);
1242 if (err < 0)
1243 goto err2;
1244
1245 master_h = __nf_conntrack_find(&init_net, &master);
1246 if (master_h == NULL) {
1247 err = -ENOENT;
1248 goto err2;
1249 }
1250 master_ct = nf_ct_tuplehash_to_ctrack(master_h);
1251 nf_conntrack_get(&master_ct->ct_general);
1245 __set_bit(IPS_EXPECTED_BIT, &ct->status); 1252 __set_bit(IPS_EXPECTED_BIT, &ct->status);
1246 ct->master = master_ct; 1253 ct->master = master_ct;
1247 } 1254 }
1248 1255
1249 nf_conntrack_get(&ct->ct_general);
1250 add_timer(&ct->timeout); 1256 add_timer(&ct->timeout);
1251 nf_conntrack_hash_insert(ct); 1257 nf_conntrack_hash_insert(ct);
1252 rcu_read_unlock(); 1258 rcu_read_unlock();
1253 ctnetlink_event_report(ct, pid, report);
1254 nf_ct_put(ct);
1255 1259
1256 return 0; 1260 return ct;
1257 1261
1258err: 1262err2:
1263 rcu_read_unlock();
1264err1:
1259 nf_conntrack_free(ct); 1265 nf_conntrack_free(ct);
1260 return err; 1266 return ERR_PTR(err);
1261} 1267}
1262 1268
1263static int 1269static int
@@ -1289,38 +1295,25 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1289 h = __nf_conntrack_find(&init_net, &rtuple); 1295 h = __nf_conntrack_find(&init_net, &rtuple);
1290 1296
1291 if (h == NULL) { 1297 if (h == NULL) {
1292 struct nf_conntrack_tuple master; 1298 err = -ENOENT;
1293 struct nf_conntrack_tuple_hash *master_h = NULL; 1299 if (nlh->nlmsg_flags & NLM_F_CREATE) {
1294 struct nf_conn *master_ct = NULL; 1300 struct nf_conn *ct;
1295
1296 if (cda[CTA_TUPLE_MASTER]) {
1297 err = ctnetlink_parse_tuple(cda,
1298 &master,
1299 CTA_TUPLE_MASTER,
1300 u3);
1301 if (err < 0)
1302 goto out_unlock;
1303 1301
1304 master_h = __nf_conntrack_find(&init_net, &master); 1302 ct = ctnetlink_create_conntrack(cda, &otuple,
1305 if (master_h == NULL) { 1303 &rtuple, u3);
1306 err = -ENOENT; 1304 if (IS_ERR(ct)) {
1305 err = PTR_ERR(ct);
1307 goto out_unlock; 1306 goto out_unlock;
1308 } 1307 }
1309 master_ct = nf_ct_tuplehash_to_ctrack(master_h); 1308 err = 0;
1310 nf_conntrack_get(&master_ct->ct_general); 1309 nf_conntrack_get(&ct->ct_general);
1311 } 1310 spin_unlock_bh(&nf_conntrack_lock);
1312 1311 ctnetlink_event_report(ct,
1313 err = -ENOENT; 1312 NETLINK_CB(skb).pid,
1314 if (nlh->nlmsg_flags & NLM_F_CREATE) 1313 nlmsg_report(nlh));
1315 err = ctnetlink_create_conntrack(cda, 1314 nf_ct_put(ct);
1316 &otuple, 1315 } else
1317 &rtuple, 1316 spin_unlock_bh(&nf_conntrack_lock);
1318 master_ct,
1319 NETLINK_CB(skb).pid,
1320 nlmsg_report(nlh));
1321 spin_unlock_bh(&nf_conntrack_lock);
1322 if (err < 0 && master_ct)
1323 nf_ct_put(master_ct);
1324 1317
1325 return err; 1318 return err;
1326 } 1319 }
@@ -1332,17 +1325,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
1332 if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { 1325 if (!(nlh->nlmsg_flags & NLM_F_EXCL)) {
1333 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); 1326 struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
1334 1327
1335 /* we only allow nat config for new conntracks */
1336 if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) {
1337 err = -EOPNOTSUPP;
1338 goto out_unlock;
1339 }
1340 /* can't link an existing conntrack to a master */
1341 if (cda[CTA_TUPLE_MASTER]) {
1342 err = -EOPNOTSUPP;
1343 goto out_unlock;
1344 }
1345
1346 err = ctnetlink_change_conntrack(ct, cda); 1328 err = ctnetlink_change_conntrack(ct, cda);
1347 if (err == 0) { 1329 if (err == 0) {
1348 nf_conntrack_get(&ct->ct_general); 1330 nf_conntrack_get(&ct->ct_general);
@@ -1533,6 +1515,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
1533nla_put_failure: 1515nla_put_failure:
1534 rcu_read_unlock(); 1516 rcu_read_unlock();
1535nlmsg_failure: 1517nlmsg_failure:
1518 nfnetlink_set_err(0, 0, -ENOBUFS);
1536 kfree_skb(skb); 1519 kfree_skb(skb);
1537 return NOTIFY_DONE; 1520 return NOTIFY_DONE;
1538} 1521}
diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c
index 592d73344d4..9a62b4efa0e 100644
--- a/net/netfilter/nf_conntrack_proto.c
+++ b/net/netfilter/nf_conntrack_proto.c
@@ -74,27 +74,6 @@ EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find);
74 74
75/* this is guaranteed to always return a valid protocol helper, since 75/* this is guaranteed to always return a valid protocol helper, since
76 * it falls back to generic_protocol */ 76 * it falls back to generic_protocol */
77struct nf_conntrack_l4proto *
78nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto)
79{
80 struct nf_conntrack_l4proto *p;
81
82 rcu_read_lock();
83 p = __nf_ct_l4proto_find(l3proto, l4proto);
84 if (!try_module_get(p->me))
85 p = &nf_conntrack_l4proto_generic;
86 rcu_read_unlock();
87
88 return p;
89}
90EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get);
91
92void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p)
93{
94 module_put(p->me);
95}
96EXPORT_SYMBOL_GPL(nf_ct_l4proto_put);
97
98struct nf_conntrack_l3proto * 77struct nf_conntrack_l3proto *
99nf_ct_l3proto_find_get(u_int16_t l3proto) 78nf_ct_l3proto_find_get(u_int16_t l3proto)
100{ 79{
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index 8fcf1762fab..d3d5a7fd73c 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -16,6 +16,9 @@
16#include <linux/skbuff.h> 16#include <linux/skbuff.h>
17#include <linux/dccp.h> 17#include <linux/dccp.h>
18 18
19#include <net/net_namespace.h>
20#include <net/netns/generic.h>
21
19#include <linux/netfilter/nfnetlink_conntrack.h> 22#include <linux/netfilter/nfnetlink_conntrack.h>
20#include <net/netfilter/nf_conntrack.h> 23#include <net/netfilter/nf_conntrack.h>
21#include <net/netfilter/nf_conntrack_l4proto.h> 24#include <net/netfilter/nf_conntrack_l4proto.h>
@@ -23,8 +26,6 @@
23 26
24static DEFINE_RWLOCK(dccp_lock); 27static DEFINE_RWLOCK(dccp_lock);
25 28
26static int nf_ct_dccp_loose __read_mostly = 1;
27
28/* Timeouts are based on values from RFC4340: 29/* Timeouts are based on values from RFC4340:
29 * 30 *
30 * - REQUEST: 31 * - REQUEST:
@@ -72,16 +73,6 @@ static int nf_ct_dccp_loose __read_mostly = 1;
72 73
73#define DCCP_MSL (2 * 60 * HZ) 74#define DCCP_MSL (2 * 60 * HZ)
74 75
75static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = {
76 [CT_DCCP_REQUEST] = 2 * DCCP_MSL,
77 [CT_DCCP_RESPOND] = 4 * DCCP_MSL,
78 [CT_DCCP_PARTOPEN] = 4 * DCCP_MSL,
79 [CT_DCCP_OPEN] = 12 * 3600 * HZ,
80 [CT_DCCP_CLOSEREQ] = 64 * HZ,
81 [CT_DCCP_CLOSING] = 64 * HZ,
82 [CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL,
83};
84
85static const char * const dccp_state_names[] = { 76static const char * const dccp_state_names[] = {
86 [CT_DCCP_NONE] = "NONE", 77 [CT_DCCP_NONE] = "NONE",
87 [CT_DCCP_REQUEST] = "REQUEST", 78 [CT_DCCP_REQUEST] = "REQUEST",
@@ -393,6 +384,22 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
393 }, 384 },
394}; 385};
395 386
387/* this module per-net specifics */
388static int dccp_net_id;
389struct dccp_net {
390 int dccp_loose;
391 unsigned int dccp_timeout[CT_DCCP_MAX + 1];
392#ifdef CONFIG_SYSCTL
393 struct ctl_table_header *sysctl_header;
394 struct ctl_table *sysctl_table;
395#endif
396};
397
398static inline struct dccp_net *dccp_pernet(struct net *net)
399{
400 return net_generic(net, dccp_net_id);
401}
402
396static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, 403static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
397 struct nf_conntrack_tuple *tuple) 404 struct nf_conntrack_tuple *tuple)
398{ 405{
@@ -419,6 +426,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
419 unsigned int dataoff) 426 unsigned int dataoff)
420{ 427{
421 struct net *net = nf_ct_net(ct); 428 struct net *net = nf_ct_net(ct);
429 struct dccp_net *dn;
422 struct dccp_hdr _dh, *dh; 430 struct dccp_hdr _dh, *dh;
423 const char *msg; 431 const char *msg;
424 u_int8_t state; 432 u_int8_t state;
@@ -429,7 +437,8 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
429 state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; 437 state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
430 switch (state) { 438 switch (state) {
431 default: 439 default:
432 if (nf_ct_dccp_loose == 0) { 440 dn = dccp_pernet(net);
441 if (dn->dccp_loose == 0) {
433 msg = "nf_ct_dccp: not picking up existing connection "; 442 msg = "nf_ct_dccp: not picking up existing connection ";
434 goto out_invalid; 443 goto out_invalid;
435 } 444 }
@@ -465,6 +474,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
465 u_int8_t pf, unsigned int hooknum) 474 u_int8_t pf, unsigned int hooknum)
466{ 475{
467 struct net *net = nf_ct_net(ct); 476 struct net *net = nf_ct_net(ct);
477 struct dccp_net *dn;
468 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); 478 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
469 struct dccp_hdr _dh, *dh; 479 struct dccp_hdr _dh, *dh;
470 u_int8_t type, old_state, new_state; 480 u_int8_t type, old_state, new_state;
@@ -542,7 +552,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
542 ct->proto.dccp.last_pkt = type; 552 ct->proto.dccp.last_pkt = type;
543 ct->proto.dccp.state = new_state; 553 ct->proto.dccp.state = new_state;
544 write_unlock_bh(&dccp_lock); 554 write_unlock_bh(&dccp_lock);
545 nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]); 555
556 dn = dccp_pernet(net);
557 nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
546 558
547 return NF_ACCEPT; 559 return NF_ACCEPT;
548} 560}
@@ -660,13 +672,11 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
660#endif 672#endif
661 673
662#ifdef CONFIG_SYSCTL 674#ifdef CONFIG_SYSCTL
663static unsigned int dccp_sysctl_table_users; 675/* template, data assigned later */
664static struct ctl_table_header *dccp_sysctl_header; 676static struct ctl_table dccp_sysctl_table[] = {
665static ctl_table dccp_sysctl_table[] = {
666 { 677 {
667 .ctl_name = CTL_UNNUMBERED, 678 .ctl_name = CTL_UNNUMBERED,
668 .procname = "nf_conntrack_dccp_timeout_request", 679 .procname = "nf_conntrack_dccp_timeout_request",
669 .data = &dccp_timeout[CT_DCCP_REQUEST],
670 .maxlen = sizeof(unsigned int), 680 .maxlen = sizeof(unsigned int),
671 .mode = 0644, 681 .mode = 0644,
672 .proc_handler = proc_dointvec_jiffies, 682 .proc_handler = proc_dointvec_jiffies,
@@ -674,7 +684,6 @@ static ctl_table dccp_sysctl_table[] = {
674 { 684 {
675 .ctl_name = CTL_UNNUMBERED, 685 .ctl_name = CTL_UNNUMBERED,
676 .procname = "nf_conntrack_dccp_timeout_respond", 686 .procname = "nf_conntrack_dccp_timeout_respond",
677 .data = &dccp_timeout[CT_DCCP_RESPOND],
678 .maxlen = sizeof(unsigned int), 687 .maxlen = sizeof(unsigned int),
679 .mode = 0644, 688 .mode = 0644,
680 .proc_handler = proc_dointvec_jiffies, 689 .proc_handler = proc_dointvec_jiffies,
@@ -682,7 +691,6 @@ static ctl_table dccp_sysctl_table[] = {
682 { 691 {
683 .ctl_name = CTL_UNNUMBERED, 692 .ctl_name = CTL_UNNUMBERED,
684 .procname = "nf_conntrack_dccp_timeout_partopen", 693 .procname = "nf_conntrack_dccp_timeout_partopen",
685 .data = &dccp_timeout[CT_DCCP_PARTOPEN],
686 .maxlen = sizeof(unsigned int), 694 .maxlen = sizeof(unsigned int),
687 .mode = 0644, 695 .mode = 0644,
688 .proc_handler = proc_dointvec_jiffies, 696 .proc_handler = proc_dointvec_jiffies,
@@ -690,7 +698,6 @@ static ctl_table dccp_sysctl_table[] = {
690 { 698 {
691 .ctl_name = CTL_UNNUMBERED, 699 .ctl_name = CTL_UNNUMBERED,
692 .procname = "nf_conntrack_dccp_timeout_open", 700 .procname = "nf_conntrack_dccp_timeout_open",
693 .data = &dccp_timeout[CT_DCCP_OPEN],
694 .maxlen = sizeof(unsigned int), 701 .maxlen = sizeof(unsigned int),
695 .mode = 0644, 702 .mode = 0644,
696 .proc_handler = proc_dointvec_jiffies, 703 .proc_handler = proc_dointvec_jiffies,
@@ -698,7 +705,6 @@ static ctl_table dccp_sysctl_table[] = {
698 { 705 {
699 .ctl_name = CTL_UNNUMBERED, 706 .ctl_name = CTL_UNNUMBERED,
700 .procname = "nf_conntrack_dccp_timeout_closereq", 707 .procname = "nf_conntrack_dccp_timeout_closereq",
701 .data = &dccp_timeout[CT_DCCP_CLOSEREQ],
702 .maxlen = sizeof(unsigned int), 708 .maxlen = sizeof(unsigned int),
703 .mode = 0644, 709 .mode = 0644,
704 .proc_handler = proc_dointvec_jiffies, 710 .proc_handler = proc_dointvec_jiffies,
@@ -706,7 +712,6 @@ static ctl_table dccp_sysctl_table[] = {
706 { 712 {
707 .ctl_name = CTL_UNNUMBERED, 713 .ctl_name = CTL_UNNUMBERED,
708 .procname = "nf_conntrack_dccp_timeout_closing", 714 .procname = "nf_conntrack_dccp_timeout_closing",
709 .data = &dccp_timeout[CT_DCCP_CLOSING],
710 .maxlen = sizeof(unsigned int), 715 .maxlen = sizeof(unsigned int),
711 .mode = 0644, 716 .mode = 0644,
712 .proc_handler = proc_dointvec_jiffies, 717 .proc_handler = proc_dointvec_jiffies,
@@ -714,7 +719,6 @@ static ctl_table dccp_sysctl_table[] = {
714 { 719 {
715 .ctl_name = CTL_UNNUMBERED, 720 .ctl_name = CTL_UNNUMBERED,
716 .procname = "nf_conntrack_dccp_timeout_timewait", 721 .procname = "nf_conntrack_dccp_timeout_timewait",
717 .data = &dccp_timeout[CT_DCCP_TIMEWAIT],
718 .maxlen = sizeof(unsigned int), 722 .maxlen = sizeof(unsigned int),
719 .mode = 0644, 723 .mode = 0644,
720 .proc_handler = proc_dointvec_jiffies, 724 .proc_handler = proc_dointvec_jiffies,
@@ -722,8 +726,7 @@ static ctl_table dccp_sysctl_table[] = {
722 { 726 {
723 .ctl_name = CTL_UNNUMBERED, 727 .ctl_name = CTL_UNNUMBERED,
724 .procname = "nf_conntrack_dccp_loose", 728 .procname = "nf_conntrack_dccp_loose",
725 .data = &nf_ct_dccp_loose, 729 .maxlen = sizeof(int),
726 .maxlen = sizeof(nf_ct_dccp_loose),
727 .mode = 0644, 730 .mode = 0644,
728 .proc_handler = proc_dointvec, 731 .proc_handler = proc_dointvec,
729 }, 732 },
@@ -751,11 +754,6 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
751 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 754 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
752 .nla_policy = nf_ct_port_nla_policy, 755 .nla_policy = nf_ct_port_nla_policy,
753#endif 756#endif
754#ifdef CONFIG_SYSCTL
755 .ctl_table_users = &dccp_sysctl_table_users,
756 .ctl_table_header = &dccp_sysctl_header,
757 .ctl_table = dccp_sysctl_table,
758#endif
759}; 757};
760 758
761static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { 759static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
@@ -776,34 +774,107 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
776 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, 774 .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
777 .nla_policy = nf_ct_port_nla_policy, 775 .nla_policy = nf_ct_port_nla_policy,
778#endif 776#endif
777};
778
779static __net_init int dccp_net_init(struct net *net)
780{
781 struct dccp_net *dn;
782 int err;
783
784 dn = kmalloc(sizeof(*dn), GFP_KERNEL);
785 if (!dn)
786 return -ENOMEM;
787
788 /* default values */
789 dn->dccp_loose = 1;
790 dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL;
791 dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL;
792 dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL;
793 dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ;
794 dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ;
795 dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ;
796 dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL;
797
798 err = net_assign_generic(net, dccp_net_id, dn);
799 if (err)
800 goto out;
801
779#ifdef CONFIG_SYSCTL 802#ifdef CONFIG_SYSCTL
780 .ctl_table_users = &dccp_sysctl_table_users, 803 err = -ENOMEM;
781 .ctl_table_header = &dccp_sysctl_header, 804 dn->sysctl_table = kmemdup(dccp_sysctl_table,
782 .ctl_table = dccp_sysctl_table, 805 sizeof(dccp_sysctl_table), GFP_KERNEL);
806 if (!dn->sysctl_table)
807 goto out;
808
809 dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
810 dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
811 dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
812 dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
813 dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
814 dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
815 dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
816 dn->sysctl_table[7].data = &dn->dccp_loose;
817
818 dn->sysctl_header = register_net_sysctl_table(net,
819 nf_net_netfilter_sysctl_path, dn->sysctl_table);
820 if (!dn->sysctl_header) {
821 kfree(dn->sysctl_table);
822 goto out;
823 }
783#endif 824#endif
825
826 return 0;
827
828out:
829 kfree(dn);
830 return err;
831}
832
833static __net_exit void dccp_net_exit(struct net *net)
834{
835 struct dccp_net *dn = dccp_pernet(net);
836#ifdef CONFIG_SYSCTL
837 unregister_net_sysctl_table(dn->sysctl_header);
838 kfree(dn->sysctl_table);
839#endif
840 kfree(dn);
841
842 net_assign_generic(net, dccp_net_id, NULL);
843}
844
845static struct pernet_operations dccp_net_ops = {
846 .init = dccp_net_init,
847 .exit = dccp_net_exit,
784}; 848};
785 849
786static int __init nf_conntrack_proto_dccp_init(void) 850static int __init nf_conntrack_proto_dccp_init(void)
787{ 851{
788 int err; 852 int err;
789 853
790 err = nf_conntrack_l4proto_register(&dccp_proto4); 854 err = register_pernet_gen_subsys(&dccp_net_id, &dccp_net_ops);
791 if (err < 0) 855 if (err < 0)
792 goto err1; 856 goto err1;
793 857
794 err = nf_conntrack_l4proto_register(&dccp_proto6); 858 err = nf_conntrack_l4proto_register(&dccp_proto4);
795 if (err < 0) 859 if (err < 0)
796 goto err2; 860 goto err2;
861
862 err = nf_conntrack_l4proto_register(&dccp_proto6);
863 if (err < 0)
864 goto err3;
797 return 0; 865 return 0;
798 866
799err2: 867err3:
800 nf_conntrack_l4proto_unregister(&dccp_proto4); 868 nf_conntrack_l4proto_unregister(&dccp_proto4);
869err2:
870 unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
801err1: 871err1:
802 return err; 872 return err;
803} 873}
804 874
805static void __exit nf_conntrack_proto_dccp_fini(void) 875static void __exit nf_conntrack_proto_dccp_fini(void)
806{ 876{
877 unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops);
807 nf_conntrack_l4proto_unregister(&dccp_proto6); 878 nf_conntrack_l4proto_unregister(&dccp_proto6);
808 nf_conntrack_l4proto_unregister(&dccp_proto4); 879 nf_conntrack_l4proto_unregister(&dccp_proto4);
809} 880}
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index 4be80d7b879..829374f426c 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -92,7 +92,7 @@ static struct ctl_table generic_compat_sysctl_table[] = {
92struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = 92struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
93{ 93{
94 .l3proto = PF_UNSPEC, 94 .l3proto = PF_UNSPEC,
95 .l4proto = 0, 95 .l4proto = 255,
96 .name = "unknown", 96 .name = "unknown",
97 .pkt_to_tuple = generic_pkt_to_tuple, 97 .pkt_to_tuple = generic_pkt_to_tuple,
98 .invert_tuple = generic_invert_tuple, 98 .invert_tuple = generic_invert_tuple,
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index f3fd154d1dd..e46f3b79adb 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -25,6 +25,8 @@
25#include <net/netfilter/nf_conntrack_l4proto.h> 25#include <net/netfilter/nf_conntrack_l4proto.h>
26#include <net/netfilter/nf_conntrack_ecache.h> 26#include <net/netfilter/nf_conntrack_ecache.h>
27#include <net/netfilter/nf_log.h> 27#include <net/netfilter/nf_log.h>
28#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
29#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
28 30
29/* Protects ct->proto.tcp */ 31/* Protects ct->proto.tcp */
30static DEFINE_RWLOCK(tcp_lock); 32static DEFINE_RWLOCK(tcp_lock);
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 2b8b1f579f9..d4021179e24 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -22,6 +22,8 @@
22#include <net/netfilter/nf_conntrack_l4proto.h> 22#include <net/netfilter/nf_conntrack_l4proto.h>
23#include <net/netfilter/nf_conntrack_ecache.h> 23#include <net/netfilter/nf_conntrack_ecache.h>
24#include <net/netfilter/nf_log.h> 24#include <net/netfilter/nf_log.h>
25#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
26#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
25 27
26static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; 28static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ;
27static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; 29static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ;
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index fa8ae5d2659..8bb998fe098 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -14,58 +14,63 @@
14 LOG target modules */ 14 LOG target modules */
15 15
16#define NF_LOG_PREFIXLEN 128 16#define NF_LOG_PREFIXLEN 128
17#define NFLOGGER_NAME_LEN 64
17 18
18static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly; 19static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly;
20static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly;
19static DEFINE_MUTEX(nf_log_mutex); 21static DEFINE_MUTEX(nf_log_mutex);
20 22
21/* return EBUSY if somebody else is registered, EEXIST if the same logger 23static struct nf_logger *__find_logger(int pf, const char *str_logger)
22 * is registred, 0 on success. */
23int nf_log_register(u_int8_t pf, const struct nf_logger *logger)
24{ 24{
25 int ret; 25 struct nf_logger *t;
26 26
27 if (pf >= ARRAY_SIZE(nf_loggers)) 27 list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) {
28 return -EINVAL; 28 if (!strnicmp(str_logger, t->name, strlen(t->name)))
29 29 return t;
30 /* Any setup of logging members must be done before 30 }
31 * substituting pointer. */
32 ret = mutex_lock_interruptible(&nf_log_mutex);
33 if (ret < 0)
34 return ret;
35
36 if (!nf_loggers[pf])
37 rcu_assign_pointer(nf_loggers[pf], logger);
38 else if (nf_loggers[pf] == logger)
39 ret = -EEXIST;
40 else
41 ret = -EBUSY;
42 31
43 mutex_unlock(&nf_log_mutex); 32 return NULL;
44 return ret;
45} 33}
46EXPORT_SYMBOL(nf_log_register);
47 34
48void nf_log_unregister_pf(u_int8_t pf) 35/* return EEXIST if the same logger is registred, 0 on success. */
36int nf_log_register(u_int8_t pf, struct nf_logger *logger)
49{ 37{
38 const struct nf_logger *llog;
39
50 if (pf >= ARRAY_SIZE(nf_loggers)) 40 if (pf >= ARRAY_SIZE(nf_loggers))
51 return; 41 return -EINVAL;
42
52 mutex_lock(&nf_log_mutex); 43 mutex_lock(&nf_log_mutex);
53 rcu_assign_pointer(nf_loggers[pf], NULL); 44
45 if (pf == NFPROTO_UNSPEC) {
46 int i;
47 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
48 list_add_tail(&(logger->list[i]), &(nf_loggers_l[i]));
49 } else {
50 /* register at end of list to honor first register win */
51 list_add_tail(&logger->list[pf], &nf_loggers_l[pf]);
52 llog = rcu_dereference(nf_loggers[pf]);
53 if (llog == NULL)
54 rcu_assign_pointer(nf_loggers[pf], logger);
55 }
56
54 mutex_unlock(&nf_log_mutex); 57 mutex_unlock(&nf_log_mutex);
55 58
56 /* Give time to concurrent readers. */ 59 return 0;
57 synchronize_rcu();
58} 60}
59EXPORT_SYMBOL(nf_log_unregister_pf); 61EXPORT_SYMBOL(nf_log_register);
60 62
61void nf_log_unregister(const struct nf_logger *logger) 63void nf_log_unregister(struct nf_logger *logger)
62{ 64{
65 const struct nf_logger *c_logger;
63 int i; 66 int i;
64 67
65 mutex_lock(&nf_log_mutex); 68 mutex_lock(&nf_log_mutex);
66 for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) { 69 for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) {
67 if (nf_loggers[i] == logger) 70 c_logger = rcu_dereference(nf_loggers[i]);
71 if (c_logger == logger)
68 rcu_assign_pointer(nf_loggers[i], NULL); 72 rcu_assign_pointer(nf_loggers[i], NULL);
73 list_del(&logger->list[i]);
69 } 74 }
70 mutex_unlock(&nf_log_mutex); 75 mutex_unlock(&nf_log_mutex);
71 76
@@ -73,6 +78,27 @@ void nf_log_unregister(const struct nf_logger *logger)
73} 78}
74EXPORT_SYMBOL(nf_log_unregister); 79EXPORT_SYMBOL(nf_log_unregister);
75 80
81int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger)
82{
83 mutex_lock(&nf_log_mutex);
84 if (__find_logger(pf, logger->name) == NULL) {
85 mutex_unlock(&nf_log_mutex);
86 return -ENOENT;
87 }
88 rcu_assign_pointer(nf_loggers[pf], logger);
89 mutex_unlock(&nf_log_mutex);
90 return 0;
91}
92EXPORT_SYMBOL(nf_log_bind_pf);
93
94void nf_log_unbind_pf(u_int8_t pf)
95{
96 mutex_lock(&nf_log_mutex);
97 rcu_assign_pointer(nf_loggers[pf], NULL);
98 mutex_unlock(&nf_log_mutex);
99}
100EXPORT_SYMBOL(nf_log_unbind_pf);
101
76void nf_log_packet(u_int8_t pf, 102void nf_log_packet(u_int8_t pf,
77 unsigned int hooknum, 103 unsigned int hooknum,
78 const struct sk_buff *skb, 104 const struct sk_buff *skb,
@@ -129,13 +155,37 @@ static int seq_show(struct seq_file *s, void *v)
129{ 155{
130 loff_t *pos = v; 156 loff_t *pos = v;
131 const struct nf_logger *logger; 157 const struct nf_logger *logger;
158 struct nf_logger *t;
159 int ret;
132 160
133 logger = rcu_dereference(nf_loggers[*pos]); 161 logger = rcu_dereference(nf_loggers[*pos]);
134 162
135 if (!logger) 163 if (!logger)
136 return seq_printf(s, "%2lld NONE\n", *pos); 164 ret = seq_printf(s, "%2lld NONE (", *pos);
165 else
166 ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
167
168 if (ret < 0)
169 return ret;
170
171 mutex_lock(&nf_log_mutex);
172 list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) {
173 ret = seq_printf(s, "%s", t->name);
174 if (ret < 0) {
175 mutex_unlock(&nf_log_mutex);
176 return ret;
177 }
178 if (&t->list[*pos] != nf_loggers_l[*pos].prev) {
179 ret = seq_printf(s, ",");
180 if (ret < 0) {
181 mutex_unlock(&nf_log_mutex);
182 return ret;
183 }
184 }
185 }
186 mutex_unlock(&nf_log_mutex);
137 187
138 return seq_printf(s, "%2lld %s\n", *pos, logger->name); 188 return seq_printf(s, ")\n");
139} 189}
140 190
141static const struct seq_operations nflog_seq_ops = { 191static const struct seq_operations nflog_seq_ops = {
@@ -158,15 +208,102 @@ static const struct file_operations nflog_file_ops = {
158 .release = seq_release, 208 .release = seq_release,
159}; 209};
160 210
211
161#endif /* PROC_FS */ 212#endif /* PROC_FS */
162 213
214#ifdef CONFIG_SYSCTL
215struct ctl_path nf_log_sysctl_path[] = {
216 { .procname = "net", .ctl_name = CTL_NET, },
217 { .procname = "netfilter", .ctl_name = NET_NETFILTER, },
218 { .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, },
219 { }
220};
221
222static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3];
223static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1];
224static struct ctl_table_header *nf_log_dir_header;
225
226static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp,
227 void *buffer, size_t *lenp, loff_t *ppos)
228{
229 const struct nf_logger *logger;
230 int r = 0;
231 int tindex = (unsigned long)table->extra1;
232
233 if (write) {
234 if (!strcmp(buffer, "NONE")) {
235 nf_log_unbind_pf(tindex);
236 return 0;
237 }
238 mutex_lock(&nf_log_mutex);
239 logger = __find_logger(tindex, buffer);
240 if (logger == NULL) {
241 mutex_unlock(&nf_log_mutex);
242 return -ENOENT;
243 }
244 rcu_assign_pointer(nf_loggers[tindex], logger);
245 mutex_unlock(&nf_log_mutex);
246 } else {
247 rcu_read_lock();
248 logger = rcu_dereference(nf_loggers[tindex]);
249 if (!logger)
250 table->data = "NONE";
251 else
252 table->data = logger->name;
253 r = proc_dostring(table, write, filp, buffer, lenp, ppos);
254 rcu_read_unlock();
255 }
256
257 return r;
258}
259
260static __init int netfilter_log_sysctl_init(void)
261{
262 int i;
263
264 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) {
265 snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i);
266 nf_log_sysctl_table[i].ctl_name = CTL_UNNUMBERED;
267 nf_log_sysctl_table[i].procname =
268 nf_log_sysctl_fnames[i-NFPROTO_UNSPEC];
269 nf_log_sysctl_table[i].data = NULL;
270 nf_log_sysctl_table[i].maxlen =
271 NFLOGGER_NAME_LEN * sizeof(char);
272 nf_log_sysctl_table[i].mode = 0644;
273 nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring;
274 nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i;
275 }
276
277 nf_log_dir_header = register_sysctl_paths(nf_log_sysctl_path,
278 nf_log_sysctl_table);
279 if (!nf_log_dir_header)
280 return -ENOMEM;
281
282 return 0;
283}
284#else
285static __init int netfilter_log_sysctl_init(void)
286{
287 return 0;
288}
289#endif /* CONFIG_SYSCTL */
163 290
164int __init netfilter_log_init(void) 291int __init netfilter_log_init(void)
165{ 292{
293 int i, r;
166#ifdef CONFIG_PROC_FS 294#ifdef CONFIG_PROC_FS
167 if (!proc_create("nf_log", S_IRUGO, 295 if (!proc_create("nf_log", S_IRUGO,
168 proc_net_netfilter, &nflog_file_ops)) 296 proc_net_netfilter, &nflog_file_ops))
169 return -1; 297 return -1;
170#endif 298#endif
299
300 /* Errors will trigger panic, unroll on error is unnecessary. */
301 r = netfilter_log_sysctl_init();
302 if (r < 0)
303 return r;
304
305 for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++)
306 INIT_LIST_HEAD(&(nf_loggers_l[i]));
307
171 return 0; 308 return 0;
172} 309}
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 9c0ba17a1dd..2785d66a7e3 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -113,6 +113,12 @@ int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo)
113} 113}
114EXPORT_SYMBOL_GPL(nfnetlink_send); 114EXPORT_SYMBOL_GPL(nfnetlink_send);
115 115
116void nfnetlink_set_err(u32 pid, u32 group, int error)
117{
118 netlink_set_err(nfnl, pid, group, error);
119}
120EXPORT_SYMBOL_GPL(nfnetlink_set_err);
121
116int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) 122int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags)
117{ 123{
118 return netlink_unicast(nfnl, skb, pid, flags); 124 return netlink_unicast(nfnl, skb, pid, flags);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index c712e9fc6bb..fd326ac27ec 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -693,7 +693,7 @@ nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
693 return -ENOTSUPP; 693 return -ENOTSUPP;
694} 694}
695 695
696static const struct nf_logger nfulnl_logger = { 696static struct nf_logger nfulnl_logger __read_mostly = {
697 .name = "nfnetlink_log", 697 .name = "nfnetlink_log",
698 .logfn = &nfulnl_log_packet, 698 .logfn = &nfulnl_log_packet,
699 .me = THIS_MODULE, 699 .me = THIS_MODULE,
@@ -725,9 +725,9 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
725 /* Commands without queue context */ 725 /* Commands without queue context */
726 switch (cmd->command) { 726 switch (cmd->command) {
727 case NFULNL_CFG_CMD_PF_BIND: 727 case NFULNL_CFG_CMD_PF_BIND:
728 return nf_log_register(pf, &nfulnl_logger); 728 return nf_log_bind_pf(pf, &nfulnl_logger);
729 case NFULNL_CFG_CMD_PF_UNBIND: 729 case NFULNL_CFG_CMD_PF_UNBIND:
730 nf_log_unregister_pf(pf); 730 nf_log_unbind_pf(pf);
731 return 0; 731 return 0;
732 } 732 }
733 } 733 }
@@ -952,17 +952,25 @@ static int __init nfnetlink_log_init(void)
952 goto cleanup_netlink_notifier; 952 goto cleanup_netlink_notifier;
953 } 953 }
954 954
955 status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger);
956 if (status < 0) {
957 printk(KERN_ERR "log: failed to register logger\n");
958 goto cleanup_subsys;
959 }
960
955#ifdef CONFIG_PROC_FS 961#ifdef CONFIG_PROC_FS
956 if (!proc_create("nfnetlink_log", 0440, 962 if (!proc_create("nfnetlink_log", 0440,
957 proc_net_netfilter, &nful_file_ops)) 963 proc_net_netfilter, &nful_file_ops))
958 goto cleanup_subsys; 964 goto cleanup_logger;
959#endif 965#endif
960 return status; 966 return status;
961 967
962#ifdef CONFIG_PROC_FS 968#ifdef CONFIG_PROC_FS
969cleanup_logger:
970 nf_log_unregister(&nfulnl_logger);
971#endif
963cleanup_subsys: 972cleanup_subsys:
964 nfnetlink_subsys_unregister(&nfulnl_subsys); 973 nfnetlink_subsys_unregister(&nfulnl_subsys);
965#endif
966cleanup_netlink_notifier: 974cleanup_netlink_notifier:
967 netlink_unregister_notifier(&nfulnl_rtnl_notifier); 975 netlink_unregister_notifier(&nfulnl_rtnl_notifier);
968 return status; 976 return status;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 5baccfa5a0d..509a95621f9 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -625,6 +625,20 @@ void xt_free_table_info(struct xt_table_info *info)
625} 625}
626EXPORT_SYMBOL(xt_free_table_info); 626EXPORT_SYMBOL(xt_free_table_info);
627 627
628void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo,
629 struct xt_table_info *newinfo)
630{
631 unsigned int cpu;
632
633 for_each_possible_cpu(cpu) {
634 void *p = oldinfo->entries[cpu];
635 rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]);
636 newinfo->entries[cpu] = p;
637 }
638
639}
640EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu);
641
628/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ 642/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
629struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, 643struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
630 const char *name) 644 const char *name)
@@ -671,21 +685,22 @@ xt_replace_table(struct xt_table *table,
671 struct xt_table_info *oldinfo, *private; 685 struct xt_table_info *oldinfo, *private;
672 686
673 /* Do the substitution. */ 687 /* Do the substitution. */
674 write_lock_bh(&table->lock); 688 mutex_lock(&table->lock);
675 private = table->private; 689 private = table->private;
676 /* Check inside lock: is the old number correct? */ 690 /* Check inside lock: is the old number correct? */
677 if (num_counters != private->number) { 691 if (num_counters != private->number) {
678 duprintf("num_counters != table->private->number (%u/%u)\n", 692 duprintf("num_counters != table->private->number (%u/%u)\n",
679 num_counters, private->number); 693 num_counters, private->number);
680 write_unlock_bh(&table->lock); 694 mutex_unlock(&table->lock);
681 *error = -EAGAIN; 695 *error = -EAGAIN;
682 return NULL; 696 return NULL;
683 } 697 }
684 oldinfo = private; 698 oldinfo = private;
685 table->private = newinfo; 699 rcu_assign_pointer(table->private, newinfo);
686 newinfo->initial_entries = oldinfo->initial_entries; 700 newinfo->initial_entries = oldinfo->initial_entries;
687 write_unlock_bh(&table->lock); 701 mutex_unlock(&table->lock);
688 702
703 synchronize_net();
689 return oldinfo; 704 return oldinfo;
690} 705}
691EXPORT_SYMBOL_GPL(xt_replace_table); 706EXPORT_SYMBOL_GPL(xt_replace_table);
@@ -719,7 +734,8 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table,
719 734
720 /* Simplifies replace_table code. */ 735 /* Simplifies replace_table code. */
721 table->private = bootstrap; 736 table->private = bootstrap;
722 rwlock_init(&table->lock); 737 mutex_init(&table->lock);
738
723 if (!xt_replace_table(table, 0, newinfo, &ret)) 739 if (!xt_replace_table(table, 0, newinfo, &ret))
724 goto unlock; 740 goto unlock;
725 741
diff --git a/net/netfilter/xt_HL.c b/net/netfilter/xt_HL.c
new file mode 100644
index 00000000000..10e789e2d12
--- /dev/null
+++ b/net/netfilter/xt_HL.c
@@ -0,0 +1,171 @@
1/*
2 * TTL modification target for IP tables
3 * (C) 2000,2005 by Harald Welte <laforge@netfilter.org>
4 *
5 * Hop Limit modification target for ip6tables
6 * Maciej Soltysiak <solt@dns.toxicfilms.tv>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/skbuff.h>
15#include <linux/ip.h>
16#include <linux/ipv6.h>
17#include <net/checksum.h>
18
19#include <linux/netfilter/x_tables.h>
20#include <linux/netfilter_ipv4/ipt_TTL.h>
21#include <linux/netfilter_ipv6/ip6t_HL.h>
22
23MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
24MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
25MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target");
26MODULE_LICENSE("GPL");
27
28static unsigned int
29ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
30{
31 struct iphdr *iph;
32 const struct ipt_TTL_info *info = par->targinfo;
33 int new_ttl;
34
35 if (!skb_make_writable(skb, skb->len))
36 return NF_DROP;
37
38 iph = ip_hdr(skb);
39
40 switch (info->mode) {
41 case IPT_TTL_SET:
42 new_ttl = info->ttl;
43 break;
44 case IPT_TTL_INC:
45 new_ttl = iph->ttl + info->ttl;
46 if (new_ttl > 255)
47 new_ttl = 255;
48 break;
49 case IPT_TTL_DEC:
50 new_ttl = iph->ttl - info->ttl;
51 if (new_ttl < 0)
52 new_ttl = 0;
53 break;
54 default:
55 new_ttl = iph->ttl;
56 break;
57 }
58
59 if (new_ttl != iph->ttl) {
60 csum_replace2(&iph->check, htons(iph->ttl << 8),
61 htons(new_ttl << 8));
62 iph->ttl = new_ttl;
63 }
64
65 return XT_CONTINUE;
66}
67
68static unsigned int
69hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
70{
71 struct ipv6hdr *ip6h;
72 const struct ip6t_HL_info *info = par->targinfo;
73 int new_hl;
74
75 if (!skb_make_writable(skb, skb->len))
76 return NF_DROP;
77
78 ip6h = ipv6_hdr(skb);
79
80 switch (info->mode) {
81 case IP6T_HL_SET:
82 new_hl = info->hop_limit;
83 break;
84 case IP6T_HL_INC:
85 new_hl = ip6h->hop_limit + info->hop_limit;
86 if (new_hl > 255)
87 new_hl = 255;
88 break;
89 case IP6T_HL_DEC:
90 new_hl = ip6h->hop_limit - info->hop_limit;
91 if (new_hl < 0)
92 new_hl = 0;
93 break;
94 default:
95 new_hl = ip6h->hop_limit;
96 break;
97 }
98
99 ip6h->hop_limit = new_hl;
100
101 return XT_CONTINUE;
102}
103
104static bool ttl_tg_check(const struct xt_tgchk_param *par)
105{
106 const struct ipt_TTL_info *info = par->targinfo;
107
108 if (info->mode > IPT_TTL_MAXMODE) {
109 printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
110 info->mode);
111 return false;
112 }
113 if (info->mode != IPT_TTL_SET && info->ttl == 0)
114 return false;
115 return true;
116}
117
118static bool hl_tg6_check(const struct xt_tgchk_param *par)
119{
120 const struct ip6t_HL_info *info = par->targinfo;
121
122 if (info->mode > IP6T_HL_MAXMODE) {
123 printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
124 info->mode);
125 return false;
126 }
127 if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
128 printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
129 "make sense with value 0\n");
130 return false;
131 }
132 return true;
133}
134
135static struct xt_target hl_tg_reg[] __read_mostly = {
136 {
137 .name = "TTL",
138 .revision = 0,
139 .family = NFPROTO_IPV4,
140 .target = ttl_tg,
141 .targetsize = sizeof(struct ipt_TTL_info),
142 .table = "mangle",
143 .checkentry = ttl_tg_check,
144 .me = THIS_MODULE,
145 },
146 {
147 .name = "HL",
148 .revision = 0,
149 .family = NFPROTO_IPV6,
150 .target = hl_tg6,
151 .targetsize = sizeof(struct ip6t_HL_info),
152 .table = "mangle",
153 .checkentry = hl_tg6_check,
154 .me = THIS_MODULE,
155 },
156};
157
158static int __init hl_tg_init(void)
159{
160 return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
161}
162
163static void __exit hl_tg_exit(void)
164{
165 xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
166}
167
168module_init(hl_tg_init);
169module_exit(hl_tg_exit);
170MODULE_ALIAS("ipt_TTL");
171MODULE_ALIAS("ip6t_HL");
diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c
new file mode 100644
index 00000000000..8ff7843bb92
--- /dev/null
+++ b/net/netfilter/xt_LED.c
@@ -0,0 +1,161 @@
1/*
2 * xt_LED.c - netfilter target to make LEDs blink upon packet matches
3 *
4 * Copyright (C) 2008 Adam Nielsen <a.nielsen@shikadi.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA.
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/skbuff.h>
24#include <linux/netfilter/x_tables.h>
25#include <linux/leds.h>
26#include <linux/mutex.h>
27
28#include <linux/netfilter/xt_LED.h>
29
30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>");
32MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match");
33
34/*
35 * This is declared in here (the kernel module) only, to avoid having these
36 * dependencies in userspace code. This is what xt_led_info.internal_data
37 * points to.
38 */
39struct xt_led_info_internal {
40 struct led_trigger netfilter_led_trigger;
41 struct timer_list timer;
42};
43
44static unsigned int
45led_tg(struct sk_buff *skb, const struct xt_target_param *par)
46{
47 const struct xt_led_info *ledinfo = par->targinfo;
48 struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
49
50 /*
51 * If "always blink" is enabled, and there's still some time until the
52 * LED will switch off, briefly switch it off now.
53 */
54 if ((ledinfo->delay > 0) && ledinfo->always_blink &&
55 timer_pending(&ledinternal->timer))
56 led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF);
57
58 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL);
59
60 /* If there's a positive delay, start/update the timer */
61 if (ledinfo->delay > 0) {
62 mod_timer(&ledinternal->timer,
63 jiffies + msecs_to_jiffies(ledinfo->delay));
64
65 /* Otherwise if there was no delay given, blink as fast as possible */
66 } else if (ledinfo->delay == 0) {
67 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
68 }
69
70 /* else the delay is negative, which means switch on and stay on */
71
72 return XT_CONTINUE;
73}
74
75static void led_timeout_callback(unsigned long data)
76{
77 struct xt_led_info *ledinfo = (struct xt_led_info *)data;
78 struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
79
80 led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF);
81}
82
83static bool led_tg_check(const struct xt_tgchk_param *par)
84{
85 struct xt_led_info *ledinfo = par->targinfo;
86 struct xt_led_info_internal *ledinternal;
87 int err;
88
89 if (ledinfo->id[0] == '\0') {
90 printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n");
91 return false;
92 }
93
94 ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL);
95 if (!ledinternal) {
96 printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n");
97 return false;
98 }
99
100 ledinternal->netfilter_led_trigger.name = ledinfo->id;
101
102 err = led_trigger_register(&ledinternal->netfilter_led_trigger);
103 if (err) {
104 printk(KERN_CRIT KBUILD_MODNAME
105 ": led_trigger_register() failed\n");
106 if (err == -EEXIST)
107 printk(KERN_ERR KBUILD_MODNAME
108 ": Trigger name is already in use.\n");
109 goto exit_alloc;
110 }
111
112 /* See if we need to set up a timer */
113 if (ledinfo->delay > 0)
114 setup_timer(&ledinternal->timer, led_timeout_callback,
115 (unsigned long)ledinfo);
116
117 ledinfo->internal_data = ledinternal;
118
119 return true;
120
121exit_alloc:
122 kfree(ledinternal);
123
124 return false;
125}
126
127static void led_tg_destroy(const struct xt_tgdtor_param *par)
128{
129 const struct xt_led_info *ledinfo = par->targinfo;
130 struct xt_led_info_internal *ledinternal = ledinfo->internal_data;
131
132 if (ledinfo->delay > 0)
133 del_timer_sync(&ledinternal->timer);
134
135 led_trigger_unregister(&ledinternal->netfilter_led_trigger);
136 kfree(ledinternal);
137}
138
139static struct xt_target led_tg_reg __read_mostly = {
140 .name = "LED",
141 .revision = 0,
142 .family = NFPROTO_UNSPEC,
143 .target = led_tg,
144 .targetsize = XT_ALIGN(sizeof(struct xt_led_info)),
145 .checkentry = led_tg_check,
146 .destroy = led_tg_destroy,
147 .me = THIS_MODULE,
148};
149
150static int __init led_tg_init(void)
151{
152 return xt_register_target(&led_tg_reg);
153}
154
155static void __exit led_tg_exit(void)
156{
157 xt_unregister_target(&led_tg_reg);
158}
159
160module_init(led_tg_init);
161module_exit(led_tg_exit);
diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c
new file mode 100644
index 00000000000..ad5bd890e4e
--- /dev/null
+++ b/net/netfilter/xt_cluster.c
@@ -0,0 +1,164 @@
1/*
2 * (C) 2008-2009 Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#include <linux/module.h>
9#include <linux/skbuff.h>
10#include <linux/jhash.h>
11#include <linux/ip.h>
12#include <net/ipv6.h>
13
14#include <linux/netfilter/x_tables.h>
15#include <net/netfilter/nf_conntrack.h>
16#include <linux/netfilter/xt_cluster.h>
17
18static inline u_int32_t nf_ct_orig_ipv4_src(const struct nf_conn *ct)
19{
20 return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
21}
22
23static inline const void *nf_ct_orig_ipv6_src(const struct nf_conn *ct)
24{
25 return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6;
26}
27
28static inline u_int32_t
29xt_cluster_hash_ipv4(u_int32_t ip, const struct xt_cluster_match_info *info)
30{
31 return jhash_1word(ip, info->hash_seed);
32}
33
34static inline u_int32_t
35xt_cluster_hash_ipv6(const void *ip, const struct xt_cluster_match_info *info)
36{
37 return jhash2(ip, NF_CT_TUPLE_L3SIZE / sizeof(__u32), info->hash_seed);
38}
39
40static inline u_int32_t
41xt_cluster_hash(const struct nf_conn *ct,
42 const struct xt_cluster_match_info *info)
43{
44 u_int32_t hash = 0;
45
46 switch(nf_ct_l3num(ct)) {
47 case AF_INET:
48 hash = xt_cluster_hash_ipv4(nf_ct_orig_ipv4_src(ct), info);
49 break;
50 case AF_INET6:
51 hash = xt_cluster_hash_ipv6(nf_ct_orig_ipv6_src(ct), info);
52 break;
53 default:
54 WARN_ON(1);
55 break;
56 }
57 return (((u64)hash * info->total_nodes) >> 32);
58}
59
60static inline bool
61xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family)
62{
63 bool is_multicast = false;
64
65 switch(family) {
66 case NFPROTO_IPV4:
67 is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr);
68 break;
69 case NFPROTO_IPV6:
70 is_multicast = ipv6_addr_type(&ipv6_hdr(skb)->daddr) &
71 IPV6_ADDR_MULTICAST;
72 break;
73 default:
74 WARN_ON(1);
75 break;
76 }
77 return is_multicast;
78}
79
80static bool
81xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par)
82{
83 struct sk_buff *pskb = (struct sk_buff *)skb;
84 const struct xt_cluster_match_info *info = par->matchinfo;
85 const struct nf_conn *ct;
86 enum ip_conntrack_info ctinfo;
87 unsigned long hash;
88
89 /* This match assumes that all nodes see the same packets. This can be
90 * achieved if the switch that connects the cluster nodes support some
91 * sort of 'port mirroring'. However, if your switch does not support
92 * this, your cluster nodes can reply ARP request using a multicast MAC
93 * address. Thus, your switch will flood the same packets to the
94 * cluster nodes with the same multicast MAC address. Using a multicast
95 * link address is a RFC 1812 (section 3.3.2) violation, but this works
96 * fine in practise.
97 *
98 * Unfortunately, if you use the multicast MAC address, the link layer
99 * sets skbuff's pkt_type to PACKET_MULTICAST, which is not accepted
100 * by TCP and others for packets coming to this node. For that reason,
101 * this match mangles skbuff's pkt_type if it detects a packet
102 * addressed to a unicast address but using PACKET_MULTICAST. Yes, I
103 * know, matches should not alter packets, but we are doing this here
104 * because we would need to add a PKTTYPE target for this sole purpose.
105 */
106 if (!xt_cluster_is_multicast_addr(skb, par->family) &&
107 skb->pkt_type == PACKET_MULTICAST) {
108 pskb->pkt_type = PACKET_HOST;
109 }
110
111 ct = nf_ct_get(skb, &ctinfo);
112 if (ct == NULL)
113 return false;
114
115 if (ct == &nf_conntrack_untracked)
116 return false;
117
118 if (ct->master)
119 hash = xt_cluster_hash(ct->master, info);
120 else
121 hash = xt_cluster_hash(ct, info);
122
123 return !!((1 << hash) & info->node_mask) ^
124 !!(info->flags & XT_CLUSTER_F_INV);
125}
126
127static bool xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
128{
129 struct xt_cluster_match_info *info = par->matchinfo;
130
131 if (info->node_mask >= (1 << info->total_nodes)) {
132 printk(KERN_ERR "xt_cluster: this node mask cannot be "
133 "higher than the total number of nodes\n");
134 return false;
135 }
136 return true;
137}
138
139static struct xt_match xt_cluster_match __read_mostly = {
140 .name = "cluster",
141 .family = NFPROTO_UNSPEC,
142 .match = xt_cluster_mt,
143 .checkentry = xt_cluster_mt_checkentry,
144 .matchsize = sizeof(struct xt_cluster_match_info),
145 .me = THIS_MODULE,
146};
147
148static int __init xt_cluster_mt_init(void)
149{
150 return xt_register_match(&xt_cluster_match);
151}
152
153static void __exit xt_cluster_mt_fini(void)
154{
155 xt_unregister_match(&xt_cluster_match);
156}
157
158MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
159MODULE_LICENSE("GPL");
160MODULE_DESCRIPTION("Xtables: hash-based cluster match");
161MODULE_ALIAS("ipt_cluster");
162MODULE_ALIAS("ip6t_cluster");
163module_init(xt_cluster_mt_init);
164module_exit(xt_cluster_mt_fini);
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index f97fded024c..a5b5369c30f 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -149,7 +149,7 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht,
149 /* initialize hash with random val at the time we allocate 149 /* initialize hash with random val at the time we allocate
150 * the first hashtable entry */ 150 * the first hashtable entry */
151 if (!ht->rnd_initialized) { 151 if (!ht->rnd_initialized) {
152 get_random_bytes(&ht->rnd, 4); 152 get_random_bytes(&ht->rnd, sizeof(ht->rnd));
153 ht->rnd_initialized = 1; 153 ht->rnd_initialized = 1;
154 } 154 }
155 155
@@ -565,8 +565,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
565static bool 565static bool
566hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) 566hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par)
567{ 567{
568 const struct xt_hashlimit_info *r = 568 const struct xt_hashlimit_info *r = par->matchinfo;
569 ((const struct xt_hashlimit_info *)par->matchinfo)->u.master;
570 struct xt_hashlimit_htable *hinfo = r->hinfo; 569 struct xt_hashlimit_htable *hinfo = r->hinfo;
571 unsigned long now = jiffies; 570 unsigned long now = jiffies;
572 struct dsthash_ent *dh; 571 struct dsthash_ent *dh;
@@ -702,8 +701,6 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par)
702 } 701 }
703 mutex_unlock(&hlimit_mutex); 702 mutex_unlock(&hlimit_mutex);
704 703
705 /* Ugly hack: For SMP, we only want to use one set */
706 r->u.master = r;
707 return true; 704 return true;
708} 705}
709 706
diff --git a/net/netfilter/xt_hl.c b/net/netfilter/xt_hl.c
new file mode 100644
index 00000000000..7726154c87b
--- /dev/null
+++ b/net/netfilter/xt_hl.c
@@ -0,0 +1,108 @@
1/*
2 * IP tables module for matching the value of the TTL
3 * (C) 2000,2001 by Harald Welte <laforge@netfilter.org>
4 *
5 * Hop Limit matching module
6 * (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/ip.h>
14#include <linux/ipv6.h>
15#include <linux/module.h>
16#include <linux/skbuff.h>
17
18#include <linux/netfilter/x_tables.h>
19#include <linux/netfilter_ipv4/ipt_ttl.h>
20#include <linux/netfilter_ipv6/ip6t_hl.h>
21
22MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
23MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match");
24MODULE_LICENSE("GPL");
25MODULE_ALIAS("ipt_ttl");
26MODULE_ALIAS("ip6t_hl");
27
28static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par)
29{
30 const struct ipt_ttl_info *info = par->matchinfo;
31 const u8 ttl = ip_hdr(skb)->ttl;
32
33 switch (info->mode) {
34 case IPT_TTL_EQ:
35 return ttl == info->ttl;
36 case IPT_TTL_NE:
37 return ttl != info->ttl;
38 case IPT_TTL_LT:
39 return ttl < info->ttl;
40 case IPT_TTL_GT:
41 return ttl > info->ttl;
42 default:
43 printk(KERN_WARNING "ipt_ttl: unknown mode %d\n",
44 info->mode);
45 return false;
46 }
47
48 return false;
49}
50
51static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
52{
53 const struct ip6t_hl_info *info = par->matchinfo;
54 const struct ipv6hdr *ip6h = ipv6_hdr(skb);
55
56 switch (info->mode) {
57 case IP6T_HL_EQ:
58 return ip6h->hop_limit == info->hop_limit;
59 break;
60 case IP6T_HL_NE:
61 return ip6h->hop_limit != info->hop_limit;
62 break;
63 case IP6T_HL_LT:
64 return ip6h->hop_limit < info->hop_limit;
65 break;
66 case IP6T_HL_GT:
67 return ip6h->hop_limit > info->hop_limit;
68 break;
69 default:
70 printk(KERN_WARNING "ip6t_hl: unknown mode %d\n",
71 info->mode);
72 return false;
73 }
74
75 return false;
76}
77
78static struct xt_match hl_mt_reg[] __read_mostly = {
79 {
80 .name = "ttl",
81 .revision = 0,
82 .family = NFPROTO_IPV4,
83 .match = ttl_mt,
84 .matchsize = sizeof(struct ipt_ttl_info),
85 .me = THIS_MODULE,
86 },
87 {
88 .name = "hl",
89 .revision = 0,
90 .family = NFPROTO_IPV6,
91 .match = hl_mt6,
92 .matchsize = sizeof(struct ip6t_hl_info),
93 .me = THIS_MODULE,
94 },
95};
96
97static int __init hl_mt_init(void)
98{
99 return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
100}
101
102static void __exit hl_mt_exit(void)
103{
104 xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg));
105}
106
107module_init(hl_mt_init);
108module_exit(hl_mt_exit);
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index c908d69a559..2e8089ecd0a 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -14,6 +14,11 @@
14#include <linux/netfilter/x_tables.h> 14#include <linux/netfilter/x_tables.h>
15#include <linux/netfilter/xt_limit.h> 15#include <linux/netfilter/xt_limit.h>
16 16
17struct xt_limit_priv {
18 unsigned long prev;
19 uint32_t credit;
20};
21
17MODULE_LICENSE("GPL"); 22MODULE_LICENSE("GPL");
18MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); 23MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>");
19MODULE_DESCRIPTION("Xtables: rate-limit match"); 24MODULE_DESCRIPTION("Xtables: rate-limit match");
@@ -60,18 +65,18 @@ static DEFINE_SPINLOCK(limit_lock);
60static bool 65static bool
61limit_mt(const struct sk_buff *skb, const struct xt_match_param *par) 66limit_mt(const struct sk_buff *skb, const struct xt_match_param *par)
62{ 67{
63 struct xt_rateinfo *r = 68 const struct xt_rateinfo *r = par->matchinfo;
64 ((const struct xt_rateinfo *)par->matchinfo)->master; 69 struct xt_limit_priv *priv = r->master;
65 unsigned long now = jiffies; 70 unsigned long now = jiffies;
66 71
67 spin_lock_bh(&limit_lock); 72 spin_lock_bh(&limit_lock);
68 r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY; 73 priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY;
69 if (r->credit > r->credit_cap) 74 if (priv->credit > r->credit_cap)
70 r->credit = r->credit_cap; 75 priv->credit = r->credit_cap;
71 76
72 if (r->credit >= r->cost) { 77 if (priv->credit >= r->cost) {
73 /* We're not limited. */ 78 /* We're not limited. */
74 r->credit -= r->cost; 79 priv->credit -= r->cost;
75 spin_unlock_bh(&limit_lock); 80 spin_unlock_bh(&limit_lock);
76 return true; 81 return true;
77 } 82 }
@@ -95,6 +100,7 @@ user2credits(u_int32_t user)
95static bool limit_mt_check(const struct xt_mtchk_param *par) 100static bool limit_mt_check(const struct xt_mtchk_param *par)
96{ 101{
97 struct xt_rateinfo *r = par->matchinfo; 102 struct xt_rateinfo *r = par->matchinfo;
103 struct xt_limit_priv *priv;
98 104
99 /* Check for overflow. */ 105 /* Check for overflow. */
100 if (r->burst == 0 106 if (r->burst == 0
@@ -104,19 +110,30 @@ static bool limit_mt_check(const struct xt_mtchk_param *par)
104 return false; 110 return false;
105 } 111 }
106 112
107 /* For SMP, we only want to use one set of counters. */ 113 priv = kmalloc(sizeof(*priv), GFP_KERNEL);
108 r->master = r; 114 if (priv == NULL)
115 return -ENOMEM;
116
117 /* For SMP, we only want to use one set of state. */
118 r->master = priv;
109 if (r->cost == 0) { 119 if (r->cost == 0) {
110 /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * 120 /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies *
111 128. */ 121 128. */
112 r->prev = jiffies; 122 priv->prev = jiffies;
113 r->credit = user2credits(r->avg * r->burst); /* Credits full. */ 123 priv->credit = user2credits(r->avg * r->burst); /* Credits full. */
114 r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ 124 r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */
115 r->cost = user2credits(r->avg); 125 r->cost = user2credits(r->avg);
116 } 126 }
117 return true; 127 return true;
118} 128}
119 129
130static void limit_mt_destroy(const struct xt_mtdtor_param *par)
131{
132 const struct xt_rateinfo *info = par->matchinfo;
133
134 kfree(info->master);
135}
136
120#ifdef CONFIG_COMPAT 137#ifdef CONFIG_COMPAT
121struct compat_xt_rateinfo { 138struct compat_xt_rateinfo {
122 u_int32_t avg; 139 u_int32_t avg;
@@ -167,6 +184,7 @@ static struct xt_match limit_mt_reg __read_mostly = {
167 .family = NFPROTO_UNSPEC, 184 .family = NFPROTO_UNSPEC,
168 .match = limit_mt, 185 .match = limit_mt,
169 .checkentry = limit_mt_check, 186 .checkentry = limit_mt_check,
187 .destroy = limit_mt_destroy,
170 .matchsize = sizeof(struct xt_rateinfo), 188 .matchsize = sizeof(struct xt_rateinfo),
171#ifdef CONFIG_COMPAT 189#ifdef CONFIG_COMPAT
172 .compatsize = sizeof(struct compat_xt_rateinfo), 190 .compatsize = sizeof(struct compat_xt_rateinfo),
diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c
index 1bcdfc12cf5..44a234ef443 100644
--- a/net/netfilter/xt_physdev.c
+++ b/net/netfilter/xt_physdev.c
@@ -20,13 +20,30 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match");
20MODULE_ALIAS("ipt_physdev"); 20MODULE_ALIAS("ipt_physdev");
21MODULE_ALIAS("ip6t_physdev"); 21MODULE_ALIAS("ip6t_physdev");
22 22
23static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
24{
25 const unsigned long *a = (const unsigned long *)_a;
26 const unsigned long *b = (const unsigned long *)_b;
27 const unsigned long *mask = (const unsigned long *)_mask;
28 unsigned long ret;
29
30 ret = (a[0] ^ b[0]) & mask[0];
31 if (IFNAMSIZ > sizeof(unsigned long))
32 ret |= (a[1] ^ b[1]) & mask[1];
33 if (IFNAMSIZ > 2 * sizeof(unsigned long))
34 ret |= (a[2] ^ b[2]) & mask[2];
35 if (IFNAMSIZ > 3 * sizeof(unsigned long))
36 ret |= (a[3] ^ b[3]) & mask[3];
37 BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
38 return ret;
39}
40
23static bool 41static bool
24physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) 42physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
25{ 43{
26 int i; 44 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
27 static const char nulldevname[IFNAMSIZ];
28 const struct xt_physdev_info *info = par->matchinfo; 45 const struct xt_physdev_info *info = par->matchinfo;
29 bool ret; 46 unsigned long ret;
30 const char *indev, *outdev; 47 const char *indev, *outdev;
31 const struct nf_bridge_info *nf_bridge; 48 const struct nf_bridge_info *nf_bridge;
32 49
@@ -68,11 +85,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par)
68 if (!(info->bitmask & XT_PHYSDEV_OP_IN)) 85 if (!(info->bitmask & XT_PHYSDEV_OP_IN))
69 goto match_outdev; 86 goto match_outdev;
70 indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; 87 indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname;
71 for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) { 88 ret = ifname_compare(indev, info->physindev, info->in_mask);
72 ret |= (((const unsigned int *)indev)[i]
73 ^ ((const unsigned int *)info->physindev)[i])
74 & ((const unsigned int *)info->in_mask)[i];
75 }
76 89
77 if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) 90 if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN))
78 return false; 91 return false;
@@ -82,13 +95,9 @@ match_outdev:
82 return true; 95 return true;
83 outdev = nf_bridge->physoutdev ? 96 outdev = nf_bridge->physoutdev ?
84 nf_bridge->physoutdev->name : nulldevname; 97 nf_bridge->physoutdev->name : nulldevname;
85 for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) { 98 ret = ifname_compare(outdev, info->physoutdev, info->out_mask);
86 ret |= (((const unsigned int *)outdev)[i]
87 ^ ((const unsigned int *)info->physoutdev)[i])
88 & ((const unsigned int *)info->out_mask)[i];
89 }
90 99
91 return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT); 100 return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));
92} 101}
93 102
94static bool physdev_mt_check(const struct xt_mtchk_param *par) 103static bool physdev_mt_check(const struct xt_mtchk_param *par)
diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c
index c84fce5e0f3..01dd07b764e 100644
--- a/net/netfilter/xt_quota.c
+++ b/net/netfilter/xt_quota.c
@@ -9,6 +9,10 @@
9#include <linux/netfilter/x_tables.h> 9#include <linux/netfilter/x_tables.h>
10#include <linux/netfilter/xt_quota.h> 10#include <linux/netfilter/xt_quota.h>
11 11
12struct xt_quota_priv {
13 uint64_t quota;
14};
15
12MODULE_LICENSE("GPL"); 16MODULE_LICENSE("GPL");
13MODULE_AUTHOR("Sam Johnston <samj@samj.net>"); 17MODULE_AUTHOR("Sam Johnston <samj@samj.net>");
14MODULE_DESCRIPTION("Xtables: countdown quota match"); 18MODULE_DESCRIPTION("Xtables: countdown quota match");
@@ -20,18 +24,20 @@ static DEFINE_SPINLOCK(quota_lock);
20static bool 24static bool
21quota_mt(const struct sk_buff *skb, const struct xt_match_param *par) 25quota_mt(const struct sk_buff *skb, const struct xt_match_param *par)
22{ 26{
23 struct xt_quota_info *q = 27 struct xt_quota_info *q = (void *)par->matchinfo;
24 ((const struct xt_quota_info *)par->matchinfo)->master; 28 struct xt_quota_priv *priv = q->master;
25 bool ret = q->flags & XT_QUOTA_INVERT; 29 bool ret = q->flags & XT_QUOTA_INVERT;
26 30
27 spin_lock_bh(&quota_lock); 31 spin_lock_bh(&quota_lock);
28 if (q->quota >= skb->len) { 32 if (priv->quota >= skb->len) {
29 q->quota -= skb->len; 33 priv->quota -= skb->len;
30 ret = !ret; 34 ret = !ret;
31 } else { 35 } else {
32 /* we do not allow even small packets from now on */ 36 /* we do not allow even small packets from now on */
33 q->quota = 0; 37 priv->quota = 0;
34 } 38 }
39 /* Copy quota back to matchinfo so that iptables can display it */
40 q->quota = priv->quota;
35 spin_unlock_bh(&quota_lock); 41 spin_unlock_bh(&quota_lock);
36 42
37 return ret; 43 return ret;
@@ -43,17 +49,28 @@ static bool quota_mt_check(const struct xt_mtchk_param *par)
43 49
44 if (q->flags & ~XT_QUOTA_MASK) 50 if (q->flags & ~XT_QUOTA_MASK)
45 return false; 51 return false;
46 /* For SMP, we only want to use one set of counters. */ 52
47 q->master = q; 53 q->master = kmalloc(sizeof(*q->master), GFP_KERNEL);
54 if (q->master == NULL)
55 return -ENOMEM;
56
48 return true; 57 return true;
49} 58}
50 59
60static void quota_mt_destroy(const struct xt_mtdtor_param *par)
61{
62 const struct xt_quota_info *q = par->matchinfo;
63
64 kfree(q->master);
65}
66
51static struct xt_match quota_mt_reg __read_mostly = { 67static struct xt_match quota_mt_reg __read_mostly = {
52 .name = "quota", 68 .name = "quota",
53 .revision = 0, 69 .revision = 0,
54 .family = NFPROTO_UNSPEC, 70 .family = NFPROTO_UNSPEC,
55 .match = quota_mt, 71 .match = quota_mt,
56 .checkentry = quota_mt_check, 72 .checkentry = quota_mt_check,
73 .destroy = quota_mt_destroy,
57 .matchsize = sizeof(struct xt_quota_info), 74 .matchsize = sizeof(struct xt_quota_info),
58 .me = THIS_MODULE, 75 .me = THIS_MODULE,
59}; 76};
diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c
index 0d75141139d..d8c0f8f1a78 100644
--- a/net/netfilter/xt_statistic.c
+++ b/net/netfilter/xt_statistic.c
@@ -16,6 +16,10 @@
16#include <linux/netfilter/xt_statistic.h> 16#include <linux/netfilter/xt_statistic.h>
17#include <linux/netfilter/x_tables.h> 17#include <linux/netfilter/x_tables.h>
18 18
19struct xt_statistic_priv {
20 uint32_t count;
21};
22
19MODULE_LICENSE("GPL"); 23MODULE_LICENSE("GPL");
20MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 24MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
21MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)"); 25MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)");
@@ -27,7 +31,7 @@ static DEFINE_SPINLOCK(nth_lock);
27static bool 31static bool
28statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) 32statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
29{ 33{
30 struct xt_statistic_info *info = (void *)par->matchinfo; 34 const struct xt_statistic_info *info = par->matchinfo;
31 bool ret = info->flags & XT_STATISTIC_INVERT; 35 bool ret = info->flags & XT_STATISTIC_INVERT;
32 36
33 switch (info->mode) { 37 switch (info->mode) {
@@ -36,10 +40,9 @@ statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par)
36 ret = !ret; 40 ret = !ret;
37 break; 41 break;
38 case XT_STATISTIC_MODE_NTH: 42 case XT_STATISTIC_MODE_NTH:
39 info = info->master;
40 spin_lock_bh(&nth_lock); 43 spin_lock_bh(&nth_lock);
41 if (info->u.nth.count++ == info->u.nth.every) { 44 if (info->master->count++ == info->u.nth.every) {
42 info->u.nth.count = 0; 45 info->master->count = 0;
43 ret = !ret; 46 ret = !ret;
44 } 47 }
45 spin_unlock_bh(&nth_lock); 48 spin_unlock_bh(&nth_lock);
@@ -56,16 +59,31 @@ static bool statistic_mt_check(const struct xt_mtchk_param *par)
56 if (info->mode > XT_STATISTIC_MODE_MAX || 59 if (info->mode > XT_STATISTIC_MODE_MAX ||
57 info->flags & ~XT_STATISTIC_MASK) 60 info->flags & ~XT_STATISTIC_MASK)
58 return false; 61 return false;
59 info->master = info; 62
63 info->master = kzalloc(sizeof(*info->master), GFP_KERNEL);
64 if (info->master == NULL) {
65 printk(KERN_ERR KBUILD_MODNAME ": Out of memory\n");
66 return false;
67 }
68 info->master->count = info->u.nth.count;
69
60 return true; 70 return true;
61} 71}
62 72
73static void statistic_mt_destroy(const struct xt_mtdtor_param *par)
74{
75 const struct xt_statistic_info *info = par->matchinfo;
76
77 kfree(info->master);
78}
79
63static struct xt_match xt_statistic_mt_reg __read_mostly = { 80static struct xt_match xt_statistic_mt_reg __read_mostly = {
64 .name = "statistic", 81 .name = "statistic",
65 .revision = 0, 82 .revision = 0,
66 .family = NFPROTO_UNSPEC, 83 .family = NFPROTO_UNSPEC,
67 .match = statistic_mt, 84 .match = statistic_mt,
68 .checkentry = statistic_mt_check, 85 .checkentry = statistic_mt_check,
86 .destroy = statistic_mt_destroy,
69 .matchsize = sizeof(struct xt_statistic_info), 87 .matchsize = sizeof(struct xt_statistic_info),
70 .me = THIS_MODULE, 88 .me = THIS_MODULE,
71}; 89};