diff -urN v2.4.20/linux/net/ipv4/ip_nat_dumb.c linux/net/ipv4/ip_nat_dumb.c --- v2.4.20/linux/net/ipv4/ip_nat_dumb.c Tue Nov 13 03:25:26 2001 +++ linux/net/ipv4/ip_nat_dumb.c Fri Nov 29 04:04:02 2002 @@ -52,6 +52,13 @@ u32 osaddr = iph->saddr; u16 check; +#ifdef CONFIG_NETFILTER +#ifdef CONFIG_IP_NF_NAT_NEEDED + if (skb->nfct) + return 0; +#endif +#endif + IPCB(skb)->flags |= IPSKB_TRANSLATED; /* Rewrite IP header */ diff -urN v2.4.20/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c --- v2.4.20/linux/net/ipv4/netfilter/ip_fw_compat.c Sun Mar 31 06:18:26 2002 +++ linux/net/ipv4/netfilter/ip_fw_compat.c Fri Nov 29 04:04:02 2002 @@ -76,6 +76,7 @@ const struct net_device *out, int (*okfn)(struct sk_buff *)) { + struct rtable *rt; int ret = FW_BLOCK; u_int16_t redirpt; @@ -117,6 +118,9 @@ demasqueraded: if so, skip forward chain. */ if ((*pskb)->nfct) ret = FW_ACCEPT; + else if (rt = (struct rtable *) (*pskb)->dst, + rt->rt_flags & RTCF_MASQ) + ret = FW_MASQUERADE; else ret = fwops->fw_forward(fwops, PF_INET, (struct net_device *)out, (*pskb)->nh.raw, &redirpt, pskb); diff -urN v2.4.20/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c --- v2.4.20/linux/net/ipv4/netfilter/ip_fw_compat_masq.c Fri Nov 29 03:00:19 2002 +++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c Fri Nov 29 04:04:02 2002 @@ -68,18 +68,25 @@ /* Setup the masquerade, if not already */ if (!info->initialized) { u_int32_t newsrc; - struct rtable *rt; + struct rtable *rt = (struct rtable *) (*pskb)->dst; struct ip_nat_multi_range range; + if (rt->rt_flags & RTCF_MASQ && (newsrc = rt->rt_src_map)) + goto have_src; + /* Pass 0 instead of saddr, since it's going to be changed anyway. */ - if (ip_route_output(&rt, iph->daddr, 0, 0, 0) != 0) { + if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), + rt->u.dst.dev->ifindex) != 0) { + WRITE_UNLOCK(&ip_nat_lock); DEBUGP("ipnat_rule_masquerade: Can't reroute.\n"); return NF_DROP; } - newsrc = inet_select_addr(rt->u.dst.dev, rt->rt_gateway, - RT_SCOPE_UNIVERSE); + newsrc = rt->rt_src; ip_rt_put(rt); + + have_src: + range = ((struct ip_nat_multi_range) { 1, {{IP_NAT_RANGE_MAP_IPS|IP_NAT_RANGE_PROTO_SPECIFIED, diff -urN v2.4.20/linux/net/ipv4/netfilter/ip_nat_rule.c linux/net/ipv4/netfilter/ip_nat_rule.c --- v2.4.20/linux/net/ipv4/netfilter/ip_nat_rule.c Fri Nov 29 03:00:19 2002 +++ linux/net/ipv4/netfilter/ip_nat_rule.c Fri Nov 29 04:09:35 2002 @@ -252,6 +252,45 @@ return ip_nat_setup_info(conntrack, &mr, hooknum); } +#ifdef CONFIG_IP_ROUTE_NAT + +static inline unsigned int +alloc_rtmasq_binding(struct ip_conntrack *conntrack, + struct ip_nat_info *info, + struct sk_buff *skb) +{ + /* Force range to this IP; let proto decide mapping for + per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED). + */ + struct rtable *rt = (struct rtable *) skb->dst; + struct ip_nat_multi_range mr + = { 1, { { IP_NAT_RANGE_MAP_IPS, 0, 0, { 0 }, { 0 } } } }; + + if (rt->rt_src_map) { + mr.range[0].min_ip = mr.range[0].max_ip = rt->rt_src_map; + } else { + struct rt_key key = { + dst: rt->rt_dst, + src: 0, + oif: rt->u.dst.dev->ifindex, + tos: RT_TOS(skb->nh.iph->tos)|RTO_CONN, +#ifdef CONFIG_IP_ROUTE_FWMARK + fwmark: skb->nfmark, +#endif + }; + + if (ip_route_output_key(&rt, &key) != 0) + return NF_DROP; + mr.range[0].min_ip = mr.range[0].max_ip = rt->rt_src; + ip_rt_put(rt); + } + DEBUGP("Allocating RTMASQ binding for %p (%u.%u.%u.%u)\n", conntrack, + NIPQUAD(mr.range[0].min_ip)); + return ip_nat_setup_info(conntrack, &mr, NF_IP_POST_ROUTING); +} + +#endif + int ip_nat_rule_find(struct sk_buff **pskb, unsigned int hooknum, const struct net_device *in, @@ -260,6 +299,16 @@ struct ip_nat_info *info) { int ret; + +#ifdef CONFIG_IP_ROUTE_NAT + { + struct rtable *rt = (struct rtable *) (*pskb)->dst; + + if (rt && rt->rt_flags & RTCF_MASQ && + hooknum == NF_IP_POST_ROUTING) + return alloc_rtmasq_binding(ct, info, *pskb); + } +#endif ret = ipt_do_table(pskb, hooknum, in, out, &nat_table, NULL);