From owner-freebsd-net@FreeBSD.ORG Tue Sep 14 01:21:16 2004 Return-Path: Delivered-To: freebsd-net@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 073CC16A4CE for ; Tue, 14 Sep 2004 01:21:16 +0000 (GMT) Received: from moutng.kundenserver.de (moutng.kundenserver.de [212.227.126.176]) by mx1.FreeBSD.org (Postfix) with ESMTP id 37DCC43D46 for ; Tue, 14 Sep 2004 01:21:15 +0000 (GMT) (envelope-from max@love2party.net) Received: from [212.227.126.155] (helo=mrelayng.kundenserver.de) by moutng.kundenserver.de with esmtp (Exim 3.35 #1) id 1C720M-0000PI-00; Tue, 14 Sep 2004 03:21:10 +0200 Received: from [84.128.140.198] (helo=donor.laier.local) by mrelayng.kundenserver.de with asmtp (TLSv1:RC4-MD5:128) (Exim 3.35 #1) id 1C720K-0008J3-00; Tue, 14 Sep 2004 03:21:09 +0200 From: Max Laier To: freebsd-net@freebsd.org Date: Tue, 14 Sep 2004 03:19:58 +0200 User-Agent: KMail/1.7 References: <20040913171931.GA5368@zibbi.icomtek.csir.co.za> In-Reply-To: MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_+ckRB4GdcGWp4fa" Message-Id: <200409140319.58203.max@love2party.net> X-Provags-ID: kundenserver.de abuse@kundenserver.de auth:61c499deaeeba3ba5be80f48ecc83056 Subject: Re: route to host on same network X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 14 Sep 2004 01:21:16 -0000 --Boundary-00=_+ckRB4GdcGWp4fa Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline On Tuesday 14 September 2004 03:05, George V. Neville-Neil wrote: > At Mon, 13 Sep 2004 19:19:31 +0200, > > John Hay wrote: > > Hi, > > > > I'm busy trying to port mobilemesh > > (www.mitre.org/tech_transfer/mobilemesh) to FreeBSD and run into a > > problem. > > > > The way mobilemesh works is that you use a subnet for the wireless > > network and then it use host routes to route packets to hosts that are > > not directly visible. Say for instance that you have hosts 1, 2 and 3 > > on the 10.0.0.0/24 subnet and machines 1 and 3 can't directly see each > > other, but both can see host 2, then the mobilemesh routing protocol > > will try to add a host route to the other machine through host 2. On > > host 1 it will do something like "route add 10.0.0.3 10.0.0.2" and > > on host 3 it will do "route add 10.0.0.1 10.0.0.2". This seems to work > > on Linux (where mobilemesh was developed), but I have been unable to > > get it to work on FreeBSD. I have also tried various ways with and > > without -interface and -iface, but none works. Is it supposed to be > > possible in FreeBSD and if so does someone know how? > > What "doesn't work" as in what error, if any, do you get? Or does it > just silently fail? Also, what does your routing table look like > before and after the commands (netstat -rn). I assume you get: 17 EEXIST "File exists" ... ... if that's the case, can you try the attached patch (originally done for the CARP import) and tell me if it works for this? I have yet to check all the side-effects of this, but it might help. [ http://people.freebsd.org/~mlaier/in.c.patch ] Thank you for reporting back! -- /"\ Best regards, | mlaier@freebsd.org \ / Max Laier | ICQ #67774661 X http://pf4freebsd.love2party.net/ | mlaier@EFnet / \ ASCII Ribbon Campaign | Against HTML Mail and News --Boundary-00=_+ckRB4GdcGWp4fa Content-Type: text/x-diff; charset="iso-8859-1"; name="in.c.patch" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="in.c.patch" Index: in.c =================================================================== RCS file: /usr/store/mlaier/fcvs/src/sys/netinet/in.c,v retrieving revision 1.77 diff -u -r1.77 in.c --- in.c 16 Aug 2004 18:32:07 -0000 1.77 +++ in.c 14 Sep 2004 01:16:12 -0000 @@ -1,4 +1,32 @@ /* + * Copyright (C) 2001 WIDE Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* * Copyright (c) 1982, 1986, 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -55,6 +83,8 @@ static int in_lifaddr_ioctl(struct socket *, u_long, caddr_t, struct ifnet *, struct thread *); +static int in_addprefix(struct in_ifaddr *, int); +static int in_scrubprefix(struct in_ifaddr *); static void in_socktrim(struct sockaddr_in *); static int in_ifinit(struct ifnet *, struct in_ifaddr *, struct sockaddr_in *, int); @@ -654,14 +684,7 @@ register struct ifnet *ifp; register struct in_ifaddr *ia; { - - if ((ia->ia_flags & IFA_ROUTE) == 0) - return; - if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); - else - rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); - ia->ia_flags &= ~IFA_ROUTE; + in_scrubprefix(ia); } /* @@ -743,26 +766,7 @@ return (0); flags |= RTF_HOST; } - - /*- - * Don't add host routes for interface addresses of - * 0.0.0.0 --> 0.255.255.255 netmask 255.0.0.0. This makes it - * possible to assign several such address pairs with consistent - * results (no host route) and is required by BOOTP. - * - * XXX: This is ugly ! There should be a way for the caller to - * say that they don't want a host route. - */ - if (ia->ia_addr.sin_addr.s_addr != INADDR_ANY || - ia->ia_netmask != IN_CLASSA_NET || - ia->ia_dstaddr.sin_addr.s_addr != htonl(IN_CLASSA_HOST)) { - if ((error = rtinit(&ia->ia_ifa, (int)RTM_ADD, flags)) != 0) { - ia->ia_addr = oldaddr; - return (error); - } - ia->ia_flags |= IFA_ROUTE; - } - + error = in_addprefix(ia, flags); /* * If the interface supports multicast, join the "all hosts" * multicast group on that interface. @@ -776,6 +780,120 @@ return (error); } +#define rtinitflags(x) \ + ((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \ + ? RTF_HOST : 0) +/* + * add a route to prefix ("connected route" in cisco terminology). + * does nothing if there's some interface address with the same prefix already. + */ +static int +in_addprefix(target, flags) + struct in_ifaddr *target; + int flags; +{ + struct in_ifaddr *ia; + struct in_addr prefix, mask, p; + int error; + + if ((flags & RTF_HOST) != 0) + prefix = target->ia_dstaddr.sin_addr; + else { + prefix = target->ia_addr.sin_addr; + mask = target->ia_sockmask.sin_addr; + prefix.s_addr &= mask.s_addr; + } + +/* for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) { */ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (rtinitflags(ia)) + p = ia->ia_dstaddr.sin_addr; + else { + p = ia->ia_addr.sin_addr; + p.s_addr &= ia->ia_sockmask.sin_addr.s_addr; + } + + if (prefix.s_addr != p.s_addr) + continue; + + /* + * if we got a matching prefix route inserted by other + * interface adderss, we don't need to bother + */ + if (ia->ia_flags & IFA_ROUTE) + return 0; + } + + /* + * noone seem to have prefix route. insert it. + */ + error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags); + if (!error) + target->ia_flags |= IFA_ROUTE; + return error; +} + +/* + * remove a route to prefix ("connected route" in cisco terminology). + * re-installs the route by using another interface address, if there's one + * with the same prefix (otherwise we lose the route mistakenly). + */ +static int +in_scrubprefix(target) + struct in_ifaddr *target; +{ + struct in_ifaddr *ia; + struct in_addr prefix, mask, p; + int error; + + if ((target->ia_flags & IFA_ROUTE) == 0) + return 0; + + if (rtinitflags(target)) + prefix = target->ia_dstaddr.sin_addr; + else { + prefix = target->ia_addr.sin_addr; + mask = target->ia_sockmask.sin_addr; + prefix.s_addr &= mask.s_addr; + } + +/* for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) { */ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (rtinitflags(ia)) + p = ia->ia_dstaddr.sin_addr; + else { + p = ia->ia_addr.sin_addr; + p.s_addr &= ia->ia_sockmask.sin_addr.s_addr; + } + + if (prefix.s_addr != p.s_addr) + continue; + + /* + * if we got a matching prefix route, move IFA_ROUTE to him + */ + if ((ia->ia_flags & IFA_ROUTE) == 0) { + rtinit(&(target->ia_ifa), (int)RTM_DELETE, + rtinitflags(target)); + target->ia_flags &= ~IFA_ROUTE; + + error = rtinit(&ia->ia_ifa, (int)RTM_ADD, + rtinitflags(ia) | RTF_UP); + if (error == 0) + ia->ia_flags |= IFA_ROUTE; + return error; + } + } + + /* + * noone seem to have prefix route. remove it. + */ + rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); + target->ia_flags &= ~IFA_ROUTE; + return 0; +} + +#undef rtinitflags /* * Return 1 if the address might be a local broadcast address. --Boundary-00=_+ckRB4GdcGWp4fa--