Exemplo n.º 1
0
/**Get local IP address.
 *
 * @deprecated
 * Use su_getlocalinfo() instead.
 */
int su_getlocalip(su_sockaddr_t *sa)
{
  su_localinfo_t *li = NULL, hints[1] = {{ 0 }};

  hints->li_family = sa->su_sa.sa_family ? sa->su_sa.sa_family : AF_INET;

  if (su_getlocalinfo(hints, &li) == 0) {
    memcpy(sa, li->li_addr, li->li_addrlen);
    su_freelocalinfo(li);
    return 0;
  }
  else
    return -1;
}
Exemplo n.º 2
0
/** Duplicate su_localinfo structure.
 */
su_localinfo_t *su_copylocalinfo(su_localinfo_t const *li0)
{
  size_t n;
  su_localinfo_t *li, *retval = NULL, **lli = &retval;

# define SLEN(s) ((s) ? strlen(s) + 1 : 0)

  for (; li0 ; li0 = li0->li_next) {
    n = sizeof(*li0) + li0->li_addrlen + SLEN(li0->li_ifname);
    if (!(li = calloc(1, n))) {
      su_freelocalinfo(retval);
      return NULL;
    }
    *lli = li;
    lli = &li->li_next;
    li->li_flags = li0->li_flags;
    li->li_family = li0->li_family;
    li->li_index = li0->li_index;
    li->li_scope = li0->li_scope;
    li->li_addrlen = li0->li_addrlen;
    li->li_addr = memcpy(li + 1, li0->li_addr, li0->li_addrlen);

    if (li0->li_canonname) {
      if (!(li->li_canonname = malloc(SLEN(li0->li_canonname)))) {
	su_freelocalinfo(retval);
	return NULL;
      }
      strcpy(li->li_canonname, li0->li_canonname);
    }

    if (li0->li_ifname)
      li->li_ifname = strcpy(li->li_addrlen + (char *)li->li_addr,
			     li0->li_ifname);
  }

  return retval;
}
Exemplo n.º 3
0
static
int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  /* Kikka #3: resolve hostname */
  char hostname[SU_MAXHOST] = "";
  char *name, *ifname;
  struct hostent *h;
  int i, flags, error, gni_flags = 0;
  su_localinfo_t *tbf = NULL;
  su_localinfo_t *li = NULL, **lli = &tbf;
  su_sockaddr_t *su;
#if SU_HAVE_IN6
  socklen_t su_sockaddr_size =
    (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : sizeof(struct sockaddr_in);
  flags = hints->li_flags & (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
#else
  socklen_t su_sockaddr_size = sizeof(struct sockaddr_in);
  flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
#endif

  error = ELI_NOERROR;

  if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
    if (hints->li_canonname)
      name = hints->li_canonname;
    else if (gethostname(name = hostname, sizeof(hostname)) != 0)
      return ELI_SYSTEM;

    h = gethostbyname(name);

    if (name)
      if (strchr(name, ':') ||
	  strspn(name, "0123456789.") == strlen(name))
	flags |= LI_NUMERIC;

    for (i = 0; h && h->h_addr_list[i]; i++) {
      if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
	error = ELI_MEMORY;
	goto err;
      }
      li->li_flags = flags;

      li->li_scope = li_scope4(*(uint32_t *)h->h_addr_list[i]);
      if (li->li_scope == LI_SCOPE_HOST)
	li->li_index = 1, ifname = "lo";
      else
	li->li_index = 2, ifname = "eth";

      li->li_addrlen = su_sockaddr_size;
      li->li_addr = su = (su_sockaddr_t *)(li + 1);
      su->su_family = li->li_family =
	li->li_flags & LI_V4MAPPED ? AF_INET6 : AF_INET;

#if SU_HAVE_IN6
      if (li->li_flags & LI_V4MAPPED) {
	((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff);
	memcpy(&((int32_t*)&su->su_sin6.sin6_addr)[3],
	       h->h_addr_list[i], h->h_length);
      }
      else
#endif
	memcpy(&su->su_sin.sin_addr.s_addr, h->h_addr_list[i], h->h_length);
      if (li->li_flags & LI_IFNAME)
	li->li_ifname = ifname;
      if (li->li_scope == LI_SCOPE_HOST || li->li_scope == LI_SCOPE_LINK)
	gni_flags = NI_NUMERICHOST;
      if ((error = li_name(hints, gni_flags, su, &li->li_canonname)) < 0)
	goto err;
      else if (error > 0) {
	free(li); li = NULL; continue;
      } else
	error = ELI_NOADDRESS;
      *lli = li; lli = &li->li_next; li = NULL;
    }
  }

  if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_HOST)) {
    if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
      error = ELI_MEMORY;
      goto err;
    }
    li->li_flags = hints->li_flags &
      (LI_V4MAPPED|LI_CANONNAME|LI_NUMERIC|LI_IFNAME);
    li->li_scope = LI_SCOPE_HOST, li->li_index = 1;
    if (li->li_flags & LI_IFNAME)
      li->li_ifname = "lo";
    li->li_addrlen = su_sockaddr_size;
    li->li_addr = su = (su_sockaddr_t *)(li + 1);
#if SU_HAVE_IN6
    if (li->li_flags & LI_V4MAPPED) {
      su->su_family = li->li_family = AF_INET6;
      ((int32_t*)&su->su_sin6.sin6_addr)[2] = htonl(0xffff);
      ((int32_t*)&su->su_sin6.sin6_addr)[3] = htonl(0x7f000001);
    }
    else
#endif
      su->su_family = li->li_family = AF_INET,
      su->su_sin.sin_addr.s_addr = htonl(0x7f000001);

    if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0) {
      goto err;
    } else if (error > 0) {
      free(li); li = NULL;
    } else {
      *lli = li; lli = &li->li_next; li = NULL;
    }
  }

  *rresult = tbf;

  return 0;

err:
  if (li) su_freelocalinfo(li);
  su_freelocalinfo(tbf);

  return error;
}
Exemplo n.º 4
0
/** Build a list of local IPv4 addresses and append it to *rresult. */
static
int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  su_localinfo_t *tbf = NULL, **lli = &tbf;
  su_localinfo_t *li = NULL, *li_first = NULL;
  su_sockaddr_t *su;
  int error = ELI_NOADDRESS;
  char *canonname = NULL;
  su_socket_t s;

#if SU_HAVE_IN6
  int su_xtra = (hints->li_flags & LI_V4MAPPED) ? sizeof(*su) : 0;
#else
  int const su_xtra = 0;
#endif

  struct ifconf ifc;
  int numifs;
  char *buffer;
  struct ifreq *ifr, *ifr_next;

#if HAVE_OPEN_C
    su_sockaddr_t *sa;
    socklen_t salen = sizeof(*sa);
#endif

  s = su_socket(AF_INET, SOCK_DGRAM, 0);
  if (s == -1) {
    SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
		su_strerror(su_errno())));
    return ELI_SYSTEM;
  }

# if HAVE_IFNUM
  /* Get the list of known IP address from the kernel */
  if (ioctl(s, SIOCGIFNUM, (char *) &numifs) < 0) {
    /* can't get number of interfaces -- fall back */
    SU_DEBUG_1(("su_localinfo: SIOCGIFNUM failed: %s\n",
		su_strerror(su_errno())));
    error = ELI_SYSTEM;
    goto err;
  }

  SU_DEBUG_9(("su_localinfo: %d active interfaces according to SIOCGIFNUM\n",
	      numifs));

  if (numifs < 0)
# endif
    /* Default to 64 interfaces. Enough? */
    numifs = 64;

  if (numifs == 0)
    return 0;

  /*
   * Allocate memory for SIOCGIFCONF ioctl buffer. This memory block is also
   * used as li_first, first localinfo struct that is returned, so it can be
   * freed by freelocalinfo() without any complications.
   */
  ifc.ifc_len = numifs * sizeof (struct ifreq);
  buffer = malloc(sizeof(su_localinfo_t) + ifc.ifc_len + su_xtra);
  if (!buffer) {
    SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
    error = ELI_MEMORY;
    goto err;
  }

  li_first = (su_localinfo_t *)buffer;
  memset(li_first, 0, sizeof(su_localinfo_t) + su_xtra);
  ifc.ifc_buf = buffer + sizeof(su_localinfo_t) + su_xtra;
#if HAVE_OPEN_C
  if (ioctl(s, SIOCGIFACTIVECONF, (char *)&ifc) < 0) {
    SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n",
		su_strerror(su_errno())));
    error = ELI_SYSTEM;
    goto err;
  }
#else
  if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
    SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n",
		su_strerror(su_errno())));
    error = ELI_SYSTEM;
    goto err;
  }
