aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-10-10 15:01:09 -0400
committerDavid S. Miller <davem@davemloft.net>2014-10-10 15:01:09 -0400
commit7b6fa1eef68591b0ba27f16c149180ce1cf7047f (patch)
treea579c2df0360e0471d9981a22e34c0ce9c5d5fbb
parent4511a4a50e1a8757f771681c3e92dbf5a928eeac (diff)
parentf0d1f04f0a2f662b6b617e24d115fddcf6ef8723 (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.h157
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h2
-rw-r--r--net/netfilter/nft_reject.c10
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
10static inline void 6static inline void
11nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, 7nf_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 */ 16void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook);
21static 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}
73EXPORT_SYMBOL_GPL(nft_reject_dump); 73EXPORT_SYMBOL_GPL(nft_reject_dump);
74 74
75static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX] = { 75static 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
82int nft_reject_icmp_code(u8 code) 82int 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)
90EXPORT_SYMBOL_GPL(nft_reject_icmp_code); 89EXPORT_SYMBOL_GPL(nft_reject_icmp_code);
91 90
92 91
93static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX] = { 92static 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
100int nft_reject_icmpv6_code(u8 code) 99int 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}