diff options
author | Patrick McHardy <kaber@trash.net> | 2013-04-05 02:41:11 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-04-08 06:34:01 -0400 |
commit | 58e35d1471287c59b9749fb82f04c628c36b9994 (patch) | |
tree | a09f82319c6a2599f8c0ab9f94913aa4faf58448 /net/ipv6 | |
parent | c9e1673a0accf086dfce9b501d8bcb4ec6bbc1e9 (diff) |
netfilter: ipv6: propagate routing errors from ip6_route_me_harder()
Propagate routing errors from ip_route_me_harder() when dropping a packet
using NF_DROP_ERR(). This makes userspace get the proper error instead of
EPERM for everything.
# ip -6 r a unreachable default table 100
# ip -6 ru add fwmark 0x1 lookup 100
# ip6tables -t mangle -A OUTPUT -d 2001:4860:4860::8888 -j MARK --set-mark 0x1
Old behaviour:
PING 2001:4860:4860::8888(2001:4860:4860::8888) 56 data bytes
ping: sendmsg: Operation not permitted
ping: sendmsg: Operation not permitted
ping: sendmsg: Operation not permitted
New behaviour:
PING 2001:4860:4860::8888(2001:4860:4860::8888) 56 data bytes
ping: sendmsg: Network is unreachable
ping: sendmsg: Network is unreachable
ping: sendmsg: Network is unreachable
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/netfilter.c | 6 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6table_mangle.c | 9 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6table_nat.c | 6 |
3 files changed, 13 insertions, 8 deletions
diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 429089cb073d..fc5fbd7f67af 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c | |||
@@ -29,7 +29,7 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
29 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); | 29 | IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
30 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); | 30 | LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); |
31 | dst_release(dst); | 31 | dst_release(dst); |
32 | return -EINVAL; | 32 | return dst->error; |
33 | } | 33 | } |
34 | 34 | ||
35 | /* Drop old route. */ | 35 | /* Drop old route. */ |
@@ -43,7 +43,7 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
43 | skb_dst_set(skb, NULL); | 43 | skb_dst_set(skb, NULL); |
44 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0); | 44 | dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0); |
45 | if (IS_ERR(dst)) | 45 | if (IS_ERR(dst)) |
46 | return -1; | 46 | return PTR_ERR(dst); |
47 | skb_dst_set(skb, dst); | 47 | skb_dst_set(skb, dst); |
48 | } | 48 | } |
49 | #endif | 49 | #endif |
@@ -53,7 +53,7 @@ int ip6_route_me_harder(struct sk_buff *skb) | |||
53 | if (skb_headroom(skb) < hh_len && | 53 | if (skb_headroom(skb) < hh_len && |
54 | pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), | 54 | pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), |
55 | 0, GFP_ATOMIC)) | 55 | 0, GFP_ATOMIC)) |
56 | return -1; | 56 | return -ENOMEM; |
57 | 57 | ||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 6134a1ebfb1b..e075399d8b72 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c | |||
@@ -38,7 +38,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
38 | struct in6_addr saddr, daddr; | 38 | struct in6_addr saddr, daddr; |
39 | u_int8_t hop_limit; | 39 | u_int8_t hop_limit; |
40 | u_int32_t flowlabel, mark; | 40 | u_int32_t flowlabel, mark; |
41 | 41 | int err; | |
42 | #if 0 | 42 | #if 0 |
43 | /* root is playing with raw sockets. */ | 43 | /* root is playing with raw sockets. */ |
44 | if (skb->len < sizeof(struct iphdr) || | 44 | if (skb->len < sizeof(struct iphdr) || |
@@ -65,8 +65,11 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
65 | !ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) || | 65 | !ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) || |
66 | skb->mark != mark || | 66 | skb->mark != mark || |
67 | ipv6_hdr(skb)->hop_limit != hop_limit || | 67 | ipv6_hdr(skb)->hop_limit != hop_limit || |
68 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) | 68 | flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) { |
69 | return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; | 69 | err = ip6_route_me_harder(skb); |
70 | if (err < 0) | ||
71 | ret = NF_DROP_ERR(err); | ||
72 | } | ||
70 | 73 | ||
71 | return ret; | 74 | return ret; |
72 | } | 75 | } |
diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index e0e788d25b14..97e2edd8c209 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c | |||
@@ -215,6 +215,7 @@ nf_nat_ipv6_local_fn(unsigned int hooknum, | |||
215 | const struct nf_conn *ct; | 215 | const struct nf_conn *ct; |
216 | enum ip_conntrack_info ctinfo; | 216 | enum ip_conntrack_info ctinfo; |
217 | unsigned int ret; | 217 | unsigned int ret; |
218 | int err; | ||
218 | 219 | ||
219 | /* root is playing with raw sockets. */ | 220 | /* root is playing with raw sockets. */ |
220 | if (skb->len < sizeof(struct ipv6hdr)) | 221 | if (skb->len < sizeof(struct ipv6hdr)) |
@@ -227,8 +228,9 @@ nf_nat_ipv6_local_fn(unsigned int hooknum, | |||
227 | 228 | ||
228 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, | 229 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, |
229 | &ct->tuplehash[!dir].tuple.src.u3)) { | 230 | &ct->tuplehash[!dir].tuple.src.u3)) { |
230 | if (ip6_route_me_harder(skb)) | 231 | err = ip6_route_me_harder(skb); |
231 | ret = NF_DROP; | 232 | if (err < 0) |
233 | ret = NF_DROP_ERR(err); | ||
232 | } | 234 | } |
233 | #ifdef CONFIG_XFRM | 235 | #ifdef CONFIG_XFRM |
234 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && | 236 | else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && |