aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2013-04-05 02:41:10 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2013-04-08 06:34:00 -0400
commitc9e1673a0accf086dfce9b501d8bcb4ec6bbc1e9 (patch)
tree7a7b6de83f82c9bbad878c3ead23dd2ad4b59c32 /net
parent6b0ee8c036ecb3ac92e18e6ca0dca7bff88beaf0 (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.c8
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c9
-rw-r--r--net/ipv4/netfilter/iptable_nat.c6
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) &&