diff options
author | Patrick McHardy <kaber@trash.net> | 2013-04-05 02:41:10 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2013-04-08 06:34:00 -0400 |
commit | c9e1673a0accf086dfce9b501d8bcb4ec6bbc1e9 (patch) | |
tree | 7a7b6de83f82c9bbad878c3ead23dd2ad4b59c32 /net | |
parent | 6b0ee8c036ecb3ac92e18e6ca0dca7bff88beaf0 (diff) |
netfilter: ipv4: propagate routing errors from ip_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.
Example:
# ip r a unreachable default table 100
# ip ru add fwmark 0x1 lookup 100
# iptables -t mangle -A OUTPUT -d 8.8.8.8 -j MARK --set-mark 0x1
Current behaviour:
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
ping: sendmsg: Operation not permitted
ping: sendmsg: Operation not permitted
ping: sendmsg: Operation not permitted
New behaviour:
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
ping: sendmsg: Network is unreachable
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')
-rw-r--r-- | net/ipv4/netfilter.c | 8 | ||||
-rw-r--r-- | net/ipv4/netfilter/iptable_mangle.c | 9 | ||||
-rw-r--r-- | net/ipv4/netfilter/iptable_nat.c | 6 |
3 files changed, 14 insertions, 9 deletions
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 4c0cf63dd92e..8b201e8095cd 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c | |||
@@ -40,14 +40,14 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type) | |||
40 | fl4.flowi4_flags = flags; | 40 | fl4.flowi4_flags = flags; |
41 | rt = ip_route_output_key(net, &fl4); | 41 | rt = ip_route_output_key(net, &fl4); |
42 | if (IS_ERR(rt)) | 42 | if (IS_ERR(rt)) |
43 | return -1; | 43 | return PTR_ERR(rt); |
44 | 44 | ||
45 | /* Drop old route. */ | 45 | /* Drop old route. */ |
46 | skb_dst_drop(skb); | 46 | skb_dst_drop(skb); |
47 | skb_dst_set(skb, &rt->dst); | 47 | skb_dst_set(skb, &rt->dst); |
48 | 48 | ||
49 | if (skb_dst(skb)->error) | 49 | if (skb_dst(skb)->error) |
50 | return -1; | 50 | return skb_dst(skb)->error; |
51 | 51 | ||
52 | #ifdef CONFIG_XFRM | 52 | #ifdef CONFIG_XFRM |
53 | if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && | 53 | if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && |
@@ -56,7 +56,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type) | |||
56 | skb_dst_set(skb, NULL); | 56 | skb_dst_set(skb, NULL); |
57 | dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), skb->sk, 0); | 57 | dst = xfrm_lookup(net, dst, flowi4_to_flowi(&fl4), skb->sk, 0); |
58 | if (IS_ERR(dst)) | 58 | if (IS_ERR(dst)) |
59 | return -1; | 59 | return PTR_ERR(dst);; |
60 | skb_dst_set(skb, dst); | 60 | skb_dst_set(skb, dst); |
61 | } | 61 | } |
62 | #endif | 62 | #endif |
@@ -66,7 +66,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned int addr_type) | |||
66 | if (skb_headroom(skb) < hh_len && | 66 | if (skb_headroom(skb) < hh_len && |
67 | pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), | 67 | pskb_expand_head(skb, HH_DATA_ALIGN(hh_len - skb_headroom(skb)), |
68 | 0, GFP_ATOMIC)) | 68 | 0, GFP_ATOMIC)) |
69 | return -1; | 69 | return -ENOMEM; |
70 | 70 | ||
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index 85d88f206447..cba5658ec82c 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c | |||
@@ -44,6 +44,7 @@ ipt_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
44 | u_int8_t tos; | 44 | u_int8_t tos; |
45 | __be32 saddr, daddr; | 45 | __be32 saddr, daddr; |
46 | u_int32_t mark; | 46 | u_int32_t mark; |
47 | int err; | ||
47 | 48 | ||
48 | /* root is playing with raw sockets. */ | 49 | /* root is playing with raw sockets. */ |
49 | if (skb->len < sizeof(struct iphdr) || | 50 | if (skb->len < sizeof(struct iphdr) || |
@@ -66,9 +67,11 @@ ipt_mangle_out(struct sk_buff *skb, const struct net_device *out) | |||
66 | if (iph->saddr != saddr || | 67 | if (iph->saddr != saddr || |
67 | iph->daddr != daddr || | 68 | iph->daddr != daddr || |
68 | skb->mark != mark || | 69 | skb->mark != mark || |
69 | iph->tos != tos) | 70 | iph->tos != tos) { |
70 | if (ip_route_me_harder(skb, RTN_UNSPEC)) | 71 | err = ip_route_me_harder(skb, RTN_UNSPEC); |
71 | ret = NF_DROP; | 72 | if (err < 0) |
73 | ret = NF_DROP_ERR(err); | ||
74 | } | ||
72 | } | 75 | } |
73 | 76 | ||
74 | return ret; | 77 | return ret; |
diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c index eeaff7e4acb5..c2937c81bb67 100644 --- a/net/ipv4/netfilter/iptable_nat.c +++ b/net/ipv4/netfilter/iptable_nat.c | |||
@@ -213,6 +213,7 @@ nf_nat_ipv4_local_fn(unsigned int hooknum, | |||
213 | const struct nf_conn *ct; | 213 | const struct nf_conn *ct; |
214 | enum ip_conntrack_info ctinfo; | 214 | enum ip_conntrack_info ctinfo; |
215 | unsigned int ret; | 215 | unsigned int ret; |
216 | int err; | ||
216 | 217 | ||
217 | /* root is playing with raw sockets. */ | 218 | /* root is playing with raw sockets. */ |
218 | if (skb->len < sizeof(struct iphdr) || | 219 | if (skb->len < sizeof(struct iphdr) || |
@@ -226,8 +227,9 @@ nf_nat_ipv4_local_fn(unsigned int hooknum, | |||
226 | 227 | ||
227 | if (ct->tuplehash[dir].tuple.dst.u3.ip != | 228 | if (ct->tuplehash[dir].tuple.dst.u3.ip != |
228 | ct->tuplehash[!dir].tuple.src.u3.ip) { | 229 | ct->tuplehash[!dir].tuple.src.u3.ip) { |
229 | if (ip_route_me_harder(skb, RTN_UNSPEC)) | 230 | err = ip_route_me_harder(skb, RTN_UNSPEC); |
230 | ret = NF_DROP; | 231 | if (err < 0) |
232 | ret = NF_DROP_ERR(err); | ||
231 | } | 233 | } |
232 | #ifdef CONFIG_XFRM | 234 | #ifdef CONFIG_XFRM |
233 | else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && | 235 | else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && |