diff options
-rw-r--r-- | include/net/netfilter/ipv4/nf_reject.h | 6 | ||||
-rw-r--r-- | include/net/netfilter/ipv6/nf_reject.h | 11 | ||||
-rw-r--r-- | net/ipv4/netfilter/ipt_REJECT.c | 17 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_reject_ipv4.c | 23 | ||||
-rw-r--r-- | net/ipv4/netfilter/nft_reject_ipv4.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/nf_reject_ipv6.c | 35 | ||||
-rw-r--r-- | net/netfilter/nft_reject_inet.c | 6 |
7 files changed, 76 insertions, 25 deletions
diff --git a/include/net/netfilter/ipv4/nf_reject.h b/include/net/netfilter/ipv4/nf_reject.h index 03e928a55229..864127573c32 100644 --- a/include/net/netfilter/ipv4/nf_reject.h +++ b/include/net/netfilter/ipv4/nf_reject.h | |||
@@ -5,11 +5,7 @@ | |||
5 | #include <net/ip.h> | 5 | #include <net/ip.h> |
6 | #include <net/icmp.h> | 6 | #include <net/icmp.h> |
7 | 7 | ||
8 | static inline void nf_send_unreach(struct sk_buff *skb_in, int code) | 8 | void nf_send_unreach(struct sk_buff *skb_in, int code, int hook); |
9 | { | ||
10 | icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); | ||
11 | } | ||
12 | |||
13 | void nf_send_reset(struct sk_buff *oldskb, int hook); | 9 | void nf_send_reset(struct sk_buff *oldskb, int hook); |
14 | 10 | ||
15 | const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb, | 11 | const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb, |
diff --git a/include/net/netfilter/ipv6/nf_reject.h b/include/net/netfilter/ipv6/nf_reject.h index 23216d48abf9..0ae445d3f217 100644 --- a/include/net/netfilter/ipv6/nf_reject.h +++ b/include/net/netfilter/ipv6/nf_reject.h | |||
@@ -3,15 +3,8 @@ | |||
3 | 3 | ||
4 | #include <linux/icmpv6.h> | 4 | #include <linux/icmpv6.h> |
5 | 5 | ||
6 | static inline void | 6 | void 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, | 7 | unsigned int hooknum); |
8 | unsigned int hooknum) | ||
9 | { | ||
10 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) | ||
11 | skb_in->dev = net->loopback_dev; | ||
12 | |||
13 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); | ||
14 | } | ||
15 | 8 | ||
16 | void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook); | 9 | void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook); |
17 | 10 | ||
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 8f48f5517e33..87907d4bd259 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -34,31 +34,32 @@ static unsigned int | |||
34 | reject_tg(struct sk_buff *skb, const struct xt_action_param *par) | 34 | reject_tg(struct sk_buff *skb, const struct xt_action_param *par) |
35 | { | 35 | { |
36 | const struct ipt_reject_info *reject = par->targinfo; | 36 | const struct ipt_reject_info *reject = par->targinfo; |
37 | int hook = par->hooknum; | ||
37 | 38 | ||
38 | switch (reject->with) { | 39 | switch (reject->with) { |
39 | case IPT_ICMP_NET_UNREACHABLE: | 40 | case IPT_ICMP_NET_UNREACHABLE: |
40 | nf_send_unreach(skb, ICMP_NET_UNREACH); | 41 | nf_send_unreach(skb, ICMP_NET_UNREACH, hook); |
41 | break; | 42 | break; |
42 | case IPT_ICMP_HOST_UNREACHABLE: | 43 | case IPT_ICMP_HOST_UNREACHABLE: |
43 | nf_send_unreach(skb, ICMP_HOST_UNREACH); | 44 | nf_send_unreach(skb, ICMP_HOST_UNREACH, hook); |
44 | break; | 45 | break; |
45 | case IPT_ICMP_PROT_UNREACHABLE: | 46 | case IPT_ICMP_PROT_UNREACHABLE: |
46 | nf_send_unreach(skb, ICMP_PROT_UNREACH); | 47 | nf_send_unreach(skb, ICMP_PROT_UNREACH, hook); |
47 | break; | 48 | break; |
48 | case IPT_ICMP_PORT_UNREACHABLE: | 49 | case IPT_ICMP_PORT_UNREACHABLE: |
49 | nf_send_unreach(skb, ICMP_PORT_UNREACH); | 50 | nf_send_unreach(skb, ICMP_PORT_UNREACH, hook); |
50 | break; | 51 | break; |
51 | case IPT_ICMP_NET_PROHIBITED: | 52 | case IPT_ICMP_NET_PROHIBITED: |
52 | nf_send_unreach(skb, ICMP_NET_ANO); | 53 | nf_send_unreach(skb, ICMP_NET_ANO, hook); |
53 | break; | 54 | break; |
54 | case IPT_ICMP_HOST_PROHIBITED: | 55 | case IPT_ICMP_HOST_PROHIBITED: |
55 | nf_send_unreach(skb, ICMP_HOST_ANO); | 56 | nf_send_unreach(skb, ICMP_HOST_ANO, hook); |
56 | break; | 57 | break; |
57 | case IPT_ICMP_ADMIN_PROHIBITED: | 58 | case IPT_ICMP_ADMIN_PROHIBITED: |
58 | nf_send_unreach(skb, ICMP_PKT_FILTERED); | 59 | nf_send_unreach(skb, ICMP_PKT_FILTERED, hook); |
59 | break; | 60 | break; |
60 | case IPT_TCP_RESET: | 61 | case IPT_TCP_RESET: |
61 | nf_send_reset(skb, par->hooknum); | 62 | nf_send_reset(skb, hook); |
62 | case IPT_ICMP_ECHOREPLY: | 63 | case IPT_ICMP_ECHOREPLY: |
63 | /* Doesn't happen. */ | 64 | /* Doesn't happen. */ |
64 | break; | 65 | break; |
diff --git a/net/ipv4/netfilter/nf_reject_ipv4.c b/net/ipv4/netfilter/nf_reject_ipv4.c index 536da7bc598a..b7405eb7f1ef 100644 --- a/net/ipv4/netfilter/nf_reject_ipv4.c +++ b/net/ipv4/netfilter/nf_reject_ipv4.c | |||
@@ -164,4 +164,27 @@ void nf_send_reset(struct sk_buff *oldskb, int hook) | |||
164 | } | 164 | } |
165 | EXPORT_SYMBOL_GPL(nf_send_reset); | 165 | EXPORT_SYMBOL_GPL(nf_send_reset); |
166 | 166 | ||
167 | void nf_send_unreach(struct sk_buff *skb_in, int code, int hook) | ||
168 | { | ||
169 | struct iphdr *iph = ip_hdr(skb_in); | ||
170 | u8 proto; | ||
171 | |||
172 | if (skb_in->csum_bad || iph->frag_off & htons(IP_OFFSET)) | ||
173 | return; | ||
174 | |||
175 | if (skb_csum_unnecessary(skb_in)) { | ||
176 | icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | if (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) | ||
181 | proto = iph->protocol; | ||
182 | else | ||
183 | proto = 0; | ||
184 | |||
185 | if (nf_ip_checksum(skb_in, hook, ip_hdrlen(skb_in), proto) == 0) | ||
186 | icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0); | ||
187 | } | ||
188 | EXPORT_SYMBOL_GPL(nf_send_unreach); | ||
189 | |||
167 | MODULE_LICENSE("GPL"); | 190 | MODULE_LICENSE("GPL"); |
diff --git a/net/ipv4/netfilter/nft_reject_ipv4.c b/net/ipv4/netfilter/nft_reject_ipv4.c index d729542bd1b7..16a5d4d73d75 100644 --- a/net/ipv4/netfilter/nft_reject_ipv4.c +++ b/net/ipv4/netfilter/nft_reject_ipv4.c | |||
@@ -27,7 +27,8 @@ static void nft_reject_ipv4_eval(const struct nft_expr *expr, | |||
27 | 27 | ||
28 | switch (priv->type) { | 28 | switch (priv->type) { |
29 | case NFT_REJECT_ICMP_UNREACH: | 29 | case NFT_REJECT_ICMP_UNREACH: |
30 | nf_send_unreach(pkt->skb, priv->icmp_code); | 30 | nf_send_unreach(pkt->skb, priv->icmp_code, |
31 | pkt->ops->hooknum); | ||
31 | break; | 32 | break; |
32 | case NFT_REJECT_TCP_RST: | 33 | case NFT_REJECT_TCP_RST: |
33 | nf_send_reset(pkt->skb, pkt->ops->hooknum); | 34 | nf_send_reset(pkt->skb, pkt->ops->hooknum); |
diff --git a/net/ipv6/netfilter/nf_reject_ipv6.c b/net/ipv6/netfilter/nf_reject_ipv6.c index d05b36440e8b..68e0bb4db1bf 100644 --- a/net/ipv6/netfilter/nf_reject_ipv6.c +++ b/net/ipv6/netfilter/nf_reject_ipv6.c | |||
@@ -208,4 +208,39 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook) | |||
208 | } | 208 | } |
209 | EXPORT_SYMBOL_GPL(nf_send_reset6); | 209 | EXPORT_SYMBOL_GPL(nf_send_reset6); |
210 | 210 | ||
211 | static bool reject6_csum_ok(struct sk_buff *skb, int hook) | ||
212 | { | ||
213 | const struct ipv6hdr *ip6h = ipv6_hdr(skb); | ||
214 | int thoff; | ||
215 | __be16 fo; | ||
216 | u8 proto; | ||
217 | |||
218 | if (skb->csum_bad) | ||
219 | return false; | ||
220 | |||
221 | if (skb_csum_unnecessary(skb)) | ||
222 | return true; | ||
223 | |||
224 | proto = ip6h->nexthdr; | ||
225 | thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); | ||
226 | |||
227 | if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) | ||
228 | return false; | ||
229 | |||
230 | return nf_ip6_checksum(skb, hook, thoff, proto) == 0; | ||
231 | } | ||
232 | |||
233 | void nf_send_unreach6(struct net *net, struct sk_buff *skb_in, | ||
234 | unsigned char code, unsigned int hooknum) | ||
235 | { | ||
236 | if (!reject6_csum_ok(skb_in, hooknum)) | ||
237 | return; | ||
238 | |||
239 | if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) | ||
240 | skb_in->dev = net->loopback_dev; | ||
241 | |||
242 | icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); | ||
243 | } | ||
244 | EXPORT_SYMBOL_GPL(nf_send_unreach6); | ||
245 | |||
211 | MODULE_LICENSE("GPL"); | 246 | MODULE_LICENSE("GPL"); |
diff --git a/net/netfilter/nft_reject_inet.c b/net/netfilter/nft_reject_inet.c index 7b5f9d58680a..92877114aff4 100644 --- a/net/netfilter/nft_reject_inet.c +++ b/net/netfilter/nft_reject_inet.c | |||
@@ -28,14 +28,16 @@ static void nft_reject_inet_eval(const struct nft_expr *expr, | |||
28 | case NFPROTO_IPV4: | 28 | case NFPROTO_IPV4: |
29 | switch (priv->type) { | 29 | switch (priv->type) { |
30 | case NFT_REJECT_ICMP_UNREACH: | 30 | case NFT_REJECT_ICMP_UNREACH: |
31 | nf_send_unreach(pkt->skb, priv->icmp_code); | 31 | nf_send_unreach(pkt->skb, priv->icmp_code, |
32 | pkt->ops->hooknum); | ||
32 | break; | 33 | break; |
33 | case NFT_REJECT_TCP_RST: | 34 | case NFT_REJECT_TCP_RST: |
34 | nf_send_reset(pkt->skb, pkt->ops->hooknum); | 35 | nf_send_reset(pkt->skb, pkt->ops->hooknum); |
35 | break; | 36 | break; |
36 | case NFT_REJECT_ICMPX_UNREACH: | 37 | case NFT_REJECT_ICMPX_UNREACH: |
37 | nf_send_unreach(pkt->skb, | 38 | nf_send_unreach(pkt->skb, |
38 | nft_reject_icmp_code(priv->icmp_code)); | 39 | nft_reject_icmp_code(priv->icmp_code), |
40 | pkt->ops->hooknum); | ||
39 | break; | 41 | break; |
40 | } | 42 | } |
41 | break; | 43 | break; |