Annotation of embedaddon/pimd/routesock.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1998-2001
        !             3:  * University of Southern California/Information Sciences Institute.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. Neither the name of the project nor the names of its contributors
        !            15:  *    may be used to endorse or promote products derived from this software
        !            16:  *    without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30: /*
        !            31:  * Part of this program has been derived from mrouted.
        !            32:  * The mrouted program is covered by the license in the accompanying file
        !            33:  * named "LICENSE.mrouted".
        !            34:  *
        !            35:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !            36:  * Leland Stanford Junior University.
        !            37:  *
        !            38:  */
        !            39: 
        !            40: #include <sys/param.h>
        !            41: #include <sys/file.h>
        !            42: #include "defs.h"
        !            43: #include <sys/socket.h>
        !            44: #include <net/route.h>
        !            45: #ifdef HAVE_ROUTING_SOCKETS
        !            46: #include <net/if_dl.h>
        !            47: #endif
        !            48: #include <arpa/inet.h>
        !            49: #include <netdb.h>
        !            50: #include <stdlib.h>
        !            51: 
        !            52: /* All the BSDs have routing sockets (not Netlink), but only Linux seems
        !            53:  * to have SIOCGETRPF, which is used in the #else below ... the original
        !            54:  * authors wanted to merge routesock.c and netlink.c, but I don't know
        !            55:  * anymore. --Joachim */
        !            56: #ifdef HAVE_ROUTING_SOCKETS
        !            57: union sockunion {
        !            58:     struct  sockaddr sa;
        !            59:     struct  sockaddr_in sin;
        !            60:     struct  sockaddr_dl sdl;
        !            61: } so_dst, so_ifp;
        !            62: typedef union sockunion *sup;
        !            63: int routing_socket = -1;
        !            64: int rtm_addrs;
        !            65: static pid_t pid;
        !            66: struct rt_metrics rt_metrics;
        !            67: uint32_t rtm_inits;
        !            68: 
        !            69: struct {
        !            70:     struct  rt_msghdr m_rtm;
        !            71:     char    m_space[512];
        !            72: } m_rtmsg;
        !            73: 
        !            74: /*
        !            75:  * Local functions definitions.
        !            76:  */
        !            77: static int getmsg(struct rt_msghdr *, int, struct rpfctl *rpfinfo);
        !            78: 
        !            79:  /*
        !            80:  * TODO: check again!
        !            81:  */
        !            82: #ifdef IRIX
        !            83: #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \
        !            84:                    : sizeof(__uint64_t))
        !            85: #else
        !            86: #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
        !            87:                    : sizeof(long))
        !            88: #endif /* IRIX */
        !            89: 
        !            90: #ifdef HAVE_SA_LEN
        !            91: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
        !            92: #else
        !            93: #define ADVANCE(x, n) (x += ROUNDUP(sizeof(*(n))))  /* XXX: sizeof(struct sockaddr) */
        !            94: #endif
        !            95: 
        !            96: /* Open and initialize the routing socket */
        !            97: int init_routesock(void)
        !            98: {
        !            99: #if 0
        !           100:     int on = 0;
        !           101: #endif
        !           102: 
        !           103:     routing_socket = socket(PF_ROUTE, SOCK_RAW, 0);
        !           104:     if (routing_socket < 0) {
        !           105:        logit(LOG_ERR, errno, "Failed creating routing socket");
        !           106:        return -1;
        !           107:     }
        !           108: 
        !           109:     if (fcntl(routing_socket, F_SETFL, O_NONBLOCK) == -1) {
        !           110:        logit(LOG_ERR, errno, "Failed setting routing socket as non-blocking");
        !           111:        return -1;
        !           112:     }
        !           113: 
        !           114: #if 0
        !           115:     /* XXX: if it is OFF, no queries will succeed (!?) */
        !           116:     if (setsockopt(routing_socket, SOL_SOCKET, SO_USELOOPBACK, (char *)&on, sizeof(on)) < 0) {
        !           117:        logit(LOG_ERR, errno , "setsockopt(SO_USELOOPBACK, 0)");
        !           118:        return -1;
        !           119:     }
        !           120: #endif
        !           121: 
        !           122:     return 0;
        !           123: }
        !           124: 
        !           125: /* get the rpf neighbor info */
        !           126: int k_req_incoming(uint32_t source, struct rpfctl *rpfp)
        !           127: {
        !           128:     int rlen, l, flags = RTF_STATIC, retry_count = 3;
        !           129:     sup su;
        !           130:     static int seq;
        !           131:     char *cp = m_rtmsg.m_space;
        !           132:     struct rpfctl rpfinfo;
        !           133: 
        !           134: /* TODO: a hack!!!! */
        !           135: #ifdef HAVE_SA_LEN
        !           136: #define NEXTADDR(w, u)                         \
        !           137:     if (rtm_addrs & (w)) {                     \
        !           138:        l = ROUNDUP(u.sa.sa_len);               \
        !           139:        memcpy(cp, &(u), l);                    \
        !           140:        cp += l;                                \
        !           141:     }
        !           142: #else
        !           143: #define NEXTADDR(w, u)                         \
        !           144:     if (rtm_addrs & (w)) {                     \
        !           145:        l = ROUNDUP(sizeof(struct sockaddr));   \
        !           146:        memcpy(cp, &(u), l);                    \
        !           147:        cp += l;                                \
        !           148:     }
        !           149: #endif /* HAVE_SA_LEN */
        !           150: 
        !           151:     /* initialize */
        !           152:     rpfp->rpfneighbor.s_addr = INADDR_ANY_N;
        !           153:     rpfp->source.s_addr = source;
        !           154: 
        !           155:     /* check if local address or directly connected before calling the
        !           156:      * routing socket
        !           157:      */
        !           158:     if ((rpfp->iif = find_vif_direct_local(source)) != NO_VIF) {
        !           159:        rpfp->rpfneighbor.s_addr = source;
        !           160:        return TRUE;
        !           161:     }
        !           162: 
        !           163:     /* prepare the routing socket params */
        !           164:     rtm_addrs |= RTA_DST;
        !           165:     rtm_addrs |= RTA_IFP;
        !           166:     su = &so_dst;
        !           167:     su->sin.sin_family = AF_INET;
        !           168: #ifdef HAVE_SA_LEN
        !           169:     su->sin.sin_len = sizeof(struct sockaddr_in);
        !           170: #endif
        !           171:     su->sin.sin_addr.s_addr = source;
        !           172: 
        !           173:     if (inet_lnaof(su->sin.sin_addr) == INADDR_ANY) {
        !           174:        IF_DEBUG(DEBUG_RPF) {
        !           175:            logit(LOG_DEBUG, 0, "k_req_incoming: Invalid source %s",
        !           176:                  inet_fmt(source, s1, sizeof(s1)));
        !           177:        }
        !           178: 
        !           179:        return FALSE;
        !           180:     }
        !           181: 
        !           182:     so_ifp.sa.sa_family = AF_LINK;
        !           183: #ifdef HAVE_SA_LEN
        !           184:     so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
        !           185: #endif
        !           186:     flags |= RTF_UP;
        !           187:     flags |= RTF_HOST;
        !           188:     flags |= RTF_GATEWAY;
        !           189:     errno = 0;
        !           190:     memset (&m_rtmsg, 0, sizeof(m_rtmsg));
        !           191: 
        !           192: #define rtm m_rtmsg.m_rtm
        !           193:     rtm.rtm_type        = RTM_GET;
        !           194:     rtm.rtm_flags       = flags;
        !           195:     rtm.rtm_version     = RTM_VERSION;
        !           196:     rtm.rtm_seq         = ++seq;
        !           197:     rtm.rtm_addrs       = rtm_addrs;
        !           198:     rtm.rtm_rmx         = rt_metrics;
        !           199:     rtm.rtm_inits       = rtm_inits;
        !           200: 
        !           201:     NEXTADDR(RTA_DST, so_dst);
        !           202:     NEXTADDR(RTA_IFP, so_ifp);
        !           203:     rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
        !           204: 
        !           205:     rlen = write(routing_socket, &m_rtmsg, l);
        !           206:     if (rlen <= 0) {
        !           207:        IF_DEBUG(DEBUG_RPF | DEBUG_KERN) {
        !           208:            if (errno == ESRCH)
        !           209:                logit(LOG_DEBUG, 0, "Writing to routing socket: no such route");
        !           210:            else
        !           211:                logit(LOG_DEBUG, 0, "Error writing to routing socket");
        !           212:        }
        !           213: 
        !           214:        return FALSE;
        !           215:     }
        !           216: 
        !           217:     pid = getpid();
        !           218: 
        !           219:     while (1) {
        !           220:        rlen = read(routing_socket, &m_rtmsg, sizeof(m_rtmsg));
        !           221:        if (rlen < 0) {
        !           222:            if (errno == EINTR)
        !           223:                continue;       /* Signalled, retry syscall. */
        !           224:            if (errno == EAGAIN && retry_count--) {
        !           225:                logit(LOG_DEBUG, 0, "Kernel busy, retrying (%d/3) routing socket read in one sec ...", 3 - retry_count);
        !           226:                sleep(1);
        !           227:                continue;
        !           228:            }
        !           229: 
        !           230:            IF_DEBUG(DEBUG_RPF | DEBUG_KERN)
        !           231:                logit(LOG_DEBUG, errno, "Read from routing socket failed");
        !           232: 
        !           233:            return FALSE;
        !           234:        }
        !           235: 
        !           236:        if (rlen > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid))
        !           237:            continue;
        !           238: 
        !           239:        break;
        !           240:     }
        !           241: 
        !           242:     memset(&rpfinfo, 0, sizeof(rpfinfo));
        !           243:     if (getmsg(&rtm, l, &rpfinfo)) {
        !           244:        rpfp->rpfneighbor.s_addr = rpfinfo.rpfneighbor.s_addr;
        !           245:        rpfp->iif = rpfinfo.iif;
        !           246:     }
        !           247: #undef rtm
        !           248: 
        !           249:     return TRUE;
        !           250: }
        !           251: 
        !           252: static void find_sockaddrs(struct rt_msghdr *rtm, struct sockaddr **dst, struct sockaddr **gate,
        !           253:                           struct sockaddr **mask, struct sockaddr_dl **ifp)
        !           254: {
        !           255:     int i;
        !           256:     char *cp = (char *)(rtm + 1);
        !           257:     struct sockaddr *sa;
        !           258: 
        !           259:     if (rtm->rtm_addrs) {
        !           260:        for (i = 1; i; i <<= 1) {
        !           261:            if (i & rtm->rtm_addrs) {
        !           262:                sa = (struct sockaddr *)cp;
        !           263: 
        !           264:                switch (i) {
        !           265:                    case RTA_DST:
        !           266:                        *dst = sa;
        !           267:                        break;
        !           268: 
        !           269:                    case RTA_GATEWAY:
        !           270:                        *gate = sa;
        !           271:                        break;
        !           272: 
        !           273:                    case RTA_NETMASK:
        !           274:                        *mask = sa;
        !           275:                        break;
        !           276: 
        !           277:                    case RTA_IFP:
        !           278:                        if (sa->sa_family == AF_LINK  && ((struct sockaddr_dl *)sa)->sdl_nlen)
        !           279:                            *ifp = (struct sockaddr_dl *)sa;
        !           280:                        break;
        !           281:                }
        !           282:                ADVANCE(cp, sa);
        !           283:            }
        !           284:        }
        !           285:     }
        !           286: }
        !           287: 
        !           288: /*
        !           289:  * Returns TRUE on success, FALSE otherwise. rpfinfo contains the result.
        !           290:  */
        !           291: static int getmsg(struct rt_msghdr *rtm, int msglen __attribute__((unused)), struct rpfctl *rpf)
        !           292: {
        !           293:     struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
        !           294:     struct sockaddr_dl *ifp = NULL;
        !           295:     struct in_addr in;
        !           296:     vifi_t vifi;
        !           297:     struct uvif *v;
        !           298: 
        !           299:     if (!rpf) {
        !           300:        logit(LOG_WARNING, 0, "Missing rpf pointer to routesock.c:getmsg()!");
        !           301:        return FALSE;
        !           302:     }
        !           303: 
        !           304:     rpf->iif = NO_VIF;
        !           305:     rpf->rpfneighbor.s_addr = INADDR_ANY;
        !           306: 
        !           307:     in = ((struct sockaddr_in *)&so_dst)->sin_addr;
        !           308:     IF_DEBUG(DEBUG_RPF)
        !           309:        logit(LOG_DEBUG, 0, "route to: %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
        !           310: 
        !           311:     find_sockaddrs(rtm, &dst, &gate, &mask, &ifp);
        !           312: 
        !           313:     if (!ifp) {                        /* No incoming interface */
        !           314:        IF_DEBUG(DEBUG_RPF)
        !           315:            logit(LOG_DEBUG, 0, "No incoming interface for destination %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
        !           316: 
        !           317:        return FALSE;
        !           318:     }
        !           319: 
        !           320:     if (dst && mask)
        !           321:        mask->sa_family = dst->sa_family;
        !           322: 
        !           323:     if (dst) {
        !           324:        in = ((struct sockaddr_in *)dst)->sin_addr;
        !           325:        IF_DEBUG(DEBUG_RPF)
        !           326:            logit(LOG_DEBUG, 0, " destination is: %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
        !           327:     }
        !           328: 
        !           329:     if (gate && (rtm->rtm_flags & RTF_GATEWAY)) {
        !           330:        in = ((struct sockaddr_in *)gate)->sin_addr;
        !           331:        IF_DEBUG(DEBUG_RPF)
        !           332:            logit(LOG_DEBUG, 0, " gateway is: %s", inet_fmt(in.s_addr, s1, sizeof(s1)));
        !           333: 
        !           334:        rpf->rpfneighbor = in;
        !           335:     }
        !           336: 
        !           337:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !           338:        /* get the number of the interface by matching the name */
        !           339:        if ((strlen(v->uv_name) == ifp->sdl_nlen)
        !           340:            && !(strncmp(v->uv_name, ifp->sdl_data, ifp->sdl_nlen)))
        !           341:            break;
        !           342:     }
        !           343: 
        !           344:     /* Found inbound interface in vifi */
        !           345:     rpf->iif = vifi;
        !           346: 
        !           347:     IF_DEBUG(DEBUG_RPF)
        !           348:        logit(LOG_DEBUG, 0, " iif is %d", vifi);
        !           349: 
        !           350:     if (vifi >= numvifs) {
        !           351:        IF_DEBUG(DEBUG_RPF)
        !           352:            logit(LOG_DEBUG, 0, "Invalid incoming interface for destination %s, because of invalid virtual interface",
        !           353:                  inet_fmt(in.s_addr, s1, sizeof(s1)));
        !           354: 
        !           355:        return FALSE;           /* invalid iif */
        !           356:     }
        !           357: 
        !           358:     return TRUE;
        !           359: }
        !           360: 
        !           361: 
        !           362: #else /* !HAVE_ROUTING_SOCKETS -- if we want to run on Linux without Netlink */
        !           363: 
        !           364: /* API compat dummy. */
        !           365: int init_routesock(void)
        !           366: {
        !           367:     return dup(udp_socket);
        !           368: }
        !           369: 
        !           370: /*
        !           371:  * Return in rpfcinfo the incoming interface and the next hop router
        !           372:  * toward source.
        !           373:  */
        !           374: /* TODO: check whether next hop router address is in network or host order */
        !           375: int k_req_incoming(uint32_t source, struct rpfctl *rpfcinfo)
        !           376: {
        !           377:     rpfcinfo->source.s_addr      = source;
        !           378:     rpfcinfo->iif                = NO_VIF;     /* Initialize, will be changed in kernel */
        !           379:     rpfcinfo->rpfneighbor.s_addr = INADDR_ANY; /* Initialize */
        !           380: 
        !           381:     if (ioctl(udp_socket, SIOCGETRPF, (char *) rpfcinfo) < 0) {
        !           382:        logit(LOG_WARNING, errno, "Failed ioctl SIOCGETRPF in k_req_incoming()");
        !           383:        return FALSE;
        !           384:     }
        !           385: 
        !           386:     return TRUE;
        !           387: }
        !           388: #endif /* HAVE_ROUTING_SOCKETS */
        !           389: 
        !           390: /**
        !           391:  * Local Variables:
        !           392:  *  version-control: t
        !           393:  *  indent-tabs-mode: t
        !           394:  *  c-file-style: "ellemtel"
        !           395:  *  c-basic-offset: 4
        !           396:  * End:
        !           397:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>