#endif

  buffer = ifc.ifc_buf + ifc.ifc_len;

  for (ifr = ifc.ifc_req;
       (void *)ifr < (void *)buffer;
       ifr = ifr_next) {
    struct ifreq ifreq[1];
    int scope, if_index, flags = 0, gni_flags = 0;
    char *if_name;
#if SU_HAVE_IN6
    su_sockaddr_t su2[1];
#endif

#if SA_LEN
    if (ifr->ifr_addr.sa_len > sizeof(ifr->ifr_addr))
      ifr_next = (struct ifreq *)
	(ifr->ifr_addr.sa_len + (char *)(&ifr->ifr_addr));
    else
#else
      ifr_next = ifr + 1;
#endif

    if_name = ifr->ifr_name;

#if defined(SIOCGIFINDEX)
    ifreq[0] = *ifr;
    if (ioctl(s, SIOCGIFINDEX, ifreq) < 0) {
      SU_DEBUG_1(("su_localinfo: SIOCGIFINDEX failed: %s\n",
		  su_strerror(su_errno())));
      error = ELI_SYSTEM;
      goto err;
    }
#if HAVE_IFR_INDEX
    if_index = ifreq->ifr_index;
#elif HAVE_IFR_IFINDEX
    if_index = ifreq->ifr_ifindex;
#else
#error Unknown index field in struct ifreq
#endif

#else
#warning su_localinfo() cannot map interface name to number
    if_index = 0;
#endif

    SU_DEBUG_9(("su_localinfo: if %s with index %d\n", if_name, if_index));


#if HAVE_OPEN_C
    su_close(s);

    li = calloc(1, sizeof(su_localinfo_t));
    sa = calloc(1, sizeof(su_sockaddr_t));

    if (su_get_local_ip_addr(sa) < 0)
      goto err;

    li->li_family = sa->su_family;
    li->li_scope = LI_SCOPE_GLOBAL /* scope */;
    li->li_index = if_index;
    li->li_addrlen = su_sockaddr_size(sa);
    li->li_addr = sa;

    if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0)
      goto err;

    if (canonname) {
      if (strchr(canonname, ':') ||
	  strspn(canonname, "0123456789.") == strlen(canonname))
	    li->li_flags |= LI_NUMERIC;
    }
    else
      li->li_flags = 0;

    li->li_canonname = canonname;

    canonname = NULL;

    *rresult = li;

    return 0;
#endif

#if defined(SIOCGIFFLAGS)
    ifreq[0] = *ifr;
    if (ioctl(s, SIOCGIFFLAGS, ifreq) < 0) {
      SU_DEBUG_1(("su_localinfo: SIOCGIFFLAGS failed: %s\n",
		  su_strerror(su_errno())));
      error = ELI_SYSTEM;
      goto err;
    }
    /* Do not include interfaces that are down unless explicitly asked */
    if ((ifreq->ifr_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0) {
      SU_DEBUG_9(("su_localinfo: if %s with index %d is down\n",
		  if_name, if_index));
      continue;
    }
#elif defined(SIOCGIFACTIVECONF)
/* Handled above in SIOCGIFACTIVECONF vs. SIOCGIFCONF*/
#else
#error su_localinfo() cannot determine interface status
#endif

#if 0
    *ifreq = *ifr;
    ifreq->ifr_addr.sa_family = AF_INET;
    if (ioctl(s, SIOCGIFADDR, ifreq) < 0) {
      SU_DEBUG_1(("su_localinfo: SIOCGIFADDR failed: %s\n",
		  su_strerror(su_errno())));
      error = ELI_SYSTEM;
      goto err;
    }
    ifr->ifr_addr = ifreq->ifr_addr;
#endif

    su = (su_sockaddr_t *)&ifr->ifr_addr;

    if (SU_HAS_INADDR_ANY(su))
      continue;

    scope = li_scope4(su->su_sin.sin_addr.s_addr);

    if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
	(hints->li_ifname && strcmp(hints->li_ifname, if_name) != 0) ||
	(hints->li_index && hints->li_index != if_index))
      continue;

#if SU_HAVE_IN6
    if (su_xtra) {
      /* Map IPv4 address to IPv6 address */
      memset(su2, 0, sizeof(*su2));
      su2->su_family = AF_INET6;
      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
      su = su2;
    }
#endif

    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
      gni_flags = NI_NUMERICHOST;

    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
      goto err;
    else if (error > 0)
      continue;

    if (canonname)
      if (strchr(canonname, ':') ||
	  strspn(canonname, "0123456789.") == strlen(canonname))
	flags |= LI_NUMERIC;

    if (li_first)
      li = li_first;      /* Use li_first with all ifr structs to be freed */
    else if (!(li = calloc(1, (sizeof *li) + su_xtra))) {
      error = ELI_MEMORY;
      goto err;
    }
    if (!tbf) tbf = li;
    *lli = li; lli = &li->li_next;

    if (su_xtra)
      su = (su_sockaddr_t *)memcpy(li + 1, su, su_xtra);

    li->li_flags = flags;
    li->li_family = su->su_family;
    li->li_scope = scope;
    li->li_index = if_index;
    li->li_addrlen = su_sockaddr_size(su);
    li->li_addr = su;
    li->li_canonname = canonname;
    li->li_ifname = if_name;

    canonname = NULL;
    li_first = NULL;
  }

  if (canonname) free(canonname);
  if (li_first) free(li_first);
  su_close(s);

  if (tbf) *rresult = tbf;
  return 0;

