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 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; }