--- v2.4.17/linux/include/net/route.h Tue Nov 13 01:30:31 2001 +++ linux/include/net/route.h Mon Feb 4 23:02:58 2002 @@ -48,6 +48,7 @@ { __u32 dst; __u32 src; + __u32 lsrc; int iif; int oif; #ifdef CONFIG_IP_ROUTE_FWMARK @@ -121,6 +122,7 @@ extern void rt_cache_flush(int how); extern int ip_route_output_key(struct rtable **, const struct rt_key *key); extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin); +extern int ip_route_input_lookup(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin, u32 lsrc); extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu); extern void ip_rt_update_pmtu(struct dst_entry *dst, unsigned mtu); extern void ip_rt_send_redirect(struct sk_buff *skb); --- v2.4.17/linux/include/linux/netfilter_ipv4/ip_nat.h Tue Nov 13 01:25:22 2001 +++ linux/include/linux/netfilter_ipv4/ip_nat.h Mon Feb 4 23:16:02 2002 @@ -124,5 +124,13 @@ extern u_int16_t ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck); + +/* Call input routing for SNAT-ed traffic */ +extern unsigned int ip_nat_route_input(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)); + #endif /*__KERNEL__*/ #endif --- v2.4.17/linux/net/ipv4/netfilter/ip_nat_core.c Sat Jan 26 11:18:25 2002 +++ linux/net/ipv4/netfilter/ip_nat_core.c Mon Feb 4 22:48:21 2002 @@ -868,6 +868,60 @@ return NF_ACCEPT; } +unsigned int +ip_nat_route_input(unsigned int hooknum, + struct sk_buff **pskb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + struct sk_buff *skb = *pskb; + struct iphdr *iph; + struct ip_conntrack *ct; + enum ip_conntrack_info ctinfo; + struct ip_nat_info *info; + enum ip_conntrack_dir dir; + __u32 saddr; + int i; + + if (!(ct = ip_conntrack_get(skb, &ctinfo))) + return NF_ACCEPT; + + info = &ct->nat.info; + if (!info->initialized) + return NF_ACCEPT; + + if (skb->dst) + return NF_ACCEPT; + + if (skb->len < sizeof(struct iphdr)) + return NF_ACCEPT; + + iph = skb->nh.iph; + saddr = iph->saddr; + hooknum = NF_IP_POST_ROUTING; + dir = CTINFO2DIR(ctinfo); + + READ_LOCK(&ip_nat_lock); + for (i = 0; i < info->num_manips; i++) { + if (info->manips[i].direction == dir + && info->manips[i].hooknum == hooknum + && info->manips[i].maniptype == IP_NAT_MANIP_SRC) { + saddr = info->manips[i].manip.ip; + } + } + READ_UNLOCK(&ip_nat_lock); + + if (saddr == iph->saddr) + return NF_ACCEPT; + + if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos, + skb->dev, saddr)) + return NF_DROP; + + return NF_ACCEPT; +} + int __init ip_nat_init(void) { size_t i; --- v2.4.17/linux/net/ipv4/netfilter/ip_nat_standalone.c Tue Nov 13 01:29:33 2001 +++ linux/net/ipv4/netfilter/ip_nat_standalone.c Mon Feb 4 22:40:21 2002 @@ -225,6 +225,9 @@ /* Before packet filtering, change destination */ static struct nf_hook_ops ip_nat_in_ops = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST }; +/* Before routing, route before mangling */ +static struct nf_hook_ops ip_nat_inr_ops += { { NULL, NULL }, ip_nat_route_input, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_LAST-1 }; /* After packet filtering, change source */ static struct nf_hook_ops ip_nat_out_ops = { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC}; @@ -290,10 +293,15 @@ printk("ip_nat_init: can't register in hook.\n"); goto cleanup_nat; } + ret = nf_register_hook(&ip_nat_inr_ops); + if (ret < 0) { + printk("ip_nat_init: can't register inr hook.\n"); + goto cleanup_inops; + } ret = nf_register_hook(&ip_nat_out_ops); if (ret < 0) { printk("ip_nat_init: can't register out hook.\n"); - goto cleanup_inops; + goto cleanup_inrops; } ret = nf_register_hook(&ip_nat_local_out_ops); if (ret < 0) { @@ -310,6 +318,8 @@ nf_unregister_hook(&ip_nat_local_out_ops); cleanup_outops: nf_unregister_hook(&ip_nat_out_ops); + cleanup_inrops: + nf_unregister_hook(&ip_nat_inr_ops); cleanup_inops: nf_unregister_hook(&ip_nat_in_ops); cleanup_nat: --- v2.4.17/linux/net/ipv4/route.c Sat Jan 26 11:18:26 2002 +++ linux/net/ipv4/route.c Mon Feb 4 23:10:17 2002 @@ -1258,6 +1258,7 @@ rth->key.fwmark = skb->nfmark; #endif rth->key.src = saddr; + rth->key.lsrc = 0; rth->rt_src = saddr; #ifdef CONFIG_IP_ROUTE_NAT rth->rt_dst_map = daddr; @@ -1310,7 +1311,7 @@ */ int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr, - u8 tos, struct net_device *dev) + u8 tos, struct net_device *dev, u32 lsrc) { struct rt_key key; struct fib_result res; @@ -1330,16 +1331,16 @@ goto out; key.dst = daddr; - key.src = saddr; + key.src = lsrc? : saddr; key.tos = tos; #ifdef CONFIG_IP_ROUTE_FWMARK key.fwmark = skb->nfmark; #endif - key.iif = dev->ifindex; + key.iif = lsrc? loopback_dev.ifindex : dev->ifindex; key.oif = 0; key.scope = RT_SCOPE_UNIVERSE; - hash = rt_hash_code(daddr, saddr ^ (key.iif << 5), tos); + hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos); /* Check for the most weird martians, which can be not detected by fib_lookup. @@ -1360,6 +1361,20 @@ if (BADCLASS(daddr) || ZERONET(daddr) || LOOPBACK(daddr)) goto martian_destination; + if (lsrc) { + struct net_device *dev_out; + + if (MULTICAST(lsrc) || BADCLASS(lsrc) || + ZERONET(lsrc) || LOOPBACK(lsrc)) + goto e_inval; + + /* It is equivalent to inet_addr_type(lsrc) == RTN_LOCAL */ + dev_out = ip_dev_find(lsrc); + if (dev_out == NULL) + goto e_inval; + dev_put(dev_out); + } + /* * Now we are ready to route packet. */ @@ -1369,6 +1384,10 @@ goto no_route; } free_res = 1; + if (lsrc && res.type != RTN_UNICAST && res.type != RTN_NAT) + goto e_inval; + key.iif = dev->ifindex; + key.src = saddr; rt_cache_stat[smp_processor_id()].in_slow_tot++; @@ -1379,7 +1398,7 @@ if (1) { u32 src_map = saddr; - if (res.r) + if (res.r && !lsrc) src_map = fib_rules_policy(saddr, &res, &flags); if (res.type == RTN_NAT) { @@ -1439,6 +1458,7 @@ flags |= RTCF_DIRECTSRC; if (out_dev == in_dev && err && !(flags & (RTCF_NAT | RTCF_MASQ)) && + !lsrc && (IN_DEV_SHARED_MEDIA(out_dev) || inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res)))) flags |= RTCF_DOREDIRECT; @@ -1465,6 +1485,7 @@ #endif rth->key.src = saddr; rth->rt_src = saddr; + rth->key.lsrc = lsrc; rth->rt_gateway = daddr; #ifdef CONFIG_IP_ROUTE_NAT rth->rt_src_map = key.src; @@ -1487,7 +1508,8 @@ rth->rt_flags = flags; #ifdef CONFIG_NET_FASTROUTE - if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT))) { + if (netdev_fastroute && !(flags&(RTCF_NAT|RTCF_MASQ|RTCF_DOREDIRECT)) && + !lsrc) { struct net_device *odev = rth->u.dst.dev; if (odev != dev && dev->accept_fastpath && @@ -1510,6 +1532,8 @@ brd_input: if (skb->protocol != __constant_htons(ETH_P_IP)) goto e_inval; + if (lsrc) + goto e_inval; if (ZERONET(saddr)) spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK); @@ -1542,6 +1566,7 @@ #endif rth->key.src = saddr; rth->rt_src = saddr; + rth->key.lsrc = 0; #ifdef CONFIG_IP_ROUTE_NAT rth->rt_dst_map = key.dst; rth->rt_src_map = key.src; @@ -1619,8 +1644,9 @@ goto e_inval; } -int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, - u8 tos, struct net_device *dev) +static inline int +ip_route_input_cached(struct sk_buff *skb, u32 daddr, u32 saddr, + u8 tos, struct net_device *dev, u32 lsrc) { struct rtable * rth; unsigned hash; @@ -1634,6 +1660,7 @@ if (rth->key.dst == daddr && rth->key.src == saddr && rth->key.iif == iif && + rth->key.lsrc == lsrc && rth->key.oif == 0 && #ifdef CONFIG_IP_ROUTE_FWMARK rth->key.fwmark == skb->nfmark && @@ -1680,7 +1707,19 @@ read_unlock(&inetdev_lock); return -EINVAL; } - return ip_route_input_slow(skb, daddr, saddr, tos, dev); + return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc); +} + +int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr, + u8 tos, struct net_device *dev) +{ + return ip_route_input_cached(skb, daddr, saddr, tos, dev, 0); +} + +int ip_route_input_lookup(struct sk_buff *skb, u32 daddr, u32 saddr, + u8 tos, struct net_device *dev, u32 lsrc) +{ + return ip_route_input_cached(skb, daddr, saddr, tos, dev, lsrc); } /* --- v2.4.17/linux/net/netsyms.c Sat Jan 26 11:18:27 2002 +++ linux/net/netsyms.c Mon Feb 4 22:48:48 2002 @@ -248,6 +248,7 @@ EXPORT_SYMBOL(inet_unregister_protosw); EXPORT_SYMBOL(ip_route_output_key); EXPORT_SYMBOL(ip_route_input); +EXPORT_SYMBOL(ip_route_input_lookup); EXPORT_SYMBOL(icmp_send); EXPORT_SYMBOL(ip_options_compile); EXPORT_SYMBOL(ip_options_undo);