Hi! First of all, I would like to commit the attached patch; it removes duplicate code. Please review. Also, I found a nasty bug in IP routing. The new route added may not take immediate effect for routing decisions, because ip_forward() may use the cached route (rt_forwarding). DEMO (only relevant routes are shown). Step 1. On a router, add a route to the network (192.168.1). : # route add -net 192.168.1 gateway : add net 192.168.1: gateway gateway : : # netstat -rn : Routing tables : : Internet: : Destination Gateway Flags Refs Use Netif Expire : 192.168.1 gateway UGSc 0 0 rl0 Step 2. From some other host for which this machine is the default router, run ``traceroute -m 2 -n 192.168.1.1''. Observe, on the router, that the reference count grown on the 192.168.1 route. : # netstat -rn : Routing tables : : Internet: : Destination Gateway Flags Refs Use Netif Expire : 192.168.1 gateway UGSc 1 3 rl0 Step 3. Add RTF_REJECT host route to the destination: : # route add 192.168.1.1 -iface lo0 -reject : add host 192.168.1.1: gateway lo0 : # netstat -rn : Routing tables : : Internet: : Destination Gateway Flags Refs Use Netif Expire : 192.168.1 gateway UGSc 1 3 rl0 : 192.168.1.1 lo0 UHRS 0 0 lo0 Step 4. The fun begins. What you would expect if you run traceroute to 192.168.1.1 again? Obviously host route should take precedence over network route, and I expected ICMP Destination Unreachable. But... what's a hell? the new route did not take immediate effect, traceroute succeeded (192.168.1.1 still has zero refcound and use): : # netstat -rn : Routing tables : : Internet: : Destination Gateway Flags Refs Use Netif Expire : 192.168.1 gateway UGSc 1 6 rl0 : 192.168.1.1 lo0 UHRS 0 0 lo0 Step 5. The fun continues. From another host, run traceroute to another destination (to help router change rt_forward.ro_dst). traceroute -m 2 -n 192.168.1.2: : # netstat -rn : Routing tables : : Internet: : Destination Gateway Flags Refs Use Netif Expire : 192.168.1 gateway UGSc 1 9 rl0 : 192.168.1.1 lo0 UHRS 0 0 lo0 Step 6. Run traceroute again to 192.168.1.1. The fun ends. The solution I found so far is to unstaticize the ``rt_forward'', and invalidate the rt_forward.ro_rt in in_addroute() (in_rmx.c). Any better ideas? Cheers, -- Ruslan Ermilov Oracle Developer/DBA, [EMAIL PROTECTED] Sunbay Software AG, [EMAIL PROTECTED] FreeBSD committer, +380.652.512.251 Simferopol, Ukraine http://www.FreeBSD.org The Power To Serve http://www.oracle.com Enabling The Information Age
Index: ip_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v retrieving revision 1.162 diff -u -p -r1.162 ip_input.c --- ip_input.c 2001/03/08 19:03:26 1.162 +++ ip_input.c 2001/03/16 17:34:30 @@ -1507,7 +1507,6 @@ ip_forward(m, srcrt) int srcrt; { register struct ip *ip = mtod(m, struct ip *); - register struct sockaddr_in *sin; register struct rtentry *rt; int error, type = 0, code = 0; struct mbuf *mcopy; @@ -1543,24 +1542,11 @@ ip_forward(m, srcrt) } #endif - sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; - if ((rt = ipforward_rt.ro_rt) == 0 || - ip->ip_dst.s_addr != sin->sin_addr.s_addr) { - if (ipforward_rt.ro_rt) { - RTFREE(ipforward_rt.ro_rt); - ipforward_rt.ro_rt = 0; - } - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = ip->ip_dst; - - rtalloc_ign(&ipforward_rt, RTF_PRCLONING); - if (ipforward_rt.ro_rt == 0) { - icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); - return; - } + if (ip_rtaddr(ip->ip_dst) == 0) { + icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); + return; + } else rt = ipforward_rt.ro_rt; - } /* * Save the IP header and at most 8 bytes of the payload,