예제 #1
0
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);
    }
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #6
0
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);
    }
}
예제 #7
0
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);
}
예제 #10
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;
}