Пример #1
0
static char *addr_toname(const scamper_addr_t *addr, char *buf, size_t len)
{
  struct sockaddr *sa = NULL;
  struct sockaddr_in in4;
  struct sockaddr_in6 in6;
  socklen_t sl;

  if(SCAMPER_ADDR_TYPE_IS_IPV4(addr))
    {
      sockaddr_compose((struct sockaddr *)&in4, AF_INET, addr->addr, 0);
      sa = (struct sockaddr *)&in4;
    }
  else if(SCAMPER_ADDR_TYPE_IS_IPV6(addr))
    {
      sockaddr_compose((struct sockaddr *)&in6, AF_INET6, addr->addr, 0);
      sa = (struct sockaddr *)&in6;
    }

  if(sa == NULL)
    return NULL;
  sl = sockaddr_len(sa);

  if(getnameinfo(sa, sl, buf, len, NULL, 0, NI_NAMEREQD) != 0)
    return NULL;

  return buf;
}
Пример #2
0
int scamper_rtsock_getroute(scamper_route_t *route)
{
  if(SCAMPER_ADDR_TYPE_IS_IPV4(route->dst) &&
     scamper_rtsock_getroute4(route) == 0)
    {
      route->cb(route);
      return 0;
    }

  return -1;
}
Пример #3
0
/*
 * scamper_rtsock_getifindex
 *
 * figure out the outgoing interface id / route using route sockets
 *
 * route(4) gives an overview of the functions called in here
 */
static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst)
{
  struct sockaddr_storage sas;
  struct sockaddr_dl *sdl;
  struct rt_msghdr *rtm;
  uint8_t buf[1024];
  size_t len;
  ssize_t ss;
  int slen;

  if(SCAMPER_ADDR_TYPE_IS_IPV4(dst))
    sockaddr_compose((struct sockaddr *)&sas, AF_INET, dst->addr, 0);
  else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst))
    sockaddr_compose((struct sockaddr *)&sas, AF_INET6, dst->addr, 0);
  else
    return -1;

  if((slen = sockaddr_len((struct sockaddr *)&sas)) <= 0)
    return -1;

  len = sizeof(struct rt_msghdr) + scamper_rtsock_roundup(slen) +
    scamper_rtsock_roundup(sizeof(struct sockaddr_dl));
  if(len > sizeof(buf))
    return -1;

  memset(buf, 0, len);
  rtm = (struct rt_msghdr *)buf;
  rtm->rtm_msglen  = len;
  rtm->rtm_version = RTM_VERSION;
  rtm->rtm_type    = RTM_GET;
  rtm->rtm_addrs   = RTA_DST | RTA_IFP;
  rtm->rtm_pid     = pid;
  rtm->rtm_seq     = seq;
  memcpy(buf + sizeof(struct rt_msghdr), &sas, (size_t)slen);

  sdl = (struct sockaddr_dl *)(buf + sizeof(struct rt_msghdr) +
			       scamper_rtsock_roundup(slen));
  sdl->sdl_family = AF_LINK;

#if !defined(__sun__)
  sdl->sdl_len    = sizeof(struct sockaddr_dl);
