static int parse_address(struct nlmsghdr *nh) { int len; struct kernel_address kaddr; struct ifaddrmsg *ifa = NULL; struct rtattr *rta = NULL; unsigned int rta_len; int is_v4 = 0; len = nh->nlmsg_len; ifa = (struct ifaddrmsg*)NLMSG_DATA(nh); len -= NLMSG_LENGTH(0); memset(&kaddr, 0, sizeof(kaddr)); kaddr.sa.sa_family = ifa->ifa_family; if (kaddr.sa.sa_family != AF_INET && kaddr.sa.sa_family != AF_INET6) { log_dbg(LOG_DEBUG_KERNEL, "Unknown family: %d\n", kaddr.sa.sa_family); return -1; } is_v4 = kaddr.sa.sa_family == AF_INET; rta = IFA_RTA(ifa); len -= NLMSG_ALIGN(sizeof(*ifa)); #define COPY_ADDR(d, s) \ do { \ if(!is_v4) { \ assert(rta_len >= 16); \ memcpy(&d.sin6.sin6_addr, s, 16); \ }else { \ assert(rta_len >= 4); \ memcpy(&d.sin.sin_addr, s, 4); \ } \ } while(0) for(; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { rta_len = RTA_PAYLOAD(rta); switch (rta->rta_type) { case IFA_UNSPEC: break; case IFA_ADDRESS: COPY_ADDR(kaddr, RTA_DATA(rta)); break; case IFA_LOCAL: COPY_ADDR(kaddr, RTA_DATA(rta)); kaddr.flags |= ADDR_LOCAL; break; default: break; } } #undef COPY_ADDR #undef GET_PLEN if (nh->nlmsg_type == RTM_NEWADDR) addr_add(&addresses, &kaddr); else addr_del(addresses, &kaddr); return 0; }
static int parse_kernel_route_rta(struct rtmsg *rtm, int len, struct kernel_route *route) { int table = rtm->rtm_table; struct rtattr *rta= RTM_RTA(rtm);; len -= NLMSG_ALIGN(sizeof(*rtm)); memset(&route->prefix, 0, sizeof(struct in6_addr)); memset(&route->gw, 0, sizeof(struct in6_addr)); route->plen = rtm->rtm_dst_len; if(rtm->rtm_family == AF_INET) { const unsigned char zeroes[4] = {0, 0, 0, 0}; v4tov6(route->prefix, zeroes); route->plen += 96; } route->metric = 0; route->ifindex = 0; route->proto = rtm->rtm_protocol; #define COPY_ADDR(d, s) \ do { \ if(rtm->rtm_family == AF_INET6) \ memcpy(d, s, 16); \ else if(rtm->rtm_family == AF_INET) \ v4tov6(d, s); \ else \ return -1; \ } while(0) while(RTA_OK(rta, len)) { switch (rta->rta_type) { case RTA_DST: COPY_ADDR(route->prefix, RTA_DATA(rta)); break; case RTA_GATEWAY: COPY_ADDR(route->gw, RTA_DATA(rta)); break; case RTA_OIF: route->ifindex = *(int*)RTA_DATA(rta); break; case RTA_PRIORITY: route->metric = *(int*)RTA_DATA(rta); if(route->metric < 0 || route->metric > KERNEL_INFINITY) route->metric = KERNEL_INFINITY; break; case RTA_TABLE: table = *(int*)RTA_DATA(rta); break; default: break; } rta = RTA_NEXT(rta, len); } #undef COPY_ADDR if(table != import_table) return -1; return 0; }