static int parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route) { void *rta = (void*)rtm + sizeof(struct rt_msghdr); struct sockaddr_in6 *sin6; char addr[INET6_ADDRSTRLEN]; memset(route, 0, sizeof(*route)); route->metric = 0; route->ifindex = rtm->rtm_index; if(!(rtm->rtm_addrs & RTA_DST)) return -1; sin6 = (struct sockaddr_in6 *)rta; if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) return -1; if((rtm->rtm_flags & RTF_PROTO2) != 0) return -1; memcpy(&route->prefix, &sin6->sin6_addr, 16); rta += ROUNDUP(sizeof(struct sockaddr_in6)); if(!(rtm->rtm_addrs & RTA_GATEWAY)) return -1; sin6 = (struct sockaddr_in6 *)rta; if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) { route->ifindex = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); } memcpy(&route->gw, &sin6->sin6_addr, 16); rta += ROUNDUP(sizeof(struct sockaddr_in6)); if(!(rtm->rtm_addrs & RTA_NETMASK)) { route->plen = 0; } else { sin6 = (struct sockaddr_in6 *)rta; route->plen = mask2len(&sin6->sin6_addr); inet_ntop(AF_INET6, &sin6->sin6_addr, addr, sizeof(addr)); rta += ROUNDUP(sizeof(struct sockaddr_in6)); } if (rtm->rtm_flags & RTF_HOST) route->plen = 128; if(ifindex_lo < 0) { ifindex_lo = if_nametoindex("lo0"); if(ifindex_lo <= 0) return -1; } if(route->ifindex == ifindex_lo) return -1; return 0; }
static int parse_kernel_route(const struct rt_msghdr *rtm, struct kernel_route *route) { struct sockaddr *sa; char *rta = (char*)rtm + sizeof(struct rt_msghdr); uint32_t excluded_flags = 0; if(ifindex_lo < 0) { ifindex_lo = if_nametoindex("lo0"); if(ifindex_lo <= 0) return -1; } memset(route, 0, sizeof(*route)); route->metric = 0; route->ifindex = rtm->rtm_index; #if defined(RTF_IFSCOPE) /* Filter out kernel route on OS X */ excluded_flags |= RTF_IFSCOPE; #endif #if defined(RTF_MULTICAST) /* Filter out multicast route on others BSD */ excluded_flags |= RTF_MULTICAST; #endif /* Filter out our own route */ excluded_flags |= RTF_PROTO2; if((rtm->rtm_flags & excluded_flags) != 0) return -1; /* Prefix */ if(!(rtm->rtm_addrs & RTA_DST)) return -1; sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; memcpy(route->prefix, &sin6->sin6_addr, 16); if(IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) return -1; } else if(sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; #if defined(IN_LINKLOCAL) if(IN_LINKLOCAL(ntohl(sin->sin_addr.s_addr))) return -1; #endif if(IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) return -1; v4tov6(route->prefix, (unsigned char *)&sin->sin_addr); } else { return -1; } /* Gateway */ if(!(rtm->rtm_addrs & RTA_GATEWAY)) return -1; sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(sa->sa_family == AF_INET6) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; memcpy(route->gw, &sin6->sin6_addr, 16); if(IN6_IS_ADDR_LINKLOCAL (&sin6->sin6_addr)) { route->ifindex = IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr); SET_IN6_LINKLOCAL_IFINDEX(sin6->sin6_addr, 0); } } else if(sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; v4tov6(route->gw, (unsigned char *)&sin->sin_addr); } if((int)route->ifindex == ifindex_lo) return -1; /* Netmask */ if((rtm->rtm_addrs & RTA_NETMASK) != 0) { sa = (struct sockaddr *)rta; rta += ROUNDUP(sa->sa_len); if(!v4mapped(route->prefix)) { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; route->plen = mask2len((unsigned char*)&sin6->sin6_addr, 16); } else { struct sockaddr_in *sin = (struct sockaddr_in *)sa; route->plen = mask2len((unsigned char*)&sin->sin_addr, 4); } } if(v4mapped(route->prefix)) route->plen += 96; if(rtm->rtm_flags & RTF_HOST) route->plen = 128; return 0; }