forked from Minki/linux
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>
This commit is contained in:
parent
c9e1673a0a
commit
58e35d1471
@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
!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,
|
|||||||
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,
|
|||||||
|
|
||||||
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) &&
|
||||||
|
Loading…
Reference in New Issue
Block a user