Example #1
0
int scamper_addr2mac_add(int ifindex, scamper_addr_t *ip, scamper_addr_t *mac)
{
  addr2mac_t *a2m = NULL;
  char ipstr[128], macstr[128];

  if(scamper_addr2mac_whohas(ifindex, ip) != NULL)
    return 0;

  if((a2m = addr2mac_alloc(ifindex, ip, mac, 0)) == NULL)
    return -1;

  if(splaytree_insert(tree, a2m) == NULL)
    {
      printerror(errno, strerror, __func__, "could not add %s:%s to tree",
		 scamper_addr_tostr(a2m->ip, ipstr, sizeof(ipstr)),
		 scamper_addr_tostr(a2m->mac, macstr, sizeof(macstr)));
      addr2mac_free(a2m);
      return -1;
    }

  scamper_debug(__func__, "ifindex %d ip %s mac %s", ifindex,
		scamper_addr_tostr(a2m->ip, ipstr, sizeof(ipstr)),
		scamper_addr_tostr(a2m->mac, macstr, sizeof(macstr)));
  return 0;
}
Example #2
0
int scamper_ip4_hlen(scamper_probe_t *pr, size_t *hlen)
{
    size_t ip4hlen = sizeof(struct ip);
    scamper_probe_ipopt_t *opt;
    int i;

    for(i=0; i<pr->pr_ipoptc; i++)
    {
        opt = &pr->pr_ipopts[i];
        if(opt->type == SCAMPER_PROBE_IPOPTS_V4RR)
        {
            /*
             * want the ability to record at least one IP address otherwise
             * the option is useless.
             */
            if(ip4hlen + 8 > 60)
                goto err;

            /* for now assume this option fills the rest of the option space */
            ip4hlen = 60;
        }
        else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSPS)
        {
            if(opt->opt_v4tsps_ipc < 1 || opt->opt_v4tsps_ipc > 4)
                goto err;

            ip4hlen += (opt->opt_v4tsps_ipc * 4 * 2) + 4;
            if(ip4hlen > 60)
                goto err;
        }
        else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSO)
        {
            ip4hlen += 40;
            if(ip4hlen > 60)
                goto err;
        }
        else if(opt->type == SCAMPER_PROBE_IPOPTS_V4TSAA)
        {
            ip4hlen += 36;
            if(ip4hlen > 60)
                goto err;
        }
        else if(opt->type == SCAMPER_PROBE_IPOPTS_QUICKSTART)
        {
            ip4hlen += 8;
            if(ip4hlen > 60)
                goto err;
        }
        else goto err;
    }

    *hlen = ip4hlen;
    return 0;

err:
    scamper_debug(__func__, "invalid IPv4 header specification");
    return -1;
}
Example #3
0
static int fds_kqueue_init(void)
{
  if((kq = kqueue()) == -1)
    {
      printerror(errno, strerror, __func__, "could not create kqueue");
      return -1;
    }
  scamper_debug(__func__, "fd %d", kq);
  return 0;
}
Example #4
0
static int fds_epoll_init(void)
{
  if((ep = epoll_create(10)) == -1)
    {
      printerror(errno, strerror, __func__, "could not epoll_create");
      return -1;
    }
  scamper_debug(__func__, "fd %d", ep);
  return 0;
}
static void rtattr_dump(struct rtattr *rta)
{
  char *rta_type;
  char  rta_data[64];
  int   i;

  switch(rta->rta_type)
    {
    case RTA_UNSPEC:    rta_type = "unspec";    break;
    case RTA_DST:       rta_type = "dst";       break;
    case RTA_SRC:       rta_type = "src";       break;
    case RTA_IIF:       rta_type = "iif";       break;
    case RTA_OIF:       rta_type = "oif";       break;
    case RTA_GATEWAY:   rta_type = "gateway";   break;
    case RTA_PRIORITY:  rta_type = "priority";  break;
    case RTA_PREFSRC:   rta_type = "prefsrc";   break;
    case RTA_METRICS:   rta_type = "metrics";   break;
    case RTA_MULTIPATH: rta_type = "multipath"; break;
    case RTA_PROTOINFO: rta_type = "protoinfo"; break;
    case RTA_FLOW:      rta_type = "flow";      break;
    case RTA_CACHEINFO: rta_type = "cacheinfo"; break;
    case RTA_SESSION:   rta_type = "session";   break;
    default:            rta_type = "<unknown>"; break;
    }

  for(i=0;i<rta->rta_len-sizeof(struct rtattr)&&i<(sizeof(rta_data)/2)-1;i++)
    {
      snprintf(&rta_data[i*2], 3, "%02x",
	       *(uint8_t *)(((char *)rta) + sizeof(struct rtattr) + i));
    }

  if(i != 0)
    {
      scamper_debug(__func__, "type %s len %d data %s",
		    rta_type, rta->rta_len-sizeof(struct rtattr), rta_data);
    }
  else
    {
      scamper_debug(__func__, "type %s\n", rta_type);
    }

  return;
}
Example #6
0
int scamper_outfile_close(scamper_outfile_t *sof)
{
  if(sof->refcnt > 1)
    {
      scamper_debug(__func__,"not closing %s refcnt %d",sof->name,sof->refcnt);
      return -1;
    }

  outfile_free(sof);
  return 0;
}
Example #7
0
/*
 * scamper_fds_init
 *
 * setup the global data structures necessary for scamper to manage a set of
 * file descriptors
 */
