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>