static char *addr_toname(const scamper_addr_t *addr, char *buf, size_t len) { struct sockaddr *sa = NULL; struct sockaddr_in in4; struct sockaddr_in6 in6; socklen_t sl; if(SCAMPER_ADDR_TYPE_IS_IPV4(addr)) { sockaddr_compose((struct sockaddr *)&in4, AF_INET, addr->addr, 0); sa = (struct sockaddr *)&in4; } else if(SCAMPER_ADDR_TYPE_IS_IPV6(addr)) { sockaddr_compose((struct sockaddr *)&in6, AF_INET6, addr->addr, 0); sa = (struct sockaddr *)&in6; } if(sa == NULL) return NULL; sl = sockaddr_len(sa); if(getnameinfo(sa, sl, buf, len, NULL, 0, NI_NAMEREQD) != 0) return NULL; return buf; }
/* * scamper_rtsock_getifindex * * figure out the outgoing interface id / route using route sockets * * route(4) gives an overview of the functions called in here */ static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst) { struct sockaddr_storage sas; struct sockaddr_dl *sdl; struct rt_msghdr *rtm; uint8_t buf[1024]; size_t len; ssize_t ss; int slen; if(SCAMPER_ADDR_TYPE_IS_IPV4(dst)) sockaddr_compose((struct sockaddr *)&sas, AF_INET, dst->addr, 0); else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst)) sockaddr_compose((struct sockaddr *)&sas, AF_INET6, dst->addr, 0); else return -1; if((slen = sockaddr_len((struct sockaddr *)&sas)) <= 0) return -1; len = sizeof(struct rt_msghdr) + scamper_rtsock_roundup(slen) + scamper_rtsock_roundup(sizeof(struct sockaddr_dl)); if(len > sizeof(buf)) return -1; memset(buf, 0, len); rtm = (struct rt_msghdr *)buf; rtm->rtm_msglen = len; rtm->rtm_version = RTM_VERSION; rtm->rtm_type = RTM_GET; rtm->rtm_addrs = RTA_DST | RTA_IFP; rtm->rtm_pid = pid; rtm->rtm_seq = seq; memcpy(buf + sizeof(struct rt_msghdr), &sas, (size_t)slen); sdl = (struct sockaddr_dl *)(buf + sizeof(struct rt_msghdr) + scamper_rtsock_roundup(slen)); sdl->sdl_family = AF_LINK; #if !defined(__sun__) sdl->sdl_len = sizeof(struct sockaddr_dl); #endif if((ss = write(fd, buf, len)) < 0 || (size_t)ss != len) { printerror(errno, strerror, __func__, "could not write routing socket"); return -1; } return 0; }
int scamper_dealias_ipid_inseq(scamper_dealias_probe_t **probes, int probec, uint16_t fudge, int bs) { static int (*const inseq[])(scamper_dealias_probe_t **,int,uint16_t,int) = { dealias_ipid16_inseq, dealias_ipid32_inseq, }; static int (*const bo[])(scamper_dealias_probe_t **, int) = { dealias_ipid16_bo, dealias_ipid32_bo, }; int i, x; if(probec < 2) return -1; if(SCAMPER_ADDR_TYPE_IS_IPV4(probes[0]->def->dst)) x = 0; else if(SCAMPER_ADDR_TYPE_IS_IPV6(probes[0]->def->dst)) x = 1; else return -1; if(bs == 3) { if((i = bo[x](probes, probec)) == -1) return -1; return inseq[x](probes, probec, fudge, i); } if(bs == 2) { if(inseq[x](probes, probec, fudge, 0) == 1) return 1; return inseq[x](probes, probec, fudge, 1); } return inseq[x](probes, probec, fudge, bs); }
static void warts_ping_reply_params(const scamper_ping_t *ping, const scamper_ping_reply_t *reply, warts_addrtable_t *table, uint8_t *flags, uint16_t *flags_len, uint16_t *params_len) { const warts_var_t *var; int i, j, max_id = 0; /* unset all the flags possible */ memset(flags, 0, ping_reply_vars_mfb); *params_len = 0; for(i=0; i<sizeof(ping_reply_vars)/sizeof(warts_var_t); i++) { var = &ping_reply_vars[i]; if(var->id == WARTS_PING_REPLY_ADDR_GID || (var->id == WARTS_PING_REPLY_ADDR && reply->addr == NULL) || (var->id == WARTS_PING_REPLY_FLAGS && reply->flags == 0) || (var->id == WARTS_PING_REPLY_REPLY_PROTO && SCAMPER_PING_METHOD_IS_ICMP(ping)) || (var->id == WARTS_PING_REPLY_REPLY_TTL && (reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_TTL) == 0) || (var->id == WARTS_PING_REPLY_REPLY_IPID && SCAMPER_ADDR_TYPE_IS_IPV4(ping->dst) && (reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID) == 0) || (var->id == WARTS_PING_REPLY_REPLY_IPID32 && SCAMPER_ADDR_TYPE_IS_IPV6(ping->dst) && (reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID) == 0) || (var->id == WARTS_PING_REPLY_PROBE_IPID && SCAMPER_ADDR_TYPE_IS_IPV4(ping->dst) && (reply->flags & SCAMPER_PING_REPLY_FLAG_PROBE_IPID) == 0) || (var->id == WARTS_PING_REPLY_ICMP_TC && SCAMPER_PING_REPLY_IS_ICMP(reply) == 0) || (var->id == WARTS_PING_REPLY_TCP_FLAGS && SCAMPER_PING_REPLY_IS_TCP(reply) == 0) || (var->id == WARTS_PING_REPLY_V4RR && reply->v4rr == NULL) || (var->id == WARTS_PING_REPLY_V4TS && reply->v4ts == NULL) || (var->id == WARTS_PING_REPLY_TX && reply->tx.tv_sec == 0) || (var->id == WARTS_PING_REPLY_TSREPLY && reply->tsreply == NULL)) { continue; } flag_set(flags, var->id, &max_id); if(var->id == WARTS_PING_REPLY_ADDR) { *params_len += warts_addr_size(table, reply->addr); } else if(var->id == WARTS_PING_REPLY_V4RR) { *params_len += 1; for(j=0; j<reply->v4rr->rrc; j++) *params_len += warts_addr_size(table, reply->v4rr->rr[j]); } else if(var->id == WARTS_PING_REPLY_V4TS) { assert(reply->v4ts != NULL); *params_len += 2; /* one byte tsc, one byte count of v4ts->ips */ *params_len += (reply->v4ts->tsc * 4); if(reply->v4ts->ips != NULL) for(j=0; j<reply->v4ts->tsc; j++) *params_len += warts_addr_size(table, reply->v4ts->ips[j]); } else { assert(var->size >= 0); *params_len += var->size; } } *flags_len = fold_flags(flags, max_id); return; }
/* * scamper_rtsock_getifindex * * figure out the outgoing interface id / route using linux netlink * * this works on Linux systems with netlink compiled into the kernel. * i think netlink comes compiled into the kernel with most distributions * these days. * * the man pages netlink(3), netlink(7), rtnetlink(3), and rtnetlink(7) * give an overview of the functions and structures used in here, but the * documentation in those man pages is pretty crap. * you'd be better off studying netlink.h and rtnetlink.h */ static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst) { struct nlmsghdr *nlmsg; struct rtmsg *rtmsg; struct rtattr *rta; int error; int dst_len; uint8_t buf[1024]; int af; if(SCAMPER_ADDR_TYPE_IS_IPV4(dst)) { dst_len = 4; af = AF_INET; } else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst)) { dst_len = 16; af = AF_INET6; } else { return -1; } /* * fill out a route request. * we use the standard netlink header, with a route msg subheader * to query for the outgoing interface. * the message includes one attribute - the destination address * we are querying the route for. */ memset(buf, 0, sizeof(buf)); nlmsg = (struct nlmsghdr *)buf; nlmsg->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); nlmsg->nlmsg_type = RTM_GETROUTE; nlmsg->nlmsg_flags = NLM_F_REQUEST; nlmsg->nlmsg_seq = seq; nlmsg->nlmsg_pid = pid; /* netlink wants the bit length of each address */ rtmsg = NLMSG_DATA(nlmsg); rtmsg->rtm_family = af; rtmsg->rtm_flags = 0; rtmsg->rtm_dst_len = dst_len * 8; rta = (struct rtattr *)(buf + NLMSG_ALIGN(nlmsg->nlmsg_len)); rta->rta_type = RTA_DST; rta->rta_len = RTA_LENGTH(dst_len); nlmsg->nlmsg_len += RTA_LENGTH(dst_len); memcpy(RTA_DATA(rta), dst->addr, dst_len); /* send the request */ if((error = send(fd, buf, nlmsg->nlmsg_len, 0)) != nlmsg->nlmsg_len) { printerror(errno, strerror, __func__, "could not send"); return -1; } return 0; }
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; }
/* * probe_build * * determine how to build the packet and call the appropriate function * to do so. */ static probe_t *probe_build(scamper_probe_t *pr) { int (*build_func)(scamper_probe_t *, uint8_t *, size_t *) = NULL; probe_t *pt = NULL; size_t len; if(SCAMPER_ADDR_TYPE_IS_IPV4(pr->pr_ip_dst)) { if((pr->pr_ip_off & IP_OFFMASK) != 0) build_func = scamper_ip4_frag_build; else if(pr->pr_ip_proto == IPPROTO_UDP) build_func = scamper_udp4_build; else if(pr->pr_ip_proto == IPPROTO_ICMP) build_func = scamper_icmp4_build; else if(pr->pr_ip_proto == IPPROTO_TCP) build_func = scamper_tcp4_build; } else if(SCAMPER_ADDR_TYPE_IS_IPV6(pr->pr_ip_dst)) { if(pr->pr_ip_off != 0) build_func = scamper_ip6_frag_build; if(pr->pr_ip_proto == IPPROTO_UDP) build_func = scamper_udp6_build; else if(pr->pr_ip_proto == IPPROTO_ICMPV6) build_func = scamper_icmp6_build; else if(pr->pr_ip_proto == IPPROTO_TCP) build_func = scamper_tcp6_build; } if(build_func == NULL) { pr->pr_errno = EINVAL; goto err; } /* allow 16 bytes at the front of the packet for layer-2 headers */ if(16 >= pktbuf_len) len = 0; else len = pktbuf_len-16; if(build_func(pr, pktbuf+16, &len) != 0) { /* reallocate the packet buffer */ if(realloc_wrap((void **)&pktbuf, len+16) != 0) { pr->pr_errno = errno; goto err; } pktbuf_len = len+16; if(build_func(pr, pktbuf+16, &len) != 0) { pr->pr_errno = EINVAL; goto err; } } if((pt = malloc_zero(sizeof(probe_t))) == NULL) { pr->pr_errno = errno; goto err; } pt->buf = pktbuf; pt->len = len; return pt; err: return NULL; }