int scamper_fds_init()
{
#ifdef HAVE_GETDTABLESIZE
  scamper_debug(__func__, "fd table size: %d", getdtablesize());
#endif

#ifdef HAVE_POLL
  pollfunc = fds_poll;
#endif

#ifdef HAVE_KQUEUE
  if(scamper_option_kqueue())
    {
      pollfunc = fds_kqueue;
      if(fds_kqueue_init() != 0)
	return -1;
    }
#endif

#ifdef HAVE_EPOLL
  if(scamper_option_epoll())
    {
      pollfunc = fds_epoll;
      if(fds_epoll_init() != 0)
	return -1;
    }
#endif

  if(scamper_option_select() || pollfunc == NULL)
    pollfunc = fds_select;

  if((fd_list     = alloc_list("fd_list")) == NULL ||
     (read_fds    = alloc_list("read_fds"))   == NULL ||
     (read_queue  = alloc_list("read_queue"))  == NULL ||
     (write_fds   = alloc_list("write_fds"))  == NULL ||
     (write_queue = alloc_list("write_queue")) == NULL ||
     (refcnt_0    = alloc_list("refcnt_0"))  == NULL)
    {
      return -1;
    }

  if((fd_tree = splaytree_alloc(fd_cmp)) == NULL)
    {
      printerror(errno, strerror, __func__, "alloc fd tree failed");
      return -1;
    }

  planetlab = scamper_option_planetlab();
  return 0;
}
Example #8
0
static int addr2mac_add(const int ifindex, const int type, const void *ipraw,
			const void *macraw, const time_t expire)
{
  const int mt = SCAMPER_ADDR_TYPE_ETHERNET;
  scamper_addr_t *mac = NULL;
  scamper_addr_t *ip  = NULL;
  addr2mac_t *addr2mac = NULL;
  char ipstr[128], macstr[128];

  if((ip = scamper_addrcache_get(addrcache, type, ipraw)) == NULL)
    {
      printerror(errno, strerror, __func__, "could not get ip");
      goto err;
    }

  if((mac = scamper_addrcache_get(addrcache, mt, macraw)) == NULL)
    {
      printerror(errno, strerror, __func__, "could not get mac");
      goto err;
    }

  if((addr2mac = addr2mac_alloc(ifindex, ip, mac, expire)) == NULL)
    {
      goto err;
    }

  scamper_addr_free(ip);  ip  = NULL;
  scamper_addr_free(mac); mac = NULL;

  if(splaytree_insert(tree, addr2mac) == NULL)
    {
      printerror(errno, strerror, __func__, "could not add %s:%s to tree",
		 scamper_addr_tostr(addr2mac->ip, ipstr, sizeof(ipstr)),
		 scamper_addr_tostr(addr2mac->mac, macstr, sizeof(macstr)));
      goto err;
    }

  scamper_debug(__func__, "ifindex %d ip %s mac %s expire %d", ifindex,
		scamper_addr_tostr(addr2mac->ip, ipstr, sizeof(ipstr)),
		scamper_addr_tostr(addr2mac->mac, macstr, sizeof(macstr)),
		expire);
  return 0;

 err:
  if(addr2mac != NULL) addr2mac_free(addr2mac);
  if(mac != NULL) scamper_addr_free(mac);
  if(ip != NULL) scamper_addr_free(ip);
  return -1;
}
Example #9
0
/*
 * fd_free
 *
 * free up memory allocated to scamper's monitoring of the file descriptor.
 */
