diff -ur v2.6.0-test1/linux/net/ipv4/ip_nat_dumb.c linux/net/ipv4/ip_nat_dumb.c --- v2.6.0-test1/linux/net/ipv4/ip_nat_dumb.c Sat Jul 26 16:38:42 2003 +++ linux/net/ipv4/ip_nat_dumb.c Sun Jul 27 18:32:43 2003 @@ -52,6 +52,13 @@ u32 osaddr = iph->saddr; u16 check; +#ifdef CONFIG_NETFILTER +#ifdef IP_NF_NAT_NEEDED + if (skb->nfct) + return 0; +#endif +#endif + IPCB(skb)->flags |= IPSKB_TRANSLATED; /* Rewrite IP header */ diff -ur v2.6.0-test1/linux/net/ipv4/netfilter/ip_fw_compat.c linux/net/ipv4/netfilter/ip_fw_compat.c --- v2.6.0-test1/linux/net/ipv4/netfilter/ip_fw_compat.c Sat Jul 26 16:38:42 2003 +++ linux/net/ipv4/netfilter/ip_fw_compat.c Sun Jul 27 18:32:43 2003 @@ -54,6 +54,7 @@ const struct net_device *out, int (*okfn)(struct sk_buff *)) { + struct rtable *rt; int ret = FW_BLOCK; u_int16_t redirpt; @@ -85,6 +86,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, &redirpt, pskb); diff -ur v2.6.0-test1/linux/net/ipv4/netfilter/ip_fw_compat_masq.c linux/net/ipv4/netfilter/ip_fw_compat_masq.c --- v2.6.0-test1/linux/net/ipv4/netfilter/ip_fw_compat_masq.c Sat Jul 26 16:38:42 2003 +++ linux/net/ipv4/netfilter/ip_fw_compat_masq.c Sun Jul 27 18:32:43 2003 @@ -68,19 +68,28 @@ /* Setup the masquerade, if not already */ if (!info->initialized) { u_int32_t newsrc; - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr } } }; - struct rtable *rt; + struct rtable *rt = (struct rtable *) (*pskb)->dst; + struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr, + .tos = RT_TOS((*pskb)->nh.iph->tos) } }, + .oif = rt->u.dst.dev->ifindex, + }; 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_key(&rt, &fl) != 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 -ur v2.6.0-test1/linux/net/ipv4/netfilter/ip_nat_rule.c linux/net/ipv4/netfilter/ip_nat_rule.c --- v2.6.0-test1/linux/net/ipv4/netfilter/ip_nat_rule.c Sat Jul 26 16:38:43 2003 +++ linux/net/ipv4/netfilter/ip_nat_rule.c Sun Jul 27 18:29:30 2003 @@ -255,6 +255,46 @@ 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 flowi fl = { + .nl_u = { .ip4_u = { + .daddr = rt->rt_dst, + .tos = RT_TOS(skb->nh.iph->tos)|RTO_CONN, +#ifdef CONFIG_IP_ROUTE_FWMARK + .fwmark = skb->nfmark, +#endif + } }, + .oif = rt->u.dst.dev->ifindex, + }; + + if (ip_route_output_key(&rt, &fl) != 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, @@ -264,6 +304,15 @@ { 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); if (ret == NF_ACCEPT) {