forked from mirrors/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
					
				
					 3 changed files with 13 additions and 8 deletions
				
			
		| 
						 | 
					@ -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 a new issue