err:
  if (canonname) free(canonname);
  if (li_first) free(li_first);
  su_freelocalinfo(tbf);
  su_close(s);

  return error;
}
Exemplo n.º 5
0
/** @brief Request local address information.
 *
 * Gather the network interfaces and the addresses corresponding to them,
 * check if they match to the search criteria specifed by @a hints and
 * return a list of matching local address information in the @a
 * return_localinfo. The local address information may include IPv4/IPv6
 * addresses, interface name, interface index, address scope, and domain
 * names corresponding to the local addresses.
 *
 * @param[in] hints specifies selection criteria
 * @param[out] return_localinfo   return list of local addresses
 *
 * @par Selection criteria - hints
 *
 * The selection criteria @a hints is used to select which addresses are
 * returned and what kind of information is included in the @a res list.
 *
 * @par Selection by flags - hints->li_flags
 *
 * The @a hints->li_flags contain flags, which can be combined with bit-wise
 * or.  The currently defined flags are as follows:
 *
 * - #LI_V4MAPPED: when returning IPv4 addresses, map them as IPv6
 *   addresses.  If this flag is specified, IPv4 addresses are returned even
 *   if @a hints->li_family is set to @c AF_INET6.
 * - #LI_CANONNAME: return the domain name (DNS PTR) corresponding to the
 *   local address in @a li_canonname.
 * - #LI_NAMEREQD: Do not return addresses not in DNS.
 * - #LI_NUMERIC: instead of domain name, return the text presentation of
 *   the addresss in @a li_canonname.
 * - #LI_DOWN: include interfaces and their addresses even if the interfaces
 *   are down. New in @VERSION_1_12_2.
 * - #LI_IFNAME: return the interface name in @a li_ifname.
 *
 * @par Selection by address family - hints->li_family
 *
 * The address family can have three values: 0, AF_INET and AF_INET6.  If
 * address family @a hints->li_family, both IPv4 and IPv6 addresses are
 * returned.
 *
 * @par Selection by interface index - hints->li_index
 *
 * If the field @a hints->li_index is non-zero, only the addresses assigned
 * to the interface with given index are returned.  The list of interface
 * indices and names can be obtained by the function @c su_if_names().
 *
 * @par Selection by interface name - hints->li_ifname
 *
 * If the field @a hints->li_ifname is not NULL, only the addresses assigned
 * to the named interface are returned.  The list of interface names can be
 * obtained by the function @c su_if_names().
 *
 * @par Selection by address scope - hints->li_scope
 *
 * If the field @a hints->li_scope is nonzero, only the addresses with
 * matching scope are returned. The different address scopes can be combined
 * with bitwise or. They are defined as follows
 * - #LI_SCOPE_HOST: host-local address, valid within host (::1, 127.0.0.1/8)
 * - #LI_SCOPE_LINK: link-local address, valid within link
 *   (IP6 addresses with prefix fe80::/10,
 *    IP4 addresses in net 169.254.0.0/16).
 * - #LI_SCOPE_SITE: site-local address, addresses valid within organization
 *   (IPv6 addresses with prefix  fec::/10,
 *    private IPv4 addresses in nets 10.0.0.0/8, 172.16.0.0/12,
 *    and 192.168.0.0/16 as defined in @RFC1918)
 * - #LI_SCOPE_GLOBAL: global address.
 *
 * For instance, setting @a hints->li_scope to @c LI_SCOPE_GLOBAL | @c
 * LI_SCOPE_SITE, both the @e global and @e site-local addresses are
 * returned.
 *
 * @sa @RFC1918, @RFC4291, su_sockaddr_scope()
 *
 * @par Selection by domain name - hints->li_canonname
 *
 * If this field is non-null, the domain name (DNS PTR) corresponding to
 * local IP addresses should match to the name given in this field.
 *
 * @return Zero (#ELI_NOERROR) when successful, or negative error code when
 * failed.
 *
 * @par Diagnostics
 * Use su_gli_strerror() in order to obtain a string describing the error
 * code returned by su_getlocalinfo().
 *
 */
int su_getlocalinfo(su_localinfo_t const *hints,
		    su_localinfo_t **return_localinfo)
{
  int error = 0, ip4 = 0;
  int ip6 = 0;
  su_localinfo_t *result = NULL, **rr = &result;
  su_localinfo_t hh[1] = {{ 0 }};

  assert(return_localinfo);

  *return_localinfo = NULL;

  if (hints) {
    /* Copy hints so that it can be modified */
    *hh = *hints;
    if (hh->li_canonname)
      hh->li_flags |= LI_CANONNAME;
#if 0
    /* hints->li_ifname is used to select by interface,
       li_ifname is returned with LI_IFNAME flag
    */
    if ((hh->li_flags & LI_IFNAME) && hh->li_ifname == NULL)
      return ELI_BADHINTS;
#endif
  }

  switch (hh->li_family) {
#if SU_HAVE_IN6
  case AF_INET6:
    if (hh->li_flags & LI_V4MAPPED)
      ip6 = ip4 = 1, hh->li_family = 0;
    else
      ip6 = 1;
    break;
#endif

  case AF_INET:
    ip4 = 1;
    break;

  case 0:
    ip4 = 1;
#if SU_HAVE_IN6  
    ip6 = 1;
#endif

    break;

  default:
    return -1;
  }

#if USE_LOCALINFO0
  error = localinfo0(hh, rr);
#else

#  if SU_HAVE_IN6
  if (ip6) {
    error = localinfo6(hh, rr);
    if (error == ELI_NOADDRESS && ip4)
      error = 0;

    if (!error)
      /* Search end of list */
      for (; *rr; rr = &(*rr)->li_next)
	;
  }
#  endif
  if (ip4 && !error) {
    /* Append IPv4 addresses */
    error = localinfo4(hh, rr);
  }
#endif

  if (ip6) {
    /* Required to make compiler happy */  
  }
  if (!result)
    error = ELI_NOADDRESS;

  if (!error)
    li_sort(result, return_localinfo);
  else
    su_freelocalinfo(result);

  return error;
}
Exemplo n.º 6
0
static
int localinfo0(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  /* This is Windows IPv4 code */
  short family = AF_INET;
  su_socket_t s;
  union {
    SOCKET_ADDRESS_LIST sal[1];
#if HAVE_INTERFACE_INFO_EX
    INTERFACE_INFO_EX   ii[1];
#else
    INTERFACE_INFO      ii[1];
#endif
    char buffer[2048];
  } b = {{ 1 }};
  DWORD salen = sizeof(b);
  int i, error = -1;
#if SU_HAVE_IN6
  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
#endif
  su_localinfo_t *li, *head = NULL, **next = &head;
  char *canonname = NULL, *if_name = NULL;

  *rresult = NULL;

  s = su_socket(family, SOCK_DGRAM, 0);
  if (s == INVALID_SOCKET) {
    SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "su_socket",
		            su_strerror(su_errno())));
    return -1;
  }

  /* get the list of known IP address (NT5 and up) */
  if (WSAIoctl(s, SIO_ADDRESS_LIST_QUERY, NULL, 0,
               &b, sizeof(b), &salen, NULL, NULL) == SOCKET_ERROR) {
    SU_DEBUG_1(("su_getlocalinfo: %s: %s\n", "SIO_ADDRESS_LIST_QUERY",
		su_strerror(su_errno())));
    error = -1; goto err;
  }
  if (b.sal->iAddressCount < 1) {
    SU_DEBUG_1(("su_getlocalinfo: no local addresses\n"));
    error = -1; goto err;
  }

  for (i = 0; i < b.sal->iAddressCount; i++) {
    su_sockaddr_t *su = (su_sockaddr_t *)b.sal->Address[i].lpSockaddr;
#if SU_HAVE_IN6
    socklen_t sulen = v4_mapped ? sizeof(*su) : b.sal->Address[i].iSockaddrLength;
    su_sockaddr_t su2[1];
#else
    socklen_t sulen = b.sal->Address[i].iSockaddrLength;
#endif
    int scope, flags = 0, gni_flags = 0;

    scope = li_scope4(su->su_sin.sin_addr.s_addr);

    if (hints->li_scope && (hints->li_scope & scope) == 0)
      continue;

    if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
      gni_flags = NI_NUMERICHOST;

    if (!(li = calloc(1, sizeof(*li) + sulen))) {
      SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
      error = -1; goto err;
    }
    *next = li, next = &li->li_next;

#if SU_HAVE_IN6
    if (v4_mapped) {
      /* Map IPv4 address to IPv6 address */
      memset(su2, 0, sizeof(*su2));
      su2->su_family = AF_INET6;
      ((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
      ((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
      su = su2;
    }
#endif

    if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
      goto err;
    else if (error > 0)
      continue;

    if (canonname)
      if (strchr(canonname, ':') ||
	  strspn(canonname, "0123456789.") == strlen(canonname))
	flags |= LI_NUMERIC;

    li->li_flags = flags;
    li->li_family = su->su_family;
    li->li_scope = scope;
    li->li_index = i;
    li->li_addrlen = su_sockaddr_size(su);
    li->li_addr = su;
    li->li_canonname = canonname, canonname = NULL;
    if (hints->li_flags & LI_IFNAME)
      li->li_ifname = if_name;
    li->li_addr = (su_sockaddr_t *)(li + 1);
    li->li_addrlen = sulen;
    memcpy(li->li_addr, su, sulen);
  }

  *rresult = head;
  su_close(s);

  return 0;

err:
  if (canonname) free(canonname);
  su_freelocalinfo(head);
  su_close(s);

  return error;
}
Exemplo n.º 7
0
static
int win_localinfo(su_localinfo_t const hints[1], su_localinfo_t **rresult)
{
  /* This is Windows XP code, for both IPv6 and IPv4. */
  ULONG iaa_size = 2048;
  IP_ADAPTER_ADDRESSES *iaa0, *iaa;
  int error, loopback_seen = 0;
  int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
  char *canonname = NULL;
  su_localinfo_t *li, **next;
  int flags = GAA_FLAG_SKIP_MULTICAST;
  *rresult = NULL; next = rresult;

  iaa0 = malloc((size_t)iaa_size);
  if (!iaa0) {
    SU_DEBUG_1(("su_localinfo: memory exhausted\n"));
    error = ELI_MEMORY;
    goto err;
  }
  error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
  if (error == ERROR_BUFFER_OVERFLOW) {
    if ((iaa0 = realloc(iaa0, iaa_size)))
      error = GetAdaptersAddresses(hints->li_family, flags, NULL, iaa0, &iaa_size);
  }
  if (error) {
    char const *empty = "";
    LPTSTR msg = empty;

    if (error == ERROR_NO_DATA) {
      error = ELI_NOADDRESS;
      goto err;
    }

    if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
	               FORMAT_MESSAGE_FROM_SYSTEM |
	               FORMAT_MESSAGE_IGNORE_INSERTS,
	  	       NULL,
	  	       error,
		       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		       msg, 0, NULL))
      msg = empty;

    SU_DEBUG_1(("su_localinfo: GetAdaptersAddresses: %s (%d)\n", msg, error));
    if (msg != empty) LocalFree((LPVOID)msg);
    error = ELI_SYSTEM;
    goto err;
  }

  for (iaa = iaa0; iaa; iaa = iaa->Next) {
    IP_ADAPTER_UNICAST_ADDRESS *ua;
    IP_ADAPTER_UNICAST_ADDRESS lua[1];
    int if_index = iaa->IfIndex;
    size_t ifnamelen = 0;
    char ifname[16];

    for (ua = iaa->FirstUnicastAddress; ;ua = ua->Next) {
      su_sockaddr_t *su;
      socklen_t sulen;
      su_sockaddr_t su2[1];
      int scope, flags = 0, gni_flags = 0;

      if (ua == NULL) {
	/* There is no loopback interface in windows */
	if (!loopback_seen && iaa->Next == NULL) {
	  struct sockaddr_in loopback_sin = { AF_INET, 0, {{ 127, 0, 0, 1 }}};

	  lua->Address.lpSockaddr = (struct sockaddr *)&loopback_sin;
	  lua->Address.iSockaddrLength = sizeof(loopback_sin);
	  lua->Next = NULL;

	  iaa->IfType = IF_TYPE_SOFTWARE_LOOPBACK;
	  if_index = 1;

	  ua = lua;
	}
	else
	  break;
      }

      su = (su_sockaddr_t *)ua->Address.lpSockaddr;
      sulen = ua->Address.iSockaddrLength;

      if (su->su_family == AF_INET) {
	scope = li_scope4(su->su_sin.sin_addr.s_addr);
	if (v4_mapped)
	  sulen = sizeof(su->su_sin6);
	if (scope == LI_SCOPE_HOST)
	  loopback_seen = 1;
      }
      else if (su->su_family == AF_INET6) {
	if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
	  continue;
	scope = li_scope6(&su->su_sin6.sin6_addr);
      }
      else
	continue;

      if (hints->li_flags & LI_IFNAME) {
	snprintf(ifname, sizeof(ifname), "%s%u",
		 ws2ifname(iaa->IfType), if_index);
	ifnamelen = strlen(ifname) + 1;
      }

      if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
	  (hints->li_family && hints->li_family != su->su_family) ||
	  /* (hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0) || */
	  (hints->li_index && hints->li_index != if_index))
	continue;

      if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
	gni_flags = NI_NUMERICHOST;

      if (v4_mapped && su->su_family == AF_INET) {
	/* Map IPv4 address to IPv6 address */
	memset(su2, 0, sizeof(*su2));
	su2->su_family = AF_INET6;
	((int32_t*)&su2->su_sin6.sin6_addr)[2] = htonl(0xffff);
	((int32_t*)&su2->su_sin6.sin6_addr)[3] = su->su_sin.sin_addr.s_addr;
	su = su2;
      }

      if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
	goto err;
      else if (error > 0)
	continue;

      if (canonname)
	if (strchr(canonname, ':') ||
	    strspn(canonname, "0123456789.") == strlen(canonname))
	  flags |= LI_NUMERIC;

      if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
	SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
	error = ELI_MEMORY; goto err;
      }
      *next = li, next = &li->li_next;

      li->li_flags = flags;
      li->li_family = su->su_family;
      li->li_scope = scope;
      li->li_index = if_index;
      li->li_addrlen = sulen;
      li->li_addr = memcpy(li + 1, su, sulen);
      li->li_canonname = canonname;
      if (ifnamelen) {
	li->li_ifname = strcpy((char *)(li + 1) + sulen, ifname);
	/* WideCharToMultiByte(CP_ACP, 0,
			    ifname, -1, (char *)(li + 1) + sulen, ifnamelen,
			    NULL, NULL); */
      }

      canonname = NULL;
    }
  }

  if (iaa0) free(iaa0);
  return 0;

err:
  if (iaa0) free(iaa0);
  if (canonname) free(canonname);
  su_freelocalinfo(*rresult), *rresult = NULL;
  return error;
}
Exemplo n.º 8
0
/* Use HOSTADDR6 */
static
int localinfo6(su_localinfo_t const *hints, su_localinfo_t **rresult)
{
  char *addr, *ifname;
  int flags, error;
  su_localinfo_t *li = NULL;
  su_sockaddr_t *su;
  int const su_sockaddr_size = sizeof(*su);

  error = ELI_NOADDRESS;

#if defined(__APPLE_CC__)
  {
    su_sockaddr_t *sa;
    int salen = sizeof(*sa);
    int s;

    if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
      if ((addr = getenv("HOSTADDR6"))) {

	li = calloc(1, sizeof(su_localinfo_t));
	sa = calloc(1, sizeof(su_sockaddr_t));

	sa->su_family = AF_INET6;
	if (su_inet_pton(AF_INET6, addr, &sa->su_sin6.sin6_addr) <= 0)
	  goto err;

	s = su_socket(AF_INET6, SOCK_DGRAM, 0);
	if (s == -1) {
	  SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
		      su_strerror(su_errno())));
	  return ELI_SYSTEM;
	}

	error = getsockname(s, (struct sockaddr *) sa, &salen);
	if (error < 0 && errno == SOCKET_ERROR) {
	  SU_DEBUG_1(("%s: getsockname() failed: %s\n", __func__,
		      su_strerror(su_errno())));
	}

	error = bind(s, (struct sockaddr *) sa, salen);

	if (error < 0) {
	  SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
		      su_strerror(su_errno())));
	  goto err;
	}

	su_close(s);

	li->li_family = sa->su_family;
	li->li_scope = LI_SCOPE_GLOBAL;
	li->li_index = 0;
	li->li_addrlen = su_sockaddr_size(sa);
	li->li_addr = sa;

	if ((error = li_name(hints, NI_NUMERICHOST, sa, &li->li_canonname)) < 0)
	  goto err;

	li->li_flags = NI_NUMERICHOST;
      }
    }

    *rresult = li;
    return 0;
  }
