Commit 58e35d14 authored by Patrick McHardy's avatar Patrick McHardy Committed by Pablo Neira Ayuso

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: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent c9e1673a
...@@ -29,7 +29,7 @@ int ip6_route_me_harder(struct sk_buff *skb) ...@@ -29,7 +29,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n"); LIMIT_NETDEBUG(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
dst_release(dst); dst_release(dst);
return -EINVAL; return dst->error;
} }
/* Drop old route. */ /* Drop old route. */
...@@ -43,7 +43,7 @@ int ip6_route_me_harder(struct sk_buff *skb) ...@@ -43,7 +43,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
skb_dst_set(skb, NULL); skb_dst_set(skb, NULL);
dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0); dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0);
if (IS_ERR(dst)) if (IS_ERR(dst))
return -1; return PTR_ERR(dst);
skb_dst_set(skb, dst); skb_dst_set(skb, dst);
} }
#endif #endif
...@@ -53,7 +53,7 @@ int ip6_route_me_harder(struct sk_buff *skb) ...@@ -53,7 +53,7 @@ int ip6_route_me_harder(struct sk_buff *skb)
if (skb_headroom(skb) < hh_len && if (skb_headroom(skb) < hh_len &&
pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)),
0, GFP_ATOMIC)) 0, GFP_ATOMIC))
return -1; return -ENOMEM;
return 0; return 0;
} }
......
...@@ -38,7 +38,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) ...@@ -38,7 +38,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
struct in6_addr saddr, daddr; struct in6_addr saddr, daddr;
u_int8_t hop_limit; u_int8_t hop_limit;
u_int32_t flowlabel, mark; u_int32_t flowlabel, mark;
int err;
#if 0 #if 0
/* root is playing with raw sockets. */ /* root is playing with raw sockets. */
if (skb->len < sizeof(struct iphdr) || if (skb->len < sizeof(struct iphdr) ||
...@@ -65,8 +65,11 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out) ...@@ -65,8 +65,11 @@ ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) || !ipv6_addr_equal(&ipv6_hdr(skb)->daddr, &daddr) ||
skb->mark != mark || skb->mark != mark ||
ipv6_hdr(skb)->hop_limit != hop_limit || ipv6_hdr(skb)->hop_limit != hop_limit ||
flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) flowlabel != *((u_int32_t *)ipv6_hdr(skb)))) {
return ip6_route_me_harder(skb) == 0 ? ret : NF_DROP; err = ip6_route_me_harder(skb);
if (err < 0)
ret = NF_DROP_ERR(err);
}
return ret; return ret;
} }
......
...@@ -215,6 +215,7 @@ nf_nat_ipv6_local_fn(unsigned int hooknum, ...@@ -215,6 +215,7 @@ nf_nat_ipv6_local_fn(unsigned int hooknum,
const struct nf_conn *ct; const struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
unsigned int ret; unsigned int ret;
int err;
/* root is playing with raw sockets. */ /* root is playing with raw sockets. */
if (skb->len < sizeof(struct ipv6hdr)) if (skb->len < sizeof(struct ipv6hdr))
...@@ -227,8 +228,9 @@ nf_nat_ipv6_local_fn(unsigned int hooknum, ...@@ -227,8 +228,9 @@ nf_nat_ipv6_local_fn(unsigned int hooknum,
if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3,
&ct->tuplehash[!dir].tuple.src.u3)) { &ct->tuplehash[!dir].tuple.src.u3)) {
if (ip6_route_me_harder(skb)) err = ip6_route_me_harder(skb);
ret = NF_DROP; if (err < 0)
ret = NF_DROP_ERR(err);
} }
#ifdef CONFIG_XFRM #ifdef CONFIG_XFRM
else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && else if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment