summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pim6dd/routesock.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/pim6dd/routesock.c')
-rw-r--r--usr.sbin/pim6dd/routesock.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/usr.sbin/pim6dd/routesock.c b/usr.sbin/pim6dd/routesock.c
new file mode 100644
index 0000000..bb2d590
--- /dev/null
+++ b/usr.sbin/pim6dd/routesock.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 1998 by the University of Southern California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation in source and binary forms for lawful
+ * purposes and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both
+ * the copyright notice and this permission notice appear in supporting
+ * documentation, and that any documentation, advertising materials,
+ * and other materials related to such distribution and use acknowledge
+ * that the software was developed by the University of Southern
+ * California and/or Information Sciences Institute.
+ * The name of the University of Southern California may not
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
+ * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
+ * NON-INFRINGEMENT.
+ *
+ * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
+ * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
+ * THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ */
+/*
+ * Questions concerning this software should be directed to
+ * Pavlin Ivanov Radoslavov (pavlin@catarina.usc.edu)
+ *
+ * $Id: routesock.c,v 1.4 1999/11/19 04:05:48 sumikawa Exp $
+ */
+/*
+ * Part of this program has been derived from mrouted.
+ * The mrouted program is covered by the license in the accompanying file
+ * named "LICENSE.mrouted".
+ *
+ * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
+ * Leland Stanford Junior University.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include "defs.h"
+#include <sys/socket.h>
+#include <net/route.h>
+#ifdef HAVE_ROUTING_SOCKETS
+#include <net/if_dl.h>
+#endif
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+
+#ifdef HAVE_ROUTING_SOCKETS
+union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_in6 sin6;
+ struct sockaddr_dl sdl;
+} so_dst, so_ifp;
+typedef union sockunion *sup;
+int routing_socket;
+int rtm_addrs, pid;
+struct rt_metrics rt_metrics;
+u_long rtm_inits;
+
+/*
+ * Local functions definitions.
+ */
+static int getmsg __P((register struct rt_msghdr *, int,
+ struct rpfctl *rpfinfo));
+
+/*
+ * TODO: check again!
+ */
+#ifdef IRIX
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \
+ : sizeof(__uint64_t))
+#else
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
+ : sizeof(long))
+#endif /* IRIX */
+
+#ifdef HAVE_SA_LEN
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+#else
+#define ADVANCE(x, n) (x += ROUNDUP(4)) /* TODO: a hack!! */
+#endif
+
+/* Open and initialize the routing socket */
+int
+init_routesock()
+{
+ pid = getpid();
+ routing_socket = socket(PF_ROUTE, SOCK_RAW, AF_INET6);
+ if (routing_socket < 0) {
+ log(LOG_ERR, 0, "\nRouting socket error");
+ return -1;
+ }
+ if (fcntl(routing_socket, F_SETFL, O_NONBLOCK) == -1){
+ log(LOG_ERR, 0, "\n Routing socket error");
+ return -1;
+ }
+#if 0
+ {
+ int off;
+
+ off = 0;
+ if (setsockopt(routing_socket, SOL_SOCKET,
+ SO_USELOOPBACK, (char *)&off,
+ sizeof(off)) < 0){
+ log(LOG_ERR, 0 , "\n setsockopt(SO_USELOOPBACK,0)");
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+
+/* get the rpf neighbor info */
+int
+k_req_incoming(source, rpfp)
+ struct sockaddr_in6 *source;
+ struct rpfctl *rpfp;
+{
+ int flags = RTF_STATIC;
+ register sup su;
+ static int seq;
+ int rlen;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+ struct rpfctl rpfinfo;
+
+/* TODO: a hack!!!! */
+#ifdef HAVE_SA_LEN
+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) { \
+ l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
+ }
+#else
+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) { \
+ l = ROUNDUP(4); bcopy((char *)&(u), cp, l); cp += l;\
+ }
+#endif /* HAVE_SA_LEN */
+
+ /* initialize */
+ memset(&rpfp->rpfneighbor, 0, sizeof(rpfp->rpfneighbor));
+ rpfp->source = *source;
+
+ /* check if local address or directly connected before calling the
+ * routing socket
+ */
+
+ if ((rpfp->iif = find_vif_direct_local(source)) != NO_VIF) {
+ rpfp->rpfneighbor = *source;
+ return(TRUE);
+ }
+
+ /* prepare the routing socket params */
+ rtm_addrs |= RTA_DST;
+ rtm_addrs |= RTA_IFP;
+ su = &so_dst;
+ su->sin6.sin6_family = AF_INET6;
+#ifdef HAVE_SA_LEN
+ su->sin6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+ su->sin6.sin6_addr = source->sin6_addr;
+ su->sin6.sin6_scope_id = source->sin6_scope_id;
+ so_ifp.sa.sa_family = AF_LINK;
+#ifdef HAVE_SA_LEN
+ so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
+#endif
+ flags |= RTF_UP;
+ flags |= RTF_HOST;
+ flags |= RTF_GATEWAY;
+ errno = 0;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+
+#define rtm m_rtmsg.m_rtm
+ rtm.rtm_type = RTM_GET;
+ rtm.rtm_flags = flags;
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_seq = ++seq;
+ rtm.rtm_addrs = rtm_addrs;
+ rtm.rtm_rmx = rt_metrics;
+ rtm.rtm_inits = rtm_inits;
+
+ NEXTADDR(RTA_DST, so_dst);
+ NEXTADDR(RTA_IFP, so_ifp);
+ rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+
+ if ((rlen = write(routing_socket, (char *)&m_rtmsg, l)) < 0) {
+ IF_DEBUG(DEBUG_RPF | DEBUG_KERN) {
+ if (errno == ESRCH)
+ log(LOG_DEBUG, 0,
+ "Writing to routing socket: no such route\n");
+ else
+ log(LOG_DEBUG, 0, "Error writing to routing socket");
+ }
+ return(FALSE);
+ }
+
+ do {
+ l = read(routing_socket, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+
+ if (l < 0) {
+ IF_DEBUG(DEBUG_RPF | DEBUG_KERN)
+ log(LOG_DEBUG, 0, "Read from routing socket failed: %s", strerror(errno));
+ return(FALSE);
+ }
+
+ if (getmsg(&rtm, l, &rpfinfo)){
+ rpfp->rpfneighbor = rpfinfo.rpfneighbor;
+ rpfp->iif = rpfinfo.iif;
+ }
+#undef rtm
+ return (TRUE);
+}
+
+
+/*
+ * Returns TRUE on success, FALSE otherwise. rpfinfo contains the result.
+ */
+int
+getmsg(rtm, msglen, rpfinfop)
+ register struct rt_msghdr *rtm;
+ int msglen;
+ struct rpfctl *rpfinfop;
+{
+ struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
+ struct sockaddr_dl *ifp = NULL;
+ register struct sockaddr *sa;
+ register char *cp;
+ register int i;
+ struct sockaddr_in6 *sin6;
+ vifi_t vifi;
+ struct uvif *v;
+ char in6txt[INET6_ADDRSTRLEN];
+
+ if (rpfinfop == (struct rpfctl *)NULL)
+ return(FALSE);
+
+ sin6 = (struct sockaddr_in6 *)&so_dst;
+ IF_DEBUG(DEBUG_RPF)
+ log(LOG_DEBUG, 0, "route to: %s",
+ inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
+ cp = ((char *)(rtm + 1));
+ if (rtm->rtm_addrs)
+ for (i = 1; i; i <<= 1)
+ if (i & rtm->rtm_addrs) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+ case RTA_DST:
+ dst = sa;
+ break;
+ case RTA_GATEWAY:
+ gate = sa;
+ break;
+ case RTA_NETMASK:
+ mask = sa;
+ break;
+ case RTA_IFP:
+ if (sa->sa_family == AF_LINK &&
+ ((struct sockaddr_dl *)sa)->sdl_nlen)
+ ifp = (struct sockaddr_dl *)sa;
+ break;
+ }
+ ADVANCE(cp, sa);
+ }
+
+ if (!ifp){ /* No incoming interface */
+ IF_DEBUG(DEBUG_RPF)
+ log(LOG_DEBUG, 0,
+ "No incoming interface for destination %s",
+ inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
+ return(FALSE);
+ }
+ if (dst && mask)
+ mask->sa_family = dst->sa_family;
+ if (dst) {
+ sin6 = (struct sockaddr_in6 *)dst;
+ IF_DEBUG(DEBUG_RPF)
+ log(LOG_DEBUG, 0, " destination is: %s",
+ inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
+ }
+ if (gate && rtm->rtm_flags & RTF_GATEWAY) {
+ sin6 = (struct sockaddr_in6 *)gate;
+ IF_DEBUG(DEBUG_RPF)
+ log(LOG_DEBUG, 0, " gateway is: %s",
+ inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
+ rpfinfop->rpfneighbor = *sin6;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+#if 0
+ rpfinfop->rpfneighbor.sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
+#endif
+ rpfinfop->rpfneighbor.sin6_scope_id = ifp->sdl_index;
+ /*
+ * XXX: KAME kernel embeds the interface index to the address.
+ * Clear the index for safety.
+ */
+ rpfinfop->rpfneighbor.sin6_addr.s6_addr[2] = 0;
+ rpfinfop->rpfneighbor.sin6_addr.s6_addr[3] = 0;
+ }
+ }
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
+ /* get the number of the interface by matching the name */
+ if ((strlen(v->uv_name) == ifp->sdl_nlen) &&
+ !(strncmp(v->uv_name,ifp->sdl_data,ifp->sdl_nlen)))
+ break;
+
+ IF_DEBUG(DEBUG_RPF)
+ log(LOG_DEBUG, 0, " iif is %d", vifi);
+
+ rpfinfop->iif = vifi;
+
+ if (vifi >= numvifs){
+ IF_DEBUG(DEBUG_RPF)
+ log(LOG_DEBUG, 0,
+ "Invalid incoming interface for destination %s, because of invalid virtual interface",
+ inet_ntop(AF_INET6, &sin6->sin6_addr, in6txt, INET6_ADDRSTRLEN));
+ return(FALSE);/* invalid iif */
+ }
+
+ return(TRUE);
+}
+
+
+#else /* HAVE_ROUTING_SOCKETS */
+
+
+/*
+ * Return in rpfcinfo the incoming interface and the next hop router
+ * toward source.
+ */
+/* TODO: check whether next hop router address is in network or host order */
+int
+k_req_incoming(source, rpfcinfo)
+ struct sockaddr_in6 *source;
+ struct rpfctl *rpfcinfo;
+{
+ rpfcinfo->source = *source;
+ rpfcinfo->iif = NO_VIF; /* just initialized, will be */
+ /* changed in kernel */
+ memset(&rpfcinfo->rpfneighbor, 0, sizeof(rpfcinfo->rpfneighbor)); /* initialized */
+
+ if (ioctl(udp_socket, SIOCGETRPF, (char *) rpfcinfo) < 0){
+ log(LOG_ERR, errno, "ioctl SIOCGETRPF k_req_incoming");
+ return(FALSE);
+ }
+ return (TRUE);
+}
+
+#endif /* HAVE_ROUTING_SOCKETS */
+
OpenPOWER on IntegriCloud