Annotation of embedaddon/pimd/netlink.c, revision 1.1

1.1     ! misho       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>