diff options
author | David S. Miller <davem@davemloft.net> | 2014-10-10 15:01:09 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-10-10 15:01:09 -0400 |
commit | 7b6fa1eef68591b0ba27f16c149180ce1cf7047f (patch) | |
tree | a579c2df0360e0471d9981a22e34c0ce9c5d5fbb | |
parent | 4511a4a50e1a8757f771681c3e92dbf5a928eeac (diff) | |
parent | f0d1f04f0a2f662b6b617e24d115fddcf6ef8723 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says:
====================
Netfilter fixes for net-next
This batch contains two fixes for what you have in your net-next,
they are:
1) Remove nf_send_reset6() from header file. This function now resides
in the nf_reject_ipv6 module. Reported by Eric Dumazet.
2) Fix wrong NFT_REJECT_ICMPX_MAX definition and adjust code to fix
errors reported by Dan Carpenter's static analysis tools.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/netfilter/ipv6/nf_reject.h | 157 | ||||
-rw-r--r-- | include/uapi/linux/netfilter/nf_tables.h | 2 | ||||
-rw-r--r-- | net/netfilter/nft_reject.c | 10 |
3 files changed, 7 insertions, 162 deletions
diff --git a/include/net/netfilter/ipv6/nf_reject.h b/include/net/netfilter/ipv6/nf_reject.h index 7a10cfcd8e33..48e18810a9be 100644 --- a/include/net/netfilter/ipv6/nf_reject.h +++ b/include/net/netfilter/ipv6/nf_reject.h | |||
@@ -1,11 +1,7 @@ | |||
1 | #ifndef _IPV6_NF_REJECT_H | 1 | #ifndef _IPV6_NF_REJECT_H |
2 | #define _IPV6_NF_REJECT_H | 2 | #define _IPV6_NF_REJECT_H |
3 | 3 | ||
4 | #include <net/ipv6.h> | 4 | #include <linux/icmpv6.h> |
5 | #include <net/ip6_route.h> | ||
6 | #include <net/ip6_fib.h> | ||
7 | #include <net/ip6_checksum.h> | ||
8 | #include <linux/netfilter_ipv6.h> | ||
9 | 5 | ||
10 | static inline void | 6 | static inline void |
11 | nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, | 7 | nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, |
@@ -17,155 +13,6 @@ nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, | |||
17 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); | 13 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); |
18 | } | 14 | } |
19 | 15 | ||
20 | /* Send RST reply */ | 16 | void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook); |
21 | static void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) | ||
22 | { | ||
23 | struct sk_buff *nskb; | ||
24 | struct tcphdr otcph, *tcph; | ||
25 | unsigned int otcplen, hh_len; | ||
26 | int tcphoff, needs_ack; | ||
27 | const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); | ||
28 | struct ipv6hdr *ip6h; | ||
29 | #define DEFAULT_TOS_VALUE 0x0U | ||
30 | const __u8 tclass = DEFAULT_TOS_VALUE; | ||
31 | struct dst_entry *dst = NULL; | ||
32 | u8 proto; | ||
33 | __be16 frag_off; | ||
34 | struct flowi6 fl6; | ||
35 | |||
36 | if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || | ||
37 | (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { | ||
38 | pr_debug("addr is not unicast.\n"); | ||
39 | return; | ||
40 | } | ||
41 | |||
42 | proto = oip6h->nexthdr; | ||
43 | tcphoff = ipv6_skip_exthdr(oldskb, ((u8*)(oip6h+1) - oldskb->data), &proto, &frag_off); | ||
44 | |||
45 | if ((tcphoff < 0) || (tcphoff > oldskb->len)) { | ||
46 | pr_debug("Cannot get TCP header.\n"); | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | otcplen = oldskb->len - tcphoff; | ||
51 | |||
52 | /* IP header checks: fragment, too short. */ | ||
53 | if (proto != IPPROTO_TCP || otcplen < sizeof(struct tcphdr)) { | ||
54 | pr_debug("proto(%d) != IPPROTO_TCP, " | ||
55 | "or too short. otcplen = %d\n", | ||
56 | proto, otcplen); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | if (skb_copy_bits(oldskb, tcphoff, &otcph, sizeof(struct tcphdr))) | ||
61 | BUG(); | ||
62 | |||
63 | /* No RST for RST. */ | ||
64 | if (otcph.rst) { | ||
65 | pr_debug("RST is set\n"); | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | /* Check checksum. */ | ||
70 | if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { | ||
71 | pr_debug("TCP checksum is invalid\n"); | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | memset(&fl6, 0, sizeof(fl6)); | ||
76 | fl6.flowi6_proto = IPPROTO_TCP; | ||
77 | fl6.saddr = oip6h->daddr; | ||
78 | fl6.daddr = oip6h->saddr; | ||
79 | fl6.fl6_sport = otcph.dest; | ||
80 | fl6.fl6_dport = otcph.source; | ||
81 | security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6)); | ||
82 | dst = ip6_route_output(net, NULL, &fl6); | ||
83 | if (dst == NULL || dst->error) { | ||
84 | dst_release(dst); | ||
85 | return; | ||
86 | } | ||
87 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); | ||
88 | if (IS_ERR(dst)) | ||
89 | return; | ||
90 | |||
91 | hh_len = (dst->dev->hard_header_len + 15)&~15; | ||
92 | nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) | ||
93 | + sizeof(struct tcphdr) + dst->trailer_len, | ||
94 | GFP_ATOMIC); | ||
95 | |||
96 | if (!nskb) { | ||
97 | net_dbg_ratelimited("cannot alloc skb\n"); | ||
98 | dst_release(dst); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | skb_dst_set(nskb, dst); | ||
103 | |||
104 | skb_reserve(nskb, hh_len + dst->header_len); | ||
105 | |||
106 | skb_put(nskb, sizeof(struct ipv6hdr)); | ||
107 | skb_reset_network_header(nskb); | ||
108 | ip6h = ipv6_hdr(nskb); | ||
109 | ip6_flow_hdr(ip6h, tclass, 0); | ||
110 | ip6h->hop_limit = ip6_dst_hoplimit(dst); | ||
111 | ip6h->nexthdr = IPPROTO_TCP; | ||
112 | ip6h->saddr = oip6h->daddr; | ||
113 | ip6h->daddr = oip6h->saddr; | ||
114 | |||
115 | skb_reset_transport_header(nskb); | ||
116 | tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); | ||
117 | /* Truncate to length (no data) */ | ||
118 | tcph->doff = sizeof(struct tcphdr)/4; | ||
119 | tcph->source = otcph.dest; | ||
120 | tcph->dest = otcph.source; | ||
121 | |||
122 | if (otcph.ack) { | ||
123 | needs_ack = 0; | ||
124 | tcph->seq = otcph.ack_seq; | ||
125 | tcph->ack_seq = 0; | ||
126 | } else { | ||
127 | needs_ack = 1; | ||
128 | tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin | ||
129 | + otcplen - (otcph.doff<<2)); | ||
130 | tcph->seq = 0; | ||
131 | } | ||
132 | |||
133 | /* Reset flags */ | ||
134 | ((u_int8_t *)tcph)[13] = 0; | ||
135 | tcph->rst = 1; | ||
136 | tcph->ack = needs_ack; | ||
137 | tcph->window = 0; | ||
138 | tcph->urg_ptr = 0; | ||
139 | tcph->check = 0; | ||
140 | |||
141 | /* Adjust TCP checksum */ | ||
142 | tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr, | ||
143 | &ipv6_hdr(nskb)->daddr, | ||
144 | sizeof(struct tcphdr), IPPROTO_TCP, | ||
145 | csum_partial(tcph, | ||
146 | sizeof(struct tcphdr), 0)); | ||
147 | |||
148 | nf_ct_attach(nskb, oldskb); | ||
149 | |||
150 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | ||
151 | /* If we use ip6_local_out for bridged traffic, the MAC source on | ||
152 | * the RST will be ours, instead of the destination's. This confuses | ||
153 | * some routers/firewalls, and they drop the packet. So we need to | ||
154 | * build the eth header using the original destination's MAC as the | ||
155 | * source, and send the RST packet directly. | ||
156 | */ | ||
157 | if (oldskb->nf_bridge) { | ||
158 | struct ethhdr *oeth = eth_hdr(oldskb); | ||
159 | nskb->dev = oldskb->nf_bridge->physindev; | ||
160 | nskb->protocol = htons(ETH_P_IPV6); | ||
161 | ip6h->payload_len = htons(sizeof(struct tcphdr)); | ||
162 | if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), | ||
163 | oeth->h_source, oeth->h_dest, nskb->len) < 0) | ||
164 | return; | ||
165 | dev_queue_xmit(nskb); | ||
166 | } else | ||
167 | #endif | ||
168 | ip6_local_out(nskb); | ||
169 | } | ||
170 | 17 | ||
171 | #endif /* _IPV6_NF_REJECT_H */ | 18 | #endif /* _IPV6_NF_REJECT_H */ |
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h index c26df6787fb0..f31fe7b660a5 100644 --- a/include/uapi/linux/netfilter/nf_tables.h +++ b/include/uapi/linux/netfilter/nf_tables.h | |||
@@ -774,7 +774,7 @@ enum nft_reject_inet_code { | |||
774 | NFT_REJECT_ICMPX_ADMIN_PROHIBITED, | 774 | NFT_REJECT_ICMPX_ADMIN_PROHIBITED, |
775 | __NFT_REJECT_ICMPX_MAX | 775 | __NFT_REJECT_ICMPX_MAX |
776 | }; | 776 | }; |
777 | #define NFT_REJECT_ICMPX_MAX (__NFT_REJECT_ICMPX_MAX + 1) | 777 | #define NFT_REJECT_ICMPX_MAX (__NFT_REJECT_ICMPX_MAX - 1) |
778 | 778 | ||
779 | /** | 779 | /** |
780 | * enum nft_reject_attributes - nf_tables reject expression netlink attributes | 780 | * enum nft_reject_attributes - nf_tables reject expression netlink attributes |
diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c index ec8a456092a7..57d3e1af5630 100644 --- a/net/netfilter/nft_reject.c +++ b/net/netfilter/nft_reject.c | |||
@@ -72,7 +72,7 @@ nla_put_failure: | |||
72 | } | 72 | } |
73 | EXPORT_SYMBOL_GPL(nft_reject_dump); | 73 | EXPORT_SYMBOL_GPL(nft_reject_dump); |
74 | 74 | ||
75 | static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX] = { | 75 | static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX + 1] = { |
76 | [NFT_REJECT_ICMPX_NO_ROUTE] = ICMP_NET_UNREACH, | 76 | [NFT_REJECT_ICMPX_NO_ROUTE] = ICMP_NET_UNREACH, |
77 | [NFT_REJECT_ICMPX_PORT_UNREACH] = ICMP_PORT_UNREACH, | 77 | [NFT_REJECT_ICMPX_PORT_UNREACH] = ICMP_PORT_UNREACH, |
78 | [NFT_REJECT_ICMPX_HOST_UNREACH] = ICMP_HOST_UNREACH, | 78 | [NFT_REJECT_ICMPX_HOST_UNREACH] = ICMP_HOST_UNREACH, |
@@ -81,8 +81,7 @@ static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX] = { | |||
81 | 81 | ||
82 | int nft_reject_icmp_code(u8 code) | 82 | int nft_reject_icmp_code(u8 code) |
83 | { | 83 | { |
84 | if (code > NFT_REJECT_ICMPX_MAX) | 84 | BUG_ON(code > NFT_REJECT_ICMPX_MAX); |
85 | return -EINVAL; | ||
86 | 85 | ||
87 | return icmp_code_v4[code]; | 86 | return icmp_code_v4[code]; |
88 | } | 87 | } |
@@ -90,7 +89,7 @@ int nft_reject_icmp_code(u8 code) | |||
90 | EXPORT_SYMBOL_GPL(nft_reject_icmp_code); | 89 | EXPORT_SYMBOL_GPL(nft_reject_icmp_code); |
91 | 90 | ||
92 | 91 | ||
93 | static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX] = { | 92 | static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX + 1] = { |
94 | [NFT_REJECT_ICMPX_NO_ROUTE] = ICMPV6_NOROUTE, | 93 | [NFT_REJECT_ICMPX_NO_ROUTE] = ICMPV6_NOROUTE, |
95 | [NFT_REJECT_ICMPX_PORT_UNREACH] = ICMPV6_PORT_UNREACH, | 94 | [NFT_REJECT_ICMPX_PORT_UNREACH] = ICMPV6_PORT_UNREACH, |
96 | [NFT_REJECT_ICMPX_HOST_UNREACH] = ICMPV6_ADDR_UNREACH, | 95 | [NFT_REJECT_ICMPX_HOST_UNREACH] = ICMPV6_ADDR_UNREACH, |
@@ -99,8 +98,7 @@ static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX] = { | |||
99 | 98 | ||
100 | int nft_reject_icmpv6_code(u8 code) | 99 | int nft_reject_icmpv6_code(u8 code) |
101 | { | 100 | { |
102 | if (code > NFT_REJECT_ICMPX_MAX) | 101 | BUG_ON(code > NFT_REJECT_ICMPX_MAX); |
103 | return -EINVAL; | ||
104 | 102 | ||
105 | return icmp_code_v6[code]; | 103 | return icmp_code_v6[code]; |
106 | } | 104 | } |