bool network_tag_probe(network_t * network, probe_t * probe) { uint16_t tag, // Network-side endianness checksum; // Host-side endianness size_t payload_size = probe_get_payload_size(probe); size_t tag_size = sizeof(uint16_t); size_t num_layers = probe_get_num_layers(probe); // For probes having a payload of size 0 and a "body" field (like icmp) layer_t * last_layer; bool tag_in_body = false; /* The probe gets assigned a unique tag. Currently we encode it in the UDP * checksum, but I guess the tag will be protocol dependent. Also, since the * tag changes the probe, the user has no direct control of what is sent on * the wire, since typically a packet is tagged just before sending, after * scheduling, to maximize the number of probes in flight. Available space * in the headers is used for tagging, + encoding some information... */ /* XXX hardcoded XXX */ /* 1) Set payload = tag : this is only possible if both the payload and the * checksum have not been set by the user. * We need a list of used tags = in flight... + an efficient way to get a * free one... Also, we need to share tags between several instances ? * randomized tags ? Also, we need to determine how much size we have to * encode information. */ if (num_layers < 2 || !(last_layer = probe_get_layer(probe, num_layers - 2))) { fprintf(stderr, "network_tag_probe: not enough layer (num_layers = %d)\n", (unsigned int)num_layers); goto ERR_GET_LAYER; } // The last layer is the payload, the previous one is the last protocol layer. // If this layer has a "body" field like icmp, we have no payload and // we use the body field. if (last_layer->protocol && protocol_get_field(last_layer->protocol, "body")) { tag_in_body = true; } tag = htons(network_get_available_tag(network)); // Write the tag at offset zero of the payload if (tag_in_body) { probe_write_field(probe, "body", &tag, tag_size); } else { if (payload_size < tag_size) { fprintf(stderr, "Payload too short (payload_size = %u tag_size = %u)\n", (unsigned int)payload_size, (unsigned int)tag_size); goto ERR_INVALID_PAYLOAD; } if (!(probe_write_payload(probe, &tag, tag_size))) { goto ERR_PROBE_WRITE_PAYLOAD; } } // Fix checksum to get a well-formed packet if (!(probe_update_checksum(probe))) { fprintf(stderr, "Can't update fields\n"); goto ERR_PROBE_UPDATE_FIELDS; } // Retrieve the checksum of UDP/TCP/ICMP checksum (host-side endianness) if (!(probe_extract_tag(probe, &checksum))) { fprintf(stderr, "Can't extract tag\n"); goto ERR_PROBE_EXTRACT_CHECKSUM; } // Write the probe ID in the UDP/TCP/ICMP checksum if (!(probe_set_tag(probe, ntohs(tag)))) { fprintf(stderr, "Can't set tag\n"); goto ERR_PROBE_SET_TAG; } // Write the tag using the network-side endianness in the payload checksum = htons(checksum); if (tag_in_body) { if (!(probe_write_field(probe, "body", &checksum, tag_size))) { fprintf(stderr, "Can't set body\n"); goto ERR_PROBE_SET_FIELD; } } else { if (!probe_write_payload(probe, &checksum, tag_size)) { fprintf(stderr, "Can't write payload (2)\n"); goto ERR_BUFFER_WRITE_BYTES2; } } return true; ERR_PROBE_SET_FIELD: ERR_BUFFER_WRITE_BYTES2: ERR_PROBE_SET_TAG: ERR_PROBE_EXTRACT_CHECKSUM: ERR_PROBE_UPDATE_FIELDS: ERR_PROBE_WRITE_PAYLOAD: ERR_INVALID_PAYLOAD: ERR_GET_LAYER: return false; }
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); }