File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / routesock.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (6 years, 11 months ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    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>