diff options
author | David S. Miller <davem@davemloft.net> | 2009-03-24 16:24:36 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-03-24 16:24:36 -0400 |
commit | b5bb14386eabcb4229ade2bc0a2b237ca166d37d (patch) | |
tree | 1966e65479f0d12cec0a204443a95b8eb57946db /net/netfilter | |
parent | bb4f92b3a33bfc31f55098da85be44702bea2d16 (diff) | |
parent | 1d45209d89e647e9f27e4afa1f47338df73bc112 (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/Kconfig | 63 | ||||
-rw-r--r-- | net/netfilter/Makefile | 4 | ||||
-rw-r--r-- | net/netfilter/core.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 14 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_expect.c | 3 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 161 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto.c | 21 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_dccp.c | 145 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_generic.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_udp.c | 2 | ||||
-rw-r--r-- | net/netfilter/nf_log.c | 201 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 6 | ||||
-rw-r--r-- | net/netfilter/nfnetlink_log.c | 18 | ||||
-rw-r--r-- | net/netfilter/x_tables.c | 26 | ||||
-rw-r--r-- | net/netfilter/xt_HL.c | 171 | ||||
-rw-r--r-- | net/netfilter/xt_LED.c | 161 | ||||
-rw-r--r-- | net/netfilter/xt_cluster.c | 164 | ||||
-rw-r--r-- | net/netfilter/xt_hashlimit.c | 7 | ||||
-rw-r--r-- | net/netfilter/xt_hl.c | 108 | ||||
-rw-r--r-- | net/netfilter/xt_limit.c | 40 | ||||
-rw-r--r-- | net/netfilter/xt_physdev.c | 37 | ||||
-rw-r--r-- | net/netfilter/xt_quota.c | 31 | ||||
-rw-r--r-- | net/netfilter/xt_statistic.c | 28 |
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 | ||
360 | config 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 | |||
375 | config 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 | |||
360 | config NETFILTER_XT_TARGET_MARK | 399 | config 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 | ||
530 | config 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 | |||
491 | config NETFILTER_XT_MATCH_COMMENT | 546 | config 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 | ||
663 | config 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 | |||
608 | config NETFILTER_XT_MATCH_IPRANGE | 671 | config 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 | |||
45 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o | 45 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o |
46 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o | 46 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o |
47 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o | 47 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o |
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o | ||
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o | ||
48 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o | 50 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o |
49 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o | 51 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o |
50 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o | 52 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o |
@@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o | |||
57 | obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o | 59 | obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o |
58 | 60 | ||
59 | # matches | 61 | # matches |
62 | obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o | ||
60 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o | 63 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o |
61 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o | 64 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o |
62 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o | 65 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o |
@@ -67,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o | |||
67 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o | 70 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o |
68 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o | 71 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o |
69 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o | 72 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o |
73 | obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o | ||
70 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o | 74 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o |
71 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o | 75 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o |
72 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o | 76 | obj-$(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 | } |
186 | unlock: | ||
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); | |||
54 | unsigned int nf_conntrack_htable_size __read_mostly; | 54 | unsigned int nf_conntrack_htable_size __read_mostly; |
55 | EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); | 55 | EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); |
56 | 56 | ||
57 | int nf_conntrack_max __read_mostly; | 57 | unsigned int nf_conntrack_max __read_mostly; |
58 | EXPORT_SYMBOL_GPL(nf_conntrack_max); | 58 | EXPORT_SYMBOL_GPL(nf_conntrack_max); |
59 | 59 | ||
60 | struct nf_conn nf_conntrack_untracked __read_mostly; | 60 | struct 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); | |||
516 | static void nf_conntrack_free_rcu(struct rcu_head *head) | 517 | static 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 | ||
526 | void nf_conntrack_free(struct nf_conn *ct) | 525 | void 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 | } |
531 | EXPORT_SYMBOL_GPL(nf_conntrack_free); | 533 | EXPORT_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, | |||
518 | nla_put_failure: | 518 | nla_put_failure: |
519 | rcu_read_unlock(); | 519 | rcu_read_unlock(); |
520 | nlmsg_failure: | 520 | nlmsg_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 | ||
1127 | static int | 1135 | static struct nf_conn * |
1128 | ctnetlink_create_conntrack(struct nlattr *cda[], | 1136 | ctnetlink_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 | ||
1258 | err: | 1262 | err2: |
1263 | rcu_read_unlock(); | ||
1264 | err1: | ||
1259 | nf_conntrack_free(ct); | 1265 | nf_conntrack_free(ct); |
1260 | return err; | 1266 | return ERR_PTR(err); |
1261 | } | 1267 | } |
1262 | 1268 | ||
1263 | static int | 1269 | static 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, | |||
1533 | nla_put_failure: | 1515 | nla_put_failure: |
1534 | rcu_read_unlock(); | 1516 | rcu_read_unlock(); |
1535 | nlmsg_failure: | 1517 | nlmsg_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 */ |
77 | struct nf_conntrack_l4proto * | ||
78 | nf_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 | } | ||
90 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); | ||
91 | |||
92 | void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) | ||
93 | { | ||
94 | module_put(p->me); | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); | ||
97 | |||
98 | struct nf_conntrack_l3proto * | 77 | struct nf_conntrack_l3proto * |
99 | nf_ct_l3proto_find_get(u_int16_t l3proto) | 78 | nf_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 | ||
24 | static DEFINE_RWLOCK(dccp_lock); | 27 | static DEFINE_RWLOCK(dccp_lock); |
25 | 28 | ||
26 | static 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 | ||
75 | static 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 | |||
85 | static const char * const dccp_state_names[] = { | 76 | static 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 */ | ||
388 | static int dccp_net_id; | ||
389 | struct 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 | |||
398 | static inline struct dccp_net *dccp_pernet(struct net *net) | ||
399 | { | ||
400 | return net_generic(net, dccp_net_id); | ||
401 | } | ||
402 | |||
396 | static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, | 403 | static 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 |
663 | static unsigned int dccp_sysctl_table_users; | 675 | /* template, data assigned later */ |
664 | static struct ctl_table_header *dccp_sysctl_header; | 676 | static struct ctl_table dccp_sysctl_table[] = { |
665 | static 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 | ||
761 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { | 759 | static 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 | |||
779 | static __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 | |||
828 | out: | ||
829 | kfree(dn); | ||
830 | return err; | ||
831 | } | ||
832 | |||
833 | static __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 | |||
845 | static struct pernet_operations dccp_net_ops = { | ||
846 | .init = dccp_net_init, | ||
847 | .exit = dccp_net_exit, | ||
784 | }; | 848 | }; |
785 | 849 | ||
786 | static int __init nf_conntrack_proto_dccp_init(void) | 850 | static 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 | ||
799 | err2: | 867 | err3: |
800 | nf_conntrack_l4proto_unregister(&dccp_proto4); | 868 | nf_conntrack_l4proto_unregister(&dccp_proto4); |
869 | err2: | ||
870 | unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops); | ||
801 | err1: | 871 | err1: |
802 | return err; | 872 | return err; |
803 | } | 873 | } |
804 | 874 | ||
805 | static void __exit nf_conntrack_proto_dccp_fini(void) | 875 | static 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[] = { | |||
92 | struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = | 92 | struct 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 */ |
30 | static DEFINE_RWLOCK(tcp_lock); | 32 | static 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 | ||
26 | static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; | 28 | static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; |
27 | static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; | 29 | static 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 | ||
18 | static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly; | 19 | static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly; |
20 | static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly; | ||
19 | static DEFINE_MUTEX(nf_log_mutex); | 21 | static DEFINE_MUTEX(nf_log_mutex); |
20 | 22 | ||
21 | /* return EBUSY if somebody else is registered, EEXIST if the same logger | 23 | static struct nf_logger *__find_logger(int pf, const char *str_logger) |
22 | * is registred, 0 on success. */ | ||
23 | int 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 | } |
46 | EXPORT_SYMBOL(nf_log_register); | ||
47 | 34 | ||
48 | void nf_log_unregister_pf(u_int8_t pf) | 35 | /* return EEXIST if the same logger is registred, 0 on success. */ |
36 | int 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 | } |
59 | EXPORT_SYMBOL(nf_log_unregister_pf); | 61 | EXPORT_SYMBOL(nf_log_register); |
60 | 62 | ||
61 | void nf_log_unregister(const struct nf_logger *logger) | 63 | void 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 | } |
74 | EXPORT_SYMBOL(nf_log_unregister); | 79 | EXPORT_SYMBOL(nf_log_unregister); |
75 | 80 | ||
81 | int 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 | } | ||
92 | EXPORT_SYMBOL(nf_log_bind_pf); | ||
93 | |||
94 | void 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 | } | ||
100 | EXPORT_SYMBOL(nf_log_unbind_pf); | ||
101 | |||
76 | void nf_log_packet(u_int8_t pf, | 102 | void 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 | ||
141 | static const struct seq_operations nflog_seq_ops = { | 191 | static 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 | ||
215 | struct 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 | |||
222 | static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; | ||
223 | static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; | ||
224 | static struct ctl_table_header *nf_log_dir_header; | ||
225 | |||
226 | static 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 | |||
260 | static __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 | ||
285 | static __init int netfilter_log_sysctl_init(void) | ||
286 | { | ||
287 | return 0; | ||
288 | } | ||
289 | #endif /* CONFIG_SYSCTL */ | ||
163 | 290 | ||
164 | int __init netfilter_log_init(void) | 291 | int __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 | } |
114 | EXPORT_SYMBOL_GPL(nfnetlink_send); | 114 | EXPORT_SYMBOL_GPL(nfnetlink_send); |
115 | 115 | ||
116 | void nfnetlink_set_err(u32 pid, u32 group, int error) | ||
117 | { | ||
118 | netlink_set_err(nfnl, pid, group, error); | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(nfnetlink_set_err); | ||
121 | |||
116 | int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) | 122 | int 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 | ||
696 | static const struct nf_logger nfulnl_logger = { | 696 | static 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 |
969 | cleanup_logger: | ||
970 | nf_log_unregister(&nfulnl_logger); | ||
971 | #endif | ||
963 | cleanup_subsys: | 972 | cleanup_subsys: |
964 | nfnetlink_subsys_unregister(&nfulnl_subsys); | 973 | nfnetlink_subsys_unregister(&nfulnl_subsys); |
965 | #endif | ||
966 | cleanup_netlink_notifier: | 974 | cleanup_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 | } |
626 | EXPORT_SYMBOL(xt_free_table_info); | 626 | EXPORT_SYMBOL(xt_free_table_info); |
627 | 627 | ||
628 | void 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 | } | ||
640 | EXPORT_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. */ |
629 | struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, | 643 | struct 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 | } |
691 | EXPORT_SYMBOL_GPL(xt_replace_table); | 706 | EXPORT_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 | |||
23 | MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | ||
24 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | ||
25 | MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target"); | ||
26 | MODULE_LICENSE("GPL"); | ||
27 | |||
28 | static unsigned int | ||
29 | ttl_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 | |||
68 | static unsigned int | ||
69 | hl_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 | |||
104 | static 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 | |||
118 | static 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 | |||
135 | static 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 | |||
158 | static int __init hl_tg_init(void) | ||
159 | { | ||
160 | return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | ||
161 | } | ||
162 | |||
163 | static void __exit hl_tg_exit(void) | ||
164 | { | ||
165 | xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | ||
166 | } | ||
167 | |||
168 | module_init(hl_tg_init); | ||
169 | module_exit(hl_tg_exit); | ||
170 | MODULE_ALIAS("ipt_TTL"); | ||
171 | MODULE_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 | |||
30 | MODULE_LICENSE("GPL"); | ||
31 | MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>"); | ||
32 | MODULE_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 | */ | ||
39 | struct xt_led_info_internal { | ||
40 | struct led_trigger netfilter_led_trigger; | ||
41 | struct timer_list timer; | ||
42 | }; | ||
43 | |||
44 | static unsigned int | ||
45 | led_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 | |||
75 | static 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 | |||
83 | static 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 | |||
121 | exit_alloc: | ||
122 | kfree(ledinternal); | ||
123 | |||
124 | return false; | ||
125 | } | ||
126 | |||
127 | static 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 | |||
139 | static 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 | |||
150 | static int __init led_tg_init(void) | ||
151 | { | ||
152 | return xt_register_target(&led_tg_reg); | ||
153 | } | ||
154 | |||
155 | static void __exit led_tg_exit(void) | ||
156 | { | ||
157 | xt_unregister_target(&led_tg_reg); | ||
158 | } | ||
159 | |||
160 | module_init(led_tg_init); | ||
161 | module_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 | |||
18 | static 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 | |||
23 | static 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 | |||
28 | static inline u_int32_t | ||
29 | xt_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 | |||
34 | static inline u_int32_t | ||
35 | xt_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 | |||
40 | static inline u_int32_t | ||
41 | xt_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 | |||
60 | static inline bool | ||
61 | xt_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 | |||
80 | static bool | ||
81 | xt_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 | |||
127 | static 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 | |||
139 | static 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 | |||
148 | static int __init xt_cluster_mt_init(void) | ||
149 | { | ||
150 | return xt_register_match(&xt_cluster_match); | ||
151 | } | ||
152 | |||
153 | static void __exit xt_cluster_mt_fini(void) | ||
154 | { | ||
155 | xt_unregister_match(&xt_cluster_match); | ||
156 | } | ||
157 | |||
158 | MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | ||
159 | MODULE_LICENSE("GPL"); | ||
160 | MODULE_DESCRIPTION("Xtables: hash-based cluster match"); | ||
161 | MODULE_ALIAS("ipt_cluster"); | ||
162 | MODULE_ALIAS("ip6t_cluster"); | ||
163 | module_init(xt_cluster_mt_init); | ||
164 | module_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, | |||
565 | static bool | 565 | static bool |
566 | hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) | 566 | hashlimit_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 | |||
22 | MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | ||
23 | MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match"); | ||
24 | MODULE_LICENSE("GPL"); | ||
25 | MODULE_ALIAS("ipt_ttl"); | ||
26 | MODULE_ALIAS("ip6t_hl"); | ||
27 | |||
28 | static 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 | |||
51 | static 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 | |||
78 | static 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 | |||
97 | static int __init hl_mt_init(void) | ||
98 | { | ||
99 | return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); | ||
100 | } | ||
101 | |||
102 | static void __exit hl_mt_exit(void) | ||
103 | { | ||
104 | xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); | ||
105 | } | ||
106 | |||
107 | module_init(hl_mt_init); | ||
108 | module_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 | ||
17 | struct xt_limit_priv { | ||
18 | unsigned long prev; | ||
19 | uint32_t credit; | ||
20 | }; | ||
21 | |||
17 | MODULE_LICENSE("GPL"); | 22 | MODULE_LICENSE("GPL"); |
18 | MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); | 23 | MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); |
19 | MODULE_DESCRIPTION("Xtables: rate-limit match"); | 24 | MODULE_DESCRIPTION("Xtables: rate-limit match"); |
@@ -60,18 +65,18 @@ static DEFINE_SPINLOCK(limit_lock); | |||
60 | static bool | 65 | static bool |
61 | limit_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 66 | limit_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) | |||
95 | static bool limit_mt_check(const struct xt_mtchk_param *par) | 100 | static 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 | ||
130 | static 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 |
121 | struct compat_xt_rateinfo { | 138 | struct 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"); | |||
20 | MODULE_ALIAS("ipt_physdev"); | 20 | MODULE_ALIAS("ipt_physdev"); |
21 | MODULE_ALIAS("ip6t_physdev"); | 21 | MODULE_ALIAS("ip6t_physdev"); |
22 | 22 | ||
23 | static 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 | |||
23 | static bool | 41 | static bool |
24 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 42 | physdev_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 | ||
94 | static bool physdev_mt_check(const struct xt_mtchk_param *par) | 103 | static 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 | ||
12 | struct xt_quota_priv { | ||
13 | uint64_t quota; | ||
14 | }; | ||
15 | |||
12 | MODULE_LICENSE("GPL"); | 16 | MODULE_LICENSE("GPL"); |
13 | MODULE_AUTHOR("Sam Johnston <samj@samj.net>"); | 17 | MODULE_AUTHOR("Sam Johnston <samj@samj.net>"); |
14 | MODULE_DESCRIPTION("Xtables: countdown quota match"); | 18 | MODULE_DESCRIPTION("Xtables: countdown quota match"); |
@@ -20,18 +24,20 @@ static DEFINE_SPINLOCK(quota_lock); | |||
20 | static bool | 24 | static bool |
21 | quota_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 25 | quota_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("a_lock); | 31 | spin_lock_bh("a_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("a_lock); | 41 | spin_unlock_bh("a_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 | ||
60 | static 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 | |||
51 | static struct xt_match quota_mt_reg __read_mostly = { | 67 | static 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 | ||
19 | struct xt_statistic_priv { | ||
20 | uint32_t count; | ||
21 | }; | ||
22 | |||
19 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
20 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); | 24 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); |
21 | MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)"); | 25 | MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)"); |
@@ -27,7 +31,7 @@ static DEFINE_SPINLOCK(nth_lock); | |||
27 | static bool | 31 | static bool |
28 | statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) | 32 | statistic_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 | ||
73 | static 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 | |||
63 | static struct xt_match xt_statistic_mt_reg __read_mostly = { | 80 | static 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 | }; |