#endif

  if((ss = write(fd, buf, len)) < 0 || (size_t)ss != len)
    {
      printerror(errno, strerror, __func__, "could not write routing socket");
      return -1;
    }

  return 0;
}
Пример #4
0
int scamper_dealias_ipid_inseq(scamper_dealias_probe_t **probes,
			       int probec, uint16_t fudge, int bs)
{
  static int (*const inseq[])(scamper_dealias_probe_t **,int,uint16_t,int) = {
    dealias_ipid16_inseq,
    dealias_ipid32_inseq,
  };
  static int (*const bo[])(scamper_dealias_probe_t **, int) = {
    dealias_ipid16_bo,
    dealias_ipid32_bo,
  };
  int i, x;

  if(probec < 2)
    return -1;

  if(SCAMPER_ADDR_TYPE_IS_IPV4(probes[0]->def->dst))
    x = 0;
  else if(SCAMPER_ADDR_TYPE_IS_IPV6(probes[0]->def->dst))
    x = 1;
  else
    return -1;

  if(bs == 3)
    {
      if((i = bo[x](probes, probec)) == -1)
	return -1;
      return inseq[x](probes, probec, fudge, i);
    }

  if(bs == 2)
    {
      if(inseq[x](probes, probec, fudge, 0) == 1)
	return 1;
      return inseq[x](probes, probec, fudge, 1);
    }

  return inseq[x](probes, probec, fudge, bs);
}
Пример #5
0
static void warts_ping_reply_params(const scamper_ping_t *ping,
				    const scamper_ping_reply_t *reply,
				    warts_addrtable_t *table,
				    uint8_t *flags, uint16_t *flags_len,
				    uint16_t *params_len)
{
  const warts_var_t *var;
  int i, j, max_id = 0;

  /* unset all the flags possible */
  memset(flags, 0, ping_reply_vars_mfb);
  *params_len = 0;

  for(i=0; i<sizeof(ping_reply_vars)/sizeof(warts_var_t); i++)
    {
      var = &ping_reply_vars[i];

      if(var->id == WARTS_PING_REPLY_ADDR_GID ||
	 (var->id == WARTS_PING_REPLY_ADDR && reply->addr == NULL) ||
	 (var->id == WARTS_PING_REPLY_FLAGS && reply->flags == 0) ||
	 (var->id == WARTS_PING_REPLY_REPLY_PROTO &&
	  SCAMPER_PING_METHOD_IS_ICMP(ping)) ||
	 (var->id == WARTS_PING_REPLY_REPLY_TTL &&
	  (reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_TTL) == 0) ||
	 (var->id == WARTS_PING_REPLY_REPLY_IPID &&
	  SCAMPER_ADDR_TYPE_IS_IPV4(ping->dst) &&
	  (reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID) == 0) ||
	 (var->id == WARTS_PING_REPLY_REPLY_IPID32 &&
	  SCAMPER_ADDR_TYPE_IS_IPV6(ping->dst) &&
	  (reply->flags & SCAMPER_PING_REPLY_FLAG_REPLY_IPID) == 0) ||
	 (var->id == WARTS_PING_REPLY_PROBE_IPID &&
	  SCAMPER_ADDR_TYPE_IS_IPV4(ping->dst) &&
	  (reply->flags & SCAMPER_PING_REPLY_FLAG_PROBE_IPID) == 0) ||
	 (var->id == WARTS_PING_REPLY_ICMP_TC &&
	  SCAMPER_PING_REPLY_IS_ICMP(reply) == 0) ||
	 (var->id == WARTS_PING_REPLY_TCP_FLAGS &&
	  SCAMPER_PING_REPLY_IS_TCP(reply) == 0) ||
	 (var->id == WARTS_PING_REPLY_V4RR && reply->v4rr == NULL) ||
	 (var->id == WARTS_PING_REPLY_V4TS && reply->v4ts == NULL) ||
	 (var->id == WARTS_PING_REPLY_TX && reply->tx.tv_sec == 0) ||
	 (var->id == WARTS_PING_REPLY_TSREPLY && reply->tsreply == NULL))
	{
	  continue;
	}

      flag_set(flags, var->id, &max_id);

      if(var->id == WARTS_PING_REPLY_ADDR)
	{
	  *params_len += warts_addr_size(table, reply->addr);
	}
      else if(var->id == WARTS_PING_REPLY_V4RR)
	{
	  *params_len += 1;
	  for(j=0; j<reply->v4rr->rrc; j++)
	    *params_len += warts_addr_size(table, reply->v4rr->rr[j]);
	}
      else if(var->id == WARTS_PING_REPLY_V4TS)
	{
	  assert(reply->v4ts != NULL);
	  *params_len += 2; /* one byte tsc, one byte count of v4ts->ips */
	  *params_len += (reply->v4ts->tsc * 4);
	  if(reply->v4ts->ips != NULL)
	    for(j=0; j<reply->v4ts->tsc; j++)
	      *params_len += warts_addr_size(table, reply->v4ts->ips[j]);
	}
      else
	{
	  assert(var->size >= 0);
	  *params_len += var->size;
	}
    }

  *flags_len = fold_flags(flags, max_id);

  return;
}
Пример #6
0
/*
 * scamper_rtsock_getifindex
 *
 * figure out the outgoing interface id / route using linux netlink
 *
 * this works on Linux systems with netlink compiled into the kernel.
 * i think netlink comes compiled into the kernel with most distributions
 * these days.
 *
 * the man pages netlink(3), netlink(7), rtnetlink(3), and rtnetlink(7)
 * give an overview of the functions and structures used in here, but the
 * documentation in those man pages is pretty crap.
 * you'd be better off studying netlink.h and rtnetlink.h
 */
