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,

Reply via email to