int scamper_addr2mac_add(int ifindex, scamper_addr_t *ip, scamper_addr_t *mac) { addr2mac_t *a2m = NULL; char ipstr[128], macstr[128]; if(scamper_addr2mac_whohas(ifindex, ip) != NULL) return 0; if((a2m = addr2mac_alloc(ifindex, ip, mac, 0)) == NULL) return -1; if(splaytree_insert(tree, a2m) == NULL) { printerror(errno, strerror, __func__, "could not add %s:%s to tree", scamper_addr_tostr(a2m->ip, ipstr, sizeof(ipstr)), scamper_addr_tostr(a2m->mac, macstr, sizeof(macstr))); addr2mac_free(a2m); return -1; } scamper_debug(__func__, "ifindex %d ip %s mac %s", ifindex, scamper_addr_tostr(a2m->ip, ipstr, sizeof(ipstr)), scamper_addr_tostr(a2m->mac, macstr, sizeof(macstr))); return 0; }
int scamper_ip4_hlen(scamper_probe_t *pr, size_t *hlen) { size_t ip4hlen = sizeof(struct ip); scamper_probe_ipopt_t *opt; int i; for(i=0; i<pr->pr_ipoptc; i++) { opt = &pr->pr_ipopts[i]; if(opt->type == SCAMPER_PROBE_IPOPTS_V4RR) { /* * want the ability to record at least one IP address otherwise * the option is useless. */ if(ip4hlen + 8 > 60) goto err; /* for now assume this option fills the rest of the option space */ ip4hlen = 60; } else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSPS) { if(opt->opt_v4tsps_ipc < 1 || opt->opt_v4tsps_ipc > 4) goto err; ip4hlen += (opt->opt_v4tsps_ipc * 4 * 2) + 4; if(ip4hlen > 60) goto err; } else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSO) { ip4hlen += 40; if(ip4hlen > 60) goto err; } else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSAA) { ip4hlen += 36; if(ip4hlen > 60) goto err; } else if(opt->type == SCAMPER_PROBE_IPOPTS_QUICKSTART) { ip4hlen += 8; if(ip4hlen > 60) goto err; } else goto err; } *hlen = ip4hlen; return 0; err: scamper_debug(__func__, "invalid IPv4 header specification"); return -1; }
static int fds_kqueue_init(void) { if((kq = kqueue()) == -1) { printerror(errno, strerror, __func__, "could not create kqueue"); return -1; } scamper_debug(__func__, "fd %d", kq); return 0; }
static int fds_epoll_init(void) { if((ep = epoll_create(10)) == -1) { printerror(errno, strerror, __func__, "could not epoll_create"); return -1; } scamper_debug(__func__, "fd %d", ep); return 0; }
static void rtattr_dump(struct rtattr *rta) { char *rta_type; char rta_data[64]; int i; switch(rta->rta_type) { case RTA_UNSPEC: rta_type = "unspec"; break; case RTA_DST: rta_type = "dst"; break; case RTA_SRC: rta_type = "src"; break; case RTA_IIF: rta_type = "iif"; break; case RTA_OIF: rta_type = "oif"; break; case RTA_GATEWAY: rta_type = "gateway"; break; case RTA_PRIORITY: rta_type = "priority"; break; case RTA_PREFSRC: rta_type = "prefsrc"; break; case RTA_METRICS: rta_type = "metrics"; break; case RTA_MULTIPATH: rta_type = "multipath"; break; case RTA_PROTOINFO: rta_type = "protoinfo"; break; case RTA_FLOW: rta_type = "flow"; break; case RTA_CACHEINFO: rta_type = "cacheinfo"; break; case RTA_SESSION: rta_type = "session"; break; default: rta_type = "<unknown>"; break; } for(i=0;i<rta->rta_len-sizeof(struct rtattr)&&i<(sizeof(rta_data)/2)-1;i++) { snprintf(&rta_data[i*2], 3, "%02x", *(uint8_t *)(((char *)rta) + sizeof(struct rtattr) + i)); } if(i != 0) { scamper_debug(__func__, "type %s len %d data %s", rta_type, rta->rta_len-sizeof(struct rtattr), rta_data); } else { scamper_debug(__func__, "type %s\n", rta_type); } return; }
int scamper_outfile_close(scamper_outfile_t *sof) { if(sof->refcnt > 1) { scamper_debug(__func__,"not closing %s refcnt %d",sof->name,sof->refcnt); return -1; } outfile_free(sof); return 0; }
/* * scamper_fds_init * * setup the global data structures necessary for scamper to manage a set of * file descriptors */ int scamper_fds_init() { #ifdef HAVE_GETDTABLESIZE scamper_debug(__func__, "fd table size: %d", getdtablesize()); #endif #ifdef HAVE_POLL pollfunc = fds_poll; #endif #ifdef HAVE_KQUEUE if(scamper_option_kqueue()) { pollfunc = fds_kqueue; if(fds_kqueue_init() != 0) return -1; } #endif #ifdef HAVE_EPOLL if(scamper_option_epoll()) { pollfunc = fds_epoll; if(fds_epoll_init() != 0) return -1; } #endif if(scamper_option_select() || pollfunc == NULL) pollfunc = fds_select; if((fd_list = alloc_list("fd_list")) == NULL || (read_fds = alloc_list("read_fds")) == NULL || (read_queue = alloc_list("read_queue")) == NULL || (write_fds = alloc_list("write_fds")) == NULL || (write_queue = alloc_list("write_queue")) == NULL || (refcnt_0 = alloc_list("refcnt_0")) == NULL) { return -1; } if((fd_tree = splaytree_alloc(fd_cmp)) == NULL) { printerror(errno, strerror, __func__, "alloc fd tree failed"); return -1; } planetlab = scamper_option_planetlab(); return 0; }
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; }
/* * fd_free * * free up memory allocated to scamper's monitoring of the file descriptor. */ static void fd_free(scamper_fd_t *fdn) { scamper_debug(__func__, "fd %d type %s", fdn->fd, fd_tostr(fdn)); if(fdn->fd >= 0 && fdn->fd < fd_array_s && fd_array != NULL) fd_array[fdn->fd] = NULL; if(fdn->read.node != NULL) dlist_node_pop(fdn->read.list, fdn->read.node); if(fdn->write.node != NULL) dlist_node_pop(fdn->write.list, fdn->write.node); if(fdn->rc0 != NULL) dlist_node_pop(refcnt_0, fdn->rc0); if(fdn->fd_tree_node != NULL) splaytree_remove_node(fd_tree, fdn->fd_tree_node); if(fdn->fd_list_node != NULL) dlist_node_pop(fd_list, fdn->fd_list_node); if(SCAMPER_FD_TYPE_IS_ICMP(fdn)) { if(fdn->fd_icmp_addr != NULL) free(fdn->fd_icmp_addr); } else if(SCAMPER_FD_TYPE_IS_UDP(fdn)) { if(fdn->fd_udp_addr != NULL) free(fdn->fd_udp_addr); } else if(SCAMPER_FD_TYPE_IS_TCP(fdn)) { if(fdn->fd_tcp_addr != NULL) free(fdn->fd_tcp_addr); } else if(SCAMPER_FD_TYPE_IS_DL(fdn)) { if(fdn->fd_dl_dl != NULL) scamper_dl_state_free(fdn->fd_dl_dl); } free(fdn); return; }
int scamper_task_sig_install(scamper_task_t *task) { scamper_task_sig_t *sig; scamper_task_t *tf; s2t_t *s2t; slist_node_t *n; if(slist_count(task->siglist) < 1) return -1; for(n=slist_head_node(task->siglist); n != NULL; n = slist_node_next(n)) { s2t = slist_node_item(n); sig = s2t->sig; /* check if another task has this signature already */ if((tf = scamper_task_find(sig)) != NULL) { if(tf != task) goto err; continue; } if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP) s2t->node = splaytree_insert(tx_ip, s2t); else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND) s2t->node = splaytree_insert(tx_nd, s2t); else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_SNIFF) s2t->node = dlist_tail_push(sniff, s2t); if(s2t->node == NULL) { scamper_debug(__func__, "could not install sig"); goto err; } } return 0; err: scamper_task_sig_deinstall(task); return -1; }
int scamper_if_getifname(char *str, size_t len, int ifindex) { char ifname[IFNAMSIZ]; if(if_indextoname(ifindex, ifname) == NULL) { printerror(errno, strerror, __func__, "could not get name for %d", ifindex); return -1; } if(strlen(ifname) + 1 > len) { scamper_debug(__func__, "ifname too small"); return -1; } strncpy(str, ifname, len); return 0; }
void scamper_outfiles_cleanup() { if(outfile_def != NULL) { if(--outfile_def->refcnt > 0) { scamper_debug(__func__, "default outfile refcnt %d", outfile_def->refcnt); } outfile_free(outfile_def); outfile_def = NULL; } if(outfiles != NULL) { splaytree_free(outfiles, NULL); outfiles = NULL; } return; }
static void outfile_free(scamper_outfile_t *sof) { assert(sof != NULL); if(sof->name != NULL && sof->sf != NULL) scamper_debug(__func__, "name %s fd %d", sof->name, scamper_file_getfd(sof->sf)); if(sof->name != NULL) { splaytree_remove_item(outfiles, sof); free(sof->name); } if(sof->sf != NULL) { scamper_file_close(sof->sf); } free(sof); return; }
static scamper_outfile_t *outfile_alloc(char *name, scamper_file_t *sf) { scamper_outfile_t *sof = NULL; if((sof = malloc_zero(sizeof(scamper_outfile_t))) == NULL) { printerror(errno, strerror, __func__, "could not malloc sof"); goto err; } sof->sf = sf; sof->refcnt = 1; if((sof->name = strdup(name)) == NULL) { printerror(errno, strerror, __func__, "could not strdup"); goto err; } if(splaytree_insert(outfiles, sof) == NULL) { printerror(errno, strerror, __func__, "could not insert"); goto err; } scamper_debug(__func__, "name %s fd %d", name, scamper_file_getfd(sf)); return sof; err: if(sof != NULL) { if(sof->name != NULL) free(sof->name); free(sof); } return NULL; }
static int ipfw_sysctl_check(void) { scamper_osinfo_t *osinfo = NULL; size_t len; char *name; int i; len = sizeof(i); name = "net.inet.ip.fw.enable"; if(sysctlbyname(name, &i, &len, NULL, 0) != 0) { printerror(errno, strerror, __func__, "could not sysctl %s", name); return -1; } else { if(i != 0) have_ipv4 = 1; else scamper_debug(__func__, "ipfw ipv4 not enabled"); } len = sizeof(i); name = "net.inet6.ip6.fw.enable"; if(sysctlbyname(name, &i, &len, NULL, 0) != 0) { printerror(errno, strerror, __func__, "could not sysctl %s", name); if(errno != ENOENT) return -1; if((osinfo = uname_wrap()) == NULL) { printerror(errno, strerror, __func__, "could not uname"); return -1; } /* * check if the system is known to not have a separate sysctl for * ipv6 ipfw. */ i = 0; if((osinfo->os_id == SCAMPER_OSINFO_OS_FREEBSD && osinfo->os_rel[0] == 6 && osinfo->os_rel[1] < 3) || (osinfo->os_id == SCAMPER_OSINFO_OS_DARWIN && osinfo->os_rel[0] == 8)) { have_ipv6 = have_ipv4; } else i++; scamper_osinfo_free(osinfo); if(i != 0) return -1; } else { if(i != 0) have_ipv6 = 1; else scamper_debug(__func__, "ipfw ipv6 not enabled"); } return 0; }
static int addr2mac_init_linux() { struct nlmsghdr *nlmsg; struct ndmsg *ndmsg; struct rtattr *rta, *tb[NDA_MAX]; struct sockaddr_nl snl; struct msghdr msg; struct iovec iov; struct timeval tv; pid_t pid; uint8_t buf[16384]; ssize_t ssize; ssize_t len; int rlen; int fd = -1; void *ip, *mac; int iptype; pid = getpid(); memset(buf, 0, sizeof(buf)); nlmsg = (struct nlmsghdr *)buf; nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); nlmsg->nlmsg_type = RTM_GETNEIGH; nlmsg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH; nlmsg->nlmsg_seq = 0; nlmsg->nlmsg_pid = pid; ndmsg = NLMSG_DATA(nlmsg); ndmsg->ndm_family = AF_UNSPEC; if((fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1) { printerror(errno, strerror, __func__, "could not open netlink"); goto err; } len = nlmsg->nlmsg_len; if((ssize = send(fd, buf, len, 0)) < len) { if(ssize == -1) { printerror(errno, strerror, __func__, "could not send netlink"); } goto err; } for(;;) { iov.iov_base = buf; iov.iov_len = sizeof(buf); msg.msg_name = &snl; msg.msg_namelen = sizeof(snl); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; if((len = recvmsg(fd, &msg, 0)) == -1) { if(errno == EINTR) continue; printerror(errno, strerror, __func__, "could not recvmsg"); goto err; } gettimeofday_wrap(&tv); nlmsg = (struct nlmsghdr *)buf; while(NLMSG_OK(nlmsg, len)) { if(nlmsg->nlmsg_pid != pid || nlmsg->nlmsg_seq != 0) { goto skip; } if(nlmsg->nlmsg_type == NLMSG_DONE) { goto done; } if(nlmsg->nlmsg_type == NLMSG_ERROR) { scamper_debug(__func__, "nlmsg error"); goto err; } /* get current neighbour entries only */ if(nlmsg->nlmsg_type != RTM_NEWNEIGH) { goto skip; } /* make sure the address is reachable */ ndmsg = NLMSG_DATA(nlmsg); if((ndmsg->ndm_state & NUD_REACHABLE) == 0) { goto skip; } /* make sure we can process this address type */ switch(ndmsg->ndm_family) { case AF_INET: iptype = SCAMPER_ADDR_TYPE_IPV4; break; case AF_INET6: iptype = SCAMPER_ADDR_TYPE_IPV6; break; default: goto skip; } /* fill a table with parameters from the payload */ memset(tb, 0, sizeof(tb)); rlen = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg)); for(rta = NDA_RTA(ndmsg); RTA_OK(rta,rlen); rta = RTA_NEXT(rta,rlen)) { if(rta->rta_type >= NDA_MAX) continue; tb[rta->rta_type] = rta; } /* * skip if we don't have a destination IP address, or if * we don't have an ethernet mac address */ if(tb[NDA_DST] == NULL || tb[NDA_LLADDR] == NULL || RTA_PAYLOAD(tb[NDA_LLADDR]) != 6) { goto skip; } ip = RTA_DATA(tb[NDA_DST]); mac = RTA_DATA(tb[NDA_LLADDR]); addr2mac_add(ndmsg->ndm_ifindex, iptype, ip, mac, tv.tv_sec+600); skip: nlmsg = NLMSG_NEXT(nlmsg, len); } } done: close(fd); return 0; err: close(fd); return -1; }
static void rtsock_parsemsg(uint8_t *buf, size_t len) { struct nlmsghdr *nlmsg; struct nlmsgerr *nlerr; struct rtmsg *rtmsg; struct rtattr *rta; void *gwa = NULL; int ifindex = -1; scamper_addr_t *gw = NULL; rtsock_pair_t *pair = NULL; scamper_route_t *route = NULL; if(len < sizeof(struct nlmsghdr)) { scamper_debug(__func__, "len %d != %d", len, sizeof(struct nlmsghdr)); return; } nlmsg = (struct nlmsghdr *)buf; /* if the message isn't addressed to this pid, drop it */ if(nlmsg->nlmsg_pid != pid) return; if((pair = rtsock_pair_get(nlmsg->nlmsg_seq)) == NULL) return; route = pair->route; rtsock_pair_free(pair); if(nlmsg->nlmsg_type == RTM_NEWROUTE) { rtmsg = NLMSG_DATA(nlmsg); /* this is the payload length of the response packet */ len = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); /* hunt through the payload for the RTA_OIF entry */ rta = RTM_RTA(rtmsg); while(RTA_OK(rta, len)) { switch(rta->rta_type) { case RTA_OIF: ifindex = *(unsigned *)RTA_DATA(rta); break; case RTA_GATEWAY: gwa = RTA_DATA(rta); break; } rta = RTA_NEXT(rta, len); } if(gwa != NULL) { if(rtmsg->rtm_family == AF_INET) gw = scamper_addrcache_get_ipv4(addrcache, gwa); else if(rtmsg->rtm_family == AF_INET6) gw = scamper_addrcache_get_ipv6(addrcache, gwa); else route->error = EINVAL; } } else if(nlmsg->nlmsg_type == NLMSG_ERROR) { nlerr = NLMSG_DATA(nlmsg); route->error = nlerr->error; } else goto skip; route->gw = gw; route->ifindex = ifindex; route->cb(route); return; skip: if(route != NULL) scamper_route_free(route); return; }
int scamper_ip4_build(scamper_probe_t *pr, uint8_t *buf, size_t *len) { scamper_probe_ipopt_t *opt; struct ip *ip; size_t off, ip4hlen; int i, j; if(scamper_ip4_hlen(pr, &ip4hlen) != 0) return -1; if(ip4hlen > *len) { *len = ip4hlen; return -1; } ip = (struct ip *)buf; off = sizeof(struct ip); #ifndef _WIN32 ip->ip_v = 4; ip->ip_hl = (ip4hlen / 4); #else ip->ip_vhl = 0x40 | (ip4hlen / 4); #endif if((pr->pr_ip_off & IP_OFFMASK) != 0 || pr->pr_no_trans) ip->ip_len = htons(ip4hlen + pr->pr_len); else if(pr->pr_ip_proto == IPPROTO_ICMP || pr->pr_ip_proto == IPPROTO_UDP) ip->ip_len = htons(ip4hlen + 8 + pr->pr_len); else if(pr->pr_ip_proto == IPPROTO_TCP) ip->ip_len = htons(ip4hlen + scamper_tcp4_hlen(pr) + pr->pr_len); else { scamper_debug(__func__, "unimplemented pr %d", pr->pr_ip_proto); return -1; } ip->ip_tos = pr->pr_ip_tos; ip->ip_id = htons(pr->pr_ip_id); ip->ip_off = htons(pr->pr_ip_off); ip->ip_ttl = pr->pr_ip_ttl; ip->ip_p = pr->pr_ip_proto; ip->ip_sum = 0; memcpy(&ip->ip_src, pr->pr_ip_src->addr, sizeof(ip->ip_src)); memcpy(&ip->ip_dst, pr->pr_ip_dst->addr, sizeof(ip->ip_dst)); for(i=0; i<pr->pr_ipoptc; i++) { opt = &pr->pr_ipopts[i]; if(opt->type == SCAMPER_PROBE_IPOPTS_V4RR) { memset(buf+off+3, 0, 37); buf[off+0] = 7; buf[off+1] = 39; buf[off+2] = 4; off = 60; } else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSPS || opt->type == SCAMPER_PROBE_IPOPTS_V4TSO || opt->type == SCAMPER_PROBE_IPOPTS_V4TSAA) { buf[off+0] = 68; buf[off+2] = 5; if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSPS) { buf[off+1] = (opt->opt_v4tsps_ipc * 4 * 2) + 4; buf[off+3] = 3; off += 4; for(j=0; j<opt->opt_v4tsps_ipc; j++) { memcpy(buf+off, &opt->opt_v4tsps_ips[j], 4); off += 4; memset(buf+off, 0, 4); off += 4; } } else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSO) { buf[off+1] = 40; memset(buf+off+3, 0, 41); off += 40; } else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSAA) { buf[off+1] = 36; buf[off+3] = 1; memset(buf+off+4, 0, 36); off += 36; } } else if(opt->type == SCAMPER_PROBE_IPOPTS_QUICKSTART) { assert(opt->opt_qs_func <= 0xf); assert(opt->opt_qs_rate <= 0xf); buf[off+0] = 25; buf[off+1] = 8; buf[off+2] = (opt->opt_qs_func << 4) | opt->opt_qs_rate; buf[off+3] = opt->opt_qs_ttl; bytes_htonl(&buf[off+4], opt->opt_qs_nonce << 2); off += 8; } else return -1; } assert(off == ip4hlen); ip->ip_sum = in_cksum(ip, ip4hlen); *len = off; return 0; }
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; }
int scamper_probe_task(scamper_probe_t *pr, scamper_task_t *task) { probe_t *pt = NULL; scamper_fd_t *icmp = NULL; scamper_fd_t *fd; int spoof = 0; uint16_t sp; void *src = NULL; int dl = 0; probe_print(pr); if((pr->pr_flags & SCAMPER_PROBE_FLAG_SPOOF) != 0) spoof = 1; /* get an ICMP socket to listen for responses */ if(SCAMPER_ADDR_TYPE_IS_IPV4(pr->pr_ip_dst)) { if(spoof == 0) { src = pr->pr_ip_src->addr; if((icmp = scamper_task_fd_icmp4(task, src)) == NULL) { pr->pr_errno = errno; goto err; } } } else if(SCAMPER_ADDR_TYPE_IS_IPV6(pr->pr_ip_dst)) { if(spoof == 0) { src = pr->pr_ip_src->addr; if((icmp = scamper_task_fd_icmp6(task, src)) == NULL) { pr->pr_errno = errno; goto err; } } } else { scamper_debug(__func__, "missing destination address"); pr->pr_errno = EINVAL; goto err; } /* * even though many operating systems allow the use of RAW TCP sockets to * send TCP probes, we still need to be able to receive TCP responses. * so we use a datalink socket to both send and receive TCP probes rather * than open both a socket to send and another to receive. */ if(dl == 0 && pr->pr_ip_proto == IPPROTO_TCP) dl = 1; else if(dl == 0 && ipid_dl != 0 && SCAMPER_PROBE_IS_IPID(pr)) dl = 1; else if(dl == 0 && (pr->pr_flags & SCAMPER_PROBE_FLAG_NOFRAG)) dl = 1; else if(dl == 0 && spoof != 0) dl = 1; if(dl != 0) { if((pt = probe_build(pr)) == NULL) { pr->pr_errno = errno; goto err; } pt->task = task; pt->mode = PROBE_MODE_RT; pt->rt = scamper_route_alloc(pr->pr_ip_dst, pt, probe_route_cb); if(pt->rt == NULL) { pr->pr_errno = errno; goto err; } #ifndef _WIN32 if((pt->rtsock = scamper_task_fd_rtsock(task)) == NULL) { pr->pr_errno = errno; goto err; } if(scamper_rtsock_getroute(pt->rtsock, pt->rt) != 0) { pr->pr_errno = errno; goto err; } #else if(scamper_rtsock_getroute(pt->rt) != 0) { pr->pr_errno = errno; goto err; } #endif if(pt->mode == PROBE_MODE_ERR) { pr->pr_errno = pt->error; goto err; } if(pt->mode != PROBE_MODE_TX) { if((pt->buf = memdup(pktbuf, pt->len + 16)) == NULL) { pr->pr_errno = errno; goto err; } if((pt->anc = scamper_task_anc_add(task, pt, probe_free_cb)) == NULL) { pr->pr_errno = errno; goto err; } gettimeofday_wrap(&pr->pr_tx); } else { timeval_cpy(&pr->pr_tx, &pt->tv); probe_free(pt); } return 0; } else if(SCAMPER_ADDR_TYPE_IS_IPV4(pr->pr_ip_dst)) { if(pr->pr_ip_proto == IPPROTO_UDP) { sp = pr->pr_udp_sport; if((fd = scamper_task_fd_udp4(task, src, sp)) == NULL) { pr->pr_errno = errno; goto err; } pr->pr_fd = scamper_fd_fd_get(fd); if(scamper_udp4_probe(pr) != 0) { pr->pr_errno = errno; goto err; } } else if(pr->pr_ip_proto == IPPROTO_ICMP) { pr->pr_fd = scamper_fd_fd_get(icmp); if(scamper_icmp4_probe(pr) != 0) { pr->pr_errno = errno; goto err; } } else { scamper_debug(__func__, "unhandled protocol %d", pr->pr_ip_proto); pr->pr_errno = EINVAL; /* actually a bug in the caller */ goto err; } } else if(SCAMPER_ADDR_TYPE_IS_IPV6(pr->pr_ip_dst)) { if(pr->pr_ip_proto == IPPROTO_UDP) { sp = pr->pr_udp_sport; if((fd = scamper_task_fd_udp6(task, src, sp)) == NULL) { pr->pr_errno = errno; goto err; } pr->pr_fd = scamper_fd_fd_get(fd); if(scamper_udp6_probe(pr) != 0) { pr->pr_errno = errno; goto err; } } else if(pr->pr_ip_proto == IPPROTO_ICMPV6) { pr->pr_fd = scamper_fd_fd_get(icmp); if(scamper_icmp6_probe(pr) != 0) { pr->pr_errno = errno; goto err; } } else { pr->pr_errno = EINVAL; /* actually a bug in the caller */ goto err; } } else { pr->pr_errno = EINVAL; goto err; } return 0; err: printerror(pr->pr_errno, strerror, __func__, "could not probe"); if(pt != NULL) probe_free(pt); return -1; }
void scamper_icmp_resp_print(const scamper_icmp_resp_t *ir) { char *t = NULL, tbuf[64]; char *c = NULL, cbuf[64]; char addr[64]; char ip[256]; char icmp[256]; char inner_ip[256]; char inner_transport[256]; char ext[256]; int i, j; size_t off; assert(ir->ir_af == AF_INET || ir->ir_af == AF_INET6); if(ir->ir_af == AF_INET) { addr_tostr(AF_INET, &ir->ir_ip_src.v4, addr, sizeof(addr)); off = 0; string_concat(ip, sizeof(ip), &off, "from %s size %d ttl %d tos 0x%02x ipid 0x%04x", addr, ir->ir_ip_size, ir->ir_ip_ttl, ir->ir_ip_tos, ir->ir_ip_id); if(ir->ir_ipopt_rrc > 0) string_concat(ip, sizeof(ip), &off, " rr %d", ir->ir_ipopt_rrc); switch(ir->ir_icmp_type) { case ICMP_UNREACH: t = "unreach"; switch(ir->ir_icmp_code) { case ICMP_UNREACH_NET: c = "net"; break; case ICMP_UNREACH_HOST: c = "host"; break; case ICMP_UNREACH_PROTOCOL: c = "protocol"; break; case ICMP_UNREACH_PORT: c = "port"; break; case ICMP_UNREACH_SRCFAIL: c = "src-rt failed"; break; case ICMP_UNREACH_NET_UNKNOWN: c = "net unknown"; break; case ICMP_UNREACH_HOST_UNKNOWN: c = "host unknown"; break; case ICMP_UNREACH_ISOLATED: c = "isolated"; break; case ICMP_UNREACH_NET_PROHIB: c = "net prohib"; break; case ICMP_UNREACH_HOST_PROHIB: c = "host prohib"; break; case ICMP_UNREACH_TOSNET: c = "tos net"; break; case ICMP_UNREACH_TOSHOST: c = "tos host"; break; case ICMP_UNREACH_FILTER_PROHIB: c = "admin prohib"; break; case ICMP_UNREACH_NEEDFRAG: /* * use the type buf to be consistent with the ICMP6 * fragmentation required message */ snprintf(tbuf, sizeof(tbuf), "need frag %d", ir->ir_icmp_nhmtu); t = tbuf; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP_TIMXCEED: t = "time exceeded"; switch(ir->ir_icmp_code) { case ICMP_TIMXCEED_INTRANS: c = "in trans"; break; case ICMP_TIMXCEED_REASS: c = "in reass"; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP_ECHOREPLY: t = "echo reply"; snprintf(cbuf, sizeof(cbuf), "id %d seq %d", ir->ir_icmp_id, ir->ir_icmp_seq); c = cbuf; break; case ICMP_TSTAMPREPLY: t = "ts reply"; snprintf(cbuf, sizeof(cbuf), "id %d seq %d", ir->ir_icmp_id, ir->ir_icmp_seq); c = cbuf; break; } } else /* if(ir->ir_af == AF_INET6) */ { addr_tostr(AF_INET6, &ir->ir_ip_src.v6, addr, sizeof(addr)); snprintf(ip, sizeof(ip), "from %s size %d hlim %d", addr, ir->ir_ip_size, ir->ir_ip_hlim); switch(ir->ir_icmp_type) { case ICMP6_DST_UNREACH: t = "unreach"; switch(ir->ir_icmp_code) { case ICMP6_DST_UNREACH_NOROUTE: c = "no route"; break; case ICMP6_DST_UNREACH_ADMIN: c = "admin prohib"; break; case ICMP6_DST_UNREACH_BEYONDSCOPE: c = "beyond scope"; break; case ICMP6_DST_UNREACH_ADDR: c = "addr"; break; case ICMP6_DST_UNREACH_NOPORT: c = "port"; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP6_TIME_EXCEEDED: t = "time exceeded"; switch(ir->ir_icmp_code) { case ICMP6_TIME_EXCEED_TRANSIT: c = "in trans"; break; case ICMP6_TIME_EXCEED_REASSEMBLY: c = "in reass"; break; default: snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code); c = cbuf; break; } break; case ICMP6_PACKET_TOO_BIG: snprintf(tbuf, sizeof(tbuf), "need frag %d", ir->ir_icmp_nhmtu); t = tbuf; break; case ICMP6_ECHO_REPLY: t = "echo reply"; snprintf(cbuf, sizeof(cbuf), "id %d seq %d", ir->ir_icmp_id, ir->ir_icmp_seq); c = cbuf; break; } } if(t == NULL) { snprintf(icmp, sizeof(icmp), "icmp %d code %d", ir->ir_icmp_type, ir->ir_icmp_code); } else if(c == NULL) { snprintf(icmp, sizeof(icmp), "icmp %s", t); } else { snprintf(icmp, sizeof(icmp), "icmp %s %s", t, c); } if(ir->ir_flags & SCAMPER_ICMP_RESP_FLAG_INNER_IP) { if(ir->ir_af == AF_INET) { addr_tostr(AF_INET, &ir->ir_inner_ip_dst.v4, addr, sizeof(addr)); off = 0; string_concat(inner_ip, sizeof(inner_ip), &off, " to %s size %d ttl %d tos 0x%02x ipid 0x%04x", addr, ir->ir_inner_ip_size, ir->ir_inner_ip_ttl, ir->ir_inner_ip_tos, ir->ir_inner_ip_id); if(ir->ir_inner_ipopt_rrc > 0) string_concat(inner_ip, sizeof(inner_ip), &off, " rr %d", ir->ir_inner_ipopt_rrc); } else /* if(ir->ir_af == AF_INET6) */ { addr_tostr(AF_INET6, &ir->ir_inner_ip_dst.v6, addr, sizeof(addr)); snprintf(inner_ip, sizeof(inner_ip), " to %s size %d hlim %d flow 0x%05x", addr, ir->ir_inner_ip_size, ir->ir_inner_ip_hlim, ir->ir_inner_ip_flow); } switch(ir->ir_inner_ip_proto) { case IPPROTO_UDP: snprintf(inner_transport, sizeof(inner_transport), " proto UDP sport %d dport %d sum 0x%04x", ir->ir_inner_udp_sport, ir->ir_inner_udp_dport, ntohs(ir->ir_inner_udp_sum)); break; case IPPROTO_ICMP: case IPPROTO_ICMPV6: snprintf(inner_transport, sizeof(inner_transport), " proto ICMP type %d code %d id %04x seq %d sum %04x", ir->ir_inner_icmp_type, ir->ir_inner_icmp_code, ir->ir_inner_icmp_id, ir->ir_inner_icmp_seq, ntohs(ir->ir_inner_icmp_sum)); break; case IPPROTO_TCP: snprintf(inner_transport, sizeof(inner_transport), " proto TCP sport %d dport %d seq %08x", ir->ir_inner_tcp_sport, ir->ir_inner_tcp_dport, ir->ir_inner_tcp_seq); break; default: inner_transport[0] = '\0'; break; } } else { inner_ip[0] = '\0'; inner_transport[0] = '\0'; } if(ir->ir_ext != NULL) { snprintf(ext, sizeof(ext), " icmp-ext"); j = 9; for(i=0; i<ir->ir_extlen; i++) { if(i % 4 == 0) { if(sizeof(ext)-j < 4) break; ext[j++] = ' '; } else if(sizeof(ext)-j < 3) break; byte2hex(ir->ir_ext[i], ext + j); j += 2; } ext[j] = '\0'; } else { ext[0] = '\0'; } scamper_debug(NULL, "%s %s%s%s%s", ip, icmp, inner_ip, inner_transport, ext); return; }
scamper_firewall_entry_t *scamper_firewall_entry_get(scamper_firewall_rule_t *sfw) { scamper_firewall_entry_t findme, *entry = NULL; int n, af, p, sp, dp; void *s, *d; /* sanity check the rule */ if((sfw->sfw_5tuple_proto != IPPROTO_TCP && sfw->sfw_5tuple_proto != IPPROTO_UDP) || sfw->sfw_5tuple_sport == 0 || sfw->sfw_5tuple_dport == 0 || (sfw->sfw_5tuple_dst == NULL || sfw->sfw_5tuple_src == NULL || sfw->sfw_5tuple_src->type != sfw->sfw_5tuple_dst->type)) { scamper_debug(__func__, "invalid 5tuple rule"); goto err; } if(sfw->sfw_5tuple_src->type == SCAMPER_ADDR_TYPE_IPV4) { af = AF_INET; if(have_ipv4 == 0) { scamper_debug(__func__, "IPv4 rule requested but no IPv4 firewall"); goto err; } } else if(sfw->sfw_5tuple_src->type == SCAMPER_ADDR_TYPE_IPV6) { af = AF_INET6; if(have_ipv6 == 0) { scamper_debug(__func__, "IPv6 rule requested but no IPv6 firewall"); goto err; } } else { scamper_debug(__func__, "invalid src type"); goto err; } findme.rule = sfw; if((entry = splaytree_find(entries, &findme)) != NULL) { entry->refcnt++; return entry; } if((entry = firewall_entry_get()) == NULL) goto err; entry->refcnt = 1; if((entry->rule = firewall_rule_dup(sfw)) == NULL || (entry->node = splaytree_insert(entries, entry)) == NULL) { goto err; } n = entry->slot; p = sfw->sfw_5tuple_proto; dp = sfw->sfw_5tuple_dport; sp = sfw->sfw_5tuple_sport; s = sfw->sfw_5tuple_src->addr; if(sfw->sfw_5tuple_dst == NULL) d = NULL; else d = sfw->sfw_5tuple_dst->addr; #if defined(HAVE_IPFW) #ifdef WITHOUT_PRIVSEP if(scamper_firewall_ipfw_add(n, af, p, s, d, sp, dp) != 0) goto err; #else if(scamper_privsep_ipfw_add(n, af, p, s, d, sp, dp) != 0) goto err; #endif #endif return entry; err: if(entry != NULL) { if(entry->rule != NULL) firewall_rule_free(entry->rule); free(entry); } return NULL; }
static void probe_print(scamper_probe_t *probe) { size_t iphl; char tcp[16]; char pos[32]; char addr[128]; char icmp[16]; char tos[8]; assert(probe->pr_ip_dst != NULL); scamper_addr_tostr(probe->pr_ip_dst, addr, sizeof(addr)); tos[0] = '\0'; icmp[0] = '\0'; if(probe->pr_ip_proto == IPPROTO_TCP) { if((probe->pr_ip_tos & IPTOS_ECN_CE) == IPTOS_ECN_CE) snprintf(tos, sizeof(tos), ", ce"); else if(probe->pr_ip_tos & IPTOS_ECN_ECT1) snprintf(tos, sizeof(tos), ", ect1"); else if(probe->pr_ip_tos & IPTOS_ECN_ECT0) snprintf(tos, sizeof(tos), ", ect0"); } if(probe->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV4) { if(scamper_ip4_hlen(probe, &iphl) != 0) return; if((probe->pr_ip_off & IP_OFFMASK) != 0) { scamper_debug("tx", "frag %s %04x:%d ttl %d, len %d", addr, probe->pr_ip_id, probe->pr_ip_off << 3, probe->pr_ip_ttl, iphl + probe->pr_len); return; } switch(probe->pr_ip_proto) { case IPPROTO_UDP: scamper_debug("tx", "udp %s, ttl %d, %d:%d, len %d", addr, probe->pr_ip_ttl, probe->pr_udp_sport, probe->pr_udp_dport, iphl + 8 + probe->pr_len); break; case IPPROTO_TCP: scamper_debug("tx", "tcp %s%s, ttl %d, %d:%d%s, ipid %04x, %s, len %d", addr, tos, probe->pr_ip_ttl, probe->pr_tcp_sport, probe->pr_tcp_dport, tcp_flags(tcp, sizeof(tcp), probe), probe->pr_ip_id, tcp_pos(pos, sizeof(pos), probe), iphl + scamper_tcp4_hlen(probe) + probe->pr_len); break; case IPPROTO_ICMP: if(probe->pr_icmp_type == ICMP_ECHO) { if(probe->pr_icmp_sum != 0) { snprintf(icmp, sizeof(icmp), ", sum %04x", ntohs(probe->pr_icmp_sum)); } scamper_debug("tx", "icmp %s echo, ttl %d%s, seq %d, len %d", addr, probe->pr_ip_ttl, icmp, probe->pr_icmp_seq, iphl + 8 + probe->pr_len); } else if(probe->pr_icmp_type == ICMP_UNREACH) { if(probe->pr_icmp_code == ICMP_UNREACH_NEEDFRAG) snprintf(icmp,sizeof(icmp),"ptb %d", probe->pr_icmp_mtu); else snprintf(icmp,sizeof(icmp),"unreach %d", probe->pr_icmp_code); scamper_debug("tx", "icmp %s %s, len %d", addr, icmp, iphl + 8 + probe->pr_len); } else { scamper_debug("tx", "icmp %s type %d, code %d, len %d", addr, probe->pr_icmp_type, probe->pr_icmp_code, iphl + 8 + probe->pr_len); } break; } } else if(probe->pr_ip_dst->type == SCAMPER_ADDR_TYPE_IPV6) { if(scamper_ip6_hlen(probe, &iphl) != 0) return; if(probe->pr_ip_off != 0) { scamper_debug("tx", "frag %s off %04x, ttl %d, len %d", addr, probe->pr_ip_off, probe->pr_ip_ttl, iphl + probe->pr_len); return; } switch(probe->pr_ip_proto) { case IPPROTO_UDP: scamper_debug("tx", "udp %s, ttl %d, %d:%d, len %d", addr, probe->pr_ip_ttl, probe->pr_udp_sport, probe->pr_udp_dport, iphl + 8 + probe->pr_len); break; case IPPROTO_TCP: scamper_debug("tx", "tcp %s%s, ttl %d, %d:%d%s, %s, len %d", addr, tos, probe->pr_ip_ttl, probe->pr_tcp_sport, probe->pr_tcp_dport, tcp_flags(tcp, sizeof(tcp), probe), tcp_pos(pos, sizeof(pos), probe), iphl + scamper_tcp6_hlen(probe) + probe->pr_len); break; case IPPROTO_ICMPV6: if(probe->pr_icmp_type == ICMP6_ECHO_REQUEST) { if(probe->pr_icmp_sum != 0) { snprintf(icmp, sizeof(icmp), ", sum %04x", ntohs(probe->pr_icmp_sum)); } scamper_debug("tx", "icmp %s echo, ttl %d%s, seq %d, len %d", addr, probe->pr_ip_ttl, icmp, probe->pr_icmp_seq, iphl + 8 + probe->pr_len); } else if(probe->pr_icmp_type == ICMP6_PACKET_TOO_BIG) { scamper_debug("tx", "icmp %s ptb %d, len %d", addr, probe->pr_icmp_mtu, iphl + 8 + probe->pr_len); } else if(probe->pr_icmp_type == ICMP6_DST_UNREACH) { scamper_debug("tx", "icmp %s unreach %d, len %d", addr, probe->pr_icmp_code, iphl + 8 + probe->pr_len); } else { scamper_debug("tx", "icmp %s type %d, code %d, len %d", addr, probe->pr_icmp_type, probe->pr_icmp_code, iphl + 8 + probe->pr_len); } break; } } return; }