diff options
author | davem <davem> | 2002-01-23 19:35:57 +0000 |
---|---|---|
committer | davem <davem> | 2002-01-23 19:35:57 +0000 |
commit | a95b56c87e5a57ebd5c8f0956cfab2f83b40fa99 (patch) | |
tree | e4deb57d6f77a0ca451ee5e6fa14aeb86006df25 | |
parent | e3577ad1ed1573268902e0005e8230dc1d15fb8f (diff) | |
download | netdev-vger-cvs-a95b56c87e5a57ebd5c8f0956cfab2f83b40fa99.tar.gz |
Move route_me_harder into a header,
fixes all cases where this duplicated function
was buggy. From Harald Welte
-rw-r--r-- | include/linux/netfilter_ipv4.h | 77 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_nat_standalone.c | 40 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 28 | ||||
-rw-r--r-- | net/ipv4/netfilter/iptable_mangle.c | 30 |
4 files changed, 79 insertions, 96 deletions
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 3a41356db..b404b2132 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -73,4 +73,81 @@ void nf_debug_ip_finish_output2(struct sk_buff *skb); /* 2.4 firewalling went 64 through 67. */ #define SO_ORIGINAL_DST 80 + +/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue + * + * Ideally this would be ins some netfilter_utility module, but creating this + * module for just one function doesn't make sense. -HW */ + +#include <linux/netdevice.h> +#include <linux/inetdevice.h> +#include <linux/skbuff.h> +#include <net/sock.h> +#include <net/route.h> +#include <linux/ip.h> + +static inline int route_me_harder(struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct rtable *rt; + struct rt_key key = { dst:iph->daddr, + src:iph->saddr, + oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, + tos:RT_TOS(iph->tos)|RTO_CONN, +#ifdef CONFIG_IP_ROUTE_FWMARK + fwmark:(*pskb)->nfmark +#endif + }; + struct net_device *dev_src = NULL; + int err; + + /* accomodate ip_route_output_slow(), which expects the key src to be + 0 or a local address; however some non-standard hacks like + ipt_REJECT.c:send_reset() can cause packets with foreign + saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */ + if(key.src && !(dev_src = ip_dev_find(key.src))) + key.src = 0; + + if ((err=ip_route_output_key(&rt, &key)) != 0) { + printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n", + NIPQUAD(iph->daddr), NIPQUAD(iph->saddr), + (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, + RT_TOS(iph->tos)|RTO_CONN, +#ifdef CONFIG_IP_ROUTE_FWMARK + (*pskb)->nfmark, +#else + 0, +#endif + err); + goto out; + } + + /* Drop old route. */ + dst_release((*pskb)->dst); + + (*pskb)->dst = &rt->u.dst; + + /* Change in oif may mean change in hh_len. */ + if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) { + struct sk_buff *nskb; + + nskb = skb_realloc_headroom(*pskb, + (*pskb)->dst->dev->hard_header_len); + if (!nskb) { + err = -ENOMEM; + goto out; + } + if ((*pskb)->sk) + skb_set_owner_w(nskb, (*pskb)->sk); + kfree_skb(*pskb); + *pskb = nskb; + } + +out: + if (dev_src) + dev_put(dev_src); + + return err; +} + #endif /*__LINUX_IP_NETFILTER_H*/ diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 50c679e63..b9c5c45ad 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c @@ -166,46 +166,6 @@ ip_nat_out(unsigned int hooknum, return ip_nat_fn(hooknum, pskb, in, out, okfn); } -static int route_me_harder(struct sk_buff **pskb) -{ - struct iphdr *iph = (*pskb)->nh.iph; - struct rtable *rt; - struct rt_key key = { dst:iph->daddr, - src:iph->saddr, - oif:(*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, - tos:RT_TOS(iph->tos)|RTO_CONN, -#ifdef CONFIG_IP_ROUTE_FWMARK - fwmark:(*pskb)->nfmark -#endif - }; - - if (ip_route_output_key(&rt, &key) != 0) { - printk("route_me_harder: No more route.\n"); - return -EINVAL; - } - - /* Drop old route. */ - dst_release((*pskb)->dst); - - (*pskb)->dst = &rt->u.dst; - - /* Change in oif may mean change in hh_len. */ - if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) { - struct sk_buff *nskb; - - nskb = skb_realloc_headroom(*pskb, - (*pskb)->dst->dev - ->hard_header_len); - if (!nskb) - return -ENOMEM; - if ((*pskb)->sk) - skb_set_owner_w(nskb, (*pskb)->sk); - kfree_skb(*pskb); - *pskb = nskb; - } - return 0; -} - static unsigned int ip_nat_local_fn(unsigned int hooknum, struct sk_buff **pskb, diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index 06949c217..8c56b6615 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -216,32 +216,6 @@ static void ipq_destroy_queue(ipq_queue_t *q) kfree(q); } -/* With a chainsaw... */ -static int route_me_harder(struct sk_buff *skb) -{ - struct iphdr *iph = skb->nh.iph; - struct rtable *rt; - - struct rt_key key = { - dst:iph->daddr, src:iph->saddr, - oif:skb->sk ? skb->sk->bound_dev_if : 0, - tos:RT_TOS(iph->tos)|RTO_CONN, -#ifdef CONFIG_IP_ROUTE_FWMARK - fwmark:skb->nfmark -#endif - }; - - if (ip_route_output_key(&rt, &key) != 0) { - printk("route_me_harder: No more route.\n"); - return -EINVAL; - } - - /* Drop old route. */ - dst_release(skb->dst); - skb->dst = &rt->u.dst; - return 0; -} - static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e) { int diff; @@ -287,7 +261,7 @@ static int ipq_mangle_ipv4(ipq_verdict_msg_t *v, ipq_queue_element_t *e) if (!(iph->tos == e->rt_info.tos && iph->daddr == e->rt_info.daddr && iph->saddr == e->rt_info.saddr)) - return route_me_harder(e->skb); + return route_me_harder(&e->skb); } return 0; } diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index c00a5a84b..0bb8ff796 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -129,34 +129,6 @@ ipt_route_hook(unsigned int hook, return ipt_do_table(pskb, hook, in, out, &packet_mangler, NULL); } -/* FIXME: change in oif may mean change in hh_len. Check and realloc - --RR */ -static int -route_me_harder(struct sk_buff *skb) -{ - struct iphdr *iph = skb->nh.iph; - struct rtable *rt; - struct rt_key key = { dst:iph->daddr, - src:iph->saddr, - oif:skb->sk ? skb->sk->bound_dev_if : 0, - tos:RT_TOS(iph->tos)|RTO_CONN, -#ifdef CONFIG_IP_ROUTE_FWMARK - fwmark:skb->nfmark -#endif - }; - - if (ip_route_output_key(&rt, &key) != 0) { - printk("route_me_harder: No more route.\n"); - return -EINVAL; - } - - /* Drop old route. */ - dst_release(skb->dst); - - skb->dst = &rt->u.dst; - return 0; -} - static unsigned int ipt_local_hook(unsigned int hook, struct sk_buff **pskb, @@ -190,7 +162,7 @@ ipt_local_hook(unsigned int hook, || (*pskb)->nh.iph->daddr != daddr || (*pskb)->nfmark != nfmark || (*pskb)->nh.iph->tos != tos)) - return route_me_harder(*pskb) == 0 ? ret : NF_DROP; + return route_me_harder(pskb) == 0 ? ret : NF_DROP; return ret; } |