static int scamper_rtsock_getifindex(int fd, scamper_addr_t *dst)
{
  struct nlmsghdr *nlmsg;
  struct rtmsg    *rtmsg;
  struct rtattr   *rta;
  int              error;
  int              dst_len;
  uint8_t          buf[1024];
  int              af;

  if(SCAMPER_ADDR_TYPE_IS_IPV4(dst))
    {
      dst_len  = 4;
      af       = AF_INET;
    }
  else if(SCAMPER_ADDR_TYPE_IS_IPV6(dst))
    {
      dst_len  = 16;
      af       = AF_INET6;
    }
  else
    {
      return -1;
    }

  /*
   * fill out a route request.
   * we use the standard netlink header, with a route msg subheader
   * to query for the outgoing interface.
   * the message includes one attribute - the destination address
   * we are querying the route for.
   */
  memset(buf, 0, sizeof(buf));
  nlmsg  = (struct nlmsghdr *)buf;
  nlmsg->nlmsg_len   = NLMSG_LENGTH(sizeof(struct rtmsg));
  nlmsg->nlmsg_type  = RTM_GETROUTE;
  nlmsg->nlmsg_flags = NLM_F_REQUEST;
  nlmsg->nlmsg_seq   = seq;
  nlmsg->nlmsg_pid   = pid;

  /* netlink wants the bit length of each address */
  rtmsg = NLMSG_DATA(nlmsg);
  rtmsg->rtm_family  = af;
  rtmsg->rtm_flags   = 0;
  rtmsg->rtm_dst_len = dst_len * 8;

  rta = (struct rtattr *)(buf + NLMSG_ALIGN(nlmsg->nlmsg_len));
  rta->rta_type = RTA_DST;
  rta->rta_len  = RTA_LENGTH(dst_len);
  nlmsg->nlmsg_len += RTA_LENGTH(dst_len);
  memcpy(RTA_DATA(rta), dst->addr, dst_len);

  /* send the request */
  if((error = send(fd, buf, nlmsg->nlmsg_len, 0)) != nlmsg->nlmsg_len)
    {
      printerror(errno, strerror, __func__, "could not send");
      return -1;
    }

  return 0;
}
Пример #7
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;
}
Пример #8
0
/*
 * probe_build
 *
 * determine how to build the packet and call the appropriate function
 * to do so.
 */
static probe_t *probe_build(scamper_probe_t *pr)
{
  int (*build_func)(scamper_probe_t *, uint8_t *, size_t *) = NULL;
  probe_t *pt = NULL;
  size_t len;

  if(SCAMPER_ADDR_TYPE_IS_IPV4(pr->pr_ip_dst))
    {
      if((pr->pr_ip_off & IP_OFFMASK) != 0)
	build_func = scamper_ip4_frag_build;
      else if(pr->pr_ip_proto == IPPROTO_UDP)
	build_func = scamper_udp4_build;
      else if(pr->pr_ip_proto == IPPROTO_ICMP)
	build_func = scamper_icmp4_build;
      else if(pr->pr_ip_proto == IPPROTO_TCP)
	build_func = scamper_tcp4_build;
    }
  else if(SCAMPER_ADDR_TYPE_IS_IPV6(pr->pr_ip_dst))
    {
      if(pr->pr_ip_off != 0)
	build_func = scamper_ip6_frag_build;
      if(pr->pr_ip_proto == IPPROTO_UDP)
	build_func = scamper_udp6_build;
      else if(pr->pr_ip_proto == IPPROTO_ICMPV6)
	build_func = scamper_icmp6_build;
      else if(pr->pr_ip_proto == IPPROTO_TCP)
	build_func = scamper_tcp6_build;
    }

  if(build_func == NULL)
    {
      pr->pr_errno = EINVAL;
      goto err;
    }

  /* allow 16 bytes at the front of the packet for layer-2 headers */
  if(16 >= pktbuf_len)
    len = 0;
  else
    len = pktbuf_len-16;

  if(build_func(pr, pktbuf+16, &len) != 0)
    {
      /* reallocate the packet buffer */
      if(realloc_wrap((void **)&pktbuf, len+16) != 0)
	{
	  pr->pr_errno = errno;
	  goto err;
	}
      pktbuf_len = len+16;
      if(build_func(pr, pktbuf+16, &len) != 0)
	{
	  pr->pr_errno = EINVAL;
	  goto err;
	}
    }

  if((pt = malloc_zero(sizeof(probe_t))) == NULL)
    {
      pr->pr_errno = errno;
      goto err;
    }
  pt->buf     = pktbuf;
  pt->len     = len;

  return pt;

 err:
  return NULL;
}