File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / netlink.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:  * Fred Griffoul <griffoul@ccrle.nec.de> sent me this file to use
    3:  * when compiling pimd under Linux.
    4:  *
    5:  * There was no copyright message or author name, so I assume he was the
    6:  * author, and deserves the copyright/credit for it: 
    7:  *
    8:  * COPYRIGHT/AUTHORSHIP by Fred Griffoul <griffoul@ccrle.nec.de>
    9:  * (until proven otherwise).
   10:  */
   11: 
   12: #include <sys/param.h>
   13: #include <sys/file.h>
   14: #include <sys/socket.h>
   15: #include <netdb.h>
   16: #include <stdlib.h>
   17: #include <strings.h>
   18: #include <paths.h>
   19: #include "defs.h"
   20: 
   21: #include <linux/rtnetlink.h>
   22: 
   23: int routing_socket = -1;
   24: static uint32_t pid; /* pid_t, but /usr/include/linux/netlink.h says __u32 ... */
   25: static uint32_t seq;
   26: 
   27: static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf);
   28: 
   29: static int addattr32(struct nlmsghdr *n, size_t maxlen, int type, uint32_t data)
   30: {
   31:     int len = RTA_LENGTH(4);
   32:     struct rtattr *rta;
   33: 
   34:     if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
   35: 	return -1;
   36: 
   37:     rta = (struct rtattr *)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len));
   38:     rta->rta_type = type;
   39:     rta->rta_len = len;
   40:     memcpy(RTA_DATA(rta), &data, 4);
   41:     n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
   42: 
   43:     return 0;
   44: }
   45: 
   46: static int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
   47: {
   48:     while (RTA_OK(rta, len)) {
   49: 	if (rta->rta_type <= max)
   50: 	    tb[rta->rta_type] = rta;
   51: 	rta = RTA_NEXT(rta, len);
   52:     }
   53: 
   54:     if (len)
   55: 	logit(LOG_WARNING, 0, "NETLINK: Deficit in rtattr %d", len);
   56: 
   57:     return 0;
   58: }
   59: 
   60: /* open and initialize the routing socket */
   61: int init_routesock(void)
   62: {
   63:     socklen_t addr_len;
   64:     struct sockaddr_nl local;
   65: 
   66:     routing_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   67:     if (routing_socket < 0) {
   68: 	logit(LOG_ERR, errno, "Failed creating netlink socket");
   69: 	return -1;
   70:     }
   71: 
   72:     memset(&local, 0, sizeof(local));
   73:     local.nl_family = AF_NETLINK;
   74:     local.nl_groups = 0;
   75:     if (bind(routing_socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
   76: 	logit(LOG_ERR, errno, "Failed binding to netlink socket");
   77: 	return -1;
   78:     }
   79: 
   80:     addr_len = sizeof(local);
   81:     if (getsockname(routing_socket, (struct sockaddr *)&local, &addr_len) < 0) {
   82: 	logit(LOG_ERR, errno, "Failed netlink getsockname");
   83: 	return -1;
   84:     }
   85: 
   86:     if (addr_len != sizeof(local)) {
   87: 	logit(LOG_ERR, 0, "Invalid netlink addr len.");
   88: 	return -1;
   89:     }
   90: 
   91:     if (local.nl_family != AF_NETLINK) {
   92: 	logit(LOG_ERR, 0, "Invalid netlink addr family.");
   93: 	return -1;
   94:     }
   95: 
   96:     pid = local.nl_pid;
   97:     seq = time(NULL);
   98: 
   99:     return 0;
  100: }
  101: 
  102: /* get the rpf neighbor info */
  103: int k_req_incoming(uint32_t source, struct rpfctl *rpf)
  104: {
  105:     int l, rlen;
  106:     char buf[512];
  107:     struct nlmsghdr *n = (struct nlmsghdr *)buf;
  108:     struct rtmsg *r = NLMSG_DATA(n);
  109:     struct sockaddr_nl addr;
  110:     
  111:     rpf->source.s_addr = source;
  112:     rpf->iif = ALL_VIFS;
  113:     rpf->rpfneighbor.s_addr = 0;
  114:     
  115:     n->nlmsg_type = RTM_GETROUTE;
  116:     n->nlmsg_flags = NLM_F_REQUEST;
  117:     n->nlmsg_len = NLMSG_LENGTH(sizeof(*r));
  118:     n->nlmsg_pid = pid;
  119:     n->nlmsg_seq = ++seq;
  120:     
  121:     memset(r, 0, sizeof(*r));
  122:     r->rtm_family = AF_INET;
  123:     r->rtm_dst_len = 32;
  124:     addattr32(n, sizeof(buf), RTA_DST, rpf->source.s_addr);
  125: #ifdef CONFIG_RTNL_OLD_IFINFO
  126:     r->rtm_optlen = n->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
  127: #endif
  128:     addr.nl_family = AF_NETLINK;
  129:     addr.nl_groups = 0;
  130:     addr.nl_pid = 0;
  131:     
  132:     if (!IN_LINK_LOCAL_RANGE(rpf->source.s_addr)) {
  133: 	IF_DEBUG(DEBUG_RPF)
  134: 	    logit(LOG_DEBUG, 0, "NETLINK: ask path to %s", inet_fmt(rpf->source.s_addr, s1, sizeof(s1)));
  135:     }
  136: 
  137:     while ((rlen = sendto(routing_socket, buf, n->nlmsg_len, 0, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
  138: 	if (errno == EINTR)
  139: 	    continue;		/* Received signal, retry syscall. */
  140: 
  141: 	logit(LOG_WARNING, errno, "Error writing to routing socket");
  142: 	return FALSE;
  143:     }
  144: 
  145:     do {
  146: 	socklen_t alen = sizeof(addr);
  147: 
  148: 	l = recvfrom(routing_socket, buf, sizeof(buf), 0, (struct sockaddr *)&addr, &alen);
  149: 	if (l < 0) {
  150: 	    if (errno == EINTR)
  151: 		continue;		/* Received signal, retry syscall. */
  152: 
  153: 	    logit(LOG_WARNING, errno, "Error writing to routing socket");
  154: 	    return FALSE;
  155: 	}
  156:     } while (n->nlmsg_seq != seq || n->nlmsg_pid != pid);
  157:     
  158:     if (n->nlmsg_type != RTM_NEWROUTE) {
  159: 	if (!IN_LINK_LOCAL_RANGE(rpf->source.s_addr)) {
  160: 	    if (n->nlmsg_type != NLMSG_ERROR)
  161: 		logit(LOG_WARNING, 0, "netlink: wrong answer type %d", n->nlmsg_type);
  162: 	    else
  163: 		logit(LOG_WARNING, -(*(int*)NLMSG_DATA(n)), "netlink get_route");
  164: 	}
  165: 
  166: 	return FALSE;
  167:     }
  168: 
  169:     return getmsg(NLMSG_DATA(n), l - sizeof(*n), rpf);
  170: }
  171: 
  172: static int getmsg(struct rtmsg *rtm, int msglen, struct rpfctl *rpf)
  173: {
  174:     int ifindex;
  175:     vifi_t vifi;
  176:     struct uvif *v;
  177:     struct rtattr *rta[RTA_MAX + 1];
  178:     
  179:     if (!rpf) {
  180: 	logit(LOG_WARNING, 0, "Missing rpf pointer to netlink.c:getmsg()!");
  181: 	return FALSE;
  182:     }
  183: 
  184:     rpf->iif = NO_VIF;
  185:     rpf->rpfneighbor.s_addr = INADDR_ANY;
  186: 
  187:     if (rtm->rtm_type == RTN_LOCAL) {
  188: 	IF_DEBUG(DEBUG_RPF)
  189: 	    logit(LOG_DEBUG, 0, "NETLINK: local address");
  190: 
  191: 	if ((rpf->iif = local_address(rpf->source.s_addr)) != MAXVIFS) {
  192: 	    rpf->rpfneighbor.s_addr = rpf->source.s_addr;
  193: 
  194: 	    return TRUE;
  195: 	}
  196: 
  197: 	return FALSE;
  198:     }
  199:     
  200:     if (rtm->rtm_type != RTN_UNICAST) {
  201: 	IF_DEBUG(DEBUG_RPF)
  202: 	    logit(LOG_DEBUG, 0, "NETLINK: route type is %d", rtm->rtm_type);
  203: 	return FALSE;
  204:     }
  205:     
  206:     memset(rta, 0, sizeof(rta));
  207:     parse_rtattr(rta, RTA_MAX, RTM_RTA(rtm), msglen - sizeof(*rtm));
  208:     
  209:     if (!rta[RTA_OIF]) {
  210: 	logit(LOG_WARNING, 0, "NETLINK: no outbound interface");
  211: 	return FALSE;
  212:     }
  213: 
  214:     /* Get ifindex of outbound interface */
  215:     ifindex = *(int *)RTA_DATA(rta[RTA_OIF]);
  216: 
  217:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
  218: 	if (v->uv_ifindex == ifindex)
  219: 	    break;
  220:     }
  221: 
  222:     if (vifi >= numvifs) {
  223: 	logit(LOG_WARNING, 0, "NETLINK: ifindex=%d, but no vif", ifindex);
  224: 	return FALSE;
  225:     }
  226: 
  227:     /* Found inbound interface in vifi */
  228:     rpf->iif = vifi;
  229: 
  230:     IF_DEBUG(DEBUG_RPF)
  231: 	logit(LOG_DEBUG, 0, "NETLINK: vif %d, ifindex=%d", vifi, ifindex);
  232: 
  233:     if (rta[RTA_GATEWAY]) {
  234: 	uint32_t gw = *(uint32_t *)RTA_DATA(rta[RTA_GATEWAY]);
  235: 
  236: 	IF_DEBUG(DEBUG_RPF)
  237: 	    logit(LOG_DEBUG, 0, "NETLINK: gateway is %s", inet_fmt(gw, s1, sizeof(s1)));
  238: 	rpf->rpfneighbor.s_addr = gw;
  239:     } else {
  240: 	rpf->rpfneighbor.s_addr = rpf->source.s_addr;
  241:     }
  242: 
  243:     return TRUE;
  244: }
  245: 
  246: /**
  247:  * Local Variables:
  248:  *  version-control: t
  249:  *  indent-tabs-mode: t
  250:  *  c-file-style: "ellemtel"
  251:  *  c-basic-offset: 4
  252:  * End:
  253:  */

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