aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-10-05 21:32:37 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-05 21:32:37 -0400
commit61b37d2f54961b336a47a501e797a05df20c3b30 (patch)
treed2b629be3e30ba71ba86573a72a4036b777e106f /net/ipv6
parentad9eef52085c5c6047e44705806a1b5b14b7f476 (diff)
parent8da4cc1b10c1aeba090d1d862b17174e4dbd50a4 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== Netfilter/IPVS updates for net-next The following patchset contains another batch with Netfilter/IPVS updates for net-next, they are: 1) Add abstracted ICMP codes to the nf_tables reject expression. We introduce four reasons to reject using ICMP that overlap in IPv4 and IPv6 from the semantic point of view. This should simplify the maintainance of dual stack rule-sets through the inet table. 2) Move nf_send_reset() functions from header files to per-family nf_reject modules, suggested by Patrick McHardy. 3) We have to use IS_ENABLED(CONFIG_BRIDGE_NETFILTER) everywhere in the code now that br_netfilter can be modularized. Convert remaining spots in the network stack code. 4) Use rcu_barrier() in the nf_tables module removal path to ensure that we don't leave object that are still pending to be released via call_rcu (that may likely result in a crash). 5) Remove incomplete arch 32/64 compat from nft_compat. The original (bad) idea was to probe the word size based on the xtables match/target info size, but this assumption is wrong when you have to dump the information back to userspace. 6) Allow to filter from prerouting and postrouting in the nf_tables bridge. In order to emulate the ebtables NAT chains (which are actually simple filter chains with no special semantics), we have support filtering from this hooks too. 7) Add explicit module dependency between xt_physdev and br_netfilter. This provides a way to detect if the user needs br_netfilter from the configuration path. This should reduce the breakage of the br_netfilter modularization. 8) Cleanup coding style in ip_vs.h, from Simon Horman. 9) Fix crash in the recently added nf_tables masq expression. We have to register/unregister the notifiers to clean up the conntrack table entries from the module init/exit path, not from the rule addition / deletion path. From Arturo Borrero. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/netfilter/Kconfig6
-rw-r--r--net/ipv6/netfilter/Makefile3
-rw-r--r--net/ipv6/netfilter/nf_defrag_ipv6_hooks.c2
-rw-r--r--net/ipv6/netfilter/nf_reject_ipv6.c163
-rw-r--r--net/ipv6/netfilter/nft_masq_ipv6.c34
5 files changed, 184 insertions, 24 deletions
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index bb1a40db7be1..6af874fc187f 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -40,8 +40,13 @@ config NFT_CHAIN_ROUTE_IPV6
40 fields such as the source, destination, flowlabel, hop-limit and 40 fields such as the source, destination, flowlabel, hop-limit and
41 the packet mark. 41 the packet mark.
42 42
43config NF_REJECT_IPV6
44 tristate "IPv6 packet rejection"
45 default m if NETFILTER_ADVANCED=n
46
43config NFT_REJECT_IPV6 47config NFT_REJECT_IPV6
44 depends on NF_TABLES_IPV6 48 depends on NF_TABLES_IPV6
49 select NF_REJECT_IPV6
45 default NFT_REJECT 50 default NFT_REJECT
46 tristate 51 tristate
47 52
@@ -208,6 +213,7 @@ config IP6_NF_FILTER
208config IP6_NF_TARGET_REJECT 213config IP6_NF_TARGET_REJECT
209 tristate "REJECT target support" 214 tristate "REJECT target support"
210 depends on IP6_NF_FILTER 215 depends on IP6_NF_FILTER
216 select NF_REJECT_IPV6
211 default m if NETFILTER_ADVANCED=n 217 default m if NETFILTER_ADVANCED=n
212 help 218 help
213 The REJECT target allows a filtering rule to specify that an ICMPv6 219 The REJECT target allows a filtering rule to specify that an ICMPv6
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index 0f7e5b3f328d..fbb25f01143c 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -27,6 +27,9 @@ obj-$(CONFIG_NF_DEFRAG_IPV6) += nf_defrag_ipv6.o
27# logging 27# logging
28obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o 28obj-$(CONFIG_NF_LOG_IPV6) += nf_log_ipv6.o
29 29
30# reject
31obj-$(CONFIG_NF_REJECT_IPV6) += nf_reject_ipv6.o
32
30# nf_tables 33# nf_tables
31obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o 34obj-$(CONFIG_NF_TABLES_IPV6) += nf_tables_ipv6.o
32obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o 35obj-$(CONFIG_NFT_CHAIN_ROUTE_IPV6) += nft_chain_route_ipv6.o
diff --git a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
index 7b9a748c6bac..e70382e4dfb5 100644
--- a/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
+++ b/net/ipv6/netfilter/nf_defrag_ipv6_hooks.c
@@ -40,7 +40,7 @@ static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
40 zone = nf_ct_zone((struct nf_conn *)skb->nfct); 40 zone = nf_ct_zone((struct nf_conn *)skb->nfct);
41#endif 41#endif
42 42
43#ifdef CONFIG_BRIDGE_NETFILTER 43#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
44 if (skb->nf_bridge && 44 if (skb->nf_bridge &&
45 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING) 45 skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
46 return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone; 46 return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c
new file mode 100644
index 000000000000..5f5f0438d74d
--- /dev/null
+++ b/net/ipv6/netfilter/nf_reject_ipv6.c
@@ -0,0 +1,163 @@
1/* (C) 1999-2001 Paul `Rusty' Russell
2 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8#include <net/ipv6.h>
9#include <net/ip6_route.h>
10#include <net/ip6_fib.h>
11#include <net/ip6_checksum.h>
12#include <linux/netfilter_ipv6.h>
13
14void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
15{
16 struct sk_buff *nskb;
17 struct tcphdr otcph, *tcph;
18 unsigned int otcplen, hh_len;
19 int tcphoff, needs_ack;
20 const struct ipv6hdr *oip6h = ipv6_hdr(oldskb);
21 struct ipv6hdr *ip6h;
22#define DEFAULT_TOS_VALUE 0x0U
23 const __u8 tclass = DEFAULT_TOS_VALUE;
24 struct dst_entry *dst = NULL;
25 u8 proto;
26 __be16 frag_off;
27 struct flowi6 fl6;
28
29 if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) ||
30 (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) {
31 pr_debug("addr is not unicast.\n");
32 return;
33 }
34
35 proto = oip6h->nexthdr;
36 tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off);
37
38 if ((tcphoff < 0) || (tcphoff > oldskb->len)) {
39 pr_debug("Cannot get TCP header.\n");
40 return;
41 }
42
43 otcplen = oldskb->len - tcphoff;
44
45 /* IP header checks: fragment, too short. */
46 if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) {
47 pr_debug("proto(%d) != IPPROTO_TCP, "
48 "or too short. otcplen = %d\n",
49 proto, otcplen);
50 return;
51 }
52
53 if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr)))
54 BUG();
55
56 /* No RST for RST. */
57 if (otcph.rst) {
58 pr_debug("RST is set\n");
59 return;
60 }
61
62 /* Check checksum. */
63 if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) {
64 pr_debug("TCP checksum is invalid\n");
65 return;
66 }
67
68 memset(&fl6, 0, sizeof(fl6));
69 fl6.flowi6_proto = IPPROTO_TCP;
70 fl6.saddr = oip6h->daddr;
71 fl6.daddr = oip6h->saddr;
72 fl6.fl6_sport = otcph.dest;
73 fl6.fl6_dport = otcph.source;
74 security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
75 dst = ip6_route_output(net, NULL, &fl6);
76 if (dst == NULL || dst->error) {
77 dst_release(dst);
78 return;
79 }
80 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0);
81 if (IS_ERR(dst))
82 return;
83
84 hh_len = (dst->dev->hard_header_len + 15)&~15;
85 nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr)
86 + sizeof(struct tcphdr) + dst->trailer_len,
87 GFP_ATOMIC);
88
89 if (!nskb) {
90 net_dbg_ratelimited("cannot alloc skb\n");
91 dst_release(dst);
92 return;
93 }
94
95 skb_dst_set(nskb, dst);
96
97 skb_reserve(nskb, hh_len + dst->header_len);
98
99 skb_put(nskb, sizeof(struct ipv6hdr));
100 skb_reset_network_header(nskb);
101 ip6h = ipv6_hdr(nskb);
102 ip6_flow_hdr(ip6h, tclass, 0);
103 ip6h->hop_limit = ip6_dst_hoplimit(dst);
104 ip6h->nexthdr = IPPROTO_TCP;
105 ip6h->saddr = oip6h->daddr;
106 ip6h->daddr = oip6h->saddr;
107
108 skb_reset_transport_header(nskb);
109 tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
110 /* Truncate to length (no data) */
111 tcph->doff = sizeof(struct tcphdr)/4;
112 tcph->source = otcph.dest;
113 tcph->dest = otcph.source;
114
115 if (otcph.ack) {
116 needs_ack = 0;
117 tcph->seq = otcph.ack_seq;
118 tcph->ack_seq = 0;
119 } else {
120 needs_ack = 1;
121 tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
122 + otcplen - (otcph.doff<<2));
123 tcph->seq = 0;
124 }
125
126 /* Reset flags */
127 ((u_int8_t *)tcph)[13] = 0;
128 tcph->rst = 1;
129 tcph->ack = needs_ack;
130 tcph->window = 0;
131 tcph->urg_ptr = 0;
132 tcph->check = 0;
133
134 /* Adjust TCP checksum */
135 tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr,
136 &ipv6_hdr(nskb)->daddr,
137 sizeof(struct tcphdr), IPPROTO_TCP,
138 csum_partial(tcph,
139 sizeof(struct tcphdr), 0));
140
141 nf_ct_attach(nskb, oldskb);
142
143#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
144 /* If we use ip6_local_out for bridged traffic, the MAC source on
145 * the RST will be ours, instead of the destination's. This confuses
146 * some routers/firewalls, and they drop the packet. So we need to
147 * build the eth header using the original destination's MAC as the
148 * source, and send the RST packet directly.
149 */
150 if (oldskb->nf_bridge) {
151 struct ethhdr *oeth = eth_hdr(oldskb);
152 nskb->dev = oldskb->nf_bridge->physindev;
153 nskb->protocol = htons(ETH_P_IPV6);
154 ip6h->payload_len = htons(sizeof(struct tcphdr));
155 if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
156 oeth->h_source, oeth->h_dest, nskb->len) < 0)
157 return;
158 dev_queue_xmit(nskb);
159 } else
160#endif
161 ip6_local_out(nskb);
162}
163EXPORT_SYMBOL_GPL(nf_send_reset6);
diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c
index 4e51334ef6b7..556262f40761 100644
--- a/net/ipv6/netfilter/nft_masq_ipv6.c
+++ b/net/ipv6/netfilter/nft_masq_ipv6.c
@@ -32,33 +32,12 @@ static void nft_masq_ipv6_eval(const struct nft_expr *expr,
32 data[NFT_REG_VERDICT].verdict = verdict; 32 data[NFT_REG_VERDICT].verdict = verdict;
33} 33}
34 34
35static int nft_masq_ipv6_init(const struct nft_ctx *ctx,
36 const struct nft_expr *expr,
37 const struct nlattr * const tb[])
38{
39 int err;
40
41 err = nft_masq_init(ctx, expr, tb);
42 if (err < 0)
43 return err;
44
45 nf_nat_masquerade_ipv6_register_notifier();
46 return 0;
47}
48
49static void nft_masq_ipv6_destroy(const struct nft_ctx *ctx,
50 const struct nft_expr *expr)
51{
52 nf_nat_masquerade_ipv6_unregister_notifier();
53}
54
55static struct nft_expr_type nft_masq_ipv6_type; 35static struct nft_expr_type nft_masq_ipv6_type;
56static const struct nft_expr_ops nft_masq_ipv6_ops = { 36static const struct nft_expr_ops nft_masq_ipv6_ops = {
57 .type = &nft_masq_ipv6_type, 37 .type = &nft_masq_ipv6_type,
58 .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)), 38 .size = NFT_EXPR_SIZE(sizeof(struct nft_masq)),
59 .eval = nft_masq_ipv6_eval, 39 .eval = nft_masq_ipv6_eval,
60 .init = nft_masq_ipv6_init, 40 .init = nft_masq_init,
61 .destroy = nft_masq_ipv6_destroy,
62 .dump = nft_masq_dump, 41 .dump = nft_masq_dump,
63}; 42};
64 43
@@ -73,12 +52,21 @@ static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
73 52
74static int __init nft_masq_ipv6_module_init(void) 53static int __init nft_masq_ipv6_module_init(void)
75{ 54{
76 return nft_register_expr(&nft_masq_ipv6_type); 55 int ret;
56
57 ret = nft_register_expr(&nft_masq_ipv6_type);
58 if (ret < 0)
59 return ret;
60
61 nf_nat_masquerade_ipv6_register_notifier();
62
63 return ret;
77} 64}
78 65
79static void __exit nft_masq_ipv6_module_exit(void) 66static void __exit nft_masq_ipv6_module_exit(void)
80{ 67{
81 nft_unregister_expr(&nft_masq_ipv6_type); 68 nft_unregister_expr(&nft_masq_ipv6_type);
69 nf_nat_masquerade_ipv6_unregister_notifier();
82} 70}
83 71
84module_init(nft_masq_ipv6_module_init); 72module_init(nft_masq_ipv6_module_init);