summaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_forward.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_forward.c')
-rw-r--r--net/ipv4/ip_forward.c159
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;
}