diff options
Diffstat (limited to 'net/netfilter')
80 files changed, 1365 insertions, 1329 deletions
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 18d77b5c351a..8593a77cfea9 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -314,8 +314,39 @@ config NETFILTER_XTABLES if NETFILTER_XTABLES +comment "Xtables combined modules" + +config NETFILTER_XT_MARK + tristate 'nfmark target and match support' + default m if NETFILTER_ADVANCED=n + ---help--- + This option adds the "MARK" target and "mark" match. + + Netfilter mark matching allows you to match packets based on the + "nfmark" value in the packet. + The target allows you to create rules in the "mangle" table which alter + the netfilter mark (nfmark) field associated with the packet. + + Prior to routing, the nfmark can influence the routing method (see + "Use netfilter MARK value as routing key") and can also be used by + other subsystems to change their behavior. + +config NETFILTER_XT_CONNMARK + tristate 'ctmark target and match support' + depends on NF_CONNTRACK + depends on NETFILTER_ADVANCED + select NF_CONNTRACK_MARK + ---help--- + This option adds the "CONNMARK" target and "connmark" match. + + Netfilter allows you to store a mark value per connection (a.k.a. + ctmark), similarly to the packet mark (nfmark). Using this + target and match, you can set and match on this mark. + # alphabetically ordered list of targets +comment "Xtables targets" + config NETFILTER_XT_TARGET_CLASSIFY tristate '"CLASSIFY" target support' depends on NETFILTER_ADVANCED @@ -332,15 +363,11 @@ config NETFILTER_XT_TARGET_CONNMARK tristate '"CONNMARK" target support' depends on NF_CONNTRACK depends on NETFILTER_ADVANCED - select NF_CONNTRACK_MARK - help - This option adds a `CONNMARK' target, which allows one to manipulate - the connection mark value. Similar to the MARK target, but - affects the connection mark value rather than the packet mark value. - - If you want to compile it as a module, say M here and read - <file:Documentation/kbuild/modules.txt>. The module will be called - ipt_CONNMARK. If unsure, say `N'. + select NETFILTER_XT_CONNMARK + ---help--- + This is a backwards-compat option for the user's convenience + (e.g. when running oldconfig). It selects + CONFIG_NETFILTER_XT_CONNMARK (combined connmark/CONNMARK module). config NETFILTER_XT_TARGET_CONNSECMARK tristate '"CONNSECMARK" target support' @@ -423,16 +450,12 @@ config NETFILTER_XT_TARGET_LED config NETFILTER_XT_TARGET_MARK tristate '"MARK" target support' - default m if NETFILTER_ADVANCED=n - help - This option adds a `MARK' target, which allows you to create rules - in the `mangle' table which alter the netfilter mark (nfmark) field - associated with the packet prior to routing. This can change - the routing method (see `Use netfilter MARK value as routing - key') and can also be used by other subsystems to change their - behavior. - - To compile it as a module, choose M here. If unsure, say N. + depends on NETFILTER_ADVANCED + select NETFILTER_XT_MARK + ---help--- + This is a backwards-compat option for the user's convenience + (e.g. when running oldconfig). It selects + CONFIG_NETFILTER_XT_MARK (combined mark/MARK module). config NETFILTER_XT_TARGET_NFLOG tristate '"NFLOG" target support' @@ -479,6 +502,15 @@ config NETFILTER_XT_TARGET_RATEEST To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_TARGET_TEE + tristate '"TEE" - packet cloning to alternate destiantion' + depends on NETFILTER_ADVANCED + depends on (IPV6 || IPV6=n) + depends on !NF_CONNTRACK || NF_CONNTRACK + ---help--- + This option adds a "TEE" target with which a packet can be cloned and + this clone be rerouted to another nexthop. + config NETFILTER_XT_TARGET_TPROXY tristate '"TPROXY" target support (EXPERIMENTAL)' depends on EXPERIMENTAL @@ -552,6 +584,10 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP This option adds a "TCPOPTSTRIP" target, which allows you to strip TCP options from TCP packets. +# alphabetically ordered list of matches + +comment "Xtables matches" + config NETFILTER_XT_MATCH_CLUSTER tristate '"cluster" match support' depends on NF_CONNTRACK @@ -602,14 +638,11 @@ config NETFILTER_XT_MATCH_CONNMARK tristate '"connmark" connection mark match support' depends on NF_CONNTRACK depends on NETFILTER_ADVANCED - select NF_CONNTRACK_MARK - help - This option adds a `connmark' match, which allows you to match the - connection mark value previously set for the session by `CONNMARK'. - - If you want to compile it as a module, say M here and read - <file:Documentation/kbuild/modules.txt>. The module will be called - ipt_connmark. If unsure, say `N'. + select NETFILTER_XT_CONNMARK + ---help--- + This is a backwards-compat option for the user's convenience + (e.g. when running oldconfig). It selects + CONFIG_NETFILTER_XT_CONNMARK (combined connmark/CONNMARK module). config NETFILTER_XT_MATCH_CONNTRACK tristate '"conntrack" connection tracking match support' @@ -733,13 +766,12 @@ config NETFILTER_XT_MATCH_MAC config NETFILTER_XT_MATCH_MARK tristate '"mark" match support' - default m if NETFILTER_ADVANCED=n - help - Netfilter mark matching allows you to match packets based on the - `nfmark' value in the packet. This can be set by the MARK target - (see below). - - To compile it as a module, choose M here. If unsure, say N. + depends on NETFILTER_ADVANCED + select NETFILTER_XT_MARK + ---help--- + This is a backwards-compat option for the user's convenience + (e.g. when running oldconfig). It selects + CONFIG_NETFILTER_XT_MARK (combined mark/MARK module). config NETFILTER_XT_MATCH_MULTIPORT tristate '"multiport" Multiple port match support' @@ -751,6 +783,19 @@ config NETFILTER_XT_MATCH_MULTIPORT To compile it as a module, choose M here. If unsure, say N. +config NETFILTER_XT_MATCH_OSF + tristate '"osf" Passive OS fingerprint match' + depends on NETFILTER_ADVANCED && NETFILTER_NETLINK + help + This option selects the Passive OS Fingerprinting match module + that allows to passively match the remote operating system by + analyzing incoming TCP SYN packets. + + Rules and loading software can be downloaded from + http://www.ioremap.net/projects/osf + + To compile it as a module, choose M here. If unsure, say N. + config NETFILTER_XT_MATCH_OWNER tristate '"owner" match support' depends on NETFILTER_ADVANCED @@ -836,13 +881,6 @@ config NETFILTER_XT_MATCH_RECENT Short options are available by using 'iptables -m recent -h' Official Website: <http://snowman.net/projects/ipt_recent/> -config NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - bool 'Enable obsolete /proc/net/ipt_recent' - depends on NETFILTER_XT_MATCH_RECENT && PROC_FS - ---help--- - This option enables the old /proc/net/ipt_recent interface, - which has been obsoleted by /proc/net/xt_recent. - config NETFILTER_XT_MATCH_SCTP tristate '"sctp" protocol match support (EXPERIMENTAL)' depends on EXPERIMENTAL @@ -942,19 +980,6 @@ config NETFILTER_XT_MATCH_U32 Details and examples are in the kernel module source. -config NETFILTER_XT_MATCH_OSF - tristate '"osf" Passive OS fingerprint match' - depends on NETFILTER_ADVANCED && NETFILTER_NETLINK - help - This option selects the Passive OS Fingerprinting match module - that allows to passively match the remote operating system by - analyzing incoming TCP SYN packets. - - Rules and loading software can be downloaded from - http://www.ioremap.net/projects/osf - - To compile it as a module, choose M here. If unsure, say N. - endif # NETFILTER_XTABLES endmenu diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index f873644f02f6..14e3a8fd8180 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -40,15 +40,17 @@ obj-$(CONFIG_NETFILTER_TPROXY) += nf_tproxy_core.o # generic X tables obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o +# combos +obj-$(CONFIG_NETFILTER_XT_MARK) += xt_mark.o +obj-$(CONFIG_NETFILTER_XT_CONNMARK) += xt_connmark.o + # targets obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o -obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o -obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o @@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o +obj-$(CONFIG_NETFILTER_XT_TARGET_TEE) += xt_TEE.o obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o # matches @@ -64,7 +67,6 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o -obj-$(CONFIG_NETFILTER_XT_MATCH_CONNMARK) += xt_connmark.o obj-$(CONFIG_NETFILTER_XT_MATCH_CONNTRACK) += xt_conntrack.o obj-$(CONFIG_NETFILTER_XT_MATCH_DCCP) += xt_dccp.o obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o @@ -76,7 +78,6 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o obj-$(CONFIG_NETFILTER_XT_MATCH_MAC) += xt_mac.o -obj-$(CONFIG_NETFILTER_XT_MATCH_MARK) += xt_mark.o obj-$(CONFIG_NETFILTER_XT_MATCH_MULTIPORT) += xt_multiport.o obj-$(CONFIG_NETFILTER_XT_MATCH_OSF) += xt_osf.o obj-$(CONFIG_NETFILTER_XT_MATCH_OWNER) += xt_owner.o diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 2c7f185dfae4..2ae747a376a5 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -209,8 +209,14 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, */ from.ip = n_cp->vaddr.ip; port = n_cp->vport; - sprintf(buf, "%u,%u,%u,%u,%u,%u", NIPQUAD(from.ip), - (ntohs(port)>>8)&255, ntohs(port)&255); + snprintf(buf, sizeof(buf), "%u,%u,%u,%u,%u,%u", + ((unsigned char *)&from.ip)[0], + ((unsigned char *)&from.ip)[1], + ((unsigned char *)&from.ip)[2], + ((unsigned char *)&from.ip)[3], + ntohs(port) >> 8, + ntohs(port) & 0xFF); + buf_len = strlen(buf); /* diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 7fc49f4cf5ad..2d3d5e4b35f8 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -167,26 +167,24 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp, ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); if (ih == NULL) - sprintf(buf, "%s TRUNCATED", pp->name); + sprintf(buf, "TRUNCATED"); else if (ih->frag_off & htons(IP_OFFSET)) - sprintf(buf, "%s %pI4->%pI4 frag", - pp->name, &ih->saddr, &ih->daddr); + sprintf(buf, "%pI4->%pI4 frag", &ih->saddr, &ih->daddr); else { __be16 _ports[2], *pptr ; pptr = skb_header_pointer(skb, offset + ih->ihl*4, sizeof(_ports), _ports); if (pptr == NULL) - sprintf(buf, "%s TRUNCATED %pI4->%pI4", - pp->name, &ih->saddr, &ih->daddr); + sprintf(buf, "TRUNCATED %pI4->%pI4", + &ih->saddr, &ih->daddr); else - sprintf(buf, "%s %pI4:%u->%pI4:%u", - pp->name, + sprintf(buf, "%pI4:%u->%pI4:%u", &ih->saddr, ntohs(pptr[0]), &ih->daddr, ntohs(pptr[1])); } - pr_debug("%s: %s\n", msg, buf); + pr_debug("%s: %s %s\n", msg, pp->name, buf); } #ifdef CONFIG_IP_VS_IPV6 @@ -201,26 +199,24 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp, ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); if (ih == NULL) - sprintf(buf, "%s TRUNCATED", pp->name); + sprintf(buf, "TRUNCATED"); else if (ih->nexthdr == IPPROTO_FRAGMENT) - sprintf(buf, "%s %pI6->%pI6 frag", - pp->name, &ih->saddr, &ih->daddr); + sprintf(buf, "%pI6->%pI6 frag", &ih->saddr, &ih->daddr); else { __be16 _ports[2], *pptr; pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr), sizeof(_ports), _ports); if (pptr == NULL) - sprintf(buf, "%s TRUNCATED %pI6->%pI6", - pp->name, &ih->saddr, &ih->daddr); + sprintf(buf, "TRUNCATED %pI6->%pI6", + &ih->saddr, &ih->daddr); else - sprintf(buf, "%s %pI6:%u->%pI6:%u", - pp->name, + sprintf(buf, "%pI6:%u->%pI6:%u", &ih->saddr, ntohs(pptr[0]), &ih->daddr, ntohs(pptr[1])); } - pr_debug("%s: %s\n", msg, buf); + pr_debug("%s: %s %s\n", msg, pp->name, buf); } #endif diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c index c30b43c36cd7..1892dfc12fdd 100644 --- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c +++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c @@ -136,12 +136,11 @@ ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb, ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); if (ih == NULL) - sprintf(buf, "%s TRUNCATED", pp->name); + sprintf(buf, "TRUNCATED"); else - sprintf(buf, "%s %pI4->%pI4", - pp->name, &ih->saddr, &ih->daddr); + sprintf(buf, "%pI4->%pI4", &ih->saddr, &ih->daddr); - pr_debug("%s: %s\n", msg, buf); + pr_debug("%s: %s %s\n", msg, pp->name, buf); } #ifdef CONFIG_IP_VS_IPV6 @@ -154,12 +153,11 @@ ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb, ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); if (ih == NULL) - sprintf(buf, "%s TRUNCATED", pp->name); + sprintf(buf, "TRUNCATED"); else - sprintf(buf, "%s %pI6->%pI6", - pp->name, &ih->saddr, &ih->daddr); + sprintf(buf, "%pI6->%pI6", &ih->saddr, &ih->daddr); - pr_debug("%s: %s\n", msg, buf); + pr_debug("%s: %s %s\n", msg, pp->name, buf); } #endif diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index 8fb0ae616761..7ba06939829f 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -802,7 +802,7 @@ static int sync_thread_backup(void *data) ip_vs_backup_mcast_ifn, ip_vs_backup_syncid); while (!kthread_should_stop()) { - wait_event_interruptible(*tinfo->sock->sk->sk_sleep, + wait_event_interruptible(*sk_sleep(tinfo->sock->sk), !skb_queue_empty(&tinfo->sock->sk->sk_receive_queue) || kthread_should_stop()); diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index e450cd6f4eb5..93c15a107b2c 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -270,7 +270,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET, skb, rt); + IP_VS_XMIT(NFPROTO_IPV4, skb, rt); LeaveFunction(10); return NF_STOLEN; @@ -334,7 +334,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET6, skb, rt); + IP_VS_XMIT(NFPROTO_IPV6, skb, rt); LeaveFunction(10); return NF_STOLEN; @@ -410,7 +410,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET, skb, rt); + IP_VS_XMIT(NFPROTO_IPV4, skb, rt); LeaveFunction(10); return NF_STOLEN; @@ -486,7 +486,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET6, skb, rt); + IP_VS_XMIT(NFPROTO_IPV6, skb, rt); LeaveFunction(10); return NF_STOLEN; @@ -785,7 +785,7 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET, skb, rt); + IP_VS_XMIT(NFPROTO_IPV4, skb, rt); LeaveFunction(10); return NF_STOLEN; @@ -838,7 +838,7 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET6, skb, rt); + IP_VS_XMIT(NFPROTO_IPV6, skb, rt); LeaveFunction(10); return NF_STOLEN; @@ -912,7 +912,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET, skb, rt); + IP_VS_XMIT(NFPROTO_IPV4, skb, rt); rc = NF_STOLEN; goto out; @@ -987,7 +987,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, /* Another hack: avoid icmp_send in ip_fragment */ skb->local_df = 1; - IP_VS_XMIT(PF_INET6, skb, rt); + IP_VS_XMIT(NFPROTO_IPV6, skb, rt); rc = NF_STOLEN; goto out; diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c index 372e80f07a81..13fd2c55e329 100644 --- a/net/netfilter/nf_conntrack_amanda.c +++ b/net/netfilter/nf_conntrack_amanda.c @@ -108,7 +108,7 @@ static int amanda_help(struct sk_buff *skb, dataoff = protoff + sizeof(struct udphdr); if (dataoff >= skb->len) { if (net_ratelimit()) - printk("amanda_help: skblen = %u\n", skb->len); + printk(KERN_ERR "amanda_help: skblen = %u\n", skb->len); return NF_ACCEPT; } diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 0c9bbe93cc16..b83c530c5e0a 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -319,8 +319,10 @@ begin: * not the expected one, we must restart lookup. * We probably met an item that was moved to another chain. */ - if (get_nulls_value(n) != hash) + if (get_nulls_value(n) != hash) { + NF_CT_STAT_INC(net, search_restart); goto begin; + } local_bh_enable(); return NULL; @@ -1333,7 +1335,7 @@ static int nf_conntrack_init_init_net(void) } nf_conntrack_max = max_factor * nf_conntrack_htable_size; - printk("nf_conntrack version %s (%u buckets, %d max)\n", + printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n", NF_CONNTRACK_VERSION, nf_conntrack_htable_size, nf_conntrack_max); diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index f516961a83b4..cdcc7649476b 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -85,7 +85,8 @@ int nf_conntrack_register_notifier(struct nf_ct_event_notifier *new) struct nf_ct_event_notifier *notify; mutex_lock(&nf_ct_ecache_mutex); - notify = rcu_dereference(nf_conntrack_event_cb); + notify = rcu_dereference_protected(nf_conntrack_event_cb, + lockdep_is_held(&nf_ct_ecache_mutex)); if (notify != NULL) { ret = -EBUSY; goto out_unlock; @@ -105,7 +106,8 @@ void nf_conntrack_unregister_notifier(struct nf_ct_event_notifier *new) struct nf_ct_event_notifier *notify; mutex_lock(&nf_ct_ecache_mutex); - notify = rcu_dereference(nf_conntrack_event_cb); + notify = rcu_dereference_protected(nf_conntrack_event_cb, + lockdep_is_held(&nf_ct_ecache_mutex)); BUG_ON(notify != new); rcu_assign_pointer(nf_conntrack_event_cb, NULL); mutex_unlock(&nf_ct_ecache_mutex); @@ -118,7 +120,8 @@ int nf_ct_expect_register_notifier(struct nf_exp_event_notifier *new) struct nf_exp_event_notifier *notify; mutex_lock(&nf_ct_ecache_mutex); - notify = rcu_dereference(nf_expect_event_cb); + notify = rcu_dereference_protected(nf_expect_event_cb, + lockdep_is_held(&nf_ct_ecache_mutex)); if (notify != NULL) { ret = -EBUSY; goto out_unlock; @@ -138,7 +141,8 @@ void nf_ct_expect_unregister_notifier(struct nf_exp_event_notifier *new) struct nf_exp_event_notifier *notify; mutex_lock(&nf_ct_ecache_mutex); - notify = rcu_dereference(nf_expect_event_cb); + notify = rcu_dereference_protected(nf_expect_event_cb, + lockdep_is_held(&nf_ct_ecache_mutex)); BUG_ON(notify != new); rcu_assign_pointer(nf_expect_event_cb, NULL); mutex_unlock(&nf_ct_ecache_mutex); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 2ae3169e7633..e17cb7c7dd8f 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -573,8 +573,8 @@ static int __init nf_conntrack_ftp_init(void) ftp[i][j].tuple.src.l3num, ports[i]); ret = nf_conntrack_helper_register(&ftp[i][j]); if (ret) { - printk("nf_ct_ftp: failed to register helper " - " for pf: %d port: %d\n", + printk(KERN_ERR "nf_ct_ftp: failed to register" + " helper for pf: %d port: %d\n", ftp[i][j].tuple.src.l3num, ports[i]); nf_conntrack_ftp_fini(); return ret; diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index a487c8038044..6eaee7c8a337 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -194,8 +194,7 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff, return 0; } - if (net_ratelimit()) - printk("nf_ct_h323: incomplete TPKT (fragmented?)\n"); + pr_debug("nf_ct_h323: incomplete TPKT (fragmented?)\n"); goto clear_out; } @@ -608,7 +607,7 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff, drop: spin_unlock_bh(&nf_h323_lock); if (net_ratelimit()) - printk("nf_ct_h245: packet dropped\n"); + pr_info("nf_ct_h245: packet dropped\n"); return NF_DROP; } @@ -1153,7 +1152,7 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff, drop: spin_unlock_bh(&nf_h323_lock); if (net_ratelimit()) - printk("nf_ct_q931: packet dropped\n"); + pr_info("nf_ct_q931: packet dropped\n"); return NF_DROP; } @@ -1728,7 +1727,7 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff, drop: spin_unlock_bh(&nf_h323_lock); if (net_ratelimit()) - printk("nf_ct_ras: packet dropped\n"); + pr_info("nf_ct_ras: packet dropped\n"); return NF_DROP; } diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index 7673930ca342..b394aa318776 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -235,7 +235,7 @@ static int __init nf_conntrack_irc_init(void) char *tmpname; if (max_dcc_channels < 1) { - printk("nf_ct_irc: max_dcc_channels must not be zero\n"); + printk(KERN_ERR "nf_ct_irc: max_dcc_channels must not be zero\n"); return -EINVAL; } @@ -267,7 +267,7 @@ static int __init nf_conntrack_irc_init(void) ret = nf_conntrack_helper_register(&irc[i]); if (ret) { - printk("nf_ct_irc: failed to register helper " + printk(KERN_ERR "nf_ct_irc: failed to register helper " "for pf: %u port: %u\n", irc[i].tuple.src.l3num, ports[i]); nf_conntrack_irc_fini(); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index afc52f2ee4ac..c42ff6aa441d 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -427,6 +427,17 @@ ctnetlink_proto_size(const struct nf_conn *ct) } static inline size_t +ctnetlink_counters_size(const struct nf_conn *ct) +{ + if (!nf_ct_ext_exist(ct, NF_CT_EXT_ACCT)) + return 0; + return 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ + + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */ + + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */ + ; +} + +static inline size_t ctnetlink_nlmsg_size(const struct nf_conn *ct) { return NLMSG_ALIGN(sizeof(struct nfgenmsg)) @@ -436,11 +447,7 @@ ctnetlink_nlmsg_size(const struct nf_conn *ct) + 3 * nla_total_size(sizeof(u_int8_t)) /* CTA_PROTO_NUM */ + nla_total_size(sizeof(u_int32_t)) /* CTA_ID */ + nla_total_size(sizeof(u_int32_t)) /* CTA_STATUS */ -#ifdef CONFIG_NF_CT_ACCT - + 2 * nla_total_size(0) /* CTA_COUNTERS_ORIG|REPL */ - + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_PACKETS */ - + 2 * nla_total_size(sizeof(uint64_t)) /* CTA_COUNTERS_BYTES */ -#endif + + ctnetlink_counters_size(ct) + nla_total_size(sizeof(u_int32_t)) /* CTA_TIMEOUT */ + nla_total_size(0) /* CTA_PROTOINFO */ + nla_total_size(0) /* CTA_HELP */ @@ -2050,29 +2057,29 @@ static int __init ctnetlink_init(void) { int ret; - printk("ctnetlink v%s: registering with nfnetlink.\n", version); + pr_info("ctnetlink v%s: registering with nfnetlink.\n", version); ret = nfnetlink_subsys_register(&ctnl_subsys); if (ret < 0) { - printk("ctnetlink_init: cannot register with nfnetlink.\n"); + pr_err("ctnetlink_init: cannot register with nfnetlink.\n"); goto err_out; } ret = nfnetlink_subsys_register(&ctnl_exp_subsys); if (ret < 0) { - printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); + pr_err("ctnetlink_init: cannot register exp with nfnetlink.\n"); goto err_unreg_subsys; } #ifdef CONFIG_NF_CONNTRACK_EVENTS ret = nf_conntrack_register_notifier(&ctnl_notifier); if (ret < 0) { - printk("ctnetlink_init: cannot register notifier.\n"); + pr_err("ctnetlink_init: cannot register notifier.\n"); goto err_unreg_exp_subsys; } ret = nf_ct_expect_register_notifier(&ctnl_notifier_exp); if (ret < 0) { - printk("ctnetlink_init: cannot expect register notifier.\n"); + pr_err("ctnetlink_init: cannot expect register notifier.\n"); goto err_unreg_notifier; } #endif @@ -2093,7 +2100,7 @@ err_out: static void __exit ctnetlink_exit(void) { - printk("ctnetlink: unregistering from nfnetlink.\n"); + pr_info("ctnetlink: unregistering from nfnetlink.\n"); #ifdef CONFIG_NF_CONNTRACK_EVENTS nf_ct_expect_unregister_notifier(&ctnl_notifier_exp); @@ -2102,7 +2109,6 @@ static void __exit ctnetlink_exit(void) nfnetlink_subsys_unregister(&ctnl_exp_subsys); nfnetlink_subsys_unregister(&ctnl_subsys); - return; } module_init(ctnetlink_init); diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index a44fa75b5178..5886ba1d52a0 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -14,12 +14,10 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/mutex.h> -#include <linux/skbuff.h> #include <linux/vmalloc.h> #include <linux/stddef.h> #include <linux/err.h> #include <linux/percpu.h> -#include <linux/moduleparam.h> #include <linux/notifier.h> #include <linux/kernel.h> #include <linux/netdevice.h> @@ -119,9 +117,13 @@ void nf_ct_l3proto_module_put(unsigned short l3proto) { struct nf_conntrack_l3proto *p; - /* rcu_read_lock not necessary since the caller holds a reference */ + /* rcu_read_lock not necessary since the caller holds a reference, but + * taken anyways to avoid lockdep warnings in __nf_ct_l3proto_find() + */ + rcu_read_lock(); p = __nf_ct_l3proto_find(l3proto); module_put(p->me); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index b68ff15ed979..c6049c2d5ea8 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -717,12 +717,12 @@ static int __init nf_conntrack_proto_sctp_init(void) ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp4); if (ret) { - printk("nf_conntrack_l4proto_sctp4: protocol register failed\n"); + pr_err("nf_conntrack_l4proto_sctp4: protocol register failed\n"); goto out; } ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp6); if (ret) { - printk("nf_conntrack_l4proto_sctp6: protocol register failed\n"); + pr_err("nf_conntrack_l4proto_sctp6: protocol register failed\n"); goto cleanup_sctp4; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index c6cd1b84eddd..b20f4275893c 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -1549,8 +1549,8 @@ static int __init nf_conntrack_sip_init(void) ret = nf_conntrack_helper_register(&sip[i][j]); if (ret) { - printk("nf_ct_sip: failed to register helper " - "for pf: %u port: %u\n", + printk(KERN_ERR "nf_ct_sip: failed to register" + " helper for pf: %u port: %u\n", sip[i][j].tuple.src.l3num, ports[i]); nf_conntrack_sip_fini(); return ret; diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index faa8eb3722b9..eb973fcd67ab 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -252,12 +252,12 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v) const struct ip_conntrack_stat *st = v; if (v == SEQ_START_TOKEN) { - seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n"); + seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete search_restart\n"); return 0; } seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " - "%08x %08x %08x %08x %08x %08x %08x %08x \n", + "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n", nr_conntracks, st->searched, st->found, @@ -274,7 +274,8 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v) st->expect_new, st->expect_create, - st->expect_delete + st->expect_delete, + st->search_restart ); return 0; } @@ -445,7 +446,7 @@ out_kmemdup: if (net_eq(net, &init_net)) unregister_sysctl_table(nf_ct_netfilter_header); out: - printk("nf_conntrack: can't register to sysctl.\n"); + printk(KERN_ERR "nf_conntrack: can't register to sysctl.\n"); return -ENOMEM; } diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c index 46e646b2e9b9..75466fd72f4f 100644 --- a/net/netfilter/nf_conntrack_tftp.c +++ b/net/netfilter/nf_conntrack_tftp.c @@ -138,8 +138,8 @@ static int __init nf_conntrack_tftp_init(void) ret = nf_conntrack_helper_register(&tftp[i][j]); if (ret) { - printk("nf_ct_tftp: failed to register helper " - "for pf: %u port: %u\n", + printk(KERN_ERR "nf_ct_tftp: failed to register" + " helper for pf: %u port: %u\n", tftp[i][j].tuple.src.l3num, ports[i]); nf_conntrack_tftp_fini(); return ret; diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h index bf6609978af7..770f76432ad0 100644 --- a/net/netfilter/nf_internals.h +++ b/net/netfilter/nf_internals.h @@ -6,7 +6,7 @@ #include <linux/netdevice.h> #ifdef CONFIG_NETFILTER_DEBUG -#define NFDEBUG(format, args...) printk(format , ## args) +#define NFDEBUG(format, args...) printk(KERN_DEBUG format , ## args) #else #define NFDEBUG(format, args...) #endif diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 015725a5cd50..7df37fd786bc 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -52,7 +52,8 @@ int nf_log_register(u_int8_t pf, struct nf_logger *logger) } else { /* register at end of list to honor first register win */ list_add_tail(&logger->list[pf], &nf_loggers_l[pf]); - llog = rcu_dereference(nf_loggers[pf]); + llog = rcu_dereference_protected(nf_loggers[pf], + lockdep_is_held(&nf_log_mutex)); if (llog == NULL) rcu_assign_pointer(nf_loggers[pf], logger); } @@ -70,7 +71,8 @@ void nf_log_unregister(struct nf_logger *logger) mutex_lock(&nf_log_mutex); for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) { - c_logger = rcu_dereference(nf_loggers[i]); + c_logger = rcu_dereference_protected(nf_loggers[i], + lockdep_is_held(&nf_log_mutex)); if (c_logger == logger) rcu_assign_pointer(nf_loggers[i], NULL); list_del(&logger->list[i]); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index c49ef219899e..78b3cf9c519c 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -9,6 +9,7 @@ #include <linux/rcupdate.h> #include <net/protocol.h> #include <net/netfilter/nf_queue.h> +#include <net/dst.h> #include "nf_internals.h" @@ -170,6 +171,7 @@ static int __nf_queue(struct sk_buff *skb, dev_hold(physoutdev); } #endif + skb_dst_force(skb); afinfo->saveroute(skb, entry); status = qh->outfn(entry, queuenum); @@ -279,7 +281,6 @@ void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict) } rcu_read_unlock(); kfree(entry); - return; } EXPORT_SYMBOL(nf_reinject); diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 6afa3d52ea5f..b4a4532823e8 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -18,12 +18,9 @@ #include <linux/types.h> #include <linux/socket.h> #include <linux/kernel.h> -#include <linux/major.h> -#include <linux/timer.h> #include <linux/string.h> #include <linux/sockios.h> #include <linux/net.h> -#include <linux/fcntl.h> #include <linux/skbuff.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -215,13 +212,13 @@ static struct pernet_operations nfnetlink_net_ops = { static int __init nfnetlink_init(void) { - printk("Netfilter messages via NETLINK v%s.\n", nfversion); + pr_info("Netfilter messages via NETLINK v%s.\n", nfversion); return register_pernet_subsys(&nfnetlink_net_ops); } static void __exit nfnetlink_exit(void) { - printk("Removing netfilter NETLINK layer.\n"); + pr_info("Removing netfilter NETLINK layer.\n"); unregister_pernet_subsys(&nfnetlink_net_ops); } module_init(nfnetlink_init); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 203643fb2c52..fc9a211e629e 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -297,7 +297,7 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size) n = max(inst_size, pkt_size); skb = alloc_skb(n, GFP_ATOMIC); if (!skb) { - PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n", + pr_notice("nfnetlink_log: can't alloc whole buffer (%u bytes)\n", inst_size); if (n > pkt_size) { @@ -306,7 +306,7 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size) skb = alloc_skb(pkt_size, GFP_ATOMIC); if (!skb) - PRINTR("nfnetlink_log: can't even alloc %u " + pr_err("nfnetlink_log: can't even alloc %u " "bytes\n", pkt_size); } } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index e70a6ef1f4f2..12e1ab37fcd8 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -246,8 +246,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, break; case NFQNL_COPY_PACKET: - if ((entskb->ip_summed == CHECKSUM_PARTIAL || - entskb->ip_summed == CHECKSUM_COMPLETE) && + if (entskb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(entskb)) { spin_unlock_bh(&queue->lock); return NULL; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 665f5beef6ad..445de702b8b7 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -12,7 +12,7 @@ * published by the Free Software Foundation. * */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/socket.h> #include <linux/net.h> @@ -55,12 +55,6 @@ struct xt_af { static struct xt_af *xt; -#ifdef DEBUG_IP_FIREWALL_USER -#define duprintf(format, args...) printk(format , ## args) -#else -#define duprintf(format, args...) -#endif - static const char *const xt_prefix[NFPROTO_NUMPROTO] = { [NFPROTO_UNSPEC] = "x", [NFPROTO_IPV4] = "ip", @@ -69,6 +63,9 @@ static const char *const xt_prefix[NFPROTO_NUMPROTO] = { [NFPROTO_IPV6] = "ip6", }; +/* Allow this many total (re)entries. */ +static const unsigned int xt_jumpstack_multiplier = 2; + /* Registration hooks for targets. */ int xt_register_target(struct xt_target *target) @@ -221,6 +218,17 @@ struct xt_match *xt_find_match(u8 af, const char *name, u8 revision) } EXPORT_SYMBOL(xt_find_match); +struct xt_match * +xt_request_find_match(uint8_t nfproto, const char *name, uint8_t revision) +{ + struct xt_match *match; + + match = try_then_request_module(xt_find_match(nfproto, name, revision), + "%st_%s", xt_prefix[nfproto], name); + return (match != NULL) ? match : ERR_PTR(-ENOENT); +} +EXPORT_SYMBOL_GPL(xt_request_find_match); + /* Find target, grabs ref. Returns ERR_PTR() on error. */ struct xt_target *xt_find_target(u8 af, const char *name, u8 revision) { @@ -257,9 +265,7 @@ struct xt_target *xt_request_find_target(u8 af, const char *name, u8 revision) target = try_then_request_module(xt_find_target(af, name, revision), "%st_%s", xt_prefix[af], name); - if (IS_ERR(target) || !target) - return NULL; - return target; + return (target != NULL) ? target : ERR_PTR(-ENOENT); } EXPORT_SYMBOL_GPL(xt_request_find_target); @@ -361,6 +367,8 @@ static char *textify_hooks(char *buf, size_t size, unsigned int mask) int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { + int ret; + if (XT_ALIGN(par->match->matchsize) != size && par->match->matchsize != -1) { /* @@ -397,8 +405,14 @@ int xt_check_match(struct xt_mtchk_param *par, par->match->proto); return -EINVAL; } - if (par->match->checkentry != NULL && !par->match->checkentry(par)) - return -EINVAL; + if (par->match->checkentry != NULL) { + ret = par->match->checkentry(par); + if (ret < 0) + return ret; + else if (ret > 0) + /* Flag up potential errors. */ + return -EIO; + } return 0; } EXPORT_SYMBOL_GPL(xt_check_match); @@ -518,6 +532,8 @@ EXPORT_SYMBOL_GPL(xt_compat_match_to_user); int xt_check_target(struct xt_tgchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { + int ret; + if (XT_ALIGN(par->target->targetsize) != size) { pr_err("%s_tables: %s.%u target: invalid size " "%u (kernel) != (user) %u\n", @@ -549,8 +565,14 @@ int xt_check_target(struct xt_tgchk_param *par, par->target->proto); return -EINVAL; } - if (par->target->checkentry != NULL && !par->target->checkentry(par)) - return -EINVAL; + if (par->target->checkentry != NULL) { + ret = par->target->checkentry(par); + if (ret < 0) + return ret; + else if (ret > 0) + /* Flag up potential errors. */ + return -EIO; + } return 0; } EXPORT_SYMBOL_GPL(xt_check_target); @@ -662,6 +684,26 @@ void xt_free_table_info(struct xt_table_info *info) else vfree(info->entries[cpu]); } + + if (info->jumpstack != NULL) { + if (sizeof(void *) * info->stacksize > PAGE_SIZE) { + for_each_possible_cpu(cpu) + vfree(info->jumpstack[cpu]); + } else { + for_each_possible_cpu(cpu) + kfree(info->jumpstack[cpu]); + } + } + + if (sizeof(void **) * nr_cpu_ids > PAGE_SIZE) + vfree(info->jumpstack); + else + kfree(info->jumpstack); + if (sizeof(unsigned int) * nr_cpu_ids > PAGE_SIZE) + vfree(info->stackptr); + else + kfree(info->stackptr); + kfree(info); } EXPORT_SYMBOL(xt_free_table_info); @@ -706,6 +748,49 @@ EXPORT_SYMBOL_GPL(xt_compat_unlock); DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks); EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks); +static int xt_jumpstack_alloc(struct xt_table_info *i) +{ + unsigned int size; + int cpu; + + size = sizeof(unsigned int) * nr_cpu_ids; + if (size > PAGE_SIZE) + i->stackptr = vmalloc(size); + else + i->stackptr = kmalloc(size, GFP_KERNEL); + if (i->stackptr == NULL) + return -ENOMEM; + memset(i->stackptr, 0, size); + + size = sizeof(void **) * nr_cpu_ids; + if (size > PAGE_SIZE) + i->jumpstack = vmalloc(size); + else + i->jumpstack = kmalloc(size, GFP_KERNEL); + if (i->jumpstack == NULL) + return -ENOMEM; + memset(i->jumpstack, 0, size); + + i->stacksize *= xt_jumpstack_multiplier; + size = sizeof(void *) * i->stacksize; + for_each_possible_cpu(cpu) { + if (size > PAGE_SIZE) + i->jumpstack[cpu] = vmalloc_node(size, + cpu_to_node(cpu)); + else + i->jumpstack[cpu] = kmalloc_node(size, + GFP_KERNEL, cpu_to_node(cpu)); + if (i->jumpstack[cpu] == NULL) + /* + * Freeing will be done later on by the callers. The + * chain is: xt_replace_table -> __do_replace -> + * do_replace -> xt_free_table_info. + */ + return -ENOMEM; + } + + return 0; +} struct xt_table_info * xt_replace_table(struct xt_table *table, @@ -714,6 +799,13 @@ xt_replace_table(struct xt_table *table, int *error) { struct xt_table_info *private; + int ret; + + ret = xt_jumpstack_alloc(newinfo); + if (ret < 0) { + *error = ret; + return NULL; + } /* Do the substitution. */ local_bh_disable(); @@ -721,7 +813,7 @@ xt_replace_table(struct xt_table *table, /* Check inside lock: is the old number correct? */ if (num_counters != private->number) { - duprintf("num_counters != table->private->number (%u/%u)\n", + pr_debug("num_counters != table->private->number (%u/%u)\n", num_counters, private->number); local_bh_enable(); *error = -EAGAIN; @@ -752,6 +844,10 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table_info *private; struct xt_table *t, *table; + ret = xt_jumpstack_alloc(newinfo); + if (ret < 0) + return ERR_PTR(ret); + /* Don't add one object to multiple lists. */ table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL); if (!table) { @@ -778,7 +874,7 @@ struct xt_table *xt_register_table(struct net *net, goto unlock; private = table->private; - duprintf("table->private->number = %u\n", private->number); + pr_debug("table->private->number = %u\n", private->number); /* save number of initial entries */ private->initial_entries = private->number; diff --git a/net/netfilter/xt_CLASSIFY.c b/net/netfilter/xt_CLASSIFY.c index 011bc80dd2a1..c2c0e4abeb99 100644 --- a/net/netfilter/xt_CLASSIFY.c +++ b/net/netfilter/xt_CLASSIFY.c @@ -27,7 +27,7 @@ MODULE_ALIAS("ipt_CLASSIFY"); MODULE_ALIAS("ip6t_CLASSIFY"); static unsigned int -classify_tg(struct sk_buff *skb, const struct xt_target_param *par) +classify_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_classify_target_info *clinfo = par->targinfo; diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c deleted file mode 100644 index 593457068ae1..000000000000 --- a/net/netfilter/xt_CONNMARK.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * xt_CONNMARK - Netfilter module to modify the connection mark values - * - * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> - * by Henrik Nordstrom <hno@marasystems.com> - * Copyright © CC Computer Consultants GmbH, 2007 - 2008 - * Jan Engelhardt <jengelh@computergmbh.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/ip.h> -#include <net/checksum.h> - -MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>"); -MODULE_DESCRIPTION("Xtables: connection mark modification"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("ipt_CONNMARK"); -MODULE_ALIAS("ip6t_CONNMARK"); - -#include <linux/netfilter/x_tables.h> -#include <linux/netfilter/xt_CONNMARK.h> -#include <net/netfilter/nf_conntrack_ecache.h> - -static unsigned int -connmark_tg(struct sk_buff *skb, const struct xt_target_param *par) -{ - const struct xt_connmark_tginfo1 *info = par->targinfo; - enum ip_conntrack_info ctinfo; - struct nf_conn *ct; - u_int32_t newmark; - - ct = nf_ct_get(skb, &ctinfo); - if (ct == NULL) - return XT_CONTINUE; - - switch (info->mode) { - case XT_CONNMARK_SET: - newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; - if (ct->mark != newmark) { - ct->mark = newmark; - nf_conntrack_event_cache(IPCT_MARK, ct); - } - break; - case XT_CONNMARK_SAVE: - newmark = (ct->mark & ~info->ctmask) ^ - (skb->mark & info->nfmask); - if (ct->mark != newmark) { - ct->mark = newmark; - nf_conntrack_event_cache(IPCT_MARK, ct); - } - break; - case XT_CONNMARK_RESTORE: - newmark = (skb->mark & ~info->nfmask) ^ - (ct->mark & info->ctmask); - skb->mark = newmark; - break; - } - - return XT_CONTINUE; -} - -static bool connmark_tg_check(const struct xt_tgchk_param *par) -{ - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "cannot load conntrack support for " - "proto=%u\n", par->family); - return false; - } - return true; -} - -static void connmark_tg_destroy(const struct xt_tgdtor_param *par) -{ - nf_ct_l3proto_module_put(par->family); -} - -static struct xt_target connmark_tg_reg __read_mostly = { - .name = "CONNMARK", - .revision = 1, - .family = NFPROTO_UNSPEC, - .checkentry = connmark_tg_check, - .target = connmark_tg, - .targetsize = sizeof(struct xt_connmark_tginfo1), - .destroy = connmark_tg_destroy, - .me = THIS_MODULE, -}; - -static int __init connmark_tg_init(void) -{ - return xt_register_target(&connmark_tg_reg); -} - -static void __exit connmark_tg_exit(void) -{ - xt_unregister_target(&connmark_tg_reg); -} - -module_init(connmark_tg_init); -module_exit(connmark_tg_exit); diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c index b54c3756fdc3..e04dc282e3bb 100644 --- a/net/netfilter/xt_CONNSECMARK.c +++ b/net/netfilter/xt_CONNSECMARK.c @@ -15,6 +15,7 @@ * published by the Free Software Foundation. * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter/x_tables.h> @@ -22,8 +23,6 @@ #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_ecache.h> -#define PFX "CONNSECMARK: " - MODULE_LICENSE("GPL"); MODULE_AUTHOR("James Morris <jmorris@redhat.com>"); MODULE_DESCRIPTION("Xtables: target for copying between connection and security mark"); @@ -65,7 +64,7 @@ static void secmark_restore(struct sk_buff *skb) } static unsigned int -connsecmark_tg(struct sk_buff *skb, const struct xt_target_param *par) +connsecmark_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_connsecmark_target_info *info = par->targinfo; @@ -85,15 +84,16 @@ connsecmark_tg(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool connsecmark_tg_check(const struct xt_tgchk_param *par) +static int connsecmark_tg_check(const struct xt_tgchk_param *par) { const struct xt_connsecmark_target_info *info = par->targinfo; + int ret; if (strcmp(par->table, "mangle") != 0 && strcmp(par->table, "security") != 0) { - printk(KERN_INFO PFX "target only valid in the \'mangle\' " - "or \'security\' tables, not \'%s\'.\n", par->table); - return false; + pr_info("target only valid in the \'mangle\' " + "or \'security\' tables, not \'%s\'.\n", par->table); + return -EINVAL; } switch (info->mode) { @@ -102,16 +102,15 @@ static bool connsecmark_tg_check(const struct xt_tgchk_param *par) break; default: - printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode); - return false; + pr_info("invalid mode: %hu\n", info->mode); + return -EINVAL; } - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "can't load conntrack support for " - "proto=%u\n", par->family); - return false; - } - return true; + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) + pr_info("cannot load conntrack support for proto=%u\n", + par->family); + return ret; } static void connsecmark_tg_destroy(const struct xt_tgdtor_param *par) diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index ee18b231b950..562bf3266e04 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -20,7 +20,7 @@ #include <net/netfilter/nf_conntrack_zones.h> static unsigned int xt_ct_target(struct sk_buff *skb, - const struct xt_target_param *par) + const struct xt_action_param *par) { const struct xt_ct_target_info *info = par->targinfo; struct nf_conn *ct = info->ct; @@ -38,13 +38,13 @@ static unsigned int xt_ct_target(struct sk_buff *skb, static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) { - if (par->family == AF_INET) { + if (par->family == NFPROTO_IPV4) { const struct ipt_entry *e = par->entryinfo; if (e->ip.invflags & IPT_INV_PROTO) return 0; return e->ip.proto; - } else if (par->family == AF_INET6) { + } else if (par->family == NFPROTO_IPV6) { const struct ip6t_entry *e = par->entryinfo; if (e->ipv6.invflags & IP6T_INV_PROTO) @@ -54,16 +54,17 @@ static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) return 0; } -static bool xt_ct_tg_check(const struct xt_tgchk_param *par) +static int xt_ct_tg_check(const struct xt_tgchk_param *par) { struct xt_ct_target_info *info = par->targinfo; struct nf_conntrack_tuple t; struct nf_conn_help *help; struct nf_conn *ct; + int ret = 0; u8 proto; if (info->flags & ~XT_CT_NOTRACK) - return false; + return -EINVAL; if (info->flags & XT_CT_NOTRACK) { ct = &nf_conntrack_untracked; @@ -76,28 +77,34 @@ static bool xt_ct_tg_check(const struct xt_tgchk_param *par) goto err1; #endif - if (nf_ct_l3proto_try_module_get(par->family) < 0) + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) goto err1; memset(&t, 0, sizeof(t)); ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); + ret = PTR_ERR(ct); if (IS_ERR(ct)) goto err2; + ret = 0; if ((info->ct_events || info->exp_events) && !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, GFP_KERNEL)) goto err3; if (info->helper[0]) { + ret = -ENOENT; proto = xt_ct_find_proto(par); if (!proto) goto err3; + ret = -ENOMEM; help = nf_ct_helper_ext_add(ct, GFP_KERNEL); if (help == NULL) goto err3; + ret = -ENOENT; help->helper = nf_conntrack_helper_try_module_get(info->helper, par->family, proto); @@ -109,14 +116,14 @@ static bool xt_ct_tg_check(const struct xt_tgchk_param *par) __set_bit(IPS_CONFIRMED_BIT, &ct->status); out: info->ct = ct; - return true; + return 0; err3: nf_conntrack_free(ct); err2: nf_ct_l3proto_module_put(par->family); err1: - return false; + return ret; } static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) @@ -138,7 +145,7 @@ static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) static struct xt_target xt_ct_tg __read_mostly = { .name = "CT", .family = NFPROTO_UNSPEC, - .targetsize = XT_ALIGN(sizeof(struct xt_ct_target_info)), + .targetsize = sizeof(struct xt_ct_target_info), .checkentry = xt_ct_tg_check, .destroy = xt_ct_tg_destroy, .target = xt_ct_target, diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c index 74ce89260056..0a229191e55b 100644 --- a/net/netfilter/xt_DSCP.c +++ b/net/netfilter/xt_DSCP.c @@ -9,7 +9,7 @@ * * See RFC2474 for a description of the DSCP field within the IP Header. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> @@ -28,7 +28,7 @@ MODULE_ALIAS("ipt_TOS"); MODULE_ALIAS("ip6t_TOS"); static unsigned int -dscp_tg(struct sk_buff *skb, const struct xt_target_param *par) +dscp_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_DSCP_info *dinfo = par->targinfo; u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; @@ -45,7 +45,7 @@ dscp_tg(struct sk_buff *skb, const struct xt_target_param *par) } static unsigned int -dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par) +dscp_tg6(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_DSCP_info *dinfo = par->targinfo; u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; @@ -60,19 +60,19 @@ dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool dscp_tg_check(const struct xt_tgchk_param *par) +static int dscp_tg_check(const struct xt_tgchk_param *par) { const struct xt_DSCP_info *info = par->targinfo; if (info->dscp > XT_DSCP_MAX) { - printk(KERN_WARNING "DSCP: dscp %x out of range\n", info->dscp); - return false; + pr_info("dscp %x out of range\n", info->dscp); + return -EDOM; } - return true; + return 0; } static unsigned int -tos_tg(struct sk_buff *skb, const struct xt_target_param *par) +tos_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_tos_target_info *info = par->targinfo; struct iphdr *iph = ip_hdr(skb); @@ -92,7 +92,7 @@ tos_tg(struct sk_buff *skb, const struct xt_target_param *par) } static unsigned int -tos_tg6(struct sk_buff *skb, const struct xt_target_param *par) +tos_tg6(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_tos_target_info *info = par->targinfo; struct ipv6hdr *iph = ipv6_hdr(skb); diff --git a/net/netfilter/xt_HL.c b/net/netfilter/xt_HL.c index 10e789e2d12a..95b084800fcc 100644 --- a/net/netfilter/xt_HL.c +++ b/net/netfilter/xt_HL.c @@ -9,7 +9,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> @@ -26,7 +26,7 @@ MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target"); MODULE_LICENSE("GPL"); static unsigned int -ttl_tg(struct sk_buff *skb, const struct xt_target_param *par) +ttl_tg(struct sk_buff *skb, const struct xt_action_param *par) { struct iphdr *iph; const struct ipt_TTL_info *info = par->targinfo; @@ -66,7 +66,7 @@ ttl_tg(struct sk_buff *skb, const struct xt_target_param *par) } static unsigned int -hl_tg6(struct sk_buff *skb, const struct xt_target_param *par) +hl_tg6(struct sk_buff *skb, const struct xt_action_param *par) { struct ipv6hdr *ip6h; const struct ip6t_HL_info *info = par->targinfo; @@ -101,35 +101,33 @@ hl_tg6(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool ttl_tg_check(const struct xt_tgchk_param *par) +static int ttl_tg_check(const struct xt_tgchk_param *par) { const struct ipt_TTL_info *info = par->targinfo; if (info->mode > IPT_TTL_MAXMODE) { - printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", - info->mode); - return false; + pr_info("TTL: invalid or unknown mode %u\n", info->mode); + return -EINVAL; } if (info->mode != IPT_TTL_SET && info->ttl == 0) - return false; - return true; + return -EINVAL; + return 0; } -static bool hl_tg6_check(const struct xt_tgchk_param *par) +static int hl_tg6_check(const struct xt_tgchk_param *par) { const struct ip6t_HL_info *info = par->targinfo; if (info->mode > IP6T_HL_MAXMODE) { - printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", - info->mode); - return false; + pr_info("invalid or unknown mode %u\n", info->mode); + return -EINVAL; } if (info->mode != IP6T_HL_SET && info->hop_limit == 0) { - printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " + pr_info("increment/decrement does not " "make sense with value 0\n"); - return false; + return -EINVAL; } - return true; + return 0; } static struct xt_target hl_tg_reg[] __read_mostly = { diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c index 3271c8e52153..a4140509eea1 100644 --- a/net/netfilter/xt_LED.c +++ b/net/netfilter/xt_LED.c @@ -18,7 +18,7 @@ * 02110-1301 USA. * */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter/x_tables.h> @@ -32,18 +32,24 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>"); MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match"); +static LIST_HEAD(xt_led_triggers); +static DEFINE_MUTEX(xt_led_mutex); + /* * This is declared in here (the kernel module) only, to avoid having these * dependencies in userspace code. This is what xt_led_info.internal_data * points to. */ struct xt_led_info_internal { + struct list_head list; + int refcnt; + char *trigger_id; struct led_trigger netfilter_led_trigger; struct timer_list timer; }; static unsigned int -led_tg(struct sk_buff *skb, const struct xt_target_param *par) +led_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_led_info *ledinfo = par->targinfo; struct xt_led_info_internal *ledinternal = ledinfo->internal_data; @@ -54,7 +60,7 @@ led_tg(struct sk_buff *skb, const struct xt_target_param *par) */ if ((ledinfo->delay > 0) && ledinfo->always_blink && timer_pending(&ledinternal->timer)) - led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF); + led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); @@ -75,54 +81,86 @@ led_tg(struct sk_buff *skb, const struct xt_target_param *par) static void led_timeout_callback(unsigned long data) { - struct xt_led_info *ledinfo = (struct xt_led_info *)data; - struct xt_led_info_internal *ledinternal = ledinfo->internal_data; + struct xt_led_info_internal *ledinternal = (struct xt_led_info_internal *)data; led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); } -static bool led_tg_check(const struct xt_tgchk_param *par) +static struct xt_led_info_internal *led_trigger_lookup(const char *name) +{ + struct xt_led_info_internal *ledinternal; + + list_for_each_entry(ledinternal, &xt_led_triggers, list) { + if (!strcmp(name, ledinternal->netfilter_led_trigger.name)) { + return ledinternal; + } + } + return NULL; +} + +static int led_tg_check(const struct xt_tgchk_param *par) { struct xt_led_info *ledinfo = par->targinfo; struct xt_led_info_internal *ledinternal; int err; if (ledinfo->id[0] == '\0') { - printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n"); - return false; + pr_info("No 'id' parameter given.\n"); + return -EINVAL; } - ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL); - if (!ledinternal) { - printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n"); - return false; + mutex_lock(&xt_led_mutex); + + ledinternal = led_trigger_lookup(ledinfo->id); + if (ledinternal) { + ledinternal->refcnt++; + goto out; } - ledinternal->netfilter_led_trigger.name = ledinfo->id; + err = -ENOMEM; + ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL); + if (!ledinternal) + goto exit_mutex_only; + + ledinternal->trigger_id = kstrdup(ledinfo->id, GFP_KERNEL); + if (!ledinternal->trigger_id) + goto exit_internal_alloc; + + ledinternal->refcnt = 1; + ledinternal->netfilter_led_trigger.name = ledinternal->trigger_id; err = led_trigger_register(&ledinternal->netfilter_led_trigger); if (err) { - printk(KERN_CRIT KBUILD_MODNAME - ": led_trigger_register() failed\n"); + pr_warning("led_trigger_register() failed\n"); if (err == -EEXIST) - printk(KERN_ERR KBUILD_MODNAME - ": Trigger name is already in use.\n"); + pr_warning("Trigger name is already in use.\n"); goto exit_alloc; } /* See if we need to set up a timer */ if (ledinfo->delay > 0) setup_timer(&ledinternal->timer, led_timeout_callback, - (unsigned long)ledinfo); + (unsigned long)ledinternal); + + list_add_tail(&ledinternal->list, &xt_led_triggers); + +out: + mutex_unlock(&xt_led_mutex); ledinfo->internal_data = ledinternal; - return true; + return 0; exit_alloc: + kfree(ledinternal->trigger_id); + +exit_internal_alloc: kfree(ledinternal); - return false; +exit_mutex_only: + mutex_unlock(&xt_led_mutex); + + return err; } static void led_tg_destroy(const struct xt_tgdtor_param *par) @@ -130,10 +168,23 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par) const struct xt_led_info *ledinfo = par->targinfo; struct xt_led_info_internal *ledinternal = ledinfo->internal_data; + mutex_lock(&xt_led_mutex); + + if (--ledinternal->refcnt) { + mutex_unlock(&xt_led_mutex); + return; + } + + list_del(&ledinternal->list); + if (ledinfo->delay > 0) del_timer_sync(&ledinternal->timer); led_trigger_unregister(&ledinternal->netfilter_led_trigger); + + mutex_unlock(&xt_led_mutex); + + kfree(ledinternal->trigger_id); kfree(ledinternal); } @@ -142,7 +193,7 @@ static struct xt_target led_tg_reg __read_mostly = { .revision = 0, .family = NFPROTO_UNSPEC, .target = led_tg, - .targetsize = XT_ALIGN(sizeof(struct xt_led_info)), + .targetsize = sizeof(struct xt_led_info), .checkentry = led_tg_check, .destroy = led_tg_destroy, .me = THIS_MODULE, diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c deleted file mode 100644 index 225f8d11e173..000000000000 --- a/net/netfilter/xt_MARK.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * xt_MARK - Netfilter module to modify the NFMARK field of an skb - * - * (C) 1999-2001 Marc Boucher <marc@mbsi.ca> - * Copyright © CC Computer Consultants GmbH, 2007 - 2008 - * Jan Engelhardt <jengelh@computergmbh.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/skbuff.h> -#include <linux/ip.h> -#include <net/checksum.h> - -#include <linux/netfilter/x_tables.h> -#include <linux/netfilter/xt_MARK.h> - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); -MODULE_DESCRIPTION("Xtables: packet mark modification"); -MODULE_ALIAS("ipt_MARK"); -MODULE_ALIAS("ip6t_MARK"); - -static unsigned int -mark_tg(struct sk_buff *skb, const struct xt_target_param *par) -{ - const struct xt_mark_tginfo2 *info = par->targinfo; - - skb->mark = (skb->mark & ~info->mask) ^ info->mark; - return XT_CONTINUE; -} - -static struct xt_target mark_tg_reg __read_mostly = { - .name = "MARK", - .revision = 2, - .family = NFPROTO_UNSPEC, - .target = mark_tg, - .targetsize = sizeof(struct xt_mark_tginfo2), - .me = THIS_MODULE, -}; - -static int __init mark_tg_init(void) -{ - return xt_register_target(&mark_tg_reg); -} - -static void __exit mark_tg_exit(void) -{ - xt_unregister_target(&mark_tg_reg); -} - -module_init(mark_tg_init); -module_exit(mark_tg_exit); diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c index a57c5cf018ec..a17dd0f589b2 100644 --- a/net/netfilter/xt_NFLOG.c +++ b/net/netfilter/xt_NFLOG.c @@ -22,7 +22,7 @@ MODULE_ALIAS("ipt_NFLOG"); MODULE_ALIAS("ip6t_NFLOG"); static unsigned int -nflog_tg(struct sk_buff *skb, const struct xt_target_param *par) +nflog_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_nflog_info *info = par->targinfo; struct nf_loginfo li; @@ -37,15 +37,15 @@ nflog_tg(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool nflog_tg_check(const struct xt_tgchk_param *par) +static int nflog_tg_check(const struct xt_tgchk_param *par) { const struct xt_nflog_info *info = par->targinfo; if (info->flags & ~XT_NFLOG_MASK) - return false; + return -EINVAL; if (info->prefix[sizeof(info->prefix) - 1] != '\0') - return false; - return true; + return -EINVAL; + return 0; } static struct xt_target nflog_tg_reg __read_mostly = { diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c index 12dcd7007c3e..039cce1bde3d 100644 --- a/net/netfilter/xt_NFQUEUE.c +++ b/net/netfilter/xt_NFQUEUE.c @@ -31,7 +31,7 @@ static u32 jhash_initval __read_mostly; static bool rnd_inited __read_mostly; static unsigned int -nfqueue_tg(struct sk_buff *skb, const struct xt_target_param *par) +nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_NFQ_info *tinfo = par->targinfo; @@ -49,17 +49,6 @@ static u32 hash_v4(const struct sk_buff *skb) return jhash_2words((__force u32)ipaddr, iph->protocol, jhash_initval); } -static unsigned int -nfqueue_tg4_v1(struct sk_buff *skb, const struct xt_target_param *par) -{ - const struct xt_NFQ_info_v1 *info = par->targinfo; - u32 queue = info->queuenum; - - if (info->queues_total > 1) - queue = hash_v4(skb) % info->queues_total + queue; - return NF_QUEUE_NR(queue); -} - #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) static u32 hash_v6(const struct sk_buff *skb) { @@ -73,20 +62,26 @@ static u32 hash_v6(const struct sk_buff *skb) return jhash2((__force u32 *)addr, ARRAY_SIZE(addr), jhash_initval); } +#endif static unsigned int -nfqueue_tg6_v1(struct sk_buff *skb, const struct xt_target_param *par) +nfqueue_tg_v1(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_NFQ_info_v1 *info = par->targinfo; u32 queue = info->queuenum; - if (info->queues_total > 1) - queue = hash_v6(skb) % info->queues_total + queue; + if (info->queues_total > 1) { + if (par->family == NFPROTO_IPV4) + queue = hash_v4(skb) % info->queues_total + queue; +#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) + else if (par->family == NFPROTO_IPV6) + queue = hash_v6(skb) % info->queues_total + queue; +#endif + } return NF_QUEUE_NR(queue); } -#endif -static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par) +static int nfqueue_tg_v1_check(const struct xt_tgchk_param *par) { const struct xt_NFQ_info_v1 *info = par->targinfo; u32 maxid; @@ -97,15 +92,15 @@ static bool nfqueue_tg_v1_check(const struct xt_tgchk_param *par) } if (info->queues_total == 0) { pr_err("NFQUEUE: number of total queues is 0\n"); - return false; + return -EINVAL; } maxid = info->queues_total - 1 + info->queuenum; if (maxid > 0xffff) { pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n", info->queues_total, maxid); - return false; + return -ERANGE; } - return true; + return 0; } static struct xt_target nfqueue_tg_reg[] __read_mostly = { @@ -119,23 +114,12 @@ static struct xt_target nfqueue_tg_reg[] __read_mostly = { { .name = "NFQUEUE", .revision = 1, - .family = NFPROTO_IPV4, - .checkentry = nfqueue_tg_v1_check, - .target = nfqueue_tg4_v1, - .targetsize = sizeof(struct xt_NFQ_info_v1), - .me = THIS_MODULE, - }, -#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) - { - .name = "NFQUEUE", - .revision = 1, - .family = NFPROTO_IPV6, + .family = NFPROTO_UNSPEC, .checkentry = nfqueue_tg_v1_check, - .target = nfqueue_tg6_v1, + .target = nfqueue_tg_v1, .targetsize = sizeof(struct xt_NFQ_info_v1), .me = THIS_MODULE, }, -#endif }; static int __init nfqueue_tg_init(void) diff --git a/net/netfilter/xt_NOTRACK.c b/net/netfilter/xt_NOTRACK.c index e7a0a54fd4ea..512b9123252f 100644 --- a/net/netfilter/xt_NOTRACK.c +++ b/net/netfilter/xt_NOTRACK.c @@ -13,7 +13,7 @@ MODULE_ALIAS("ipt_NOTRACK"); MODULE_ALIAS("ip6t_NOTRACK"); static unsigned int -notrack_tg(struct sk_buff *skb, const struct xt_target_param *par) +notrack_tg(struct sk_buff *skb, const struct xt_action_param *par) { /* Previously seen (loopback)? Ignore. */ if (skb->nfct != NULL) diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c index d16d55df4f61..69c01e10f8af 100644 --- a/net/netfilter/xt_RATEEST.c +++ b/net/netfilter/xt_RATEEST.c @@ -73,7 +73,7 @@ void xt_rateest_put(struct xt_rateest *est) EXPORT_SYMBOL_GPL(xt_rateest_put); static unsigned int -xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par) +xt_rateest_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_rateest_target_info *info = par->targinfo; struct gnet_stats_basic_packed *stats = &info->est->bstats; @@ -86,7 +86,7 @@ xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) +static int xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) { struct xt_rateest_target_info *info = par->targinfo; struct xt_rateest *est; @@ -94,6 +94,7 @@ static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) struct nlattr opt; struct gnet_estimator est; } cfg; + int ret; if (unlikely(!rnd_inited)) { get_random_bytes(&jhash_rnd, sizeof(jhash_rnd)); @@ -110,12 +111,13 @@ static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) (info->interval != est->params.interval || info->ewma_log != est->params.ewma_log)) { xt_rateest_put(est); - return false; + return -EINVAL; } info->est = est; - return true; + return 0; } + ret = -ENOMEM; est = kzalloc(sizeof(*est), GFP_KERNEL); if (!est) goto err1; @@ -131,19 +133,19 @@ static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par) cfg.est.interval = info->interval; cfg.est.ewma_log = info->ewma_log; - if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock, - &cfg.opt) < 0) + ret = gen_new_estimator(&est->bstats, &est->rstats, + &est->lock, &cfg.opt); + if (ret < 0) goto err2; info->est = est; xt_rateest_hash_insert(est); - - return true; + return 0; err2: kfree(est); err1: - return false; + return ret; } static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par) diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c index 7a6f9e6f5dfa..23b2d6c486b5 100644 --- a/net/netfilter/xt_SECMARK.c +++ b/net/netfilter/xt_SECMARK.c @@ -12,6 +12,7 @@ * published by the Free Software Foundation. * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/selinux.h> @@ -29,7 +30,7 @@ MODULE_ALIAS("ip6t_SECMARK"); static u8 mode; static unsigned int -secmark_tg(struct sk_buff *skb, const struct xt_target_param *par) +secmark_tg(struct sk_buff *skb, const struct xt_action_param *par) { u32 secmark = 0; const struct xt_secmark_target_info *info = par->targinfo; @@ -49,7 +50,7 @@ secmark_tg(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool checkentry_selinux(struct xt_secmark_target_info *info) +static int checkentry_selinux(struct xt_secmark_target_info *info) { int err; struct xt_secmark_target_selinux_info *sel = &info->u.sel; @@ -59,58 +60,59 @@ static bool checkentry_selinux(struct xt_secmark_target_info *info) err = selinux_string_to_sid(sel->selctx, &sel->selsid); if (err) { if (err == -EINVAL) - printk(KERN_INFO PFX "invalid SELinux context \'%s\'\n", - sel->selctx); - return false; + pr_info("invalid SELinux context \'%s\'\n", + sel->selctx); + return err; } if (!sel->selsid) { - printk(KERN_INFO PFX "unable to map SELinux context \'%s\'\n", - sel->selctx); - return false; + pr_info("unable to map SELinux context \'%s\'\n", sel->selctx); + return -ENOENT; } err = selinux_secmark_relabel_packet_permission(sel->selsid); if (err) { - printk(KERN_INFO PFX "unable to obtain relabeling permission\n"); - return false; + pr_info("unable to obtain relabeling permission\n"); + return err; } selinux_secmark_refcount_inc(); - return true; + return 0; } -static bool secmark_tg_check(const struct xt_tgchk_param *par) +static int secmark_tg_check(const struct xt_tgchk_param *par) { struct xt_secmark_target_info *info = par->targinfo; + int err; if (strcmp(par->table, "mangle") != 0 && strcmp(par->table, "security") != 0) { - printk(KERN_INFO PFX "target only valid in the \'mangle\' " - "or \'security\' tables, not \'%s\'.\n", par->table); - return false; + pr_info("target only valid in the \'mangle\' " + "or \'security\' tables, not \'%s\'.\n", par->table); + return -EINVAL; } if (mode && mode != info->mode) { - printk(KERN_INFO PFX "mode already set to %hu cannot mix with " - "rules for mode %hu\n", mode, info->mode); - return false; + pr_info("mode already set to %hu cannot mix with " + "rules for mode %hu\n", mode, info->mode); + return -EINVAL; } switch (info->mode) { case SECMARK_MODE_SEL: - if (!checkentry_selinux(info)) - return false; + err = checkentry_selinux(info); + if (err <= 0) + return err; break; default: - printk(KERN_INFO PFX "invalid mode: %hu\n", info->mode); - return false; + pr_info("invalid mode: %hu\n", info->mode); + return -EINVAL; } if (!mode) mode = info->mode; - return true; + return 0; } static void secmark_tg_destroy(const struct xt_tgdtor_param *par) diff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c index c5f4b9919e9a..62ec021fbd50 100644 --- a/net/netfilter/xt_TCPMSS.c +++ b/net/netfilter/xt_TCPMSS.c @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> @@ -68,15 +68,14 @@ tcpmss_mangle_packet(struct sk_buff *skb, if (info->mss == XT_TCPMSS_CLAMP_PMTU) { if (dst_mtu(skb_dst(skb)) <= minlen) { if (net_ratelimit()) - printk(KERN_ERR "xt_TCPMSS: " - "unknown or invalid path-MTU (%u)\n", + pr_err("unknown or invalid path-MTU (%u)\n", dst_mtu(skb_dst(skb))); return -1; } if (in_mtu <= minlen) { if (net_ratelimit()) - printk(KERN_ERR "xt_TCPMSS: unknown or " - "invalid path-MTU (%u)\n", in_mtu); + pr_err("unknown or invalid path-MTU (%u)\n", + in_mtu); return -1; } newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen; @@ -173,7 +172,7 @@ static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb, } static unsigned int -tcpmss_tg4(struct sk_buff *skb, const struct xt_target_param *par) +tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par) { struct iphdr *iph = ip_hdr(skb); __be16 newlen; @@ -196,7 +195,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_target_param *par) #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) static unsigned int -tcpmss_tg6(struct sk_buff *skb, const struct xt_target_param *par) +tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par) { struct ipv6hdr *ipv6h = ipv6_hdr(skb); u8 nexthdr; @@ -236,7 +235,7 @@ static inline bool find_syn_match(const struct xt_entry_match *m) return false; } -static bool tcpmss_tg4_check(const struct xt_tgchk_param *par) +static int tcpmss_tg4_check(const struct xt_tgchk_param *par) { const struct xt_tcpmss_info *info = par->targinfo; const struct ipt_entry *e = par->entryinfo; @@ -246,19 +245,19 @@ static bool tcpmss_tg4_check(const struct xt_tgchk_param *par) (par->hook_mask & ~((1 << NF_INET_FORWARD) | (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_POST_ROUTING))) != 0) { - printk("xt_TCPMSS: path-MTU clamping only supported in " - "FORWARD, OUTPUT and POSTROUTING hooks\n"); - return false; + pr_info("path-MTU clamping only supported in " + "FORWARD, OUTPUT and POSTROUTING hooks\n"); + return -EINVAL; } xt_ematch_foreach(ematch, e) if (find_syn_match(ematch)) - return true; - printk("xt_TCPMSS: Only works on TCP SYN packets\n"); - return false; + return 0; + pr_info("Only works on TCP SYN packets\n"); + return -EINVAL; } #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) -static bool tcpmss_tg6_check(const struct xt_tgchk_param *par) +static int tcpmss_tg6_check(const struct xt_tgchk_param *par) { const struct xt_tcpmss_info *info = par->targinfo; const struct ip6t_entry *e = par->entryinfo; @@ -268,15 +267,15 @@ static bool tcpmss_tg6_check(const struct xt_tgchk_param *par) (par->hook_mask & ~((1 << NF_INET_FORWARD) | (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_POST_ROUTING))) != 0) { - printk("xt_TCPMSS: path-MTU clamping only supported in " - "FORWARD, OUTPUT and POSTROUTING hooks\n"); - return false; + pr_info("path-MTU clamping only supported in " + "FORWARD, OUTPUT and POSTROUTING hooks\n"); + return -EINVAL; } xt_ematch_foreach(ematch, e) if (find_syn_match(ematch)) - return true; - printk("xt_TCPMSS: Only works on TCP SYN packets\n"); - return false; + return 0; + pr_info("Only works on TCP SYN packets\n"); + return -EINVAL; } #endif diff --git a/net/netfilter/xt_TCPOPTSTRIP.c b/net/netfilter/xt_TCPOPTSTRIP.c index 9dd8c8ef63eb..9dc9ecfdd546 100644 --- a/net/netfilter/xt_TCPOPTSTRIP.c +++ b/net/netfilter/xt_TCPOPTSTRIP.c @@ -3,7 +3,6 @@ * * Copyright (C) 2007 Sven Schnelle <svens@bitebene.org> * Copyright © CC Computer Consultants GmbH, 2007 - * Contact: Jan Engelhardt <jengelh@computergmbh.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -75,7 +74,7 @@ tcpoptstrip_mangle_packet(struct sk_buff *skb, } static unsigned int -tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_target_param *par) +tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_action_param *par) { return tcpoptstrip_mangle_packet(skb, par->targinfo, ip_hdrlen(skb), sizeof(struct iphdr) + sizeof(struct tcphdr)); @@ -83,7 +82,7 @@ tcpoptstrip_tg4(struct sk_buff *skb, const struct xt_target_param *par) #if defined(CONFIG_IP6_NF_MANGLE) || defined(CONFIG_IP6_NF_MANGLE_MODULE) static unsigned int -tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_target_param *par) +tcpoptstrip_tg6(struct sk_buff *skb, const struct xt_action_param *par) { struct ipv6hdr *ipv6h = ipv6_hdr(skb); int tcphoff; @@ -136,7 +135,7 @@ static void __exit tcpoptstrip_tg_exit(void) module_init(tcpoptstrip_tg_init); module_exit(tcpoptstrip_tg_exit); -MODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@computergmbh.de>"); +MODULE_AUTHOR("Sven Schnelle <svens@bitebene.org>, Jan Engelhardt <jengelh@medozas.de>"); MODULE_DESCRIPTION("Xtables: TCP option stripping"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_TCPOPTSTRIP"); diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c new file mode 100644 index 000000000000..d7920d9f49e9 --- /dev/null +++ b/net/netfilter/xt_TEE.c @@ -0,0 +1,309 @@ +/* + * "TEE" target extension for Xtables + * Copyright © Sebastian Claßen, 2007 + * Jan Engelhardt, 2007-2010 + * + * based on ipt_ROUTE.c from Cédric de Launois + * <delaunois@info.ucl.be> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 or later, as published by the Free Software Foundation. + */ +#include <linux/ip.h> +#include <linux/module.h> +#include <linux/percpu.h> +#include <linux/route.h> +#include <linux/skbuff.h> +#include <linux/notifier.h> +#include <net/checksum.h> +#include <net/icmp.h> +#include <net/ip.h> +#include <net/ipv6.h> +#include <net/ip6_route.h> +#include <net/route.h> +#include <linux/netfilter/x_tables.h> +#include <linux/netfilter/xt_TEE.h> + +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +# define WITH_CONNTRACK 1 +# include <net/netfilter/nf_conntrack.h> +#endif +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +# define WITH_IPV6 1 +#endif + +struct xt_tee_priv { + struct notifier_block notifier; + struct xt_tee_tginfo *tginfo; + int oif; +}; + +static const union nf_inet_addr tee_zero_address; +static DEFINE_PER_CPU(bool, tee_active); + +static struct net *pick_net(struct sk_buff *skb) +{ +#ifdef CONFIG_NET_NS + const struct dst_entry *dst; + + if (skb->dev != NULL) + return dev_net(skb->dev); + dst = skb_dst(skb); + if (dst != NULL && dst->dev != NULL) + return dev_net(dst->dev); +#endif + return &init_net; +} + +static bool +tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info) +{ + const struct iphdr *iph = ip_hdr(skb); + struct net *net = pick_net(skb); + struct rtable *rt; + struct flowi fl; + + memset(&fl, 0, sizeof(fl)); + if (info->priv) { + if (info->priv->oif == -1) + return false; + fl.oif = info->priv->oif; + } + fl.nl_u.ip4_u.daddr = info->gw.ip; + fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); + fl.nl_u.ip4_u.scope = RT_SCOPE_UNIVERSE; + if (ip_route_output_key(net, &rt, &fl) != 0) + return false; + + dst_release(skb_dst(skb)); + skb_dst_set(skb, &rt->u.dst); + skb->dev = rt->u.dst.dev; + skb->protocol = htons(ETH_P_IP); + return true; +} + +static unsigned int +tee_tg4(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_tee_tginfo *info = par->targinfo; + struct iphdr *iph; + + if (percpu_read(tee_active)) + return XT_CONTINUE; + /* + * Copy the skb, and route the copy. Will later return %XT_CONTINUE for + * the original skb, which should continue on its way as if nothing has + * happened. The copy should be independently delivered to the TEE + * --gateway. + */ + skb = pskb_copy(skb, GFP_ATOMIC); + if (skb == NULL) + return XT_CONTINUE; + +#ifdef WITH_CONNTRACK + /* Avoid counting cloned packets towards the original connection. */ + nf_conntrack_put(skb->nfct); + skb->nfct = &nf_conntrack_untracked.ct_general; + skb->nfctinfo = IP_CT_NEW; + nf_conntrack_get(skb->nfct); +#endif + /* + * If we are in PREROUTING/INPUT, the checksum must be recalculated + * since the length could have changed as a result of defragmentation. + * + * We also decrease the TTL to mitigate potential TEE loops + * between two hosts. + * + * Set %IP_DF so that the original source is notified of a potentially + * decreased MTU on the clone route. IPv6 does this too. + */ + iph = ip_hdr(skb); + iph->frag_off |= htons(IP_DF); + if (par->hooknum == NF_INET_PRE_ROUTING || + par->hooknum == NF_INET_LOCAL_IN) + --iph->ttl; + ip_send_check(iph); + + if (tee_tg_route4(skb, info)) { + percpu_write(tee_active, true); + ip_local_out(skb); + percpu_write(tee_active, false); + } else { + kfree_skb(skb); + } + return XT_CONTINUE; +} + +#ifdef WITH_IPV6 +static bool +tee_tg_route6(struct sk_buff *skb, const struct xt_tee_tginfo *info) +{ + const struct ipv6hdr *iph = ipv6_hdr(skb); + struct net *net = pick_net(skb); + struct dst_entry *dst; + struct flowi fl; + + memset(&fl, 0, sizeof(fl)); + if (info->priv) { + if (info->priv->oif == -1) + return false; + fl.oif = info->priv->oif; + } + fl.nl_u.ip6_u.daddr = info->gw.in6; + fl.nl_u.ip6_u.flowlabel = ((iph->flow_lbl[0] & 0xF) << 16) | + (iph->flow_lbl[1] << 8) | iph->flow_lbl[2]; + dst = ip6_route_output(net, NULL, &fl); + if (dst == NULL) + return false; + + dst_release(skb_dst(skb)); + skb_dst_set(skb, dst); + skb->dev = dst->dev; + skb->protocol = htons(ETH_P_IPV6); + return true; +} + +static unsigned int +tee_tg6(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_tee_tginfo *info = par->targinfo; + + if (percpu_read(tee_active)) + return XT_CONTINUE; + skb = pskb_copy(skb, GFP_ATOMIC); + if (skb == NULL) + return XT_CONTINUE; + +#ifdef WITH_CONNTRACK + nf_conntrack_put(skb->nfct); + skb->nfct = &nf_conntrack_untracked.ct_general; + skb->nfctinfo = IP_CT_NEW; + nf_conntrack_get(skb->nfct); +#endif + if (par->hooknum == NF_INET_PRE_ROUTING || + par->hooknum == NF_INET_LOCAL_IN) { + struct ipv6hdr *iph = ipv6_hdr(skb); + --iph->hop_limit; + } + if (tee_tg_route6(skb, info)) { + percpu_write(tee_active, true); + ip6_local_out(skb); + percpu_write(tee_active, false); + } else { + kfree_skb(skb); + } + return XT_CONTINUE; +} +#endif /* WITH_IPV6 */ + +static int tee_netdev_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct net_device *dev = ptr; + struct xt_tee_priv *priv; + + priv = container_of(this, struct xt_tee_priv, notifier); + switch (event) { + case NETDEV_REGISTER: + if (!strcmp(dev->name, priv->tginfo->oif)) + priv->oif = dev->ifindex; + break; + case NETDEV_UNREGISTER: + if (dev->ifindex == priv->oif) + priv->oif = -1; + break; + case NETDEV_CHANGENAME: + if (!strcmp(dev->name, priv->tginfo->oif)) + priv->oif = dev->ifindex; + else if (dev->ifindex == priv->oif) + priv->oif = -1; + break; + } + + return NOTIFY_DONE; +} + +static int tee_tg_check(const struct xt_tgchk_param *par) +{ + struct xt_tee_tginfo *info = par->targinfo; + struct xt_tee_priv *priv; + + /* 0.0.0.0 and :: not allowed */ + if (memcmp(&info->gw, &tee_zero_address, + sizeof(tee_zero_address)) == 0) + return -EINVAL; + + if (info->oif[0]) { + if (info->oif[sizeof(info->oif)-1] != '\0') + return -EINVAL; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->tginfo = info; + priv->oif = -1; + priv->notifier.notifier_call = tee_netdev_event; + info->priv = priv; + + register_netdevice_notifier(&priv->notifier); + } else + info->priv = NULL; + + return 0; +} + +static void tee_tg_destroy(const struct xt_tgdtor_param *par) +{ + struct xt_tee_tginfo *info = par->targinfo; + + if (info->priv) { + unregister_netdevice_notifier(&info->priv->notifier); + kfree(info->priv); + } +} + +static struct xt_target tee_tg_reg[] __read_mostly = { + { + .name = "TEE", + .revision = 1, + .family = NFPROTO_IPV4, + .target = tee_tg4, + .targetsize = sizeof(struct xt_tee_tginfo), + .checkentry = tee_tg_check, + .destroy = tee_tg_destroy, + .me = THIS_MODULE, + }, +#ifdef WITH_IPV6 + { + .name = "TEE", + .revision = 1, + .family = NFPROTO_IPV6, + .target = tee_tg6, + .targetsize = sizeof(struct xt_tee_tginfo), + .checkentry = tee_tg_check, + .destroy = tee_tg_destroy, + .me = THIS_MODULE, + }, +#endif +}; + +static int __init tee_tg_init(void) +{ + return xt_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); +} + +static void __exit tee_tg_exit(void) +{ + xt_unregister_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); +} + +module_init(tee_tg_init); +module_exit(tee_tg_exit); +MODULE_AUTHOR("Sebastian Claßen <sebastian.classen@freenet.ag>"); +MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); +MODULE_DESCRIPTION("Xtables: Reroute packet copy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_TEE"); +MODULE_ALIAS("ip6t_TEE"); diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index 1340c2fa3621..e1a0dedac258 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c @@ -9,7 +9,7 @@ * published by the Free Software Foundation. * */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> @@ -25,7 +25,7 @@ #include <net/netfilter/nf_tproxy_core.h> static unsigned int -tproxy_tg(struct sk_buff *skb, const struct xt_target_param *par) +tproxy_tg(struct sk_buff *skb, const struct xt_action_param *par) { const struct iphdr *iph = ip_hdr(skb); const struct xt_tproxy_target_info *tgi = par->targinfo; @@ -59,17 +59,17 @@ tproxy_tg(struct sk_buff *skb, const struct xt_target_param *par) return NF_DROP; } -static bool tproxy_tg_check(const struct xt_tgchk_param *par) +static int tproxy_tg_check(const struct xt_tgchk_param *par) { const struct ipt_ip *i = par->entryinfo; if ((i->proto == IPPROTO_TCP || i->proto == IPPROTO_UDP) && !(i->invflags & IPT_INV_PROTO)) - return true; + return 0; - pr_info("xt_TPROXY: Can be used only in combination with " + pr_info("Can be used only in combination with " "either -p tcp or -p udp\n"); - return false; + return -EINVAL; } static struct xt_target tproxy_tg_reg __read_mostly = { diff --git a/net/netfilter/xt_TRACE.c b/net/netfilter/xt_TRACE.c index fbb04b86c46b..df48967af382 100644 --- a/net/netfilter/xt_TRACE.c +++ b/net/netfilter/xt_TRACE.c @@ -11,7 +11,7 @@ MODULE_ALIAS("ipt_TRACE"); MODULE_ALIAS("ip6t_TRACE"); static unsigned int -trace_tg(struct sk_buff *skb, const struct xt_target_param *par) +trace_tg(struct sk_buff *skb, const struct xt_action_param *par) { skb->nf_trace = 1; return XT_CONTINUE; diff --git a/net/netfilter/xt_cluster.c b/net/netfilter/xt_cluster.c index 225ee3ecd69d..30b95a1c1c89 100644 --- a/net/netfilter/xt_cluster.c +++ b/net/netfilter/xt_cluster.c @@ -5,6 +5,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/jhash.h> @@ -85,7 +86,7 @@ xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family) } static bool -xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par) +xt_cluster_mt(const struct sk_buff *skb, struct xt_action_param *par) { struct sk_buff *pskb = (struct sk_buff *)skb; const struct xt_cluster_match_info *info = par->matchinfo; @@ -131,22 +132,22 @@ xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par) !!(info->flags & XT_CLUSTER_F_INV); } -static bool xt_cluster_mt_checkentry(const struct xt_mtchk_param *par) +static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par) { struct xt_cluster_match_info *info = par->matchinfo; if (info->total_nodes > XT_CLUSTER_NODES_MAX) { - printk(KERN_ERR "xt_cluster: you have exceeded the maximum " - "number of cluster nodes (%u > %u)\n", - info->total_nodes, XT_CLUSTER_NODES_MAX); - return false; + pr_info("you have exceeded the maximum " + "number of cluster nodes (%u > %u)\n", + info->total_nodes, XT_CLUSTER_NODES_MAX); + return -EINVAL; } if (info->node_mask >= (1ULL << info->total_nodes)) { - printk(KERN_ERR "xt_cluster: this node mask cannot be " - "higher than the total number of nodes\n"); - return false; + pr_info("this node mask cannot be " + "higher than the total number of nodes\n"); + return -EDOM; } - return true; + return 0; } static struct xt_match xt_cluster_match __read_mostly = { diff --git a/net/netfilter/xt_comment.c b/net/netfilter/xt_comment.c index e82179832acd..5c861d2f21ca 100644 --- a/net/netfilter/xt_comment.c +++ b/net/netfilter/xt_comment.c @@ -16,7 +16,7 @@ MODULE_ALIAS("ipt_comment"); MODULE_ALIAS("ip6t_comment"); static bool -comment_mt(const struct sk_buff *skb, const struct xt_match_param *par) +comment_mt(const struct sk_buff *skb, struct xt_action_param *par) { /* We always match */ return true; diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c index 955e6598a7f0..73517835303d 100644 --- a/net/netfilter/xt_connbytes.c +++ b/net/netfilter/xt_connbytes.c @@ -1,6 +1,7 @@ /* Kernel module to match connection tracking byte counter. * GPL (C) 2002 Martin Devera (devik@cdi.cz). */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/bitops.h> #include <linux/skbuff.h> @@ -17,7 +18,7 @@ MODULE_ALIAS("ipt_connbytes"); MODULE_ALIAS("ip6t_connbytes"); static bool -connbytes_mt(const struct sk_buff *skb, const struct xt_match_param *par) +connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_connbytes_info *sinfo = par->matchinfo; const struct nf_conn *ct; @@ -92,27 +93,26 @@ connbytes_mt(const struct sk_buff *skb, const struct xt_match_param *par) return what >= sinfo->count.from; } -static bool connbytes_mt_check(const struct xt_mtchk_param *par) +static int connbytes_mt_check(const struct xt_mtchk_param *par) { const struct xt_connbytes_info *sinfo = par->matchinfo; + int ret; if (sinfo->what != XT_CONNBYTES_PKTS && sinfo->what != XT_CONNBYTES_BYTES && sinfo->what != XT_CONNBYTES_AVGPKT) - return false; + return -EINVAL; if (sinfo->direction != XT_CONNBYTES_DIR_ORIGINAL && sinfo->direction != XT_CONNBYTES_DIR_REPLY && sinfo->direction != XT_CONNBYTES_DIR_BOTH) - return false; - - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "can't load conntrack support for " - "proto=%u\n", par->family); - return false; - } + return -EINVAL; - return true; + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) + pr_info("cannot load conntrack support for proto=%u\n", + par->family); + return ret; } static void connbytes_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 388ca4596098..5c5b6b921b84 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -5,13 +5,13 @@ * Nov 2002: Martin Bene <martin.bene@icomedias.com>: * only ignore TIME_WAIT or gone connections * (C) CC Computer Consultants GmbH, 2007 - * Contact: <jengelh@computergmbh.de> * * based on ... * * Kernel module to match connection tracking information. * GPL (C) 1999 Rusty Russell (rusty@rustcorp.com.au). */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/in.h> #include <linux/in6.h> #include <linux/ip.h> @@ -173,7 +173,7 @@ static int count_them(struct net *net, } static bool -connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) +connlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) { struct net *net = dev_net(par->in ? par->in : par->out); const struct xt_connlimit_info *info = par->matchinfo; @@ -206,44 +206,46 @@ connlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (connections < 0) { /* kmalloc failed, drop it entirely */ - *par->hotdrop = true; + par->hotdrop = true; return false; } return (connections > info->limit) ^ info->inverse; hotdrop: - *par->hotdrop = true; + par->hotdrop = true; return false; } -static bool connlimit_mt_check(const struct xt_mtchk_param *par) +static int connlimit_mt_check(const struct xt_mtchk_param *par) { struct xt_connlimit_info *info = par->matchinfo; unsigned int i; + int ret; if (unlikely(!connlimit_rnd_inited)) { get_random_bytes(&connlimit_rnd, sizeof(connlimit_rnd)); connlimit_rnd_inited = true; } - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "cannot load conntrack support for " - "address family %u\n", par->family); - return false; + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) { + pr_info("cannot load conntrack support for " + "address family %u\n", par->family); + return ret; } /* init private data */ info->data = kmalloc(sizeof(struct xt_connlimit_data), GFP_KERNEL); if (info->data == NULL) { nf_ct_l3proto_module_put(par->family); - return false; + return -ENOMEM; } spin_lock_init(&info->data->lock); for (i = 0; i < ARRAY_SIZE(info->data->iphash); ++i) INIT_LIST_HEAD(&info->data->iphash[i]); - return true; + return 0; } static void connlimit_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 122aa8b0147b..7278145e6a68 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -1,10 +1,10 @@ /* - * xt_connmark - Netfilter module to match connection mark values + * xt_connmark - Netfilter module to operate on connection marks * * Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com> * by Henrik Nordstrom <hno@marasystems.com> * Copyright © CC Computer Consultants GmbH, 2007 - 2008 - * Jan Engelhardt <jengelh@computergmbh.de> + * Jan Engelhardt <jengelh@medozas.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,17 +24,74 @@ #include <linux/module.h> #include <linux/skbuff.h> #include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_conntrack_ecache.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_connmark.h> MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>"); -MODULE_DESCRIPTION("Xtables: connection mark match"); +MODULE_DESCRIPTION("Xtables: connection mark operations"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("ipt_CONNMARK"); +MODULE_ALIAS("ip6t_CONNMARK"); MODULE_ALIAS("ipt_connmark"); MODULE_ALIAS("ip6t_connmark"); +static unsigned int +connmark_tg(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_connmark_tginfo1 *info = par->targinfo; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct; + u_int32_t newmark; + + ct = nf_ct_get(skb, &ctinfo); + if (ct == NULL) + return XT_CONTINUE; + + switch (info->mode) { + case XT_CONNMARK_SET: + newmark = (ct->mark & ~info->ctmask) ^ info->ctmark; + if (ct->mark != newmark) { + ct->mark = newmark; + nf_conntrack_event_cache(IPCT_MARK, ct); + } + break; + case XT_CONNMARK_SAVE: + newmark = (ct->mark & ~info->ctmask) ^ + (skb->mark & info->nfmask); + if (ct->mark != newmark) { + ct->mark = newmark; + nf_conntrack_event_cache(IPCT_MARK, ct); + } + break; + case XT_CONNMARK_RESTORE: + newmark = (skb->mark & ~info->nfmask) ^ + (ct->mark & info->ctmask); + skb->mark = newmark; + break; + } + + return XT_CONTINUE; +} + +static int connmark_tg_check(const struct xt_tgchk_param *par) +{ + int ret; + + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) + pr_info("cannot load conntrack support for proto=%u\n", + par->family); + return ret; +} + +static void connmark_tg_destroy(const struct xt_tgdtor_param *par) +{ + nf_ct_l3proto_module_put(par->family); +} + static bool -connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par) +connmark_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_connmark_mtinfo1 *info = par->matchinfo; enum ip_conntrack_info ctinfo; @@ -47,14 +104,15 @@ connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ((ct->mark & info->mask) == info->mark) ^ info->invert; } -static bool connmark_mt_check(const struct xt_mtchk_param *par) +static int connmark_mt_check(const struct xt_mtchk_param *par) { - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "cannot load conntrack support for " - "proto=%u\n", par->family); - return false; - } - return true; + int ret; + + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) + pr_info("cannot load conntrack support for proto=%u\n", + par->family); + return ret; } static void connmark_mt_destroy(const struct xt_mtdtor_param *par) @@ -62,6 +120,17 @@ static void connmark_mt_destroy(const struct xt_mtdtor_param *par) nf_ct_l3proto_module_put(par->family); } +static struct xt_target connmark_tg_reg __read_mostly = { + .name = "CONNMARK", + .revision = 1, + .family = NFPROTO_UNSPEC, + .checkentry = connmark_tg_check, + .target = connmark_tg, + .targetsize = sizeof(struct xt_connmark_tginfo1), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, +}; + static struct xt_match connmark_mt_reg __read_mostly = { .name = "connmark", .revision = 1, @@ -75,12 +144,23 @@ static struct xt_match connmark_mt_reg __read_mostly = { static int __init connmark_mt_init(void) { - return xt_register_match(&connmark_mt_reg); + int ret; + + ret = xt_register_target(&connmark_tg_reg); + if (ret < 0) + return ret; + ret = xt_register_match(&connmark_mt_reg); + if (ret < 0) { + xt_unregister_target(&connmark_tg_reg); + return ret; + } + return 0; } static void __exit connmark_mt_exit(void) { xt_unregister_match(&connmark_mt_reg); + xt_unregister_target(&connmark_tg_reg); } module_init(connmark_mt_init); diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index ae66305f0fe5..39681f10291c 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -9,7 +9,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <net/ipv6.h> @@ -113,7 +113,7 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info, } static bool -conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par, +conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par, u16 state_mask, u16 status_mask) { const struct xt_conntrack_mtinfo2 *info = par->matchinfo; @@ -191,7 +191,7 @@ conntrack_mt(const struct sk_buff *skb, const struct xt_match_param *par, } static bool -conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) +conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_conntrack_mtinfo1 *info = par->matchinfo; @@ -199,21 +199,22 @@ conntrack_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) } static bool -conntrack_mt_v2(const struct sk_buff *skb, const struct xt_match_param *par) +conntrack_mt_v2(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_conntrack_mtinfo2 *info = par->matchinfo; return conntrack_mt(skb, par, info->state_mask, info->status_mask); } -static bool conntrack_mt_check(const struct xt_mtchk_param *par) +static int conntrack_mt_check(const struct xt_mtchk_param *par) { - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "can't load conntrack support for " - "proto=%u\n", par->family); - return false; - } - return true; + int ret; + + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) + pr_info("cannot load conntrack support for proto=%u\n", + par->family); + return ret; } static void conntrack_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c index 395af5943ffd..b63d2a3d80ba 100644 --- a/net/netfilter/xt_dccp.c +++ b/net/netfilter/xt_dccp.c @@ -96,7 +96,7 @@ match_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff, } static bool -dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +dccp_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_dccp_info *info = par->matchinfo; const struct dccp_hdr *dh; @@ -107,7 +107,7 @@ dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par) dh = skb_header_pointer(skb, par->thoff, sizeof(_dh), &_dh); if (dh == NULL) { - *par->hotdrop = true; + par->hotdrop = true; return false; } @@ -120,17 +120,21 @@ dccp_mt(const struct sk_buff *skb, const struct xt_match_param *par) && DCCHECK(match_types(dh, info->typemask), XT_DCCP_TYPE, info->flags, info->invflags) && DCCHECK(match_option(info->option, skb, par->thoff, dh, - par->hotdrop), + &par->hotdrop), XT_DCCP_OPTION, info->flags, info->invflags); } -static bool dccp_mt_check(const struct xt_mtchk_param *par) +static int dccp_mt_check(const struct xt_mtchk_param *par) { const struct xt_dccp_info *info = par->matchinfo; - return !(info->flags & ~XT_DCCP_VALID_FLAGS) - && !(info->invflags & ~XT_DCCP_VALID_FLAGS) - && !(info->invflags & ~info->flags); + if (info->flags & ~XT_DCCP_VALID_FLAGS) + return -EINVAL; + if (info->invflags & ~XT_DCCP_VALID_FLAGS) + return -EINVAL; + if (info->invflags & ~info->flags) + return -EINVAL; + return 0; } static struct xt_match dccp_mt_reg[] __read_mostly = { diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c index 0280d3a8c161..64670fc5d0e1 100644 --- a/net/netfilter/xt_dscp.c +++ b/net/netfilter/xt_dscp.c @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> @@ -25,7 +25,7 @@ MODULE_ALIAS("ipt_tos"); MODULE_ALIAS("ip6t_tos"); static bool -dscp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +dscp_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_dscp_info *info = par->matchinfo; u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT; @@ -34,7 +34,7 @@ dscp_mt(const struct sk_buff *skb, const struct xt_match_param *par) } static bool -dscp_mt6(const struct sk_buff *skb, const struct xt_match_param *par) +dscp_mt6(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_dscp_info *info = par->matchinfo; u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT; @@ -42,23 +42,23 @@ dscp_mt6(const struct sk_buff *skb, const struct xt_match_param *par) return (dscp == info->dscp) ^ !!info->invert; } -static bool dscp_mt_check(const struct xt_mtchk_param *par) +static int dscp_mt_check(const struct xt_mtchk_param *par) { const struct xt_dscp_info *info = par->matchinfo; if (info->dscp > XT_DSCP_MAX) { - printk(KERN_ERR "xt_dscp: dscp %x out of range\n", info->dscp); - return false; + pr_info("dscp %x out of range\n", info->dscp); + return -EDOM; } - return true; + return 0; } -static bool tos_mt(const struct sk_buff *skb, const struct xt_match_param *par) +static bool tos_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_tos_match_info *info = par->matchinfo; - if (par->match->family == NFPROTO_IPV4) + if (par->family == NFPROTO_IPV4) return ((ip_hdr(skb)->tos & info->tos_mask) == info->tos_value) ^ !!info->invert; else diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c index 609439967c2c..171ba82b5902 100644 --- a/net/netfilter/xt_esp.c +++ b/net/netfilter/xt_esp.c @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/in.h> @@ -24,25 +24,19 @@ MODULE_DESCRIPTION("Xtables: IPsec-ESP packet match"); MODULE_ALIAS("ipt_esp"); MODULE_ALIAS("ip6t_esp"); -#if 0 -#define duprintf(format, args...) printk(format , ## args) -#else -#define duprintf(format, args...) -#endif - /* Returns 1 if the spi is matched by the range, 0 otherwise */ static inline bool spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, bool invert) { bool r; - duprintf("esp spi_match:%c 0x%x <= 0x%x <= 0x%x", invert ? '!' : ' ', - min, spi, max); + pr_debug("spi_match:%c 0x%x <= 0x%x <= 0x%x\n", + invert ? '!' : ' ', min, spi, max); r = (spi >= min && spi <= max) ^ invert; - duprintf(" result %s\n", r ? "PASS" : "FAILED"); + pr_debug(" result %s\n", r ? "PASS" : "FAILED"); return r; } -static bool esp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +static bool esp_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct ip_esp_hdr *eh; struct ip_esp_hdr _esp; @@ -57,8 +51,8 @@ static bool esp_mt(const struct sk_buff *skb, const struct xt_match_param *par) /* We've been asked to examine this packet, and we * can't. Hence, no choice but to drop. */ - duprintf("Dropping evil ESP tinygram.\n"); - *par->hotdrop = true; + pr_debug("Dropping evil ESP tinygram.\n"); + par->hotdrop = true; return false; } @@ -66,16 +60,16 @@ static bool esp_mt(const struct sk_buff *skb, const struct xt_match_param *par) !!(espinfo->invflags & XT_ESP_INV_SPI)); } -static bool esp_mt_check(const struct xt_mtchk_param *par) +static int esp_mt_check(const struct xt_mtchk_param *par) { const struct xt_esp *espinfo = par->matchinfo; if (espinfo->invflags & ~XT_ESP_INV_MASK) { - duprintf("xt_esp: unknown flags %X\n", espinfo->invflags); - return false; + pr_debug("unknown flags %X\n", espinfo->invflags); + return -EINVAL; } - return true; + return 0; } static struct xt_match esp_mt_reg[] __read_mostly = { diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 215a64835de8..b46a8390896d 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -7,6 +7,7 @@ * * Development of this code was funded by Astaro AG, http://www.astaro.com/ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/spinlock.h> #include <linux/random.h> @@ -36,7 +37,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); -MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>"); +MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); MODULE_DESCRIPTION("Xtables: per hash-bucket rate-limit match"); MODULE_ALIAS("ipt_hashlimit"); MODULE_ALIAS("ip6t_hashlimit"); @@ -80,12 +81,14 @@ struct dsthash_ent { struct dsthash_dst dst; /* modified structure members in the end */ + spinlock_t lock; unsigned long expires; /* precalculated expiry time */ struct { unsigned long prev; /* last modification */ u_int32_t credit; u_int32_t credit_cap, cost; } rateinfo; + struct rcu_head rcu; }; struct xt_hashlimit_htable { @@ -142,9 +145,11 @@ dsthash_find(const struct xt_hashlimit_htable *ht, u_int32_t hash = hash_dst(ht, dst); if (!hlist_empty(&ht->hash[hash])) { - hlist_for_each_entry(ent, pos, &ht->hash[hash], node) - if (dst_cmp(ent, dst)) + hlist_for_each_entry_rcu(ent, pos, &ht->hash[hash], node) + if (dst_cmp(ent, dst)) { + spin_lock(&ent->lock); return ent; + } } return NULL; } @@ -156,9 +161,10 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht, { struct dsthash_ent *ent; + spin_lock(&ht->lock); /* initialize hash with random val at the time we allocate * the first hashtable entry */ - if (!ht->rnd_initialized) { + if (unlikely(!ht->rnd_initialized)) { get_random_bytes(&ht->rnd, sizeof(ht->rnd)); ht->rnd_initialized = true; } @@ -166,106 +172,40 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht, if (ht->cfg.max && ht->count >= ht->cfg.max) { /* FIXME: do something. question is what.. */ if (net_ratelimit()) - printk(KERN_WARNING - "xt_hashlimit: max count of %u reached\n", - ht->cfg.max); - return NULL; - } - - ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); + pr_err("max count of %u reached\n", ht->cfg.max); + ent = NULL; + } else + ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); if (!ent) { if (net_ratelimit()) - printk(KERN_ERR - "xt_hashlimit: can't allocate dsthash_ent\n"); - return NULL; - } - memcpy(&ent->dst, dst, sizeof(ent->dst)); + pr_err("cannot allocate dsthash_ent\n"); + } else { + memcpy(&ent->dst, dst, sizeof(ent->dst)); + spin_lock_init(&ent->lock); - hlist_add_head(&ent->node, &ht->hash[hash_dst(ht, dst)]); - ht->count++; + spin_lock(&ent->lock); + hlist_add_head_rcu(&ent->node, &ht->hash[hash_dst(ht, dst)]); + ht->count++; + } + spin_unlock(&ht->lock); return ent; } -static inline void -dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) +static void dsthash_free_rcu(struct rcu_head *head) { - hlist_del(&ent->node); + struct dsthash_ent *ent = container_of(head, struct dsthash_ent, rcu); + kmem_cache_free(hashlimit_cachep, ent); - ht->count--; } -static void htable_gc(unsigned long htlong); -static int htable_create_v0(struct net *net, struct xt_hashlimit_info *minfo, u_int8_t family) +static inline void +dsthash_free(struct xt_hashlimit_htable *ht, struct dsthash_ent *ent) { - struct hashlimit_net *hashlimit_net = hashlimit_pernet(net); - struct xt_hashlimit_htable *hinfo; - unsigned int size; - unsigned int i; - - if (minfo->cfg.size) - size = minfo->cfg.size; - else { - size = ((totalram_pages << PAGE_SHIFT) / 16384) / - sizeof(struct list_head); - if (totalram_pages > (1024 * 1024 * 1024 / PAGE_SIZE)) - size = 8192; - if (size < 16) - size = 16; - } - /* FIXME: don't use vmalloc() here or anywhere else -HW */ - hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + - sizeof(struct list_head) * size); - if (!hinfo) { - printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n"); - return -1; - } - minfo->hinfo = hinfo; - - /* copy match config into hashtable config */ - hinfo->cfg.mode = minfo->cfg.mode; - hinfo->cfg.avg = minfo->cfg.avg; - hinfo->cfg.burst = minfo->cfg.burst; - hinfo->cfg.max = minfo->cfg.max; - hinfo->cfg.gc_interval = minfo->cfg.gc_interval; - hinfo->cfg.expire = minfo->cfg.expire; - - if (family == NFPROTO_IPV4) - hinfo->cfg.srcmask = hinfo->cfg.dstmask = 32; - else - hinfo->cfg.srcmask = hinfo->cfg.dstmask = 128; - - hinfo->cfg.size = size; - if (!hinfo->cfg.max) - hinfo->cfg.max = 8 * hinfo->cfg.size; - else if (hinfo->cfg.max < hinfo->cfg.size) - hinfo->cfg.max = hinfo->cfg.size; - - for (i = 0; i < hinfo->cfg.size; i++) - INIT_HLIST_HEAD(&hinfo->hash[i]); - - hinfo->use = 1; - hinfo->count = 0; - hinfo->family = family; - hinfo->rnd_initialized = false; - spin_lock_init(&hinfo->lock); - hinfo->pde = proc_create_data(minfo->name, 0, - (family == NFPROTO_IPV4) ? - hashlimit_net->ipt_hashlimit : hashlimit_net->ip6t_hashlimit, - &dl_file_ops, hinfo); - if (!hinfo->pde) { - vfree(hinfo); - return -1; - } - hinfo->net = net; - - setup_timer(&hinfo->timer, htable_gc, (unsigned long )hinfo); - hinfo->timer.expires = jiffies + msecs_to_jiffies(hinfo->cfg.gc_interval); - add_timer(&hinfo->timer); - - hlist_add_head(&hinfo->node, &hashlimit_net->htables); - - return 0; + hlist_del_rcu(&ent->node); + call_rcu_bh(&ent->rcu, dsthash_free_rcu); + ht->count--; } +static void htable_gc(unsigned long htlong); static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, u_int8_t family) @@ -288,10 +228,8 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, /* FIXME: don't use vmalloc() here or anywhere else -HW */ hinfo = vmalloc(sizeof(struct xt_hashlimit_htable) + sizeof(struct list_head) * size); - if (hinfo == NULL) { - printk(KERN_ERR "xt_hashlimit: unable to create hashtable\n"); - return -1; - } + if (hinfo == NULL) + return -ENOMEM; minfo->hinfo = hinfo; /* copy match config into hashtable config */ @@ -317,7 +255,7 @@ static int htable_create(struct net *net, struct xt_hashlimit_mtinfo1 *minfo, &dl_file_ops, hinfo); if (hinfo->pde == NULL) { vfree(hinfo); - return -1; + return -ENOMEM; } hinfo->net = net; @@ -578,58 +516,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, } static bool -hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct xt_hashlimit_info *r = par->matchinfo; - struct xt_hashlimit_htable *hinfo = r->hinfo; - unsigned long now = jiffies; - struct dsthash_ent *dh; - struct dsthash_dst dst; - - if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0) - goto hotdrop; - - spin_lock_bh(&hinfo->lock); - dh = dsthash_find(hinfo, &dst); - if (!dh) { - dh = dsthash_alloc_init(hinfo, &dst); - if (!dh) { - spin_unlock_bh(&hinfo->lock); - goto hotdrop; - } - - dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); - dh->rateinfo.prev = jiffies; - dh->rateinfo.credit = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.credit_cap = user2credits(hinfo->cfg.avg * - hinfo->cfg.burst); - dh->rateinfo.cost = user2credits(hinfo->cfg.avg); - } else { - /* update expiration timeout */ - dh->expires = now + msecs_to_jiffies(hinfo->cfg.expire); - rateinfo_recalc(dh, now); - } - - if (dh->rateinfo.credit >= dh->rateinfo.cost) { - /* We're underlimit. */ - dh->rateinfo.credit -= dh->rateinfo.cost; - spin_unlock_bh(&hinfo->lock); - return true; - } - - spin_unlock_bh(&hinfo->lock); - - /* default case: we're overlimit, thus don't match */ - return false; - -hotdrop: - *par->hotdrop = true; - return false; -} - -static bool -hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) +hashlimit_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_hashlimit_mtinfo1 *info = par->matchinfo; struct xt_hashlimit_htable *hinfo = info->hinfo; @@ -640,15 +527,14 @@ hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (hashlimit_init_dst(hinfo, &dst, skb, par->thoff) < 0) goto hotdrop; - spin_lock_bh(&hinfo->lock); + rcu_read_lock_bh(); dh = dsthash_find(hinfo, &dst); if (dh == NULL) { dh = dsthash_alloc_init(hinfo, &dst); if (dh == NULL) { - spin_unlock_bh(&hinfo->lock); + rcu_read_unlock_bh(); goto hotdrop; } - dh->expires = jiffies + msecs_to_jiffies(hinfo->cfg.expire); dh->rateinfo.prev = jiffies; dh->rateinfo.credit = user2credits(hinfo->cfg.avg * @@ -665,96 +551,58 @@ hashlimit_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (dh->rateinfo.credit >= dh->rateinfo.cost) { /* below the limit */ dh->rateinfo.credit -= dh->rateinfo.cost; - spin_unlock_bh(&hinfo->lock); + spin_unlock(&dh->lock); + rcu_read_unlock_bh(); return !(info->cfg.mode & XT_HASHLIMIT_INVERT); } - spin_unlock_bh(&hinfo->lock); + spin_unlock(&dh->lock); + rcu_read_unlock_bh(); /* default match is underlimit - so over the limit, we need to invert */ return info->cfg.mode & XT_HASHLIMIT_INVERT; hotdrop: - *par->hotdrop = true; + par->hotdrop = true; return false; } -static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) -{ - struct net *net = par->net; - struct xt_hashlimit_info *r = par->matchinfo; - - /* Check for overflow. */ - if (r->cfg.burst == 0 || - user2credits(r->cfg.avg * r->cfg.burst) < user2credits(r->cfg.avg)) { - printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n", - r->cfg.avg, r->cfg.burst); - return false; - } - if (r->cfg.mode == 0 || - r->cfg.mode > (XT_HASHLIMIT_HASH_DPT | - XT_HASHLIMIT_HASH_DIP | - XT_HASHLIMIT_HASH_SIP | - XT_HASHLIMIT_HASH_SPT)) - return false; - if (!r->cfg.gc_interval) - return false; - if (!r->cfg.expire) - return false; - if (r->name[sizeof(r->name) - 1] != '\0') - return false; - - mutex_lock(&hashlimit_mutex); - r->hinfo = htable_find_get(net, r->name, par->match->family); - if (!r->hinfo && htable_create_v0(net, r, par->match->family) != 0) { - mutex_unlock(&hashlimit_mutex); - return false; - } - mutex_unlock(&hashlimit_mutex); - - return true; -} - -static bool hashlimit_mt_check(const struct xt_mtchk_param *par) +static int hashlimit_mt_check(const struct xt_mtchk_param *par) { struct net *net = par->net; struct xt_hashlimit_mtinfo1 *info = par->matchinfo; + int ret; /* Check for overflow. */ if (info->cfg.burst == 0 || user2credits(info->cfg.avg * info->cfg.burst) < user2credits(info->cfg.avg)) { - printk(KERN_ERR "xt_hashlimit: overflow, try lower: %u/%u\n", - info->cfg.avg, info->cfg.burst); - return false; + pr_info("overflow, try lower: %u/%u\n", + info->cfg.avg, info->cfg.burst); + return -ERANGE; } if (info->cfg.gc_interval == 0 || info->cfg.expire == 0) - return false; + return -EINVAL; if (info->name[sizeof(info->name)-1] != '\0') - return false; - if (par->match->family == NFPROTO_IPV4) { + return -EINVAL; + if (par->family == NFPROTO_IPV4) { if (info->cfg.srcmask > 32 || info->cfg.dstmask > 32) - return false; + return -EINVAL; } else { if (info->cfg.srcmask > 128 || info->cfg.dstmask > 128) - return false; + return -EINVAL; } mutex_lock(&hashlimit_mutex); - info->hinfo = htable_find_get(net, info->name, par->match->family); - if (!info->hinfo && htable_create(net, info, par->match->family) != 0) { - mutex_unlock(&hashlimit_mutex); - return false; + info->hinfo = htable_find_get(net, info->name, par->family); + if (info->hinfo == NULL) { + ret = htable_create(net, info, par->family); + if (ret < 0) { + mutex_unlock(&hashlimit_mutex); + return ret; + } } mutex_unlock(&hashlimit_mutex); - return true; -} - -static void -hashlimit_mt_destroy_v0(const struct xt_mtdtor_param *par) -{ - const struct xt_hashlimit_info *r = par->matchinfo; - - htable_put(r->hinfo); + return 0; } static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par) @@ -764,47 +612,8 @@ static void hashlimit_mt_destroy(const struct xt_mtdtor_param *par) htable_put(info->hinfo); } -#ifdef CONFIG_COMPAT -struct compat_xt_hashlimit_info { - char name[IFNAMSIZ]; - struct hashlimit_cfg cfg; - compat_uptr_t hinfo; - compat_uptr_t master; -}; - -static void hashlimit_mt_compat_from_user(void *dst, const void *src) -{ - int off = offsetof(struct compat_xt_hashlimit_info, hinfo); - - memcpy(dst, src, off); - memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off); -} - -static int hashlimit_mt_compat_to_user(void __user *dst, const void *src) -{ - int off = offsetof(struct compat_xt_hashlimit_info, hinfo); - - return copy_to_user(dst, src, off) ? -EFAULT : 0; -} -#endif - static struct xt_match hashlimit_mt_reg[] __read_mostly = { { - .name = "hashlimit", - .revision = 0, - .family = NFPROTO_IPV4, - .match = hashlimit_mt_v0, - .matchsize = sizeof(struct xt_hashlimit_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_hashlimit_info), - .compat_from_user = hashlimit_mt_compat_from_user, - .compat_to_user = hashlimit_mt_compat_to_user, -#endif - .checkentry = hashlimit_mt_check_v0, - .destroy = hashlimit_mt_destroy_v0, - .me = THIS_MODULE - }, - { .name = "hashlimit", .revision = 1, .family = NFPROTO_IPV4, @@ -816,20 +625,6 @@ static struct xt_match hashlimit_mt_reg[] __read_mostly = { }, #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) { - .name = "hashlimit", - .family = NFPROTO_IPV6, - .match = hashlimit_mt_v0, - .matchsize = sizeof(struct xt_hashlimit_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_hashlimit_info), - .compat_from_user = hashlimit_mt_compat_from_user, - .compat_to_user = hashlimit_mt_compat_to_user, -#endif - .checkentry = hashlimit_mt_check_v0, - .destroy = hashlimit_mt_destroy_v0, - .me = THIS_MODULE - }, - { .name = "hashlimit", .revision = 1, .family = NFPROTO_IPV6, @@ -888,12 +683,15 @@ static void dl_seq_stop(struct seq_file *s, void *v) static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family, struct seq_file *s) { + int res; + + spin_lock(&ent->lock); /* recalculate to show accurate numbers */ rateinfo_recalc(ent, jiffies); switch (family) { case NFPROTO_IPV4: - return seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n", + res = seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n", (long)(ent->expires - jiffies)/HZ, &ent->dst.ip.src, ntohs(ent->dst.src_port), @@ -901,9 +699,10 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family, ntohs(ent->dst.dst_port), ent->rateinfo.credit, ent->rateinfo.credit_cap, ent->rateinfo.cost); + break; #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) case NFPROTO_IPV6: - return seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n", + res = seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n", (long)(ent->expires - jiffies)/HZ, &ent->dst.ip6.src, ntohs(ent->dst.src_port), @@ -911,11 +710,14 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family, ntohs(ent->dst.dst_port), ent->rateinfo.credit, ent->rateinfo.credit_cap, ent->rateinfo.cost); + break; #endif default: BUG(); - return 0; + res = 0; } + spin_unlock(&ent->lock); + return res; } static int dl_seq_show(struct seq_file *s, void *v) @@ -1024,7 +826,7 @@ static int __init hashlimit_mt_init(void) sizeof(struct dsthash_ent), 0, 0, NULL); if (!hashlimit_cachep) { - printk(KERN_ERR "xt_hashlimit: unable to create slab cache\n"); + pr_warning("unable to create slab cache\n"); goto err2; } return 0; @@ -1039,9 +841,11 @@ err1: static void __exit hashlimit_mt_exit(void) { - kmem_cache_destroy(hashlimit_cachep); xt_unregister_matches(hashlimit_mt_reg, ARRAY_SIZE(hashlimit_mt_reg)); unregister_pernet_subsys(&hashlimit_net_ops); + + rcu_barrier_bh(); + kmem_cache_destroy(hashlimit_cachep); } module_init(hashlimit_mt_init); diff --git a/net/netfilter/xt_helper.c b/net/netfilter/xt_helper.c index 64fc7f277221..9f4ab00c8050 100644 --- a/net/netfilter/xt_helper.c +++ b/net/netfilter/xt_helper.c @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter.h> @@ -24,7 +24,7 @@ MODULE_ALIAS("ip6t_helper"); static bool -helper_mt(const struct sk_buff *skb, const struct xt_match_param *par) +helper_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_helper_info *info = par->matchinfo; const struct nf_conn *ct; @@ -54,17 +54,19 @@ helper_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ret; } -static bool helper_mt_check(const struct xt_mtchk_param *par) +static int helper_mt_check(const struct xt_mtchk_param *par) { struct xt_helper_info *info = par->matchinfo; + int ret; - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "can't load conntrack support for " - "proto=%u\n", par->family); - return false; + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) { + pr_info("cannot load conntrack support for proto=%u\n", + par->family); + return ret; } info->name[29] = '\0'; - return true; + return 0; } static void helper_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_hl.c b/net/netfilter/xt_hl.c index 7726154c87b2..7d12221ead89 100644 --- a/net/netfilter/xt_hl.c +++ b/net/netfilter/xt_hl.c @@ -25,7 +25,7 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_ttl"); MODULE_ALIAS("ip6t_hl"); -static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par) +static bool ttl_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct ipt_ttl_info *info = par->matchinfo; const u8 ttl = ip_hdr(skb)->ttl; @@ -39,16 +39,12 @@ static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ttl < info->ttl; case IPT_TTL_GT: return ttl > info->ttl; - default: - printk(KERN_WARNING "ipt_ttl: unknown mode %d\n", - info->mode); - return false; } return false; } -static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par) +static bool hl_mt6(const struct sk_buff *skb, struct xt_action_param *par) { const struct ip6t_hl_info *info = par->matchinfo; const struct ipv6hdr *ip6h = ipv6_hdr(skb); @@ -56,20 +52,12 @@ static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par) switch (info->mode) { case IP6T_HL_EQ: return ip6h->hop_limit == info->hop_limit; - break; case IP6T_HL_NE: return ip6h->hop_limit != info->hop_limit; - break; case IP6T_HL_LT: return ip6h->hop_limit < info->hop_limit; - break; case IP6T_HL_GT: return ip6h->hop_limit > info->hop_limit; - break; - default: - printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", - info->mode); - return false; } return false; diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c index ffc96387d556..88f7c3511c72 100644 --- a/net/netfilter/xt_iprange.c +++ b/net/netfilter/xt_iprange.c @@ -8,6 +8,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/ip.h> @@ -16,7 +17,7 @@ #include <linux/netfilter/xt_iprange.h> static bool -iprange_mt4(const struct sk_buff *skb, const struct xt_match_param *par) +iprange_mt4(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_iprange_mtinfo *info = par->matchinfo; const struct iphdr *iph = ip_hdr(skb); @@ -67,7 +68,7 @@ iprange_ipv6_sub(const struct in6_addr *a, const struct in6_addr *b) } static bool -iprange_mt6(const struct sk_buff *skb, const struct xt_match_param *par) +iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_iprange_mtinfo *info = par->matchinfo; const struct ipv6hdr *iph = ipv6_hdr(skb); diff --git a/net/netfilter/xt_length.c b/net/netfilter/xt_length.c index c4871ca6c86d..176e5570a999 100644 --- a/net/netfilter/xt_length.c +++ b/net/netfilter/xt_length.c @@ -21,7 +21,7 @@ MODULE_ALIAS("ipt_length"); MODULE_ALIAS("ip6t_length"); static bool -length_mt(const struct sk_buff *skb, const struct xt_match_param *par) +length_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_length_info *info = par->matchinfo; u_int16_t pktlen = ntohs(ip_hdr(skb)->tot_len); @@ -30,7 +30,7 @@ length_mt(const struct sk_buff *skb, const struct xt_match_param *par) } static bool -length_mt6(const struct sk_buff *skb, const struct xt_match_param *par) +length_mt6(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_length_info *info = par->matchinfo; const u_int16_t pktlen = ntohs(ipv6_hdr(skb)->payload_len) + diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c index e5d7e1ffb1a4..32b7a579a032 100644 --- a/net/netfilter/xt_limit.c +++ b/net/netfilter/xt_limit.c @@ -5,6 +5,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/slab.h> #include <linux/module.h> @@ -64,7 +65,7 @@ static DEFINE_SPINLOCK(limit_lock); #define CREDITS_PER_JIFFY POW2_BELOW32(MAX_CPJ) static bool -limit_mt(const struct sk_buff *skb, const struct xt_match_param *par) +limit_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_rateinfo *r = par->matchinfo; struct xt_limit_priv *priv = r->master; @@ -98,7 +99,7 @@ user2credits(u_int32_t user) return (user * HZ * CREDITS_PER_JIFFY) / XT_LIMIT_SCALE; } -static bool limit_mt_check(const struct xt_mtchk_param *par) +static int limit_mt_check(const struct xt_mtchk_param *par) { struct xt_rateinfo *r = par->matchinfo; struct xt_limit_priv *priv; @@ -106,14 +107,14 @@ static bool limit_mt_check(const struct xt_mtchk_param *par) /* Check for overflow. */ if (r->burst == 0 || user2credits(r->avg * r->burst) < user2credits(r->avg)) { - printk("Overflow in xt_limit, try lower: %u/%u\n", - r->avg, r->burst); - return false; + pr_info("Overflow, try lower: %u/%u\n", + r->avg, r->burst); + return -ERANGE; } priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) - return false; + return -ENOMEM; /* For SMP, we only want to use one set of state. */ r->master = priv; @@ -125,7 +126,7 @@ static bool limit_mt_check(const struct xt_mtchk_param *par) r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ r->cost = user2credits(r->avg); } - return true; + return 0; } static void limit_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c index c2007116ce5b..8160f6b1435d 100644 --- a/net/netfilter/xt_mac.c +++ b/net/netfilter/xt_mac.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/skbuff.h> +#include <linux/if_arp.h> #include <linux/if_ether.h> #include <linux/etherdevice.h> @@ -24,16 +25,20 @@ MODULE_DESCRIPTION("Xtables: MAC address match"); MODULE_ALIAS("ipt_mac"); MODULE_ALIAS("ip6t_mac"); -static bool mac_mt(const struct sk_buff *skb, const struct xt_match_param *par) +static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par) { - const struct xt_mac_info *info = par->matchinfo; - - /* Is mac pointer valid? */ - return skb_mac_header(skb) >= skb->head && - skb_mac_header(skb) + ETH_HLEN <= skb->data - /* If so, compare... */ - && ((!compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr)) - ^ info->invert); + const struct xt_mac_info *info = par->matchinfo; + bool ret; + + if (skb->dev == NULL || skb->dev->type != ARPHRD_ETHER) + return false; + if (skb_mac_header(skb) < skb->head) + return false; + if (skb_mac_header(skb) + ETH_HLEN > skb->data) + return false; + ret = compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr) == 0; + ret ^= info->invert; + return ret; } static struct xt_match mac_mt_reg __read_mostly = { diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c index 1db07d8125f8..23345238711b 100644 --- a/net/netfilter/xt_mark.c +++ b/net/netfilter/xt_mark.c @@ -18,18 +18,38 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); -MODULE_DESCRIPTION("Xtables: packet mark match"); +MODULE_DESCRIPTION("Xtables: packet mark operations"); MODULE_ALIAS("ipt_mark"); MODULE_ALIAS("ip6t_mark"); +MODULE_ALIAS("ipt_MARK"); +MODULE_ALIAS("ip6t_MARK"); + +static unsigned int +mark_tg(struct sk_buff *skb, const struct xt_action_param *par) +{ + const struct xt_mark_tginfo2 *info = par->targinfo; + + skb->mark = (skb->mark & ~info->mask) ^ info->mark; + return XT_CONTINUE; +} static bool -mark_mt(const struct sk_buff *skb, const struct xt_match_param *par) +mark_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_mark_mtinfo1 *info = par->matchinfo; return ((skb->mark & info->mask) == info->mark) ^ info->invert; } +static struct xt_target mark_tg_reg __read_mostly = { + .name = "MARK", + .revision = 2, + .family = NFPROTO_UNSPEC, + .target = mark_tg, + .targetsize = sizeof(struct xt_mark_tginfo2), + .me = THIS_MODULE, +}; + static struct xt_match mark_mt_reg __read_mostly = { .name = "mark", .revision = 1, @@ -41,12 +61,23 @@ static struct xt_match mark_mt_reg __read_mostly = { static int __init mark_mt_init(void) { - return xt_register_match(&mark_mt_reg); + int ret; + + ret = xt_register_target(&mark_tg_reg); + if (ret < 0) + return ret; + ret = xt_register_match(&mark_mt_reg); + if (ret < 0) { + xt_unregister_target(&mark_tg_reg); + return ret; + } + return 0; } static void __exit mark_mt_exit(void) { xt_unregister_match(&mark_mt_reg); + xt_unregister_target(&mark_tg_reg); } module_init(mark_mt_init); diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index d06bb2dd3900..ac1d3c3d09e7 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c @@ -8,7 +8,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/types.h> #include <linux/udp.h> @@ -26,29 +26,6 @@ MODULE_DESCRIPTION("Xtables: multiple port matching for TCP, UDP, UDP-Lite, SCTP MODULE_ALIAS("ipt_multiport"); MODULE_ALIAS("ip6t_multiport"); -#if 0 -#define duprintf(format, args...) printk(format , ## args) -#else -#define duprintf(format, args...) -#endif - -/* Returns 1 if the port is matched by the test, 0 otherwise. */ -static inline bool -ports_match_v0(const u_int16_t *portlist, enum xt_multiport_flags flags, - u_int8_t count, u_int16_t src, u_int16_t dst) -{ - unsigned int i; - for (i = 0; i < count; i++) { - if (flags != XT_MULTIPORT_DESTINATION && portlist[i] == src) - return true; - - if (flags != XT_MULTIPORT_SOURCE && portlist[i] == dst) - return true; - } - - return false; -} - /* Returns 1 if the port is matched by the test, 0 otherwise. */ static inline bool ports_match_v1(const struct xt_multiport_v1 *minfo, @@ -63,7 +40,7 @@ ports_match_v1(const struct xt_multiport_v1 *minfo, if (minfo->pflags[i]) { /* range port matching */ e = minfo->ports[++i]; - duprintf("src or dst matches with %d-%d?\n", s, e); + pr_debug("src or dst matches with %d-%d?\n", s, e); if (minfo->flags == XT_MULTIPORT_SOURCE && src >= s && src <= e) @@ -77,7 +54,7 @@ ports_match_v1(const struct xt_multiport_v1 *minfo, return true ^ minfo->invert; } else { /* exact port matching */ - duprintf("src or dst matches with %d?\n", s); + pr_debug("src or dst matches with %d?\n", s); if (minfo->flags == XT_MULTIPORT_SOURCE && src == s) @@ -95,31 +72,7 @@ ports_match_v1(const struct xt_multiport_v1 *minfo, } static bool -multiport_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const __be16 *pptr; - __be16 _ports[2]; - const struct xt_multiport *multiinfo = par->matchinfo; - - if (par->fragoff != 0) - return false; - - pptr = skb_header_pointer(skb, par->thoff, sizeof(_ports), _ports); - if (pptr == NULL) { - /* We've been asked to examine this packet, and we - * can't. Hence, no choice but to drop. - */ - duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); - *par->hotdrop = true; - return false; - } - - return ports_match_v0(multiinfo->ports, multiinfo->flags, - multiinfo->count, ntohs(pptr[0]), ntohs(pptr[1])); -} - -static bool -multiport_mt(const struct sk_buff *skb, const struct xt_match_param *par) +multiport_mt(const struct sk_buff *skb, struct xt_action_param *par) { const __be16 *pptr; __be16 _ports[2]; @@ -133,8 +86,8 @@ multiport_mt(const struct sk_buff *skb, const struct xt_match_param *par) /* We've been asked to examine this packet, and we * can't. Hence, no choice but to drop. */ - duprintf("xt_multiport: Dropping evil offset=0 tinygram.\n"); - *par->hotdrop = true; + pr_debug("Dropping evil offset=0 tinygram.\n"); + par->hotdrop = true; return false; } @@ -158,55 +111,28 @@ check(u_int16_t proto, && count <= XT_MULTI_PORTS; } -static bool multiport_mt_check_v0(const struct xt_mtchk_param *par) -{ - const struct ipt_ip *ip = par->entryinfo; - const struct xt_multiport *multiinfo = par->matchinfo; - - return check(ip->proto, ip->invflags, multiinfo->flags, - multiinfo->count); -} - -static bool multiport_mt_check(const struct xt_mtchk_param *par) +static int multiport_mt_check(const struct xt_mtchk_param *par) { const struct ipt_ip *ip = par->entryinfo; const struct xt_multiport_v1 *multiinfo = par->matchinfo; return check(ip->proto, ip->invflags, multiinfo->flags, - multiinfo->count); + multiinfo->count) ? 0 : -EINVAL; } -static bool multiport_mt6_check_v0(const struct xt_mtchk_param *par) -{ - const struct ip6t_ip6 *ip = par->entryinfo; - const struct xt_multiport *multiinfo = par->matchinfo; - - return check(ip->proto, ip->invflags, multiinfo->flags, - multiinfo->count); -} - -static bool multiport_mt6_check(const struct xt_mtchk_param *par) +static int multiport_mt6_check(const struct xt_mtchk_param *par) { const struct ip6t_ip6 *ip = par->entryinfo; const struct xt_multiport_v1 *multiinfo = par->matchinfo; return check(ip->proto, ip->invflags, multiinfo->flags, - multiinfo->count); + multiinfo->count) ? 0 : -EINVAL; } static struct xt_match multiport_mt_reg[] __read_mostly = { { .name = "multiport", .family = NFPROTO_IPV4, - .revision = 0, - .checkentry = multiport_mt_check_v0, - .match = multiport_mt_v0, - .matchsize = sizeof(struct xt_multiport), - .me = THIS_MODULE, - }, - { - .name = "multiport", - .family = NFPROTO_IPV4, .revision = 1, .checkentry = multiport_mt_check, .match = multiport_mt, @@ -216,15 +142,6 @@ static struct xt_match multiport_mt_reg[] __read_mostly = { { .name = "multiport", .family = NFPROTO_IPV6, - .revision = 0, - .checkentry = multiport_mt6_check_v0, - .match = multiport_mt_v0, - .matchsize = sizeof(struct xt_multiport), - .me = THIS_MODULE, - }, - { - .name = "multiport", - .family = NFPROTO_IPV6, .revision = 1, .checkentry = multiport_mt6_check, .match = multiport_mt, diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 4169e200588d..4327e101c047 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/kernel.h> @@ -193,8 +193,8 @@ static inline int xt_osf_ttl(const struct sk_buff *skb, const struct xt_osf_info return ip->ttl == f_ttl; } -static bool xt_osf_match_packet(const struct sk_buff *skb, - const struct xt_match_param *p) +static bool +xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p) { const struct xt_osf_info *info = p->matchinfo; const struct iphdr *ip = ip_hdr(skb); @@ -382,14 +382,14 @@ static int __init xt_osf_init(void) err = nfnetlink_subsys_register(&xt_osf_nfnetlink); if (err < 0) { - printk(KERN_ERR "Failed (%d) to register OSF nsfnetlink helper.\n", err); + pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err); goto err_out_exit; } err = xt_register_match(&xt_osf_match); if (err) { - printk(KERN_ERR "Failed (%d) to register OS fingerprint " - "matching module.\n", err); + pr_err("Failed to register OS fingerprint " + "matching module (%d)\n", err); goto err_out_remove; } diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c index d24c76dffee2..772d7389b337 100644 --- a/net/netfilter/xt_owner.c +++ b/net/netfilter/xt_owner.c @@ -18,7 +18,7 @@ #include <linux/netfilter/xt_owner.h> static bool -owner_mt(const struct sk_buff *skb, const struct xt_match_param *par) +owner_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_owner_match_info *info = par->matchinfo; const struct file *filp; diff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c index 8d28ca5848bc..d7ca16b8b8df 100644 --- a/net/netfilter/xt_physdev.c +++ b/net/netfilter/xt_physdev.c @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter_bridge.h> @@ -22,7 +22,7 @@ MODULE_ALIAS("ip6t_physdev"); static bool -physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) +physdev_mt(const struct sk_buff *skb, struct xt_action_param *par) { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); const struct xt_physdev_info *info = par->matchinfo; @@ -83,25 +83,25 @@ match_outdev: return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); } -static bool physdev_mt_check(const struct xt_mtchk_param *par) +static int physdev_mt_check(const struct xt_mtchk_param *par) { const struct xt_physdev_info *info = par->matchinfo; if (!(info->bitmask & XT_PHYSDEV_OP_MASK) || info->bitmask & ~XT_PHYSDEV_OP_MASK) - return false; + return -EINVAL; if (info->bitmask & XT_PHYSDEV_OP_OUT && (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) || info->invert & XT_PHYSDEV_OP_BRIDGED) && par->hook_mask & ((1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) { - printk(KERN_WARNING "physdev match: using --physdev-out in the " - "OUTPUT, FORWARD and POSTROUTING chains for non-bridged " - "traffic is not supported anymore.\n"); + pr_info("using --physdev-out in the OUTPUT, FORWARD and " + "POSTROUTING chains for non-bridged traffic is not " + "supported anymore.\n"); if (par->hook_mask & (1 << NF_INET_LOCAL_OUT)) - return false; + return -EINVAL; } - return true; + return 0; } static struct xt_match physdev_mt_reg __read_mostly = { diff --git a/net/netfilter/xt_pkttype.c b/net/netfilter/xt_pkttype.c index 69da1d3a1d85..5b645cb598fc 100644 --- a/net/netfilter/xt_pkttype.c +++ b/net/netfilter/xt_pkttype.c @@ -23,7 +23,7 @@ MODULE_ALIAS("ipt_pkttype"); MODULE_ALIAS("ip6t_pkttype"); static bool -pkttype_mt(const struct sk_buff *skb, const struct xt_match_param *par) +pkttype_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_pkttype_info *info = par->matchinfo; u_int8_t type; diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c index 4cbfebda8fa1..f23e97bb42d7 100644 --- a/net/netfilter/xt_policy.c +++ b/net/netfilter/xt_policy.c @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/module.h> #include <linux/skbuff.h> @@ -110,15 +110,15 @@ match_policy_out(const struct sk_buff *skb, const struct xt_policy_info *info, } static bool -policy_mt(const struct sk_buff *skb, const struct xt_match_param *par) +policy_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_policy_info *info = par->matchinfo; int ret; if (info->flags & XT_POLICY_MATCH_IN) - ret = match_policy_in(skb, info, par->match->family); + ret = match_policy_in(skb, info, par->family); else - ret = match_policy_out(skb, info, par->match->family); + ret = match_policy_out(skb, info, par->family); if (ret < 0) ret = info->flags & XT_POLICY_MATCH_NONE ? true : false; @@ -128,32 +128,29 @@ policy_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ret; } -static bool policy_mt_check(const struct xt_mtchk_param *par) +static int policy_mt_check(const struct xt_mtchk_param *par) { const struct xt_policy_info *info = par->matchinfo; if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) { - printk(KERN_ERR "xt_policy: neither incoming nor " - "outgoing policy selected\n"); - return false; + pr_info("neither incoming nor outgoing policy selected\n"); + return -EINVAL; } if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) { - printk(KERN_ERR "xt_policy: output policy not valid in " - "PRE_ROUTING and INPUT\n"); - return false; + pr_info("output policy not valid in PREROUTING and INPUT\n"); + return -EINVAL; } if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) { - printk(KERN_ERR "xt_policy: input policy not valid in " - "POST_ROUTING and OUTPUT\n"); - return false; + pr_info("input policy not valid in POSTROUTING and OUTPUT\n"); + return -EINVAL; } if (info->len > XT_POLICY_MAX_ELEM) { - printk(KERN_ERR "xt_policy: too many policy elements\n"); - return false; + pr_info("too many policy elements\n"); + return -EINVAL; } - return true; + return 0; } static struct xt_match policy_mt_reg[] __read_mostly = { diff --git a/net/netfilter/xt_quota.c b/net/netfilter/xt_quota.c index 2d5562498c43..b4f7dfea5980 100644 --- a/net/netfilter/xt_quota.c +++ b/net/netfilter/xt_quota.c @@ -23,7 +23,7 @@ MODULE_ALIAS("ip6t_quota"); static DEFINE_SPINLOCK(quota_lock); static bool -quota_mt(const struct sk_buff *skb, const struct xt_match_param *par) +quota_mt(const struct sk_buff *skb, struct xt_action_param *par) { struct xt_quota_info *q = (void *)par->matchinfo; struct xt_quota_priv *priv = q->master; @@ -44,19 +44,19 @@ quota_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ret; } -static bool quota_mt_check(const struct xt_mtchk_param *par) +static int quota_mt_check(const struct xt_mtchk_param *par) { struct xt_quota_info *q = par->matchinfo; if (q->flags & ~XT_QUOTA_MASK) - return false; + return -EINVAL; q->master = kmalloc(sizeof(*q->master), GFP_KERNEL); if (q->master == NULL) - return false; + return -ENOMEM; q->master->quota = q->quota; - return true; + return 0; } static void quota_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c index 4fc6a917f6de..76a083184d8e 100644 --- a/net/netfilter/xt_rateest.c +++ b/net/netfilter/xt_rateest.c @@ -15,7 +15,7 @@ static bool -xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par) +xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_rateest_match_info *info = par->matchinfo; struct gnet_stats_rate_est *r; @@ -74,10 +74,11 @@ xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ret; } -static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) +static int xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) { struct xt_rateest_match_info *info = par->matchinfo; struct xt_rateest *est1, *est2; + int ret = false; if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | XT_RATEEST_MATCH_REL)) != 1) @@ -95,6 +96,7 @@ static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) goto err1; } + ret = -ENOENT; est1 = xt_rateest_lookup(info->name1); if (!est1) goto err1; @@ -109,12 +111,12 @@ static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par) info->est1 = est1; info->est2 = est2; - return true; + return 0; err2: xt_rateest_put(est1); err1: - return false; + return -EINVAL; } static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_realm.c b/net/netfilter/xt_realm.c index 484d1689bfde..459a7b256eb2 100644 --- a/net/netfilter/xt_realm.c +++ b/net/netfilter/xt_realm.c @@ -22,7 +22,7 @@ MODULE_DESCRIPTION("Xtables: Routing realm match"); MODULE_ALIAS("ipt_realm"); static bool -realm_mt(const struct sk_buff *skb, const struct xt_match_param *par) +realm_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_realm_info *info = par->matchinfo; const struct dst_entry *dst = skb_dst(skb); diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 834b736857cb..76aec6a44762 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -12,6 +12,7 @@ * Author: Stephen Frost <sfrost@snowman.net> * Copyright 2002-2003, Stephen Frost, 2.5.x port by laforge@netfilter.org */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> #include <linux/ip.h> #include <linux/ipv6.h> @@ -35,8 +36,8 @@ #include <linux/netfilter/xt_recent.h> MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); -MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>"); -MODULE_DESCRIPTION("Xtables: \"recently-seen\" host matching for IPv4"); +MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); +MODULE_DESCRIPTION("Xtables: \"recently-seen\" host matching"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_recent"); MODULE_ALIAS("ip6t_recent"); @@ -51,14 +52,14 @@ module_param(ip_list_tot, uint, 0400); module_param(ip_pkt_list_tot, uint, 0400); module_param(ip_list_hash_size, uint, 0400); module_param(ip_list_perms, uint, 0400); -module_param(ip_list_uid, uint, 0400); -module_param(ip_list_gid, uint, 0400); +module_param(ip_list_uid, uint, S_IRUGO | S_IWUSR); +module_param(ip_list_gid, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list"); MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)"); MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs"); MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files"); -MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/xt_recent/* files"); -MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/xt_recent/* files"); +MODULE_PARM_DESC(ip_list_uid, "default owner of /proc/net/xt_recent/* files"); +MODULE_PARM_DESC(ip_list_gid, "default owning group of /proc/net/xt_recent/* files"); struct recent_entry { struct list_head list; @@ -84,9 +85,6 @@ struct recent_net { struct list_head tables; #ifdef CONFIG_PROC_FS struct proc_dir_entry *xt_recent; -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - struct proc_dir_entry *ipt_recent; -#endif #endif }; @@ -147,6 +145,25 @@ static void recent_entry_remove(struct recent_table *t, struct recent_entry *e) t->entries--; } +/* + * Drop entries with timestamps older then 'time'. + */ +static void recent_entry_reap(struct recent_table *t, unsigned long time) +{ + struct recent_entry *e; + + /* + * The head of the LRU list is always the oldest entry. + */ + e = list_entry(t->lru_list.next, struct recent_entry, lru_list); + + /* + * The last time stamp is the most recent. + */ + if (time_after(time, e->stamps[e->index-1])) + recent_entry_remove(t, e); +} + static struct recent_entry * recent_entry_init(struct recent_table *t, const union nf_inet_addr *addr, u_int16_t family, u_int8_t ttl) @@ -207,7 +224,7 @@ static void recent_table_flush(struct recent_table *t) } static bool -recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) +recent_mt(const struct sk_buff *skb, struct xt_action_param *par) { struct net *net = dev_net(par->in ? par->in : par->out); struct recent_net *recent_net = recent_pernet(net); @@ -218,7 +235,7 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) u_int8_t ttl; bool ret = info->invert; - if (par->match->family == NFPROTO_IPV4) { + if (par->family == NFPROTO_IPV4) { const struct iphdr *iph = ip_hdr(skb); if (info->side == XT_RECENT_DEST) @@ -244,14 +261,14 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) spin_lock_bh(&recent_lock); t = recent_table_lookup(recent_net, info->name); - e = recent_entry_lookup(t, &addr, par->match->family, + e = recent_entry_lookup(t, &addr, par->family, (info->check_set & XT_RECENT_TTL) ? ttl : 0); if (e == NULL) { if (!(info->check_set & XT_RECENT_SET)) goto out; - e = recent_entry_init(t, &addr, par->match->family, ttl); + e = recent_entry_init(t, &addr, par->family, ttl); if (e == NULL) - *par->hotdrop = true; + par->hotdrop = true; ret = !ret; goto out; } @@ -273,6 +290,10 @@ recent_mt(const struct sk_buff *skb, const struct xt_match_param *par) break; } } + + /* info->seconds must be non-zero */ + if (info->check_set & XT_RECENT_REAP) + recent_entry_reap(t, time); } if (info->check_set & XT_RECENT_SET || @@ -285,7 +306,7 @@ out: return ret; } -static bool recent_mt_check(const struct xt_mtchk_param *par) +static int recent_mt_check(const struct xt_mtchk_param *par) { struct recent_net *recent_net = recent_pernet(par->net); const struct xt_recent_mtinfo *info = par->matchinfo; @@ -294,41 +315,51 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) struct proc_dir_entry *pde; #endif unsigned i; - bool ret = false; + int ret = -EINVAL; if (unlikely(!hash_rnd_inited)) { get_random_bytes(&hash_rnd, sizeof(hash_rnd)); hash_rnd_inited = true; } + if (info->check_set & ~XT_RECENT_VALID_FLAGS) { + pr_info("Unsupported user space flags (%08x)\n", + info->check_set); + return -EINVAL; + } if (hweight8(info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE | XT_RECENT_CHECK | XT_RECENT_UPDATE)) != 1) - return false; + return -EINVAL; if ((info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE)) && - (info->seconds || info->hit_count)) - return false; + (info->seconds || info->hit_count || + (info->check_set & XT_RECENT_MODIFIERS))) + return -EINVAL; + if ((info->check_set & XT_RECENT_REAP) && !info->seconds) + return -EINVAL; if (info->hit_count > ip_pkt_list_tot) { - pr_info(KBUILD_MODNAME ": hitcount (%u) is larger than " + pr_info("hitcount (%u) is larger than " "packets to be remembered (%u)\n", info->hit_count, ip_pkt_list_tot); - return false; + return -EINVAL; } if (info->name[0] == '\0' || strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) - return false; + return -EINVAL; mutex_lock(&recent_mutex); t = recent_table_lookup(recent_net, info->name); if (t != NULL) { t->refcnt++; - ret = true; + ret = 0; goto out; } t = kzalloc(sizeof(*t) + sizeof(t->iphash[0]) * ip_list_hash_size, GFP_KERNEL); - if (t == NULL) + if (t == NULL) { + ret = -ENOMEM; goto out; + } t->refcnt = 1; strcpy(t->name, info->name); INIT_LIST_HEAD(&t->lru_list); @@ -339,26 +370,16 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) &recent_mt_fops, t); if (pde == NULL) { kfree(t); - goto out; - } - pde->uid = ip_list_uid; - pde->gid = ip_list_gid; -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - pde = proc_create_data(t->name, ip_list_perms, recent_net->ipt_recent, - &recent_old_fops, t); - if (pde == NULL) { - remove_proc_entry(t->name, recent_net->xt_recent); - kfree(t); + ret = -ENOMEM; goto out; } pde->uid = ip_list_uid; pde->gid = ip_list_gid; #endif -#endif spin_lock_bh(&recent_lock); list_add_tail(&t->list, &recent_net->tables); spin_unlock_bh(&recent_lock); - ret = true; + ret = 0; out: mutex_unlock(&recent_mutex); return ret; @@ -377,9 +398,6 @@ static void recent_mt_destroy(const struct xt_mtdtor_param *par) list_del(&t->list); spin_unlock_bh(&recent_lock); #ifdef CONFIG_PROC_FS -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - remove_proc_entry(t->name, recent_net->ipt_recent); -#endif remove_proc_entry(t->name, recent_net->xt_recent); #endif recent_table_flush(t); @@ -471,84 +489,6 @@ static int recent_seq_open(struct inode *inode, struct file *file) return 0; } -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT -static int recent_old_seq_open(struct inode *inode, struct file *filp) -{ - static bool warned_of_old; - - if (unlikely(!warned_of_old)) { - printk(KERN_INFO KBUILD_MODNAME ": Use of /proc/net/ipt_recent" - " is deprecated; use /proc/net/xt_recent.\n"); - warned_of_old = true; - } - return recent_seq_open(inode, filp); -} - -static ssize_t recent_old_proc_write(struct file *file, - const char __user *input, - size_t size, loff_t *loff) -{ - const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); - struct recent_table *t = pde->data; - struct recent_entry *e; - char buf[sizeof("+255.255.255.255")], *c = buf; - union nf_inet_addr addr = {}; - int add; - - if (size > sizeof(buf)) - size = sizeof(buf); - if (copy_from_user(buf, input, size)) - return -EFAULT; - - c = skip_spaces(c); - - if (size - (c - buf) < 5) - return c - buf; - if (!strncmp(c, "clear", 5)) { - c += 5; - spin_lock_bh(&recent_lock); - recent_table_flush(t); - spin_unlock_bh(&recent_lock); - return c - buf; - } - - switch (*c) { - case '-': - add = 0; - c++; - break; - case '+': - c++; - default: - add = 1; - break; - } - addr.ip = in_aton(c); - - spin_lock_bh(&recent_lock); - e = recent_entry_lookup(t, &addr, NFPROTO_IPV4, 0); - if (e == NULL) { - if (add) - recent_entry_init(t, &addr, NFPROTO_IPV4, 0); - } else { - if (add) - recent_entry_update(t, e); - else - recent_entry_remove(t, e); - } - spin_unlock_bh(&recent_lock); - return size; -} - -static const struct file_operations recent_old_fops = { - .open = recent_old_seq_open, - .read = seq_read, - .write = recent_old_proc_write, - .release = seq_release_private, - .owner = THIS_MODULE, -}; -#endif - static ssize_t recent_mt_proc_write(struct file *file, const char __user *input, size_t size, loff_t *loff) @@ -585,7 +525,7 @@ recent_mt_proc_write(struct file *file, const char __user *input, add = true; break; default: - printk(KERN_INFO KBUILD_MODNAME ": Need +ip, -ip or /\n"); + pr_info("Need \"+ip\", \"-ip\" or \"/\"\n"); return -EINVAL; } @@ -600,8 +540,7 @@ recent_mt_proc_write(struct file *file, const char __user *input, } if (!succ) { - printk(KERN_INFO KBUILD_MODNAME ": illegal address written " - "to procfs\n"); + pr_info("illegal address written to procfs\n"); return -EINVAL; } @@ -637,21 +576,11 @@ static int __net_init recent_proc_net_init(struct net *net) recent_net->xt_recent = proc_mkdir("xt_recent", net->proc_net); if (!recent_net->xt_recent) return -ENOMEM; -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - recent_net->ipt_recent = proc_mkdir("ipt_recent", net->proc_net); - if (!recent_net->ipt_recent) { - proc_net_remove(net, "xt_recent"); - return -ENOMEM; - } -#endif return 0; } static void __net_exit recent_proc_net_exit(struct net *net) { -#ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - proc_net_remove(net, "ipt_recent"); -#endif proc_net_remove(net, "xt_recent"); } #else diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index a189ada9128f..c04fcf385c59 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c @@ -1,3 +1,4 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <net/ip.h> @@ -15,12 +16,6 @@ MODULE_DESCRIPTION("Xtables: SCTP protocol packet match"); MODULE_ALIAS("ipt_sctp"); MODULE_ALIAS("ip6t_sctp"); -#ifdef DEBUG_SCTP -#define duprintf(format, args...) printk(format , ## args) -#else -#define duprintf(format, args...) -#endif - #define SCCHECK(cond, option, flag, invflag) (!((flag) & (option)) \ || (!!((invflag) & (option)) ^ (cond))) @@ -52,7 +47,7 @@ match_packet(const struct sk_buff *skb, const struct xt_sctp_flag_info *flag_info = info->flag_info; int flag_count = info->flag_count; -#ifdef DEBUG_SCTP +#ifdef DEBUG int i = 0; #endif @@ -62,17 +57,19 @@ match_packet(const struct sk_buff *skb, do { sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch); if (sch == NULL || sch->length == 0) { - duprintf("Dropping invalid SCTP packet.\n"); + pr_debug("Dropping invalid SCTP packet.\n"); *hotdrop = true; return false; } - - duprintf("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d\tflags: %x\n", - ++i, offset, sch->type, htons(sch->length), sch->flags); - +#ifdef DEBUG + pr_debug("Chunk num: %d\toffset: %d\ttype: %d\tlength: %d" + "\tflags: %x\n", + ++i, offset, sch->type, htons(sch->length), + sch->flags); +#endif offset += (ntohs(sch->length) + 3) & ~3; - duprintf("skb->len: %d\toffset: %d\n", skb->len, offset); + pr_debug("skb->len: %d\toffset: %d\n", skb->len, offset); if (SCTP_CHUNKMAP_IS_SET(info->chunkmap, sch->type)) { switch (chunk_match_type) { @@ -117,24 +114,24 @@ match_packet(const struct sk_buff *skb, } static bool -sctp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +sctp_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_sctp_info *info = par->matchinfo; const sctp_sctphdr_t *sh; sctp_sctphdr_t _sh; if (par->fragoff != 0) { - duprintf("Dropping non-first fragment.. FIXME\n"); + pr_debug("Dropping non-first fragment.. FIXME\n"); return false; } sh = skb_header_pointer(skb, par->thoff, sizeof(_sh), &_sh); if (sh == NULL) { - duprintf("Dropping evil TCP offset=0 tinygram.\n"); - *par->hotdrop = true; + pr_debug("Dropping evil TCP offset=0 tinygram.\n"); + par->hotdrop = true; return false; } - duprintf("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest)); + pr_debug("spt: %d\tdpt: %d\n", ntohs(sh->source), ntohs(sh->dest)); return SCCHECK(ntohs(sh->source) >= info->spts[0] && ntohs(sh->source) <= info->spts[1], @@ -143,22 +140,26 @@ sctp_mt(const struct sk_buff *skb, const struct xt_match_param *par) && ntohs(sh->dest) <= info->dpts[1], XT_SCTP_DEST_PORTS, info->flags, info->invflags) && SCCHECK(match_packet(skb, par->thoff + sizeof(sctp_sctphdr_t), - info, par->hotdrop), + info, &par->hotdrop), XT_SCTP_CHUNK_TYPES, info->flags, info->invflags); } -static bool sctp_mt_check(const struct xt_mtchk_param *par) +static int sctp_mt_check(const struct xt_mtchk_param *par) { const struct xt_sctp_info *info = par->matchinfo; - return !(info->flags & ~XT_SCTP_VALID_FLAGS) - && !(info->invflags & ~XT_SCTP_VALID_FLAGS) - && !(info->invflags & ~info->flags) - && ((!(info->flags & XT_SCTP_CHUNK_TYPES)) || - (info->chunk_match_type & - (SCTP_CHUNK_MATCH_ALL - | SCTP_CHUNK_MATCH_ANY - | SCTP_CHUNK_MATCH_ONLY))); + if (info->flags & ~XT_SCTP_VALID_FLAGS) + return -EINVAL; + if (info->invflags & ~XT_SCTP_VALID_FLAGS) + return -EINVAL; + if (info->invflags & ~info->flags) + return -EINVAL; + if (!(info->flags & XT_SCTP_CHUNK_TYPES)) + return 0; + if (info->chunk_match_type & (SCTP_CHUNK_MATCH_ALL | + SCTP_CHUNK_MATCH_ANY | SCTP_CHUNK_MATCH_ONLY)) + return 0; + return -EINVAL; } static struct xt_match sctp_mt_reg[] __read_mostly = { diff --git a/net/netfilter/xt_socket.c b/net/netfilter/xt_socket.c index 6a902564d24f..3d54c236a1ba 100644 --- a/net/netfilter/xt_socket.c +++ b/net/netfilter/xt_socket.c @@ -9,7 +9,7 @@ * published by the Free Software Foundation. * */ - +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netfilter/x_tables.h> @@ -88,7 +88,7 @@ extract_icmp_fields(const struct sk_buff *skb, static bool -socket_match(const struct sk_buff *skb, const struct xt_match_param *par, +socket_match(const struct sk_buff *skb, struct xt_action_param *par, const struct xt_socket_mtinfo1 *info) { const struct iphdr *iph = ip_hdr(skb); @@ -165,8 +165,7 @@ socket_match(const struct sk_buff *skb, const struct xt_match_param *par, sk = NULL; } - pr_debug("socket match: proto %u %08x:%u -> %08x:%u " - "(orig %08x:%u) sock %p\n", + pr_debug("proto %u %08x:%u -> %08x:%u (orig %08x:%u) sock %p\n", protocol, ntohl(saddr), ntohs(sport), ntohl(daddr), ntohs(dport), ntohl(iph->daddr), hp ? ntohs(hp->dest) : 0, sk); @@ -175,13 +174,13 @@ socket_match(const struct sk_buff *skb, const struct xt_match_param *par, } static bool -socket_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) +socket_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) { return socket_match(skb, par, NULL); } static bool -socket_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) +socket_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) { return socket_match(skb, par, par->matchinfo); } diff --git a/net/netfilter/xt_state.c b/net/netfilter/xt_state.c index 4c946cbd731f..e12e053d3782 100644 --- a/net/netfilter/xt_state.c +++ b/net/netfilter/xt_state.c @@ -21,7 +21,7 @@ MODULE_ALIAS("ipt_state"); MODULE_ALIAS("ip6t_state"); static bool -state_mt(const struct sk_buff *skb, const struct xt_match_param *par) +state_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_state_info *sinfo = par->matchinfo; enum ip_conntrack_info ctinfo; @@ -37,50 +37,40 @@ state_mt(const struct sk_buff *skb, const struct xt_match_param *par) return (sinfo->statemask & statebit); } -static bool state_mt_check(const struct xt_mtchk_param *par) +static int state_mt_check(const struct xt_mtchk_param *par) { - if (nf_ct_l3proto_try_module_get(par->match->family) < 0) { - printk(KERN_WARNING "can't load conntrack support for " - "proto=%u\n", par->match->family); - return false; - } - return true; + int ret; + + ret = nf_ct_l3proto_try_module_get(par->family); + if (ret < 0) + pr_info("cannot load conntrack support for proto=%u\n", + par->family); + return ret; } static void state_mt_destroy(const struct xt_mtdtor_param *par) { - nf_ct_l3proto_module_put(par->match->family); + nf_ct_l3proto_module_put(par->family); } -static struct xt_match state_mt_reg[] __read_mostly = { - { - .name = "state", - .family = NFPROTO_IPV4, - .checkentry = state_mt_check, - .match = state_mt, - .destroy = state_mt_destroy, - .matchsize = sizeof(struct xt_state_info), - .me = THIS_MODULE, - }, - { - .name = "state", - .family = NFPROTO_IPV6, - .checkentry = state_mt_check, - .match = state_mt, - .destroy = state_mt_destroy, - .matchsize = sizeof(struct xt_state_info), - .me = THIS_MODULE, - }, +static struct xt_match state_mt_reg __read_mostly = { + .name = "state", + .family = NFPROTO_UNSPEC, + .checkentry = state_mt_check, + .match = state_mt, + .destroy = state_mt_destroy, + .matchsize = sizeof(struct xt_state_info), + .me = THIS_MODULE, }; static int __init state_mt_init(void) { - return xt_register_matches(state_mt_reg, ARRAY_SIZE(state_mt_reg)); + return xt_register_match(&state_mt_reg); } static void __exit state_mt_exit(void) { - xt_unregister_matches(state_mt_reg, ARRAY_SIZE(state_mt_reg)); + xt_unregister_match(&state_mt_reg); } module_init(state_mt_init); diff --git a/net/netfilter/xt_statistic.c b/net/netfilter/xt_statistic.c index 937ce0633e99..96e62b8fd6b1 100644 --- a/net/netfilter/xt_statistic.c +++ b/net/netfilter/xt_statistic.c @@ -30,7 +30,7 @@ MODULE_ALIAS("ip6t_statistic"); static DEFINE_SPINLOCK(nth_lock); static bool -statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) +statistic_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_statistic_info *info = par->matchinfo; bool ret = info->flags & XT_STATISTIC_INVERT; @@ -53,22 +53,20 @@ statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ret; } -static bool statistic_mt_check(const struct xt_mtchk_param *par) +static int statistic_mt_check(const struct xt_mtchk_param *par) { struct xt_statistic_info *info = par->matchinfo; if (info->mode > XT_STATISTIC_MODE_MAX || info->flags & ~XT_STATISTIC_MASK) - return false; + return -EINVAL; info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); - if (info->master == NULL) { - printk(KERN_ERR KBUILD_MODNAME ": Out of memory\n"); - return false; - } + if (info->master == NULL) + return -ENOMEM; info->master->count = info->u.nth.count; - return true; + return 0; } static void statistic_mt_destroy(const struct xt_mtdtor_param *par) diff --git a/net/netfilter/xt_string.c b/net/netfilter/xt_string.c index 96801ffd8af8..d3c48b14ab94 100644 --- a/net/netfilter/xt_string.c +++ b/net/netfilter/xt_string.c @@ -23,16 +23,14 @@ MODULE_ALIAS("ipt_string"); MODULE_ALIAS("ip6t_string"); static bool -string_mt(const struct sk_buff *skb, const struct xt_match_param *par) +string_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_string_info *conf = par->matchinfo; struct ts_state state; - int invert; + bool invert; memset(&state, 0, sizeof(struct ts_state)); - - invert = (par->match->revision == 0 ? conf->u.v0.invert : - conf->u.v1.flags & XT_STRING_FLAG_INVERT); + invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT; return (skb_find_text((struct sk_buff *)skb, conf->from_offset, conf->to_offset, conf->config, &state) @@ -41,7 +39,7 @@ string_mt(const struct sk_buff *skb, const struct xt_match_param *par) #define STRING_TEXT_PRIV(m) ((struct xt_string_info *)(m)) -static bool string_mt_check(const struct xt_mtchk_param *par) +static int string_mt_check(const struct xt_mtchk_param *par) { struct xt_string_info *conf = par->matchinfo; struct ts_config *ts_conf; @@ -49,26 +47,23 @@ static bool string_mt_check(const struct xt_mtchk_param *par) /* Damn, can't handle this case properly with iptables... */ if (conf->from_offset > conf->to_offset) - return false; + return -EINVAL; if (conf->algo[XT_STRING_MAX_ALGO_NAME_SIZE - 1] != '\0') - return false; + return -EINVAL; if (conf->patlen > XT_STRING_MAX_PATTERN_SIZE) - return false; - if (par->match->revision == 1) { - if (conf->u.v1.flags & - ~(XT_STRING_FLAG_IGNORECASE | XT_STRING_FLAG_INVERT)) - return false; - if (conf->u.v1.flags & XT_STRING_FLAG_IGNORECASE) - flags |= TS_IGNORECASE; - } + return -EINVAL; + if (conf->u.v1.flags & + ~(XT_STRING_FLAG_IGNORECASE | XT_STRING_FLAG_INVERT)) + return -EINVAL; + if (conf->u.v1.flags & XT_STRING_FLAG_IGNORECASE) + flags |= TS_IGNORECASE; ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen, GFP_KERNEL, flags); if (IS_ERR(ts_conf)) - return false; + return PTR_ERR(ts_conf); conf->config = ts_conf; - - return true; + return 0; } static void string_mt_destroy(const struct xt_mtdtor_param *par) @@ -76,38 +71,25 @@ static void string_mt_destroy(const struct xt_mtdtor_param *par) textsearch_destroy(STRING_TEXT_PRIV(par->matchinfo)->config); } -static struct xt_match xt_string_mt_reg[] __read_mostly = { - { - .name = "string", - .revision = 0, - .family = NFPROTO_UNSPEC, - .checkentry = string_mt_check, - .match = string_mt, - .destroy = string_mt_destroy, - .matchsize = sizeof(struct xt_string_info), - .me = THIS_MODULE - }, - { - .name = "string", - .revision = 1, - .family = NFPROTO_UNSPEC, - .checkentry = string_mt_check, - .match = string_mt, - .destroy = string_mt_destroy, - .matchsize = sizeof(struct xt_string_info), - .me = THIS_MODULE - }, +static struct xt_match xt_string_mt_reg __read_mostly = { + .name = "string", + .revision = 1, + .family = NFPROTO_UNSPEC, + .checkentry = string_mt_check, + .match = string_mt, + .destroy = string_mt_destroy, + .matchsize = sizeof(struct xt_string_info), + .me = THIS_MODULE, }; static int __init string_mt_init(void) { - return xt_register_matches(xt_string_mt_reg, - ARRAY_SIZE(xt_string_mt_reg)); + return xt_register_match(&xt_string_mt_reg); } static void __exit string_mt_exit(void) { - xt_unregister_matches(xt_string_mt_reg, ARRAY_SIZE(xt_string_mt_reg)); + xt_unregister_match(&xt_string_mt_reg); } module_init(string_mt_init); diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index 4809b34b10f8..c53d4d18eadf 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c @@ -25,7 +25,7 @@ MODULE_ALIAS("ipt_tcpmss"); MODULE_ALIAS("ip6t_tcpmss"); static bool -tcpmss_mt(const struct sk_buff *skb, const struct xt_match_param *par) +tcpmss_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_tcpmss_match_info *info = par->matchinfo; const struct tcphdr *th; @@ -73,7 +73,7 @@ out: return info->invert; dropit: - *par->hotdrop = true; + par->hotdrop = true; return false; } diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index 1ebdc4934eed..c14d4645daa3 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c @@ -1,3 +1,4 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/types.h> #include <linux/module.h> #include <net/ip.h> @@ -19,13 +20,6 @@ MODULE_ALIAS("ipt_tcp"); MODULE_ALIAS("ip6t_udp"); MODULE_ALIAS("ip6t_tcp"); -#ifdef DEBUG_IP_FIREWALL_USER -#define duprintf(format, args...) printk(format , ## args) -#else -#define duprintf(format, args...) -#endif - - /* Returns 1 if the port is matched by the range, 0 otherwise */ static inline bool port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert) @@ -46,7 +40,7 @@ tcp_find_option(u_int8_t option, u_int8_t _opt[60 - sizeof(struct tcphdr)]; unsigned int i; - duprintf("tcp_match: finding option\n"); + pr_debug("finding option\n"); if (!optlen) return invert; @@ -68,7 +62,7 @@ tcp_find_option(u_int8_t option, return invert; } -static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct tcphdr *th; struct tcphdr _tcph; @@ -82,8 +76,8 @@ static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par) flag overwrite to pass the direction checks. */ if (par->fragoff == 1) { - duprintf("Dropping evil TCP offset=1 frag.\n"); - *par->hotdrop = true; + pr_debug("Dropping evil TCP offset=1 frag.\n"); + par->hotdrop = true; } /* Must not be a fragment. */ return false; @@ -95,8 +89,8 @@ static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (th == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ - duprintf("Dropping evil TCP offset=0 tinygram.\n"); - *par->hotdrop = true; + pr_debug("Dropping evil TCP offset=0 tinygram.\n"); + par->hotdrop = true; return false; } @@ -114,27 +108,27 @@ static bool tcp_mt(const struct sk_buff *skb, const struct xt_match_param *par) return false; if (tcpinfo->option) { if (th->doff * 4 < sizeof(_tcph)) { - *par->hotdrop = true; + par->hotdrop = true; return false; } if (!tcp_find_option(tcpinfo->option, skb, par->thoff, th->doff*4 - sizeof(_tcph), tcpinfo->invflags & XT_TCP_INV_OPTION, - par->hotdrop)) + &par->hotdrop)) return false; } return true; } -static bool tcp_mt_check(const struct xt_mtchk_param *par) +static int tcp_mt_check(const struct xt_mtchk_param *par) { const struct xt_tcp *tcpinfo = par->matchinfo; /* Must specify no unknown invflags */ - return !(tcpinfo->invflags & ~XT_TCP_INV_MASK); + return (tcpinfo->invflags & ~XT_TCP_INV_MASK) ? -EINVAL : 0; } -static bool udp_mt(const struct sk_buff *skb, const struct xt_match_param *par) +static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct udphdr *uh; struct udphdr _udph; @@ -148,8 +142,8 @@ static bool udp_mt(const struct sk_buff *skb, const struct xt_match_param *par) if (uh == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ - duprintf("Dropping evil UDP tinygram.\n"); - *par->hotdrop = true; + pr_debug("Dropping evil UDP tinygram.\n"); + par->hotdrop = true; return false; } @@ -161,12 +155,12 @@ static bool udp_mt(const struct sk_buff *skb, const struct xt_match_param *par) !!(udpinfo->invflags & XT_UDP_INV_DSTPT)); } -static bool udp_mt_check(const struct xt_mtchk_param *par) +static int udp_mt_check(const struct xt_mtchk_param *par) { const struct xt_udp *udpinfo = par->matchinfo; /* Must specify no unknown invflags */ - return !(udpinfo->invflags & ~XT_UDP_INV_MASK); + return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0; } static struct xt_match tcpudp_mt_reg[] __read_mostly = { diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c index 93acaa59d108..c48975ff8ea2 100644 --- a/net/netfilter/xt_time.c +++ b/net/netfilter/xt_time.c @@ -1,7 +1,6 @@ /* * xt_time * Copyright © CC Computer Consultants GmbH, 2007 - * Contact: <jengelh@computergmbh.de> * * based on ipt_time by Fabrice MARIE <fabrice@netfilter.org> * This is a module which is used for time matching @@ -149,11 +148,10 @@ static void localtime_3(struct xtm *r, time_t time) } r->month = i + 1; - return; } static bool -time_mt(const struct sk_buff *skb, const struct xt_match_param *par) +time_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_time_info *info = par->matchinfo; unsigned int packet_time; @@ -218,18 +216,18 @@ time_mt(const struct sk_buff *skb, const struct xt_match_param *par) return true; } -static bool time_mt_check(const struct xt_mtchk_param *par) +static int time_mt_check(const struct xt_mtchk_param *par) { const struct xt_time_info *info = par->matchinfo; if (info->daytime_start > XT_TIME_MAX_DAYTIME || info->daytime_stop > XT_TIME_MAX_DAYTIME) { - printk(KERN_WARNING "xt_time: invalid argument - start or " - "stop time greater than 23:59:59\n"); - return false; + pr_info("invalid argument - start or " + "stop time greater than 23:59:59\n"); + return -EDOM; } - return true; + return 0; } static struct xt_match xt_time_mt_reg __read_mostly = { @@ -264,7 +262,7 @@ static void __exit time_mt_exit(void) module_init(time_mt_init); module_exit(time_mt_exit); -MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>"); +MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); MODULE_DESCRIPTION("Xtables: time-based matching"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_time"); diff --git a/net/netfilter/xt_u32.c b/net/netfilter/xt_u32.c index 24a527624500..a95b50342dbb 100644 --- a/net/netfilter/xt_u32.c +++ b/net/netfilter/xt_u32.c @@ -3,7 +3,6 @@ * * Original author: Don Cohen <don@isis.cs3-inc.com> * (C) CC Computer Consultants GmbH, 2007 - * Contact: <jengelh@computergmbh.de> */ #include <linux/module.h> @@ -87,7 +86,7 @@ static bool u32_match_it(const struct xt_u32 *data, return true; } -static bool u32_mt(const struct sk_buff *skb, const struct xt_match_param *par) +static bool u32_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_u32 *data = par->matchinfo; bool ret; @@ -117,7 +116,7 @@ static void __exit u32_mt_exit(void) module_init(u32_mt_init); module_exit(u32_mt_exit); -MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>"); +MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); MODULE_DESCRIPTION("Xtables: arbitrary byte matching"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_u32"); |