--- v2.2.19-before-key_gw/linux/include/net/route.h Sat Oct 21 12:10:57 2000 +++ linux/include/net/route.h Sun Oct 14 20:26:58 2001 @@ -57,6 +57,7 @@ __u32 src; int iif; int oif; + __u32 gw; #ifdef CONFIG_IP_ROUTE_FWMARK __u32 fwmark; #endif @@ -111,7 +112,7 @@ u32 src, u8 tos, struct device *dev); extern void ip_rt_advice(struct rtable **rp, int advice); extern void rt_cache_flush(int how); -extern int ip_route_output(struct rtable **, u32 dst, u32 src, u32 tos, int oif); +extern int ip_route_output(struct rtable **, u32 dst, u32 src, u32 tos, int oif, u32 gw); extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct device *devin); 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); @@ -140,14 +141,14 @@ extern __inline__ int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif) { int err; - err = ip_route_output(rp, dst, src, tos, oif); + err = ip_route_output(rp, dst, src, tos, oif, 0); if (err || (dst && src)) return err; dst = (*rp)->rt_dst; src = (*rp)->rt_src; ip_rt_put(*rp); *rp = NULL; - return ip_route_output(rp, dst, src, tos, oif); + return ip_route_output(rp, dst, src, tos, oif, 0); } #endif /* _ROUTE_H */ --- v2.2.19-before-key_gw/linux/net/ipv4/arp.c Sun Oct 14 14:47:49 2001 +++ linux/net/ipv4/arp.c Sun Oct 14 20:26:58 2001 @@ -315,7 +315,7 @@ int probes = neigh->probes; struct rtable *rt; - if (ip_route_output(&rt, target, 0, 0, dev->ifindex) < 0) + if (ip_route_output(&rt, target, 0, 0, dev->ifindex, 0) < 0) return; saddr = rt->rt_src; ip_rt_put(rt); @@ -343,7 +343,7 @@ int flag = 0; //unsigned long now; - if (ip_route_output(&rt, sip, tip, 0, 0) < 0) + if (ip_route_output(&rt, sip, tip, 0, 0, 0) < 0) return 1; if (rt->u.dst.dev != dev) { net_statistics.ArpFilter++; @@ -831,7 +831,7 @@ r->arp_flags |= ATF_COM; if (dev == NULL) { struct rtable * rt; - if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) + if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0, 0)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); @@ -916,7 +916,7 @@ if (dev == NULL) { struct rtable * rt; - if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0)) != 0) + if ((err = ip_route_output(&rt, ip, 0, RTO_ONLINK, 0, 0)) != 0) return err; dev = rt->u.dst.dev; ip_rt_put(rt); --- v2.2.19-before-key_gw/linux/net/ipv4/fib_hash.c Sun Oct 14 14:44:56 2001 +++ linux/net/ipv4/fib_hash.c Sun Oct 14 20:26:58 2001 @@ -318,6 +318,8 @@ for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) { if (key->oif && key->oif != nh->nh_oif) continue; + if (key->gw && key->gw != nh->nh_gw && nh->nh_gw) + continue; if (nh->nh_flags & RTNH_F_DEAD) continue; --- v2.2.19-before-key_gw/linux/net/ipv4/fib_frontend.c Sun Oct 14 14:44:56 2001 +++ linux/net/ipv4/fib_frontend.c Sun Oct 14 20:26:58 2001 @@ -205,6 +205,7 @@ key.src = dst; key.tos = tos; key.oif = 0; + key.gw = 0; key.iif = oif; key.scope = RT_SCOPE_UNIVERSE; --- v2.2.19-before-key_gw/linux/net/ipv4/fib_semantics.c Sun Oct 14 14:44:56 2001 +++ linux/net/ipv4/fib_semantics.c Sun Oct 14 20:26:58 2001 @@ -600,8 +600,12 @@ for_nexthops(fi) { if (nh->nh_flags&RTNH_F_DEAD) continue; - if (!key->oif || key->oif == nh->nh_oif) - break; + if (key->oif && key->oif != nh->nh_oif) + continue; + if (key->gw && key->gw != nh->nh_gw && + nh->nh_gw) + continue; + break; } #ifdef CONFIG_IP_ROUTE_MULTIPATH if (nhsel < fi->fib_nhs) { @@ -970,6 +974,9 @@ change_nexthops(fi) { if (key->oif != nh->nh_oif) continue; + if (key->gw && key->gw != nh->nh_gw && + nh->nh_gw) + continue; if (!(nh->nh_flags&RTNH_F_BADSTATE)) { if (nh->nh_power > w) { w = nh->nh_power; @@ -1032,10 +1039,13 @@ for_nexthops(fi) { if (!(nh->nh_flags&RTNH_F_DEAD)) { - if (!key->oif || key->oif == nh->nh_oif) { - res->nh_sel = nhsel; - return; - } + if (key->oif && key->oif != nh->nh_oif) + continue; + if (key->gw && key->gw != nh->nh_gw && + nh->nh_gw) + continue; + res->nh_sel = nhsel; + return; } } endfor_nexthops(fi); --- v2.2.19-before-key_gw/linux/net/ipv4/icmp.c Sat Aug 4 12:52:33 2001 +++ linux/net/ipv4/icmp.c Sun Oct 14 20:26:58 2001 @@ -492,7 +492,7 @@ ipc.opt = &icmp_param->replyopts; if (ipc.opt->srr) daddr = icmp_param->replyopts.faddr; - if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) + if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0, 0)) return; if (icmpv4_xrlim_allow(rt, icmp_param->icmph.type, icmp_param->icmph.code)) { @@ -614,7 +614,7 @@ * fast routing cache at first. Otherwise an attacker can * grow the routing table. */ - if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) + if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0, 0)) return; if (ip_options_echo(&icmp_param.replyopts, skb_in)) @@ -637,7 +637,7 @@ ipc.opt = &icmp_param.replyopts; if (icmp_param.replyopts.srr) { ip_rt_put(rt); - if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos), 0)) + if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos), 0, 0)) return; } --- v2.2.19-before-key_gw/linux/net/ipv4/igmp.c Sat Aug 4 12:52:33 2001 +++ linux/net/ipv4/igmp.c Sun Oct 14 20:26:58 2001 @@ -164,7 +164,7 @@ if (type == IGMP_HOST_LEAVE_MESSAGE) dst = IGMP_ALL_ROUTER; - if (ip_route_output(&rt, dst, 0, 0, dev->ifindex)) + if (ip_route_output(&rt, dst, 0, 0, dev->ifindex, 0)) return -1; if (rt->rt_src == 0) { ip_rt_put(rt); @@ -527,7 +527,7 @@ return NULL; } - if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) { + if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0, 0)) { dev = rt->u.dst.dev; ip_rt_put(rt); } --- v2.2.19-before-key_gw/linux/net/ipv4/ipip.c Sat Oct 21 12:10:50 2000 +++ linux/net/ipv4/ipip.c Sun Oct 14 20:26:58 2001 @@ -400,7 +400,7 @@ skb2->nh.raw = skb2->data; /* Try to guess incoming interface */ - if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) { + if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0, 0)) { kfree_skb(skb2); return; } @@ -410,7 +410,7 @@ if (rt->rt_flags&RTCF_LOCAL) { ip_rt_put(rt); rt = NULL; - if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) || + if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0, 0) || rt->u.dst.dev->type != ARPHRD_IPGRE) { ip_rt_put(rt); kfree_skb(skb2); @@ -516,7 +516,7 @@ goto tx_error_icmp; } - if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) { + if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link, 0)) { tunnel->stat.tx_carrier_errors++; goto tx_error_icmp; } @@ -775,7 +775,7 @@ if (iph->daddr) { struct rtable *rt; - if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) { + if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link, 0)) { tdev = rt->u.dst.dev; ip_rt_put(rt); } --- v2.2.19-before-key_gw/linux/net/ipv4/ipmr.c Sat Aug 4 12:52:33 2001 +++ linux/net/ipv4/ipmr.c Sun Oct 14 20:26:58 2001 @@ -1049,11 +1049,11 @@ #endif if (vif->flags&VIFF_TUNNEL) { - if (ip_route_output(&rt, vif->remote, vif->local, RT_TOS(iph->tos), vif->link)) + if (ip_route_output(&rt, vif->remote, vif->local, RT_TOS(iph->tos), vif->link, 0)) return; encap = sizeof(struct iphdr); } else { - if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), vif->link)) + if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(iph->tos), vif->link, 0)) return; } --- v2.2.19-before-key_gw/linux/net/ipv4/ip_gre.c Sat Oct 21 12:10:50 2000 +++ linux/net/ipv4/ip_gre.c Sun Oct 14 20:26:58 2001 @@ -471,7 +471,7 @@ skb2->nh.raw = skb2->data; /* Try to guess incoming interface */ - if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) { + if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0, 0)) { kfree_skb(skb2); return; } @@ -481,7 +481,7 @@ if (rt->rt_flags&RTCF_LOCAL) { ip_rt_put(rt); rt = NULL; - if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) || + if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0, 0) || rt->u.dst.dev->type != ARPHRD_IPGRE) { ip_rt_put(rt); kfree_skb(skb2); @@ -672,7 +672,7 @@ tos &= ~1; } - if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) { + if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link, 0)) { tunnel->stat.tx_carrier_errors++; goto tx_error; } @@ -1026,7 +1026,7 @@ struct rtable *rt; if (ip_route_output(&rt, t->parms.iph.daddr, t->parms.iph.saddr, RT_TOS(t->parms.iph.tos), - t->parms.link)) { + t->parms.link, 0)) { MOD_DEC_USE_COUNT; return -EADDRNOTAVAIL; } @@ -1096,7 +1096,7 @@ if (iph->daddr) { struct rtable *rt; - if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link)) { + if (!ip_route_output(&rt, iph->daddr, iph->saddr, RT_TOS(iph->tos), tunnel->parms.link, 0)) { tdev = rt->u.dst.dev; ip_rt_put(rt); } --- v2.2.19-before-key_gw/linux/net/ipv4/ip_masq.c Sun Oct 14 20:25:08 2001 +++ linux/net/ipv4/ip_masq.c Sun Oct 14 20:26:58 2001 @@ -2574,7 +2574,8 @@ if ((ms && !(ms->flags & IP_MASQ_F_NOREROUTE)) || !*maddr) { if (ip_route_output(&rt, iph->daddr, *maddr, RT_TOS(iph->tos)|RTO_CONN, - (!*maddr && skb_dev)?skb_dev->ifindex:0) || + (!*maddr && skb_dev)?skb_dev->ifindex:0, + (!*maddr && skb_dev)?skb_rt->rt_gateway:0) || RTN_UNICAST != rt->rt_type) return -1; *maddr = rt->rt_src; --- v2.2.19-before-key_gw/linux/net/ipv4/ip_masq_user.c Sat Aug 4 12:52:33 2001 +++ linux/net/ipv4/ip_masq_user.c Sun Oct 14 20:26:58 2001 @@ -93,7 +93,7 @@ rt_saddr = 0; tos = RT_TOS(ums->ip_tos) | RTO_CONN; - if ((ret=ip_route_output(&rt, rt_daddr, rt_saddr, tos, 0 /* dev */))) { + if ((ret=ip_route_output(&rt, rt_daddr, rt_saddr, tos, 0, 0))) { IP_MASQ_DEBUG(0-debug, "could not setup maddr for routing daddr=%lX, saddr=%lX\n", ntohl(rt_daddr), ntohl(rt_saddr)); return ret; --- v2.2.19-before-key_gw/linux/net/ipv4/ip_nat_dumb.c Sat Oct 21 12:10:47 2000 +++ linux/net/ipv4/ip_nat_dumb.c Sun Oct 14 20:26:58 2001 @@ -120,6 +120,7 @@ key.dst = ciph->saddr; key.iif = skb->dev->ifindex; key.oif = 0; + key.gw = 0; #ifdef CONFIG_IP_ROUTE_TOS key.tos = RT_TOS(ciph->tos); #endif --- v2.2.19-before-key_gw/linux/net/ipv4/ip_output.c Sat Oct 21 12:11:45 2000 +++ linux/net/ipv4/ip_output.c Sun Oct 14 20:26:58 2001 @@ -259,7 +259,7 @@ */ if(ip_route_output(&rt, daddr, sk->saddr, RT_TOS(sk->ip_tos) | RTO_CONN | sk->localroute, - sk->bound_dev_if)) + sk->bound_dev_if, 0)) goto drop; sk->dst_cache = &rt->u.dst; } @@ -939,7 +939,7 @@ if (ipc.opt->srr) daddr = replyopts.opt.faddr; - if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0)) + if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0, 0)) return; /* And let IP do all the hard work. */ --- v2.2.19-before-key_gw/linux/net/ipv4/rarp.c Mon Jul 27 06:35:57 1998 +++ linux/net/ipv4/rarp.c Sun Oct 14 20:26:58 2001 @@ -347,7 +347,7 @@ * Is it reachable directly ? */ - err = ip_route_output(&rt, ip, 0, 1, 0); + err = ip_route_output(&rt, ip, 0, 1, 0, 0); if (err) return err; if (rt->rt_flags&(RTCF_LOCAL|RTCF_BROADCAST|RTCF_MULTICAST|RTCF_DNAT)) { --- v2.2.19-before-key_gw/linux/net/ipv4/raw.c Sat Aug 4 12:52:33 2001 +++ linux/net/ipv4/raw.c Sun Oct 14 20:26:58 2001 @@ -344,7 +344,7 @@ rfh.saddr = sk->ip_mc_addr; } - err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif); + err = ip_route_output(&rt, daddr, rfh.saddr, tos, ipc.oif, 0); if (err) goto done; --- v2.2.19-before-key_gw/linux/net/ipv4/route.c Sun Oct 14 14:44:56 2001 +++ linux/net/ipv4/route.c Sun Oct 14 20:26:58 2001 @@ -691,6 +691,7 @@ /* Gateway is different ... */ rt->rt_gateway = new_gw; + if (rt->key.gw) rt->key.gw = new_gw; /* Redirect received -> path was valid */ dst_confirm(&rth->u.dst); @@ -1066,6 +1067,7 @@ rth->key.iif = dev->ifindex; rth->u.dst.dev = &loopback_dev; rth->key.oif = 0; + rth->key.gw = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->rt_type = RTN_MULTICAST; @@ -1123,6 +1125,7 @@ #endif key.iif = dev->ifindex; key.oif = 0; + key.gw = 0; key.scope = RT_SCOPE_UNIVERSE; hash = rt_hash_code(daddr, saddr^(key.iif<<5), tos); @@ -1251,6 +1254,7 @@ rth->key.iif = dev->ifindex; rth->u.dst.dev = out_dev->dev; rth->key.oif = 0; + rth->key.gw = 0; rth->rt_spec_dst= spec_dst; rth->u.dst.input = ip_forward; @@ -1316,6 +1320,7 @@ rth->key.iif = dev->ifindex; rth->u.dst.dev = &loopback_dev; rth->key.oif = 0; + rth->key.gw = 0; rth->rt_gateway = daddr; rth->rt_spec_dst= spec_dst; rth->u.dst.input= ip_local_deliver; @@ -1419,7 +1424,7 @@ * Major route resolver routine. */ -int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) +int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif, u32 gw) { struct rt_key key; struct fib_result res; @@ -1437,6 +1442,7 @@ key.tos = tos&IPTOS_TOS_MASK; key.iif = loopback_dev.ifindex; key.oif = oif; + key.gw = gw; key.scope = (tos&RTO_ONLINK) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE; res.fi = NULL; #ifdef CONFIG_IP_MULTIPLE_TABLES @@ -1522,6 +1528,7 @@ key.dst = key.src = htonl(INADDR_LOOPBACK); dev_out = &loopback_dev; key.oif = loopback_dev.ifindex; + key.gw = 0; res.type = RTN_LOCAL; flags |= RTCF_LOCAL; goto make_route; @@ -1564,6 +1571,7 @@ key.src = key.dst; dev_out = &loopback_dev; key.oif = dev_out->ifindex; + key.gw = 0; res.fi = NULL; flags |= RTCF_LOCAL; goto make_route; @@ -1621,6 +1629,7 @@ rth->key.src = saddr; rth->key.iif = 0; rth->key.oif = oif; + rth->key.gw = gw; rth->rt_dst = key.dst; rth->rt_src = key.src; #ifdef CONFIG_IP_ROUTE_NAT @@ -1661,19 +1670,21 @@ return rt_intern_hash(hash, rth, rp); } -int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) +int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif, u32 gw) { unsigned hash; struct rtable *rth; hash = rt_hash_code(daddr, saddr^(oif<<5), tos); + if (!oif) gw = 0; start_bh_atomic(); for (rth=rt_hash_table[hash]; rth; rth=rth->u.rt_next) { if (rth->key.dst == daddr && rth->key.src == saddr && rth->key.iif == 0 && rth->key.oif == oif && + rth->key.gw == gw && #ifndef CONFIG_IP_TRANSPARENT_PROXY rth->key.tos == tos #else @@ -1691,7 +1702,7 @@ } end_bh_atomic(); - return ip_route_output_slow(rp, daddr, saddr, tos, oif); + return ip_route_output_slow(rp, daddr, saddr, tos, oif, gw); } #ifdef CONFIG_RTNETLINK @@ -1842,7 +1853,7 @@ int oif = 0; if (rta[RTA_OIF-1]) memcpy(&oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); - err = ip_route_output(&rt, dst, src, rtm->rtm_tos, oif); + err = ip_route_output(&rt, dst, src, rtm->rtm_tos, oif, 0); } if (err) { kfree_skb(skb); --- v2.2.19-before-key_gw/linux/net/ipv4/syncookies.c Sat Oct 21 12:12:34 2000 +++ linux/net/ipv4/syncookies.c Sun Oct 14 20:26:58 2001 @@ -191,7 +191,7 @@ opt->srr ? opt->faddr : req->af.v4_req.rmt_addr, req->af.v4_req.loc_addr, sk->ip_tos | RTO_CONN, - 0)) { + 0, 0)) { if (req->af.v4_req.opt) kfree(req->af.v4_req.opt); tcp_openreq_free(req); --- v2.2.19-before-key_gw/linux/net/ipv4/tcp_ipv4.c Sat Aug 4 12:52:33 2001 +++ linux/net/ipv4/tcp_ipv4.c Sun Oct 14 20:26:58 2001 @@ -1154,7 +1154,7 @@ req->af.v4_req.rmt_addr), req->af.v4_req.loc_addr, RT_TOS(sk->ip_tos) | RTO_CONN | sk->localroute, - sk->bound_dev_if)) { + sk->bound_dev_if, 0)) { ip_statistics.IpOutNoRoutes++; return; } @@ -1518,7 +1518,7 @@ if (ip_route_output(&rt, opt && opt->srr ? opt->faddr : req->af.v4_req.rmt_addr, - req->af.v4_req.loc_addr, sk->ip_tos|RTO_CONN, 0)) + req->af.v4_req.loc_addr, sk->ip_tos|RTO_CONN, 0, 0)) return NULL; dst = &rt->u.dst; } @@ -1865,7 +1865,7 @@ } if (rt->u.dst.obsolete) { int err; - err = ip_route_output(&rt, rt->rt_dst, rt->rt_src, rt->key.tos|RTO_CONN, rt->key.oif); + err = ip_route_output(&rt, rt->rt_dst, rt->rt_src, rt->key.tos|RTO_CONN, rt->key.oif, 0); if (err) { sk->err_soft=-err; sk->error_report(sk); --- v2.2.19-before-key_gw/linux/net/ipv4/udp.c Sat Aug 4 12:52:33 2001 +++ linux/net/ipv4/udp.c Sun Oct 14 20:26:58 2001 @@ -704,7 +704,7 @@ #ifdef CONFIG_IP_TRANSPARENT_PROXY (msg->msg_flags&MSG_PROXY ? RTO_TPROXY : 0) | #endif - tos, ipc.oif); + tos, ipc.oif, 0); if (err) goto out;