diff options
Diffstat (limited to 'net/ipv4/ip_forward.c')
-rw-r--r-- | net/ipv4/ip_forward.c | 159 |
1 files changed, 81 insertions, 78 deletions
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 7010e3a30..45a2ed588 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -5,7 +5,7 @@ * * The IP forwarding functionality. * - * Version: $Id: ip_forward.c,v 1.2 1997/12/16 05:37:36 ralf Exp $ + * Version: $Id: ip_forward.c,v 1.3 1998/03/03 01:23:37 ralf Exp $ * * Authors: see ip.c * @@ -18,6 +18,7 @@ * use output device for accounting. * Jos Vos : Call forward firewall after routing * (always use output device). + * Mike McLagan : Routing by source */ #include <linux/config.h> @@ -112,7 +113,7 @@ int ip_forward(struct sk_buff *skb) if (ip_decrease_ttl(iph) <= 0) goto too_many_hops; - if (opt->is_strictroute && (rt->rt_flags&RTF_GATEWAY)) + if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) goto sr_failed; /* @@ -141,51 +142,46 @@ int ip_forward(struct sk_buff *skb) * If the indicated interface is up and running, kick it. */ - if (dev2->flags & IFF_UP) { - if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF)) - goto frag_needed; + if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF)) + goto frag_needed; #ifdef CONFIG_IP_ROUTE_NAT - if (rt->rt_flags & RTCF_NAT) { - if (skb_headroom(skb) < dev2->hard_header_len || skb_cloned(skb)) { - struct sk_buff *skb2; - skb2 = skb_realloc_headroom(skb, (dev2->hard_header_len + 15)&~15); - kfree_skb(skb, FREE_WRITE); - skb = skb2; - } - if (ip_do_nat(skb)) { - kfree_skb(skb, FREE_WRITE); + if (rt->rt_flags & RTCF_NAT) { + if (skb_headroom(skb) < dev2->hard_header_len || skb_cloned(skb)) { + struct sk_buff *skb2; + skb2 = skb_realloc_headroom(skb, (dev2->hard_header_len + 15)&~15); + kfree_skb(skb); + if (skb2 == NULL) return -1; - } + skb = skb2; } + if (ip_do_nat(skb)) { + kfree_skb(skb); + return -1; + } + } #endif #ifdef CONFIG_IP_MASQUERADE - if(!(IPCB(skb)->flags&IPSKB_MASQUERADED)) { - - if (rt->rt_flags&RTCF_VALVE) { - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PKT_FILTERED, 0); - kfree_skb(skb, FREE_READ); - return -1; - } - - /* - * Check that any ICMP packets are not for a - * masqueraded connection. If so rewrite them - * and skip the firewall checks - */ - if (iph->protocol == IPPROTO_ICMP) { - __u32 maddr; + if(!(IPCB(skb)->flags&IPSKB_MASQUERADED)) { + /* + * Check that any ICMP packets are not for a + * masqueraded connection. If so rewrite them + * and skip the firewall checks + */ + if (iph->protocol == IPPROTO_ICMP) { + __u32 maddr; #ifdef CONFIG_IP_MASQUERADE_ICMP -#define icmph ((struct icmphdr *)((char *)iph + (iph->ihl<<2))) - if ((icmph->type==ICMP_DEST_UNREACH)|| - (icmph->type==ICMP_SOURCE_QUENCH)|| - (icmph->type==ICMP_TIME_EXCEEDED)) - { + struct icmphdr *icmph = (struct icmphdr *)((char*)iph + (iph->ihl << 2)); + if ((icmph->type==ICMP_DEST_UNREACH)|| + (icmph->type==ICMP_SOURCE_QUENCH)|| + (icmph->type==ICMP_TIME_EXCEEDED)) + { #endif maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE); - if (fw_res = ip_fw_masq_icmp(&skb, maddr) < 0) { - kfree_skb(skb, FREE_READ); + fw_res = ip_fw_masq_icmp(&skb, maddr); + if (fw_res < 0) { + kfree_skb(skb); return -1; } @@ -195,9 +191,9 @@ int ip_forward(struct sk_buff *skb) #ifdef CONFIG_IP_MASQUERADE_ICMP } #endif - } - if (rt->rt_flags&RTCF_MASQ) - goto skip_call_fw_firewall; + } + if (rt->rt_flags&RTCF_MASQ) + goto skip_call_fw_firewall; #endif /* CONFIG_IP_MASQUERADE */ #ifdef CONFIG_FIREWALL @@ -210,32 +206,32 @@ int ip_forward(struct sk_buff *skb) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); /* fall thru */ default: - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return -1; } #endif #ifdef CONFIG_IP_MASQUERADE - } + } skip_call_fw_firewall: - /* - * If this fragment needs masquerading, make it so... - * (Don't masquerade de-masqueraded fragments) - */ - if (!(IPCB(skb)->flags&IPSKB_MASQUERADED) && - (fw_res==FW_MASQUERADE || rt->rt_flags&RTCF_MASQ)) { - u32 maddr; + /* + * If this fragment needs masquerading, make it so... + * (Don't masquerade de-masqueraded fragments) + */ + if (!(IPCB(skb)->flags&IPSKB_MASQUERADED) && + (fw_res==FW_MASQUERADE || rt->rt_flags&RTCF_MASQ)) { + u32 maddr; #ifdef CONFIG_IP_ROUTE_NAT - maddr = (rt->rt_flags&RTCF_MASQ) ? rt->rt_src_map : 0; + maddr = (rt->rt_flags&RTCF_MASQ) ? rt->rt_src_map : 0; - if (maddr == 0) + if (maddr == 0) #endif maddr = inet_select_addr(dev2, rt->rt_gateway, RT_SCOPE_UNIVERSE); if (ip_fw_masquerade(&skb, maddr) < 0) { - kfree_skb(skb, FREE_READ); + kfree_skb(skb); return -1; } else { /* @@ -244,48 +240,55 @@ skip_call_fw_firewall: iph = skb->nh.iph; opt = &(IPCB(skb)->opt); } - } + } #endif - if (skb_headroom(skb) < dev2->hard_header_len || skb_cloned(skb)) { - struct sk_buff *skb2; - skb2 = skb_realloc_headroom(skb, (dev2->hard_header_len + 15)&~15); - kfree_skb(skb, FREE_WRITE); + if (skb_headroom(skb) < dev2->hard_header_len || skb_cloned(skb)) { + struct sk_buff *skb2; + skb2 = skb_realloc_headroom(skb, (dev2->hard_header_len + 15)&~15); + kfree_skb(skb); - if (skb2 == NULL) { - NETDEBUG(printk(KERN_ERR "\nIP: No memory available for IP forward\n")); - return -1; - } - skb = skb2; - iph = skb2->nh.iph; + if (skb2 == NULL) { + NETDEBUG(printk(KERN_ERR "\nIP: No memory available for IP forward\n")); + return -1; } + skb = skb2; + iph = skb2->nh.iph; + } #ifdef CONFIG_FIREWALL - if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL,&skb)) < FW_ACCEPT) { - /* FW_ACCEPT and FW_MASQUERADE are treated equal: - masquerading is only supported via forward rules */ - if (fw_res == FW_REJECT) - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - kfree_skb(skb,FREE_WRITE); - return -1; - } + if ((fw_res = call_out_firewall(PF_INET, dev2, iph, NULL,&skb)) < FW_ACCEPT) { + /* FW_ACCEPT and FW_MASQUERADE are treated equal: + masquerading is only supported via forward rules */ + if (fw_res == FW_REJECT) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); + kfree_skb(skb); + return -1; + } #endif - ip_statistics.IpForwDatagrams++; + ip_statistics.IpForwDatagrams++; - if (opt->optlen == 0) { - ip_send(skb); - return 0; + if (opt->optlen == 0) { +#ifdef CONFIG_NET_FASTROUTE + if (rt->rt_flags&RTCF_FAST && !netdev_fastroute_obstacles) { + unsigned h = ((*(u8*)&rt->key.dst)^(*(u8*)&rt->key.src))&NETDEV_FASTROUTE_HMASK; + /* Time to switch to functional programming :-) */ + dst_release(xchg(&skb->dev->fastpath[h], dst_clone(&rt->u.dst))); } - ip_forward_options(skb); +#endif ip_send(skb); + return 0; } + + ip_forward_options(skb); + ip_send(skb); return 0; #ifdef CONFIG_TRANSPARENT_PROXY local_pkt: -#endif return ip_local_deliver(skb); +#endif frag_needed: ip_statistics.IpFragFails++; @@ -303,6 +306,6 @@ too_many_hops: /* Tell the sender its packet died... */ icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); drop: - kfree_skb(skb,FREE_WRITE); + kfree_skb(skb); return -1; } |