void probe_reply_deep_free(probe_reply_t * probe_reply) { if (probe_reply) { if (probe_reply->probe) probe_free(probe_reply->probe); if (probe_reply->reply) probe_free(probe_reply->reply); probe_reply_free(probe_reply); } }
bool network_process_recvq(network_t * network) { probe_t * probe, * reply; packet_t * packet; probe_reply_t * probe_reply; // Pop the packet from the queue if (!(packet = queue_pop_element(network->recvq, NULL))) { goto ERR_PACKET_POP; } // Transform the reply into a probe_t instance if(!(reply = probe_wrap_packet(packet))) { goto ERR_PROBE_WRAP_PACKET; } probe_set_recv_time(reply, get_timestamp()); if (network->is_verbose) { printf("Got reply:\n"); probe_dump(reply); } // Find the probe corresponding to this reply // The corresponding pointer (if any) is removed from network->probes if (!(probe = network_get_matching_probe(network, reply))) { goto ERR_PROBE_DISCARDED; } // Build a pair made of the probe and its corresponding reply if (!(probe_reply = probe_reply_create())) { goto ERR_PROBE_REPLY_CREATE; } // We're pass to the upper layer the probe and the reply to the upper layer. probe_reply_set_probe(probe_reply, probe); probe_reply_set_reply(probe_reply, reply); // Notify the instance which has build the probe that we've got the corresponding reply // TODO this provokes a double free: //pt_throw(NULL, probe->caller, event_create(PROBE_REPLY, probe_reply, NULL, (ELEMENT_FREE) probe_reply_free)); pt_throw(NULL, probe->caller, event_create(PROBE_REPLY, probe_reply, NULL, NULL)); // TODO probe_reply_free frees only the reply but probe_reply_deep_free cannot be used as other things may have references to its contents. return true; ERR_PROBE_REPLY_CREATE: ERR_PROBE_DISCARDED: probe_free(reply); ERR_PROBE_WRAP_PACKET: //packet_free(packet); TODO provoke segfault in case of stars ERR_PACKET_POP: return false; }
static void probe_route_cb(scamper_route_t *rt) { scamper_fd_t *fd = NULL; scamper_dl_t *dl = NULL; probe_t *pr = rt->param; if(rt->error != 0 || rt->ifindex < 0) { pr->error = rt->error; goto err; } if((fd = scamper_task_fd_dl(pr->task, rt->ifindex)) == NULL) { pr->error = errno; goto err; } if((pr->dlhdr = scamper_dlhdr_alloc()) == NULL) { pr->error = errno; goto err; } dl = scamper_fd_dl_get(fd); pr->dlhdr->dst = scamper_addr_use(rt->dst); pr->dlhdr->gw = rt->gw != NULL ? scamper_addr_use(rt->gw) : NULL; pr->dlhdr->ifindex = rt->ifindex; pr->dlhdr->txtype = scamper_dl_tx_type(dl); pr->dlhdr->param = pr; pr->dlhdr->cb = probe_dlhdr_cb; pr->mode = PROBE_MODE_DL; if(scamper_dlhdr_get(pr->dlhdr) != 0) { pr->error = pr->dlhdr->error; goto err; } return; err: pr->mode = PROBE_MODE_ERR; if(pr->anc != NULL) probe_free(pr); return; }
static void probe_dlhdr_cb(scamper_dlhdr_t *dlhdr) { probe_t *pr = dlhdr->param; scamper_fd_t *fd = NULL; scamper_dl_t *dl = NULL; uint8_t *pkt; if(dlhdr->error != 0) { pr->error = dlhdr->error; goto err; } assert(dlhdr->len < 16); pkt = pr->buf+16-dlhdr->len; if(dlhdr->len > 0) memcpy(pkt, dlhdr->buf, dlhdr->len); if((fd = scamper_task_fd_dl(pr->task, pr->rt->ifindex)) == NULL) { pr->error = EINVAL; goto err; } if(pr->buf == pktbuf) gettimeofday_wrap(&pr->tv); dl = scamper_fd_dl_get(fd); if(scamper_dl_tx(dl, pkt, dlhdr->len + pr->len) == -1) { pr->error = errno; goto err; } pr->mode = PROBE_MODE_TX; goto done; err: pr->mode = PROBE_MODE_ERR; done: if(pr->anc != NULL) probe_free(pr); return; }
algorithm_instance_t * pt_add_instance( struct pt_loop_s * loop, const char * name, void * options, probe_t * probe_skel ) { bool probe_allocated = false; algorithm_t * algorithm; algorithm_instance_t * instance = NULL; if (!(algorithm = algorithm_search(name))) { goto ERR_ALGORITHM_NOT_FOUND; } // If the probe skeleton does not exist, create it. if (!probe_skel) { probe_skel = probe_create(); probe_allocated = (probe_skel != NULL); if (!probe_allocated) goto ERR_PROBE_SKEL; } // Create a new instance of a running algorithm if (!(instance = algorithm_instance_create(loop, algorithm, options, probe_skel))) { goto ERR_INSTANCE; } // We need to queue a new event for the algorithm: it has been started pt_throw(NULL, instance, event_create(ALGORITHM_INIT, NULL, NULL, NULL)); // Add this algorithms to the list of handled algorithms pt_algorithm_instance_add(loop, instance); return instance; ERR_INSTANCE: ERR_PROBE_SKEL: if (probe_allocated) probe_free(probe_skel); ERR_ALGORITHM_NOT_FOUND: return NULL; }
void probe_debug(const probe_t * probe) { size_t i, num_layers = probe_get_num_layers(probe); layer_t * layer1, * layer2; probe_t * probe_should_be; if ((probe_should_be = probe_dup(probe))) { // Compute expected values probe_update_fields(probe_should_be); // Dump fields printf("** PROBE **\n\n"); for (i = 0; i < num_layers; i++) { layer1 = probe_get_layer(probe, i); layer2 = probe_get_layer(probe_should_be, i); layer_debug(layer1, layer2, i); printf("\n"); } printf("\n"); probe_free(probe_should_be); } }
probe_t * probe_wrap_packet(packet_t * packet) { probe_t * probe; size_t segment_size, remaining_size; layer_t * layer; uint8_t * segment; const protocol_t * protocol; if (!(probe = probe_create())) { goto ERR_PROBE_CREATE; } // Clear the probe packet_free(probe->packet); probe->packet = packet; probe_layers_clear(probe); // Prepare iteration segment = packet_get_bytes(probe->packet); remaining_size = packet_get_size(probe->packet); // Push layers for (protocol = get_first_protocol(packet); protocol; protocol = protocol->get_next_protocol(layer)) { if (remaining_size < protocol->write_default_header(NULL)) { // Not enough bytes left for the header, packet is truncated segment_size = remaining_size; } else { segment_size = protocol->get_header_size(segment); } if (!(layer = layer_create_from_segment(protocol, segment, segment_size))) { goto ERR_CREATE_LAYER; } if (!probe_push_layer(probe, layer)) { goto ERR_PUSH_LAYER; } segment += segment_size; remaining_size -= segment_size; if (remaining_size < 0) { fprintf(stderr, "probe_wrap_packet: Truncated packet\n"); goto ERR_TRUNCATED_PACKET; } if (!protocol->get_next_protocol) { break; } continue; ERR_TRUNCATED_PACKET: ERR_PUSH_LAYER: layer_free(layer); ERR_CREATE_LAYER: goto ERR_LAYER_DISCOVER_LAYER; } // Rq: Some packets (e.g ICMP type 3) do not have payload. // In this case we push an empty payload probe_push_payload(probe, remaining_size); return probe; ERR_LAYER_DISCOVER_LAYER: probe_free(probe); ERR_PROBE_CREATE: return NULL; }
int main(int argc, char ** argv) { algorithm_instance_t * instance; traceroute_options_t options = traceroute_get_default_options(); probe_t * probe; pt_loop_t * loop; int family; int ret = EXIT_FAILURE; const char * ip_protocol_name; const char * protocol_name; address_t dst_addr; // Harcoded command line parsing here char dst_ip[] = "8.8.8.8"; //char dst_ip[] = "1.1.1.2"; //char dst_ip[] = "2001:db8:85a3::8a2e:370:7338"; if (!address_guess_family(dst_ip, &family)) { fprintf(stderr, "Cannot guess family of destination address (%s)", dst_ip); goto ERR_ADDRESS_GUESS_FAMILY; } if (address_from_string(family, dst_ip, &dst_addr) != 0) { fprintf(stderr, "Cannot guess family of destination address (%s)", dst_ip); goto ERR_ADDRESS_FROM_STRING; } // Prepare options related to the 'traceroute' algorithm options.do_resolv = false; options.dst_addr = &dst_addr; options.num_probes = 1; // options.max_ttl = 1; printf("num_probes = %zu max_ttl = %u\n", options.num_probes, options.max_ttl); // Create libparistraceroute loop // No information shared by traceroute algorithm instances, so we pass NULL if (!(loop = pt_loop_create(loop_handler, NULL))) { fprintf(stderr, "Cannot create libparistraceroute loop"); goto ERR_LOOP_CREATE; } // Probe skeleton definition: IPv4/UDP probe targetting 'dst_ip' if (!(probe = probe_create())) { fprintf(stderr, "Cannot create probe skeleton"); goto ERR_PROBE_CREATE; } switch (family) { case AF_INET: ip_protocol_name = "ipv4"; protocol_name = "icmpv4"; break; case AF_INET6: ip_protocol_name = "ipv6"; protocol_name = "icmpv6"; break; default: fprintf(stderr, "Internet family not supported (%d)\n", family); goto ERR_FAMILY; } // protocol_name = "udp"; protocol_name = "tcp"; printf("protocol_name = %s\n", protocol_name); if (!probe_set_protocols(probe, ip_protocol_name, protocol_name, NULL)) { fprintf(stderr, "Can't set protocols %s/%s\n", ip_protocol_name, protocol_name); goto ERR_PROBE_SET_PROTOCOLS; } if (strncmp("icmp", protocol_name, 4) != 0) { probe_write_payload(probe, "\0\0\0\0", 4); } else { probe_set_field(probe, I32("body", 1)); } probe_set_fields(probe, ADDRESS("dst_ip", &dst_addr), I16("dst_port", 3000), NULL ); /* if (strcmp("tcp", protocol_name) == 0) { printf("setting tcp fields\n"); uint8_t one = 1; probe_set_fields(probe, BITS("reserved", 1, &one), BITS("ns", 1, &one), BITS("cwr", 1, &one), BITS("ece", 1, &one), BITS("urg", 1, &one), BITS("ack", 1, &one), BITS("psh", 1, &one), BITS("rst", 1, &one), BITS("syn", 1, &one), BITS("fin", 1, &one), NULL ); } */ probe_dump(probe); // Instanciate a 'traceroute' algorithm if (!(instance = pt_add_instance(loop, "traceroute", &options, probe))) { fprintf(stderr, "Cannot add 'traceroute' algorithm"); goto ERR_INSTANCE; } // Wait for events. They will be catched by handler_user() if (pt_loop(loop, 0) < 0) { fprintf(stderr, "Main loop interrupted"); goto ERR_IN_PT_LOOP; } ret = EXIT_SUCCESS; // Free data and quit properly ERR_IN_PT_LOOP: // instance is freed by pt_loop_free ERR_INSTANCE: ERR_PROBE_SET_PROTOCOLS: ERR_FAMILY: probe_free(probe); ERR_PROBE_CREATE: pt_loop_free(loop); ERR_LOOP_CREATE: ERR_ADDRESS_FROM_STRING: ERR_ADDRESS_GUESS_FAMILY: exit(ret); }
int main(int argc, char ** argv) { int exit_code = EXIT_FAILURE; char * version = strdup("version 1.0"); const char * usage = "usage: %s [options] host\n"; void * algorithm_options; traceroute_options_t traceroute_options; traceroute_options_t * ptraceroute_options; mda_options_t mda_options; probe_t * probe; pt_loop_t * loop; int family; address_t dst_addr; options_t * options; char * dst_ip; const char * algorithm_name; const char * protocol_name; bool use_icmp, use_udp, use_tcp; // Prepare the commande line options if (!(options = init_options(version))) { fprintf(stderr, "E: Can't initialize options\n"); goto ERR_INIT_OPTIONS; } // Retrieve values passed in the command-line if (options_parse(options, usage, argv) != 1) { fprintf(stderr, "%s: destination required\n", basename(argv[0])); goto ERR_OPT_PARSE; } // We assume that the target IP address is always the last argument dst_ip = argv[argc - 1]; algorithm_name = algorithm_names[0]; protocol_name = protocol_names[0]; // Checking if there is any conflicts between options passed in the commandline if (!check_options(is_icmp, is_tcp, is_udp, is_ipv4, is_ipv6, dst_port[3], src_port[3], protocol_name, algorithm_name)) { goto ERR_CHECK_OPTIONS; } use_icmp = is_icmp || strcmp(protocol_name, "icmp") == 0; use_tcp = is_tcp || strcmp(protocol_name, "tcp") == 0; use_udp = is_udp || strcmp(protocol_name, "udp") == 0; // If not any ip version is set, call address_guess_family. // If only one is set to true, set family to AF_INET or AF_INET6 if (is_ipv4) { family = AF_INET; } else if (is_ipv6) { family = AF_INET6; } else { // Get address family if not defined by the user if (!address_guess_family(dst_ip, &family)) goto ERR_ADDRESS_GUESS_FAMILY; } // Translate the string IP / FQDN into an address_t * instance if (address_from_string(family, dst_ip, &dst_addr) != 0) { fprintf(stderr, "E: Invalid destination address %s\n", dst_ip); goto ERR_ADDRESS_IP_FROM_STRING; } // Probe skeleton definition: IPv4/UDP probe targetting 'dst_ip' if (!(probe = probe_create())) { fprintf(stderr,"E: Cannot create probe skeleton"); goto ERR_PROBE_CREATE; } // Prepare the probe skeleton probe_set_protocols( probe, get_ip_protocol_name(family), // "ipv4" | "ipv6" get_protocol_name(family, use_icmp, use_tcp, use_udp), // "icmpv4" | "icmpv6" | "tcp" | "udp" NULL ); probe_set_field(probe, ADDRESS("dst_ip", &dst_addr)); if (send_time[3]) { if(send_time[0] <= 10) { // seconds probe_set_delay(probe, DOUBLE("delay", send_time[0])); } else { // milli-seconds probe_set_delay(probe, DOUBLE("delay", 0.001 * send_time[0])); } } // ICMPv* do not support src_port and dst_port fields nor payload. if (!use_icmp) { uint16_t sport = 0, dport = 0; if (use_udp) { // Option -U sets port to 53 (DNS) if dst_port is not explicitely set sport = src_port[3] ? src_port[0] : UDP_DEFAULT_SRC_PORT; dport = dst_port[3] ? dst_port[0] : (is_udp ? UDP_DST_PORT_USING_U : UDP_DEFAULT_DST_PORT); } else if (use_tcp) { // Option -T sets port to 80 (http) if dst_port is not explicitely set sport = src_port[3] ? src_port[0] : TCP_DEFAULT_SRC_PORT; dport = dst_port[3] ? dst_port[0] : (is_tcp ? TCP_DST_PORT_USING_T : TCP_DEFAULT_DST_PORT); } // Update ports probe_set_fields( probe, I16("src_port", sport), I16("dst_port", dport), NULL ); // Resize payload (it will be use to set our customized checksum in the {TCP, UDP} layer) probe_payload_resize(probe, 2); } // Algorithm options (dedicated options) if (strcmp(algorithm_name, "paris-traceroute") == 0) { traceroute_options = traceroute_get_default_options(); ptraceroute_options = &traceroute_options; algorithm_options = &traceroute_options; algorithm_name = "traceroute"; } else if ((strcmp(algorithm_name, "mda") == 0) || options_mda_get_is_set()) { mda_options = mda_get_default_options(); ptraceroute_options = &mda_options.traceroute_options; algorithm_options = &mda_options; options_mda_init(&mda_options); } else { fprintf(stderr, "E: Unknown algorithm"); goto ERR_UNKNOWN_ALGORITHM; } // Algorithm options (common options) options_traceroute_init(ptraceroute_options, &dst_addr); // Create libparistraceroute loop if (!(loop = pt_loop_create(loop_handler, NULL))) { fprintf(stderr, "E: Cannot create libparistraceroute loop"); goto ERR_LOOP_CREATE; } // Set network options (network and verbose) options_network_init(loop->network, is_debug); printf("%s to %s (", algorithm_name, dst_ip); address_dump(&dst_addr); printf("), %u hops max, %u bytes packets\n", ptraceroute_options->max_ttl, (unsigned int)packet_get_size(probe->packet) ); // Add an algorithm instance in the main loop if (!pt_add_instance(loop, algorithm_name, algorithm_options, probe)) { fprintf(stderr, "E: Cannot add the chosen algorithm"); goto ERR_INSTANCE; } // Wait for events. They will be catched by handler_user() if (pt_loop(loop, 0) < 0) { fprintf(stderr, "E: Main loop interrupted"); goto ERR_PT_LOOP; } exit_code = EXIT_SUCCESS; // Leave the program ERR_PT_LOOP: ERR_INSTANCE: // pt_loop_free() automatically removes algorithms instances, // probe_replies and events from the memory. // Options and probe must be manually removed. pt_loop_free(loop); ERR_LOOP_CREATE: ERR_UNKNOWN_ALGORITHM: probe_free(probe); ERR_PROBE_CREATE: ERR_ADDRESS_IP_FROM_STRING: ERR_ADDRESS_GUESS_FAMILY: if (errno) perror(gai_strerror(errno)); ERR_CHECK_OPTIONS: ERR_OPT_PARSE: ERR_INIT_OPTIONS: free(version); exit(exit_code); }
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; }