aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2015-02-16 12:54:04 -0500
committerPablo Neira Ayuso <pablo@netfilter.org>2015-03-02 20:10:35 -0500
commitee586bbc28fb7128133457cf711880d13a3b7ce4 (patch)
treed1e1991b5d622b588c11608b9164499a96869e51 /net/ipv6
parentb898441f4ece44933af90b116b467f7864dd1ae7 (diff)
netfilter: reject: don't send icmp error if csum is invalid
tcp resets are never emitted if the packet that triggers the reject/reset has an invalid checksum. For icmp error responses there was no such check. It allows to distinguish icmp response generated via iptables -I INPUT -p udp --dport 42 -j REJECT and those emitted by network stack (won't respond if csum is invalid, REJECT does). Arguably its possible to avoid this by using conntrack and only using REJECT with -m conntrack NEW/RELATED. However, this doesn't work when connection tracking is not in use or when using nf_conntrack_checksum=0. Furthermore, sending errors in response to invalid csums doesn't make much sense so just add similar test as in nf_send_reset. Validate csum if needed and only send the response if it is ok. Reference: http://bugzilla.redhat.com/show_bug.cgi?id=1169829 Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/netfilter/nf_reject_ipv6.c35
1 files changed, 35 insertions, 0 deletions
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}
209EXPORT_SYMBOL_GPL(nf_send_reset6); 209EXPORT_SYMBOL_GPL(nf_send_reset6);
210 210
211static 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
233void 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}
244EXPORT_SYMBOL_GPL(nf_send_unreach6);
245
211MODULE_LICENSE("GPL"); 246MODULE_LICENSE("GPL");