static void fd_free(scamper_fd_t *fdn)
{
  scamper_debug(__func__, "fd %d type %s", fdn->fd, fd_tostr(fdn));

  if(fdn->fd >= 0 && fdn->fd < fd_array_s && fd_array != NULL)
    fd_array[fdn->fd] = NULL;

  if(fdn->read.node != NULL)
    dlist_node_pop(fdn->read.list, fdn->read.node);

  if(fdn->write.node != NULL)
    dlist_node_pop(fdn->write.list, fdn->write.node);

  if(fdn->rc0 != NULL)
    dlist_node_pop(refcnt_0, fdn->rc0);

  if(fdn->fd_tree_node != NULL)
    splaytree_remove_node(fd_tree, fdn->fd_tree_node);

  if(fdn->fd_list_node != NULL)
    dlist_node_pop(fd_list, fdn->fd_list_node);

  if(SCAMPER_FD_TYPE_IS_ICMP(fdn))
    {
      if(fdn->fd_icmp_addr != NULL)
	free(fdn->fd_icmp_addr);
    }
  else if(SCAMPER_FD_TYPE_IS_UDP(fdn))
    {
      if(fdn->fd_udp_addr != NULL)
	free(fdn->fd_udp_addr);
    }
  else if(SCAMPER_FD_TYPE_IS_TCP(fdn))
    {
      if(fdn->fd_tcp_addr != NULL)
	free(fdn->fd_tcp_addr);
    }
  else if(SCAMPER_FD_TYPE_IS_DL(fdn))
    {
      if(fdn->fd_dl_dl != NULL)
	scamper_dl_state_free(fdn->fd_dl_dl);
    }

  free(fdn);

  return;
}
int scamper_task_sig_install(scamper_task_t *task)
{
  scamper_task_sig_t *sig;
  scamper_task_t *tf;
  s2t_t *s2t;
  slist_node_t *n;

  if(slist_count(task->siglist) < 1)
    return -1;

  for(n=slist_head_node(task->siglist); n != NULL; n = slist_node_next(n))
    {
      s2t = slist_node_item(n); sig = s2t->sig;

      /* check if another task has this signature already */
      if((tf = scamper_task_find(sig)) != NULL)
	{
	  if(tf != task)
	    goto err;
	  continue;
	}

      if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_IP)
	s2t->node = splaytree_insert(tx_ip, s2t);
      else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_TX_ND)
	s2t->node = splaytree_insert(tx_nd, s2t);
      else if(sig->sig_type == SCAMPER_TASK_SIG_TYPE_SNIFF)
	s2t->node = dlist_tail_push(sniff, s2t);

      if(s2t->node == NULL)
	{
	  scamper_debug(__func__, "could not install sig");
	  goto err;
	}
    }

  return 0;

 err:
  scamper_task_sig_deinstall(task);
  return -1;
}
Example #11
0
int scamper_if_getifname(char *str, size_t len, int ifindex)
{
  char ifname[IFNAMSIZ];

  if(if_indextoname(ifindex, ifname) == NULL)
    {
      printerror(errno, strerror, __func__,
		 "could not get name for %d", ifindex);
      return -1;
    }

  if(strlen(ifname) + 1 > len)
    {
      scamper_debug(__func__, "ifname too small");
      return -1;
    }

  strncpy(str, ifname, len);
  return 0;
}
Example #12
0
void scamper_outfiles_cleanup()
{
  if(outfile_def != NULL)
    {
      if(--outfile_def->refcnt > 0)
	{
	  scamper_debug(__func__,
			"default outfile refcnt %d", outfile_def->refcnt);
	}

      outfile_free(outfile_def);
      outfile_def = NULL;
    }

  if(outfiles != NULL)
    {
      splaytree_free(outfiles, NULL);
      outfiles = NULL;
    }

  return;
}
Example #13
0
static void outfile_free(scamper_outfile_t *sof)
{
  assert(sof != NULL);

  if(sof->name != NULL && sof->sf != NULL)
    scamper_debug(__func__, "name %s fd %d", sof->name,
		  scamper_file_getfd(sof->sf));

  if(sof->name != NULL)
    {
      splaytree_remove_item(outfiles, sof);
      free(sof->name);
    }

  if(sof->sf != NULL)
    {
      scamper_file_close(sof->sf);
    }

  free(sof);
  return;
}
Example #14
0
static scamper_outfile_t *outfile_alloc(char *name, scamper_file_t *sf)
{
  scamper_outfile_t *sof = NULL;

  if((sof = malloc_zero(sizeof(scamper_outfile_t))) == NULL)
    {
      printerror(errno, strerror, __func__, "could not malloc sof");
      goto err;
    }

  sof->sf = sf;
  sof->refcnt = 1;

  if((sof->name = strdup(name)) == NULL)
    {
      printerror(errno, strerror, __func__, "could not strdup");
      goto err;
    }

  if(splaytree_insert(outfiles, sof) == NULL)
    {
      printerror(errno, strerror, __func__, "could not insert");
      goto err;
    }

  scamper_debug(__func__, "name %s fd %d", name, scamper_file_getfd(sf));
  return sof;

 err:
  if(sof != NULL)
    {
      if(sof->name != NULL) free(sof->name);
      free(sof);
    }
  return NULL;
}
Example #15
0
static int ipfw_sysctl_check(void)
{
  scamper_osinfo_t *osinfo = NULL;
  size_t len;
  char *name;
  int i;

  len = sizeof(i);
  name = "net.inet.ip.fw.enable";
  if(sysctlbyname(name, &i, &len, NULL, 0) != 0)
    {
      printerror(errno, strerror, __func__, "could not sysctl %s", name);
      return -1;
    }
  else
    {
      if(i != 0)
	have_ipv4 = 1;
      else
	scamper_debug(__func__, "ipfw ipv4 not enabled");
    }

  len = sizeof(i);
  name = "net.inet6.ip6.fw.enable";
  if(sysctlbyname(name, &i, &len, NULL, 0) != 0)
    {
      printerror(errno, strerror, __func__, "could not sysctl %s", name);
      if(errno != ENOENT)
	return -1;

      if((osinfo = uname_wrap()) == NULL)
	{
	  printerror(errno, strerror, __func__, "could not uname");
	  return -1;
	}

      /*
       * check if the system is known to not have a separate sysctl for
       * ipv6 ipfw.
       */
      i = 0;
      if((osinfo->os_id == SCAMPER_OSINFO_OS_FREEBSD &&
	  osinfo->os_rel[0] == 6 && osinfo->os_rel[1] < 3) ||
	 (osinfo->os_id == SCAMPER_OSINFO_OS_DARWIN &&
	  osinfo->os_rel[0] == 8))
	{
	  have_ipv6 = have_ipv4;
	}
      else i++;

      scamper_osinfo_free(osinfo);

      if(i != 0)
	return -1;
    }
  else
    {
      if(i != 0)
	have_ipv6 = 1;
      else
	scamper_debug(__func__, "ipfw ipv6 not enabled");
    }

  return 0;
}
Example #16
0
static int addr2mac_init_linux()
{
  struct nlmsghdr   *nlmsg;
  struct ndmsg      *ndmsg;
  struct rtattr     *rta, *tb[NDA_MAX];
  struct sockaddr_nl snl;
  struct msghdr      msg;
  struct iovec       iov;
  struct timeval     tv;
  pid_t              pid;
  uint8_t            buf[16384];
  ssize_t            ssize;
  ssize_t            len;
  int                rlen;
  int                fd = -1;
  void              *ip, *mac;
  int                iptype;

  pid = getpid();

  memset(buf, 0, sizeof(buf));
  nlmsg = (struct nlmsghdr *)buf;
  nlmsg->nlmsg_len   = NLMSG_LENGTH(sizeof(struct ndmsg));
  nlmsg->nlmsg_type  = RTM_GETNEIGH;
  nlmsg->nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT | NLM_F_MATCH;
  nlmsg->nlmsg_seq   = 0;
  nlmsg->nlmsg_pid   = pid;

  ndmsg = NLMSG_DATA(nlmsg);
  ndmsg->ndm_family = AF_UNSPEC;

  if((fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1)
    {
      printerror(errno, strerror, __func__, "could not open netlink");
      goto err;
    }

  len = nlmsg->nlmsg_len;
  if((ssize = send(fd, buf, len, 0)) < len)
    {
      if(ssize == -1)
	{
	  printerror(errno, strerror, __func__, "could not send netlink");
	}
      goto err;
    }

  for(;;)
    {
      iov.iov_base = buf;
      iov.iov_len = sizeof(buf);

      msg.msg_name = &snl;
      msg.msg_namelen = sizeof(snl);
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
      msg.msg_control = NULL;
      msg.msg_controllen = 0;
      msg.msg_flags = 0;

      if((len = recvmsg(fd, &msg, 0)) == -1)
	{
	  if(errno == EINTR) continue;
	  printerror(errno, strerror, __func__, "could not recvmsg");
	  goto err;
	}

      gettimeofday_wrap(&tv);

      nlmsg = (struct nlmsghdr *)buf;
      while(NLMSG_OK(nlmsg, len))
	{
	  if(nlmsg->nlmsg_pid != pid || nlmsg->nlmsg_seq != 0)
	    {
	      goto skip;
	    }

	  if(nlmsg->nlmsg_type == NLMSG_DONE)
	    {
	      goto done;
	    }

	  if(nlmsg->nlmsg_type == NLMSG_ERROR)
	    {
	      scamper_debug(__func__, "nlmsg error");
	      goto err;
	    }

	  /* get current neighbour entries only */
	  if(nlmsg->nlmsg_type != RTM_NEWNEIGH)
	    {
	      goto skip;
	    }

	  /* make sure the address is reachable */
	  ndmsg = NLMSG_DATA(nlmsg);
	  if((ndmsg->ndm_state & NUD_REACHABLE) == 0)
	    {
	      goto skip;
	    }

	  /* make sure we can process this address type */
	  switch(ndmsg->ndm_family)
	    {
	    case AF_INET:
	      iptype = SCAMPER_ADDR_TYPE_IPV4;
	      break;

	    case AF_INET6:
	      iptype = SCAMPER_ADDR_TYPE_IPV6;
	      break;

	    default:
	      goto skip;
	    }

	  /* fill a table with parameters from the payload */
	  memset(tb, 0, sizeof(tb));
	  rlen = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
	  for(rta = NDA_RTA(ndmsg); RTA_OK(rta,rlen); rta = RTA_NEXT(rta,rlen))
	    {
	      if(rta->rta_type >= NDA_MAX)
		continue;
	      tb[rta->rta_type] = rta;
	    }

	  /*
	   * skip if we don't have a destination IP address, or if
	   * we don't have an ethernet mac address
	   */
	  if(tb[NDA_DST] == NULL ||
	     tb[NDA_LLADDR] == NULL || RTA_PAYLOAD(tb[NDA_LLADDR]) != 6)
	    {
	      goto skip;
	    }

	  ip = RTA_DATA(tb[NDA_DST]);
	  mac = RTA_DATA(tb[NDA_LLADDR]);

	  addr2mac_add(ndmsg->ndm_ifindex, iptype, ip, mac, tv.tv_sec+600);

	skip:
	  nlmsg = NLMSG_NEXT(nlmsg, len);
	}
    }

 done:
  close(fd);
  return 0;

 err:
  close(fd);
  return -1;
}
static void rtsock_parsemsg(uint8_t *buf, size_t len)
{
  struct nlmsghdr *nlmsg;
  struct nlmsgerr *nlerr;
  struct rtmsg    *rtmsg;
  struct rtattr   *rta;
  void            *gwa = NULL;
  int              ifindex = -1;
  scamper_addr_t  *gw = NULL;
  rtsock_pair_t   *pair = NULL;
  scamper_route_t *route = NULL;

  if(len < sizeof(struct nlmsghdr))
    {
      scamper_debug(__func__, "len %d != %d", len, sizeof(struct nlmsghdr));
      return;
    }

  nlmsg = (struct nlmsghdr *)buf;

  /* if the message isn't addressed to this pid, drop it */
  if(nlmsg->nlmsg_pid != pid)
    return;

  if((pair = rtsock_pair_get(nlmsg->nlmsg_seq)) == NULL)
    return;
  route = pair->route;
  rtsock_pair_free(pair);

  if(nlmsg->nlmsg_type == RTM_NEWROUTE)
    {
      rtmsg = NLMSG_DATA(nlmsg);

      /* this is the payload length of the response packet */
      len = nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));

      /* hunt through the payload for the RTA_OIF entry */
      rta = RTM_RTA(rtmsg);
      while(RTA_OK(rta, len))
	{
	  switch(rta->rta_type)
	    {
	    case RTA_OIF:
	      ifindex = *(unsigned *)RTA_DATA(rta);
	      break;

	    case RTA_GATEWAY:
	      gwa = RTA_DATA(rta);
	      break;
	    }
	  rta = RTA_NEXT(rta, len);
	}

      if(gwa != NULL)
	{
	  if(rtmsg->rtm_family == AF_INET)
	    gw = scamper_addrcache_get_ipv4(addrcache, gwa);
	  else if(rtmsg->rtm_family == AF_INET6)
	    gw = scamper_addrcache_get_ipv6(addrcache, gwa);
	  else
	    route->error = EINVAL;
	}
    }
  else if(nlmsg->nlmsg_type == NLMSG_ERROR)
    {
      nlerr = NLMSG_DATA(nlmsg);
      route->error = nlerr->error;
    }
  else goto skip;

  route->gw = gw;
  route->ifindex = ifindex;
  route->cb(route);

  return;

 skip:
  if(route != NULL) scamper_route_free(route);
  return;
}
Example #18
0
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 rtsock_parsemsg(uint8_t *buf, size_t len)
{
  struct rt_msghdr   *rtm;
  struct sockaddr    *addrs[RTAX_MAX];
  struct sockaddr_dl *sdl;
  struct sockaddr    *sa;
  struct in6_addr    *ip6;
  size_t              off, tmp, x;
  int                 i, ifindex;
  void               *addr;
  scamper_addr_t     *gw;
  rtsock_pair_t      *pair;
  scamper_route_t    *route;

  x = 0;
  while(x < len)
    {
      if(len - x < sizeof(struct rt_msghdr))
	{
	  scamper_debug(__func__,"len %d != %d",len,sizeof(struct rt_msghdr));
	  return;
	}

      /*
       * check if the message is something we want, and that we have
       * a pair for it
       */
      rtm = (struct rt_msghdr *)(buf + x);
      if(rtm->rtm_pid != pid ||
	 rtm->rtm_msglen > len - x ||
	 rtm->rtm_type != RTM_GET ||
	 (rtm->rtm_flags & RTF_DONE) == 0 ||
	 (pair = rtsock_pair_get(rtm->rtm_seq)) == NULL)
	{
	  x += rtm->rtm_msglen;
	  continue;
	}

      route = pair->route;
      rtsock_pair_free(pair);

      ifindex = -1;
      addr = NULL;
      gw = NULL;

      if(rtm->rtm_errno != 0)
	{
	  route->error = rtm->rtm_errno;
	  goto done;
	}

      off = sizeof(struct rt_msghdr);
      memset(addrs, 0, sizeof(addrs));
      for(i=0; i<RTAX_MAX; i++)
	{
	  if(rtm->rtm_addrs & (1 << i))
	    {
	      addrs[i] = sa = (struct sockaddr *)(buf + x + off);
	      if((tmp = sockaddr_len(sa)) == -1)
		{
		  printerror(0,NULL,__func__,"unhandled af %d",sa->sa_family);
		  route->error = EINVAL;
		  goto done;
		}
	      off += scamper_rtsock_roundup(tmp);
	    }
	}

      if((sdl = (struct sockaddr_dl *)addrs[RTAX_IFP]) != NULL)
	{
	  if(sdl->sdl_family != AF_LINK)
	    {
	      printerror(0, NULL, __func__, "sdl_family %d", sdl->sdl_family);
	      route->error = EINVAL;
	      goto done;
	    }
	  ifindex = sdl->sdl_index;
	}

      if((sa = addrs[RTAX_GATEWAY]) != NULL)
	{
	  if(sa->sa_family == AF_INET)
	    {
	      i = SCAMPER_ADDR_TYPE_IPV4;
	      addr = &((struct sockaddr_in *)sa)->sin_addr;
	    }
	  else if(sa->sa_family == AF_INET6)
	    {
	      /*
	       * check to see if the gw address is a link local address.  if
	       * it is, then drop the embedded index from the gateway address
	       */
	      ip6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
	      if(IN6_IS_ADDR_LINKLOCAL(ip6))
		{
		  ip6->s6_addr[2] = 0;
		  ip6->s6_addr[3] = 0;
		}
	      i = SCAMPER_ADDR_TYPE_IPV6;
	      addr = ip6;
	    }
	  else if(sa->sa_family == AF_LINK)
	    {
	      sdl = (struct sockaddr_dl *)sa;
	      if(sdl->sdl_type == IFT_ETHER && sdl->sdl_alen == ETHER_ADDR_LEN)
		{
		  i = SCAMPER_ADDR_TYPE_ETHERNET;
		  addr = sdl->sdl_data + sdl->sdl_nlen;
		}
	    }

	  /*
	   * if we have got a gateway address that we know what to do with,
	   * then store it here.
	   */
	  if(addr != NULL &&
	     (gw = scamper_addrcache_get(addrcache, i, addr)) == NULL)
	    {
	      scamper_debug(__func__, "could not get rtsmsg->rr.gw");
	      route->error = EINVAL;
	      goto done;
	    }
	}

    done:
      route->gw      = gw;
      route->ifindex = ifindex;
      route->cb(route);
      x += rtm->rtm_msglen;
    }

  return;
}
Example #20
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;
}
Example #21
0
void scamper_icmp_resp_print(const scamper_icmp_resp_t *ir)
{
  char *t = NULL, tbuf[64];
  char *c = NULL, cbuf[64];
  char addr[64];
  char ip[256];
  char icmp[256];
  char inner_ip[256];
  char inner_transport[256];
  char ext[256];
  int  i, j;
  size_t off;

  assert(ir->ir_af == AF_INET || ir->ir_af == AF_INET6);

  if(ir->ir_af == AF_INET)
    {
      addr_tostr(AF_INET, &ir->ir_ip_src.v4, addr, sizeof(addr));

      off = 0;
      string_concat(ip, sizeof(ip), &off,
		    "from %s size %d ttl %d tos 0x%02x ipid 0x%04x",
		    addr, ir->ir_ip_size, ir->ir_ip_ttl, ir->ir_ip_tos,
		    ir->ir_ip_id);

      if(ir->ir_ipopt_rrc > 0)
	string_concat(ip, sizeof(ip), &off, " rr %d", ir->ir_ipopt_rrc);

      switch(ir->ir_icmp_type)
        {
        case ICMP_UNREACH:
          t = "unreach";
          switch(ir->ir_icmp_code)
            {
            case ICMP_UNREACH_NET:           c = "net";           break;
            case ICMP_UNREACH_HOST:          c = "host";          break;
            case ICMP_UNREACH_PROTOCOL:      c = "protocol";      break;
            case ICMP_UNREACH_PORT:          c = "port";          break;
            case ICMP_UNREACH_SRCFAIL:       c = "src-rt failed"; break;
            case ICMP_UNREACH_NET_UNKNOWN:   c = "net unknown";   break;
            case ICMP_UNREACH_HOST_UNKNOWN:  c = "host unknown";  break;
            case ICMP_UNREACH_ISOLATED:      c = "isolated";      break;
            case ICMP_UNREACH_NET_PROHIB:    c = "net prohib";    break;
            case ICMP_UNREACH_HOST_PROHIB:   c = "host prohib";   break;
            case ICMP_UNREACH_TOSNET:        c = "tos net";       break;
            case ICMP_UNREACH_TOSHOST:       c = "tos host";      break;
            case ICMP_UNREACH_FILTER_PROHIB: c = "admin prohib";  break;
            case ICMP_UNREACH_NEEDFRAG:
	      /*
	       * use the type buf to be consistent with the ICMP6
	       * fragmentation required message
	       */
	      snprintf(tbuf, sizeof(tbuf), "need frag %d", ir->ir_icmp_nhmtu);
	      t = tbuf;
	      break;

            default:
	      snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code);
	      c = cbuf;
	      break;
            }
          break;

        case ICMP_TIMXCEED:
          t = "time exceeded";
          switch(ir->ir_icmp_code)
            {
            case ICMP_TIMXCEED_INTRANS: c = "in trans"; break;
            case ICMP_TIMXCEED_REASS:   c = "in reass"; break;
            default:
	      snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code);
	      c = cbuf;
	      break;
            }
          break;

	case ICMP_ECHOREPLY:
	  t = "echo reply";
	  snprintf(cbuf, sizeof(cbuf), "id %d seq %d",
		   ir->ir_icmp_id, ir->ir_icmp_seq);
	  c = cbuf;
	  break;

	case ICMP_TSTAMPREPLY:
	  t = "ts reply";
	  snprintf(cbuf, sizeof(cbuf), "id %d seq %d",
		   ir->ir_icmp_id, ir->ir_icmp_seq);
	  c = cbuf;
	  break;
        }
    }
  else /* if(ir->ir_af == AF_INET6) */
    {
      addr_tostr(AF_INET6, &ir->ir_ip_src.v6, addr, sizeof(addr));

      snprintf(ip, sizeof(ip), "from %s size %d hlim %d", addr,
	       ir->ir_ip_size, ir->ir_ip_hlim);

      switch(ir->ir_icmp_type)
        {
        case ICMP6_DST_UNREACH:
          t = "unreach";
          switch(ir->ir_icmp_code)
            {
            case ICMP6_DST_UNREACH_NOROUTE:     c = "no route";     break;
            case ICMP6_DST_UNREACH_ADMIN:       c = "admin prohib"; break;
            case ICMP6_DST_UNREACH_BEYONDSCOPE: c = "beyond scope"; break;
            case ICMP6_DST_UNREACH_ADDR:        c = "addr";         break;
            case ICMP6_DST_UNREACH_NOPORT:      c = "port";         break;

            default:
	      snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code);
	      c = cbuf;
	      break;
            }
          break;

        case ICMP6_TIME_EXCEEDED:
          t = "time exceeded";
          switch(ir->ir_icmp_code)
            {
            case ICMP6_TIME_EXCEED_TRANSIT:    c = "in trans"; break;
            case ICMP6_TIME_EXCEED_REASSEMBLY: c = "in reass"; break;

            default:
	      snprintf(cbuf, sizeof(cbuf), "code %d", ir->ir_icmp_code);
	      c = cbuf;
	      break;
            }
          break;

	case ICMP6_PACKET_TOO_BIG:
	  snprintf(tbuf, sizeof(tbuf), "need frag %d", ir->ir_icmp_nhmtu);
	  t = tbuf;
	  break;

	case ICMP6_ECHO_REPLY:
	  t = "echo reply";
	  snprintf(cbuf, sizeof(cbuf), "id %d seq %d",
		   ir->ir_icmp_id, ir->ir_icmp_seq);
	  c = cbuf;
	  break;
        }
    }

  if(t == NULL)
    {
      snprintf(icmp, sizeof(icmp), "icmp %d code %d",
	       ir->ir_icmp_type, ir->ir_icmp_code);
    }
  else if(c == NULL)
    {
      snprintf(icmp, sizeof(icmp), "icmp %s", t);
    }
  else
    {
      snprintf(icmp, sizeof(icmp), "icmp %s %s", t, c);
    }

  if(ir->ir_flags & SCAMPER_ICMP_RESP_FLAG_INNER_IP)
    {
      if(ir->ir_af == AF_INET)
	{
	  addr_tostr(AF_INET, &ir->ir_inner_ip_dst.v4, addr, sizeof(addr));

	  off = 0;
	  string_concat(inner_ip, sizeof(inner_ip), &off,
			" to %s size %d ttl %d tos 0x%02x ipid 0x%04x",
			addr, ir->ir_inner_ip_size, ir->ir_inner_ip_ttl,
			ir->ir_inner_ip_tos, ir->ir_inner_ip_id);
	  if(ir->ir_inner_ipopt_rrc > 0)
	    string_concat(inner_ip, sizeof(inner_ip), &off, " rr %d",
			  ir->ir_inner_ipopt_rrc);
	}
      else /* if(ir->ir_af == AF_INET6) */
	{
	  addr_tostr(AF_INET6, &ir->ir_inner_ip_dst.v6, addr, sizeof(addr));
	  snprintf(inner_ip, sizeof(inner_ip),
		   " to %s size %d hlim %d flow 0x%05x", addr,
		   ir->ir_inner_ip_size, ir->ir_inner_ip_hlim,
		   ir->ir_inner_ip_flow);
	}

      switch(ir->ir_inner_ip_proto)
	{
	case IPPROTO_UDP:
	  snprintf(inner_transport, sizeof(inner_transport),
		   " proto UDP sport %d dport %d sum 0x%04x",
		   ir->ir_inner_udp_sport, ir->ir_inner_udp_dport,
		   ntohs(ir->ir_inner_udp_sum));
	  break;

	case IPPROTO_ICMP:
	case IPPROTO_ICMPV6:
	  snprintf(inner_transport, sizeof(inner_transport),
		   " proto ICMP type %d code %d id %04x seq %d sum %04x",
		   ir->ir_inner_icmp_type, ir->ir_inner_icmp_code,
		   ir->ir_inner_icmp_id, ir->ir_inner_icmp_seq,
		   ntohs(ir->ir_inner_icmp_sum));
	  break;

	case IPPROTO_TCP:
	  snprintf(inner_transport, sizeof(inner_transport),
		   " proto TCP sport %d dport %d seq %08x",
		   ir->ir_inner_tcp_sport, ir->ir_inner_tcp_dport,
		   ir->ir_inner_tcp_seq);
	  break;

	default:
	  inner_transport[0] = '\0';
	  break;
	}
    }
  else
    {
      inner_ip[0] = '\0';
      inner_transport[0] = '\0';
    }

  if(ir->ir_ext != NULL)
    {
      snprintf(ext, sizeof(ext), " icmp-ext");
      j = 9;
      for(i=0; i<ir->ir_extlen; i++)
	{
	  if(i % 4 == 0)
	    {
	      if(sizeof(ext)-j < 4)
		break;
	      ext[j++] = ' ';
	    }
	  else if(sizeof(ext)-j < 3)
	    break;
	  byte2hex(ir->ir_ext[i], ext + j);
	  j += 2;
	}
      ext[j] = '\0';
    }
  else
    {
      ext[0] = '\0';
    }

  scamper_debug(NULL, "%s %s%s%s%s", ip, icmp, inner_ip, inner_transport, ext);
  return;
}
Example #22
0
scamper_firewall_entry_t *scamper_firewall_entry_get(scamper_firewall_rule_t *sfw)
{
  scamper_firewall_entry_t findme, *entry = NULL;
  int n, af, p, sp, dp;
  void *s, *d;

  /* sanity check the rule */
  if((sfw->sfw_5tuple_proto != IPPROTO_TCP &&
      sfw->sfw_5tuple_proto != IPPROTO_UDP) ||
      sfw->sfw_5tuple_sport == 0 ||
      sfw->sfw_5tuple_dport == 0 ||
     (sfw->sfw_5tuple_dst == NULL || sfw->sfw_5tuple_src == NULL ||
      sfw->sfw_5tuple_src->type != sfw->sfw_5tuple_dst->type))
    {
      scamper_debug(__func__, "invalid 5tuple rule");
      goto err;
    }

  if(sfw->sfw_5tuple_src->type == SCAMPER_ADDR_TYPE_IPV4)
    {
      af = AF_INET;
      if(have_ipv4 == 0)
	{
	  scamper_debug(__func__, "IPv4 rule requested but no IPv4 firewall");
	  goto err;
	}
    }
  else if(sfw->sfw_5tuple_src->type == SCAMPER_ADDR_TYPE_IPV6)
    {
      af = AF_INET6;
      if(have_ipv6 == 0)
	{
	  scamper_debug(__func__, "IPv6 rule requested but no IPv6 firewall");
	  goto err;
	}
    }
  else
    {
      scamper_debug(__func__, "invalid src type");
      goto err;
    }

  findme.rule = sfw;
  if((entry = splaytree_find(entries, &findme)) != NULL)
    {
      entry->refcnt++;
      return entry;
    }

  if((entry = firewall_entry_get()) == NULL)
    goto err;

  entry->refcnt = 1;
  if((entry->rule = firewall_rule_dup(sfw)) == NULL ||
     (entry->node = splaytree_insert(entries, entry)) == NULL)
    {
      goto err;
    }

  n  = entry->slot;
  p  = sfw->sfw_5tuple_proto;
  dp = sfw->sfw_5tuple_dport;
  sp = sfw->sfw_5tuple_sport;
  s  = sfw->sfw_5tuple_src->addr;
  if(sfw->sfw_5tuple_dst == NULL)
    d = NULL;
  else
    d = sfw->sfw_5tuple_dst->addr;

#if defined(HAVE_IPFW)
#ifdef WITHOUT_PRIVSEP
  if(scamper_firewall_ipfw_add(n, af, p, s, d, sp, dp) != 0)
    goto err;
#else
  if(scamper_privsep_ipfw_add(n, af, p, s, d, sp, dp) != 0)
    goto err;
#endif
#endif

  return entry;

 err:
  if(entry != NULL)
    {
      if(entry->rule != NULL)
	firewall_rule_free(entry->rule);
      free(entry);
    }
  return NULL;
}
Example #23
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;
}