#endif


  if (hints->li_scope == 0 || (hints->li_scope & LI_SCOPE_GLOBAL)) {
    if ((addr = getenv("HOSTADDR6"))) {
      flags = hints->li_flags & (LI_CANONNAME|LI_NUMERIC|LI_IFNAME);

      if ((li = calloc(1, sizeof(*li) + su_sockaddr_size)) == NULL) {
	error = ELI_MEMORY;
	goto err;
      }
      li->li_flags = flags;
      li->li_scope = LI_SCOPE_GLOBAL, li->li_index = 2, ifname = "eth";
      li->li_addrlen = sizeof(*su);
      li->li_addr = su = (su_sockaddr_t *)(li + 1);
      su->su_family = li->li_family = AF_INET6;
      if (su_inet_pton(AF_INET6, addr, &su->su_sin6.sin6_addr) <= 0)
	goto err;
      if (li->li_flags & LI_IFNAME)
	li->li_ifname = ifname;
      if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0)
	goto err;
      else if (error > 0) {
	free(li); li = NULL;
      }
    }
  }

  *rresult = li;

  return 0;

err:
  if (li) su_freelocalinfo(li);
  return error;
}
Exemplo n.º 9
0
int main(int argc, char *argv[])
{
  char buffer[SU_ADDRSIZE];
  su_localinfo_t hints[1] = {{ LI_CANONNAME }};
  su_localinfo_t *li, *res = NULL;
  int error;
  int ifindex = 0;

  if (argv[1] && strcmp(argv[1], "--help") == 0)
    usage(0);

  for (;;) {
    switch(getopt(argc, argv, "iImdn46gslh")) {

    case 'I': ifindex = 1; break;
    case 'i': hints->li_flags |= LI_IFNAME; ifindex = 1; break;
    case 'm': hints->li_flags |= LI_V4MAPPED; break;
    case '4': hints->li_family = AF_INET; break;
#if SU_HAVE_IN6
    case '6': hints->li_family = AF_INET6; break;
#endif
    case 'd': hints->li_flags |= LI_NAMEREQD; break;
    case 'n': hints->li_flags |= LI_NUMERIC; break;
    case 'g': hints->li_scope |= LI_SCOPE_GLOBAL; break;
    case 's': hints->li_scope |= LI_SCOPE_SITE; break;
    case 'l': hints->li_scope |= LI_SCOPE_LINK; break;
    case 'h': hints->li_scope |= LI_SCOPE_HOST; break;

    case -1:
      goto main;

    default:
      usage(1);
    }
  }

 main:
  if (optind < argc)
    hints->li_canonname = argv[optind++];

  if (optind < argc)
    usage(1);

  su_init();

  if ((error = su_getlocalinfo(hints, &res)) == 0) {
    for (li = res; li; li = li->li_next) {
      if (li->li_flags & LI_NUMERIC) {
        fputs(li->li_canonname, stdout);
      }
      else {
        su_inet_ntop(li->li_family, SU_ADDR(li->li_addr),
		     buffer, sizeof(buffer));
        printf("%s maddr=[%s]", li->li_canonname, buffer);
      }
      if (li->li_scope & LI_SCOPE_GLOBAL)
	fputs(" scope=global", stdout);
      else if (li->li_scope & LI_SCOPE_SITE)
	fputs(" scope=site", stdout);
      else if (li->li_scope & LI_SCOPE_LINK)
	fputs(" scope=link", stdout);
      else if (li->li_scope & LI_SCOPE_HOST)
	fputs(" scope=host", stdout);
      if (ifindex) {
	if (li->li_ifname)
	  printf(" if[%d]=%s", li->li_index, li->li_ifname);
	else
	  printf(" if[%d]", li->li_index);
      }
      puts("");
    }
    su_freelocalinfo(res);
  }
  else {
    fprintf(stderr, "localinfo: %s\n", su_gli_strerror(error));
    error = 1;
  }

  su_deinit();

  return error;
}
Exemplo n.º 10
0
static int test_sockaddr(void)
{
  su_localinfo_t hints[1] = {{ LI_CANONNAME }};
  su_localinfo_t *li, *res = NULL;
  int s;
  su_sockaddr_t  su[1], a[1], b[1];

  BEGIN();

  hints->li_family = AF_INET;

  TEST(su_getlocalinfo(hints, &res), 0);

  for (li = res; li; li = li->li_next) {
    if (li->li_addrlen != res->li_addrlen ||
	memcmp(li->li_addr, res->li_addr, li->li_addrlen) != 0)
      TEST_1(su_cmp_sockaddr(li->li_addr, res->li_addr) != 0);
    else
      TEST_1(su_cmp_sockaddr(li->li_addr, res->li_addr) == 0);
  }

  memset(su, 0, sizeof su);
  TEST(su_getlocalip(su), 0);

  if (res->li_family == AF_INET)
    TEST(su_cmp_sockaddr(res->li_addr, su), 0);

  TEST_1(su_gli_strerror(ELI_NOERROR));
  TEST_1(su_gli_strerror(ELI_NOADDRESS));
  TEST_1(su_gli_strerror(ELI_FAMILY));
  TEST_1(su_gli_strerror(ELI_MEMORY));
  TEST_1(su_gli_strerror(ELI_RESOLVER));
  TEST_1(su_gli_strerror(ELI_SYSTEM));
  TEST_1(su_gli_strerror(-100));

  li = su_copylocalinfo(res); TEST_1(li);
  su_freelocalinfo(li);

  s = su_socket(res->li_family, SOCK_DGRAM, 0); TEST_1(s != -1);
  TEST(su_setblocking(s, 0), 0);
  TEST(su_setblocking(s, 1), 0);
  TEST(su_close(s), 0);

  su_freelocalinfo(res), res = NULL;

#if SU_HAVE_IN6
  hints->li_family = AF_INET6;
  hints->li_flags &= ~LI_CANONNAME;
  hints->li_flags |= LI_V4MAPPED;

  TEST(su_getlocalinfo(hints, &res), 0);
  for (li = res; li; li = li->li_next)
    TEST(li->li_family, AF_INET6);

  su_freelocalinfo(res), res = NULL;
#endif

  hints->li_flags |= LI_NUMERIC;
  TEST(su_getlocalinfo(hints, &res), 0);
  su_freelocalinfo(res), res = NULL;

  res = NULL;
  hints->li_flags |= LI_NAMEREQD;
  su_getlocalinfo(hints, &res);
  su_freelocalinfo(res), res = NULL;

  memset(a, 0, sizeof *a);
  memset(b, 0, sizeof *b);

  TEST_1(su_match_sockaddr(a, b));
  b->su_family = AF_INET;
  TEST_1(su_match_sockaddr(a, b));
  a->su_port = htons(12);
  TEST_1(!su_match_sockaddr(a, b));
  b->su_port = htons(12);
  TEST_1(su_match_sockaddr(a, b));
  a->su_sin.sin_addr.s_addr = htonl(0x7f000001);
  TEST_1(su_match_sockaddr(a, b));
  a->su_family = AF_INET;
  TEST_1(!su_match_sockaddr(a, b));
  b->su_sin.sin_addr.s_addr = htonl(0x7f000001);
  TEST_1(su_match_sockaddr(a, b));
  a->su_sin.sin_addr.s_addr = 0;
  TEST_1(su_match_sockaddr(a, b));
#if SU_HAVE_IN6
  a->su_family = AF_INET6;
  TEST_1(!su_match_sockaddr(a, b));
  b->su_family = AF_INET6;
  TEST_1(su_match_sockaddr(a, b));
  b->su_sin6.sin6_addr.s6_addr[15] = 1;
  TEST_1(su_match_sockaddr(a, b));
  TEST_1(!su_match_sockaddr(b, a));
  a->su_sin6.sin6_addr.s6_addr[15] = 2;
  TEST_1(!su_match_sockaddr(a, b));
  a->su_family = 0;
  TEST_1(su_match_sockaddr(a, b));
  TEST_1(!su_match_sockaddr(b, a));
#endif
  END();
}