static int addr2mac_add(const int ifindex, const int type, const void *ipraw, const void *macraw, const time_t expire) { const int mt = SCAMPER_ADDR_TYPE_ETHERNET; scamper_addr_t *mac = NULL; scamper_addr_t *ip = NULL; addr2mac_t *addr2mac = NULL; char ipstr[128], macstr[128]; if((ip = scamper_addrcache_get(addrcache, type, ipraw)) == NULL) { printerror(errno, strerror, __func__, "could not get ip"); goto err; } if((mac = scamper_addrcache_get(addrcache, mt, macraw)) == NULL) { printerror(errno, strerror, __func__, "could not get mac"); goto err; } if((addr2mac = addr2mac_alloc(ifindex, ip, mac, expire)) == NULL) { goto err; } scamper_addr_free(ip); ip = NULL; scamper_addr_free(mac); mac = NULL; if(splaytree_insert(tree, addr2mac) == NULL) { printerror(errno, strerror, __func__, "could not add %s:%s to tree", scamper_addr_tostr(addr2mac->ip, ipstr, sizeof(ipstr)), scamper_addr_tostr(addr2mac->mac, macstr, sizeof(macstr))); goto err; } scamper_debug(__func__, "ifindex %d ip %s mac %s expire %d", ifindex, scamper_addr_tostr(addr2mac->ip, ipstr, sizeof(ipstr)), scamper_addr_tostr(addr2mac->mac, macstr, sizeof(macstr)), expire); return 0; err: if(addr2mac != NULL) addr2mac_free(addr2mac); if(mac != NULL) scamper_addr_free(mac); if(ip != NULL) scamper_addr_free(ip); return -1; }
/* * scamper_getsrc * * given a destination address, determine the src address used in the IP * header to transmit probes to it. */ scamper_addr_t *scamper_getsrc(const scamper_addr_t *dst, int ifindex) { struct sockaddr_storage sas; scamper_addr_t *src; socklen_t socklen, sockleno; int sock; void *addr; char buf[64]; if(dst->type == SCAMPER_ADDR_TYPE_IPV4) { if(udp4 == -1 && (udp4 = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) { printerror(errno, strerror, __func__, "could not open udp4 sock"); return NULL; } sock = udp4; addr = &((struct sockaddr_in *)&sas)->sin_addr; socklen = sizeof(struct sockaddr_in); sockaddr_compose((struct sockaddr *)&sas, AF_INET, dst->addr, 80); } else if(dst->type == SCAMPER_ADDR_TYPE_IPV6) { if(udp6 == -1 && (udp6 = socket(AF_INET6, SOCK_DGRAM,IPPROTO_UDP)) == -1) { printerror(errno, strerror, __func__, "could not open udp6 sock"); return NULL; } sock = udp6; addr = &((struct sockaddr_in6 *)&sas)->sin6_addr; socklen = sizeof(struct sockaddr_in6); sockaddr_compose((struct sockaddr *)&sas, AF_INET6, dst->addr, 80); if(scamper_addr_islinklocal(dst) != 0) { ((struct sockaddr_in6 *)&sas)->sin6_scope_id = ifindex; } } else return NULL; if(connect(sock, (struct sockaddr *)&sas, socklen) != 0) { printerror(errno, strerror, __func__, "connect to dst failed for %s", scamper_addr_tostr(dst, buf, sizeof(buf))); return NULL; } sockleno = socklen; if(getsockname(sock, (struct sockaddr *)&sas, &sockleno) != 0) { printerror(errno, strerror, __func__, "could not getsockname for %s", scamper_addr_tostr(dst, buf, sizeof(buf))); return NULL; } src = scamper_addrcache_get(addrcache, dst->type, addr); memset(&sas, 0, sizeof(sas)); connect(sock, (struct sockaddr *)&sas, socklen); return src; }
static void rtsock_parsemsg(uint8_t *buf, size_t len) { struct rt_msghdr *rtm; struct sockaddr *addrs[RTAX_MAX]; struct sockaddr_dl *sdl; struct sockaddr *sa; struct in6_addr *ip6; size_t off, tmp, x; int i, ifindex; void *addr; scamper_addr_t *gw; rtsock_pair_t *pair; scamper_route_t *route; x = 0; while(x < len) { if(len - x < sizeof(struct rt_msghdr)) { scamper_debug(__func__,"len %d != %d",len,sizeof(struct rt_msghdr)); return; } /* * check if the message is something we want, and that we have * a pair for it */ rtm = (struct rt_msghdr *)(buf + x); if(rtm->rtm_pid != pid || rtm->rtm_msglen > len - x || rtm->rtm_type != RTM_GET || (rtm->rtm_flags & RTF_DONE) == 0 || (pair = rtsock_pair_get(rtm->rtm_seq)) == NULL) { x += rtm->rtm_msglen; continue; } route = pair->route; rtsock_pair_free(pair); ifindex = -1; addr = NULL; gw = NULL; if(rtm->rtm_errno != 0) { route->error = rtm->rtm_errno; goto done; } off = sizeof(struct rt_msghdr); memset(addrs, 0, sizeof(addrs)); for(i=0; i<RTAX_MAX; i++) { if(rtm->rtm_addrs & (1 << i)) { addrs[i] = sa = (struct sockaddr *)(buf + x + off); if((tmp = sockaddr_len(sa)) == -1) { printerror(0,NULL,__func__,"unhandled af %d",sa->sa_family); route->error = EINVAL; goto done; } off += scamper_rtsock_roundup(tmp); } } if((sdl = (struct sockaddr_dl *)addrs[RTAX_IFP]) != NULL) { if(sdl->sdl_family != AF_LINK) { printerror(0, NULL, __func__, "sdl_family %d", sdl->sdl_family); route->error = EINVAL; goto done; } ifindex = sdl->sdl_index; } if((sa = addrs[RTAX_GATEWAY]) != NULL) { if(sa->sa_family == AF_INET) { i = SCAMPER_ADDR_TYPE_IPV4; addr = &((struct sockaddr_in *)sa)->sin_addr; } else if(sa->sa_family == AF_INET6) { /* * check to see if the gw address is a link local address. if * it is, then drop the embedded index from the gateway address */ ip6 = &((struct sockaddr_in6 *)sa)->sin6_addr; if(IN6_IS_ADDR_LINKLOCAL(ip6)) { ip6->s6_addr[2] = 0; ip6->s6_addr[3] = 0; } i = SCAMPER_ADDR_TYPE_IPV6; addr = ip6; } else if(sa->sa_family == AF_LINK) { sdl = (struct sockaddr_dl *)sa; if(sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ETHER_ADDR_LEN) { i = SCAMPER_ADDR_TYPE_ETHERNET; addr = sdl->sdl_data + sdl->sdl_nlen; } } /* * if we have got a gateway address that we know what to do with, * then store it here. */ if(addr != NULL && (gw = scamper_addrcache_get(addrcache, i, addr)) == NULL) { scamper_debug(__func__, "could not get rtsmsg->rr.gw"); route->error = EINVAL; goto done; } } done: route->gw = gw; route->ifindex = ifindex; route->cb(route); x += rtm->rtm_msglen; } return; }