Annotation of embedaddon/pimd/routesock.c, revision 1.1.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>