Annotation of embedaddon/pimd/netlink.c, revision 1.1.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>