2006-12-21 01:30:28 -05:00
|
|
|
/*
|
|
|
|
* This file is part of the Sofia-SIP package
|
|
|
|
*
|
|
|
|
* Copyright (C) 2005 Nokia Corporation.
|
|
|
|
*
|
|
|
|
* Contact: Pekka Pessi <pekka.pessi@nokia.com>
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2.1 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
|
|
* 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**@ingroup su_socket
|
|
|
|
* @CFILE su_localinfo.c
|
|
|
|
*
|
|
|
|
* Obtain list of local addresses.
|
|
|
|
*
|
|
|
|
* @author Pekka Pessi <Pekka.Pessi@nokia.com>
|
2007-08-06 15:24:10 -04:00
|
|
|
* @author Martti Mela <Martti.Mela@nokia.com>
|
2008-12-16 13:05:22 -05:00
|
|
|
*
|
2006-12-21 01:30:28 -05:00
|
|
|
* @date Created: Wed Oct 4 14:09:29 EET 2000 ppessi
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#if HAVE_SYS_SOCKIO_H
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#endif
|
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
#include <sofia-sip/su.h>
|
|
|
|
#include <sofia-sip/su_localinfo.h>
|
2009-02-11 11:45:51 -05:00
|
|
|
#include <sofia-sip/su_string.h>
|
2007-08-06 15:24:10 -04:00
|
|
|
#include "su_module_debug.h"
|
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#if HAVE_SYS_SOCKET_H
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
#if HAVE_NETINET_IN_H
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#endif
|
|
|
|
#if HAVE_SYS_IOCTL_H
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#endif
|
|
|
|
#if HAVE_NET_IF_H
|
|
|
|
#include <net/if.h>
|
|
|
|
#endif
|
|
|
|
#if HAVE_NET_IF_TYPES_H
|
|
|
|
#include <net/if_types.h>
|
|
|
|
#endif
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#if SU_LOCALINFO_TEST
|
|
|
|
|
|
|
|
#undef USE_LOCALINFO0
|
|
|
|
|
|
|
|
#elif HAVE_GETIFADDRS
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
#define USE_LOCALINFO0 1
|
|
|
|
#define localinfo0 bsd_localinfo
|
|
|
|
static int bsd_localinfo(su_localinfo_t const *, su_localinfo_t **);
|
|
|
|
|
|
|
|
#elif HAVE_IPHLPAPI_H
|
|
|
|
|
|
|
|
#include <iphlpapi.h>
|
|
|
|
#define USE_LOCALINFO0 1
|
|
|
|
#define localinfo0 win_localinfo
|
|
|
|
static int win_localinfo(su_localinfo_t const *, su_localinfo_t **);
|
|
|
|
|
|
|
|
#else
|
2009-02-11 11:57:55 -05:00
|
|
|
/* No localinfo0(), use localinfo4() and localinfo6() */
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
#undef USE_LOCALINFO0
|
|
|
|
static int localinfo4(su_localinfo_t const *, su_localinfo_t **);
|
|
|
|
# if SU_HAVE_IN6
|
|
|
|
static int localinfo6(su_localinfo_t const *, su_localinfo_t **);
|
|
|
|
# endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
static int li_scope4(uint32_t ip4);
|
2009-02-26 13:38:34 -05:00
|
|
|
#if SU_HAVE_IN6
|
2009-02-11 11:57:55 -05:00
|
|
|
static int li_scope6(struct in6_addr const *ip6);
|
2009-02-14 18:18:53 -05:00
|
|
|
#endif
|
2009-02-11 11:57:55 -05:00
|
|
|
|
|
|
|
#if !SU_LOCALINFO_TEST
|
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
static int li_name(su_localinfo_t const*, int, su_sockaddr_t const*, char **);
|
|
|
|
static void li_sort(su_localinfo_t *i, su_localinfo_t **rresult);
|
|
|
|
|
|
|
|
/** @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.
|
2008-12-16 13:05:22 -05:00
|
|
|
* - #LI_CANONNAME: return the domain name (DNS PTR) corresponding to the
|
2006-12-21 01:30:28 -05:00
|
|
|
* local address in @a li_canonname.
|
2008-12-16 13:05:22 -05:00
|
|
|
* - #LI_NAMEREQD: Do not return addresses not in DNS.
|
2006-12-21 01:30:28 -05:00
|
|
|
* - #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)
|
2008-12-16 13:05:22 -05:00
|
|
|
* - #LI_SCOPE_LINK: link-local address, valid within link
|
|
|
|
* (IP6 addresses with prefix fe80::/10,
|
2006-12-21 01:30:28 -05:00
|
|
|
* 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,
|
2008-12-16 13:05:22 -05:00
|
|
|
* private IPv4 addresses in nets 10.0.0.0/8, 172.16.0.0/12,
|
2006-12-21 01:30:28 -05:00
|
|
|
* 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.
|
2008-12-16 13:05:22 -05:00
|
|
|
*
|
2006-12-21 01:30:28 -05:00
|
|
|
* @par Diagnostics
|
|
|
|
* Use su_gli_strerror() in order to obtain a string describing the error
|
|
|
|
* code returned by su_getlocalinfo().
|
|
|
|
*
|
|
|
|
*/
|
2008-12-16 13:05:22 -05:00
|
|
|
int su_getlocalinfo(su_localinfo_t const *hints,
|
2006-12-21 01:30:28 -05:00
|
|
|
su_localinfo_t **return_localinfo)
|
|
|
|
{
|
2011-04-23 20:33:19 -04:00
|
|
|
int error = 0, ip4 = 0;
|
|
|
|
int ip6 = 0;
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2009-02-11 11:57:55 -05:00
|
|
|
#if 0
|
|
|
|
/* hints->li_ifname is used to select by interface,
|
|
|
|
li_ifname is returned with LI_IFNAME flag
|
|
|
|
*/
|
2006-12-21 01:30:28 -05:00
|
|
|
if ((hh->li_flags & LI_IFNAME) && hh->li_ifname == NULL)
|
|
|
|
return ELI_BADHINTS;
|
2009-02-11 11:57:55 -05:00
|
|
|
#endif
|
2006-12-21 01:30:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
2011-04-23 20:33:19 -04:00
|
|
|
ip4 = 1;
|
|
|
|
#if SU_HAVE_IN6
|
|
|
|
ip6 = 1;
|
|
|
|
#endif
|
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
#if USE_LOCALINFO0
|
2006-12-21 01:30:28 -05:00
|
|
|
error = localinfo0(hh, rr);
|
|
|
|
#else
|
|
|
|
|
|
|
|
# if SU_HAVE_IN6
|
|
|
|
if (ip6) {
|
|
|
|
error = localinfo6(hh, rr);
|
|
|
|
if (error == ELI_NOADDRESS && ip4)
|
|
|
|
error = 0;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
|
|
|
if (!error)
|
2006-12-21 01:30:28 -05:00
|
|
|
/* Search end of list */
|
|
|
|
for (; *rr; rr = &(*rr)->li_next)
|
|
|
|
;
|
|
|
|
}
|
|
|
|
# endif
|
|
|
|
if (ip4 && !error) {
|
|
|
|
/* Append IPv4 addresses */
|
|
|
|
error = localinfo4(hh, rr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-04-23 20:33:19 -04:00
|
|
|
if (ip6) {
|
|
|
|
/* Required to make compiler happy */
|
|
|
|
}
|
2006-12-21 01:30:28 -05:00
|
|
|
if (!result)
|
|
|
|
error = ELI_NOADDRESS;
|
|
|
|
|
|
|
|
if (!error)
|
|
|
|
li_sort(result, return_localinfo);
|
|
|
|
else
|
|
|
|
su_freelocalinfo(result);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#endif
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
/** Free local address information.
|
2006-12-21 01:30:28 -05:00
|
|
|
*
|
|
|
|
* Free a list of su_localinfo_t structures obtained with su_getlocalinfo()
|
|
|
|
* or su_copylocalinfo() along with socket addresses and strings associated
|
|
|
|
* with them.
|
|
|
|
*
|
|
|
|
* @sa su_getlocalinfo(), su_copylocalinfo(), #su_localinfo_t
|
|
|
|
*/
|
|
|
|
void su_freelocalinfo(su_localinfo_t *tbf)
|
|
|
|
{
|
|
|
|
su_localinfo_t *li;
|
|
|
|
|
|
|
|
for (li = tbf; li; li = tbf) {
|
|
|
|
tbf = li->li_next;
|
|
|
|
if (li->li_canonname)
|
|
|
|
free(li->li_canonname);
|
|
|
|
free(li);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
/** Describe su_localinfo errors.
|
2006-12-21 01:30:28 -05:00
|
|
|
*
|
|
|
|
* The function su_gli_strerror() returns a string describing the error
|
|
|
|
* condition indicated by the code that was returned by the function
|
|
|
|
* su_getlocalinfo().
|
|
|
|
*
|
|
|
|
* @param error error code returned by su_getlocalinfo()
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
* A pointer to string describing the error condition.
|
|
|
|
*/
|
|
|
|
char const *su_gli_strerror(int error)
|
|
|
|
{
|
|
|
|
switch (error) {
|
|
|
|
case ELI_NOERROR: return "No error";
|
|
|
|
case ELI_NOADDRESS: return "No matching address";
|
|
|
|
case ELI_MEMORY: return "Memory allocation error";
|
|
|
|
case ELI_FAMILY: return "Unknown address family";
|
|
|
|
case ELI_RESOLVER: return "Error when resolving address";
|
|
|
|
case ELI_SYSTEM: return "System error";
|
|
|
|
case ELI_BADHINTS: return "Invalid value for hints";
|
|
|
|
default: return "Unknown error";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** 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)
|
2008-12-16 13:05:22 -05:00
|
|
|
li->li_ifname = strcpy(li->li_addrlen + (char *)li->li_addr,
|
2006-12-21 01:30:28 -05:00
|
|
|
li0->li_ifname);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Return IPv4 address scope */
|
2008-12-16 13:05:22 -05:00
|
|
|
static int
|
2006-12-21 01:30:28 -05:00
|
|
|
li_scope4(uint32_t ip4)
|
|
|
|
{
|
|
|
|
ip4 = ntohl(ip4);
|
|
|
|
|
|
|
|
if (0x7f000000 == (ip4 & 0xff000000))
|
|
|
|
return LI_SCOPE_HOST;
|
|
|
|
/* draft-ietf-zeroconf-ipv4-linklocal-02.txt - 169.254/16. */
|
|
|
|
else if (0xa9fe0000 == (ip4 & 0xffff0000))
|
|
|
|
return LI_SCOPE_LINK;
|
|
|
|
/* RFC1918 - 10/8, 172.16/12, 192.168/16. */
|
|
|
|
else if (0x0a000000 == (ip4 & 0xff000000) ||
|
|
|
|
0xac100000 == (ip4 & 0xfff00000) ||
|
|
|
|
0xc0a80000 == (ip4 & 0xffff0000))
|
|
|
|
return LI_SCOPE_SITE;
|
|
|
|
else
|
|
|
|
return LI_SCOPE_GLOBAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if SU_HAVE_IN6
|
|
|
|
|
|
|
|
#if HAVE_WINSOCK2_H
|
|
|
|
#define IN6_IS_ADDR_LOOPBACK SU_IN6_IS_ADDR_LOOPBACK
|
2007-05-08 15:14:10 -04:00
|
|
|
su_inline int
|
2006-12-21 01:30:28 -05:00
|
|
|
IN6_IS_ADDR_LOOPBACK(void const *ip6)
|
|
|
|
{
|
|
|
|
uint8_t const *u = ip6;
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
return
|
|
|
|
u[0] == 0 && u[1] == 0 && u[2] == 0 && u[3] == 0 &&
|
|
|
|
u[4] == 0 && u[5] == 0 && u[6] == 0 && u[7] == 0 &&
|
|
|
|
u[8] == 0 && u[9] == 0 && u[10] == 0 && u[11] == 0 &&
|
2006-12-21 01:30:28 -05:00
|
|
|
u[12] == 0 && u[13] == 0 && u[14] == 0 && u[15] == 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Return IPv6 address scope */
|
2008-12-16 13:05:22 -05:00
|
|
|
static int
|
2006-12-21 01:30:28 -05:00
|
|
|
li_scope6(struct in6_addr const *ip6)
|
|
|
|
{
|
|
|
|
if (IN6_IS_ADDR_V4MAPPED(ip6) || IN6_IS_ADDR_V4COMPAT(ip6)) {
|
|
|
|
uint32_t ip4 = *(uint32_t *)(ip6->s6_addr + 12);
|
|
|
|
return li_scope4(ip4);
|
|
|
|
}
|
|
|
|
else if (IN6_IS_ADDR_LOOPBACK(ip6))
|
|
|
|
return LI_SCOPE_HOST;
|
|
|
|
else if (IN6_IS_ADDR_LINKLOCAL(ip6))
|
|
|
|
return LI_SCOPE_LINK;
|
|
|
|
else if (IN6_IS_ADDR_SITELOCAL(ip6))
|
|
|
|
return LI_SCOPE_SITE;
|
|
|
|
else
|
|
|
|
return LI_SCOPE_GLOBAL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** Return the scope of address in the sockaddr structure */
|
|
|
|
int su_sockaddr_scope(su_sockaddr_t const *su, socklen_t sulen)
|
|
|
|
{
|
|
|
|
if (sulen >= (sizeof su->su_sin) && su->su_family == AF_INET)
|
|
|
|
return li_scope4(su->su_sin.sin_addr.s_addr);
|
|
|
|
|
|
|
|
#if SU_HAVE_IN6
|
|
|
|
if (sulen >= (sizeof su->su_sin6) && su->su_family == AF_INET6)
|
|
|
|
return li_scope6(&su->su_sin6.sin6_addr);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
#if HAVE_OPEN_C
|
|
|
|
extern int su_get_local_ip_addr(su_sockaddr_t *su);
|
|
|
|
#endif
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#if SU_LOCALINFO_TEST
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#elif USE_LOCALINFO0
|
|
|
|
/* no localinfo4 */
|
2006-12-21 01:30:28 -05:00
|
|
|
#elif HAVE_IFCONF
|
2007-08-06 15:24:10 -04:00
|
|
|
#if __APPLE_CC__
|
2006-12-21 01:30:28 -05:00
|
|
|
/** Build a list of local IPv4 addresses and append it to *rresult. */
|
|
|
|
static
|
|
|
|
int localinfo4(su_localinfo_t const *hints, su_localinfo_t **rresult)
|
|
|
|
{
|
2009-02-11 11:57:55 -05:00
|
|
|
su_localinfo_t *li = NULL;
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
su_sockaddr_t *sa;
|
|
|
|
socklen_t salen = sizeof(*sa);
|
|
|
|
int scope = 0, gni_flags = 0;
|
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
s = su_socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (s == -1) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
su_strerror(su_errno())));
|
|
|
|
return ELI_SYSTEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
li = calloc(1, (sizeof *li) + (sizeof *sa));
|
|
|
|
sa = (void *)(li + 1);
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
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())));
|
|
|
|
}
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
error = bind(s, (struct sockaddr *) sa, salen);
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
if (error < 0) {
|
|
|
|
SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
|
|
|
|
su_strerror(su_errno())));
|
|
|
|
goto err;
|
|
|
|
}
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
su_close(s);
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
scope = li_scope4(sa->su_sin.sin_addr.s_addr);
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
|
|
|
|
gni_flags = NI_NUMERICHOST;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
if (su_xtra) {
|
|
|
|
/* Map IPv4 address to IPv6 address */
|
|
|
|
memset(sa, 0, sizeof(*sa));
|
|
|
|
sa->su_family = AF_INET6;
|
|
|
|
((int32_t*)&sa->su_sin6.sin6_addr)[3] = sa->su_sin.sin_addr.s_addr;
|
2006-12-21 01:30:28 -05:00
|
|
|
((int32_t*)&sa->su_sin6.sin6_addr)[2] = htonl(0xffff);
|
2007-08-06 15:24:10 -04:00
|
|
|
}
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
li->li_family = sa->su_family;
|
|
|
|
li->li_scope = scope;
|
|
|
|
li->li_index = 0;
|
|
|
|
li->li_addrlen = su_sockaddr_size(sa);
|
|
|
|
li->li_addr = sa;
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
if ((error = li_name(hints, gni_flags, sa, &canonname)) < 0)
|
|
|
|
goto err;
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
if (canonname) {
|
|
|
|
if (strchr(canonname, ':') ||
|
|
|
|
strspn(canonname, "0123456789.") == strlen(canonname))
|
|
|
|
li->li_flags |= LI_NUMERIC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
li->li_flags = 0;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
li->li_canonname = canonname;
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
canonname = NULL;
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
*rresult = li;
|
|
|
|
return 0;
|
2006-12-21 01:30:28 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
err:
|
|
|
|
if (canonname) free(canonname);
|
2009-02-11 11:57:55 -05:00
|
|
|
if (li) free(li);
|
2007-08-06 15:24:10 -04:00
|
|
|
su_close(s);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
#else /* !__APPLE_CC__ */
|
|
|
|
/** 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);
|
2006-12-21 01:30:28 -05:00
|
|
|
#endif
|
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
s = su_socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (s == -1) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
|
2007-08-06 15:24:10 -04:00
|
|
|
su_strerror(su_errno())));
|
|
|
|
return ELI_SYSTEM;
|
|
|
|
}
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
# 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 */
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: SIOCGIFNUM failed: %s\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
su_strerror(su_errno())));
|
|
|
|
error = ELI_SYSTEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_9(("su_localinfo: %d active interfaces according to SIOCGIFNUM\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2007-08-06 15:24:10 -04:00
|
|
|
#if HAVE_OPEN_C
|
|
|
|
if (ioctl(s, SIOCGIFACTIVECONF, (char *)&ifc) < 0) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n",
|
2007-08-06 15:24:10 -04:00
|
|
|
su_strerror(su_errno())));
|
|
|
|
error = ELI_SYSTEM;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
#else
|
2006-12-21 01:30:28 -05:00
|
|
|
if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: SIOCGIFCONF failed: %s\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
su_strerror(su_errno())));
|
|
|
|
error = ELI_SYSTEM;
|
|
|
|
goto err;
|
|
|
|
}
|
2007-08-06 15:24:10 -04:00
|
|
|
#endif
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
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;
|
2009-02-26 13:38:34 -05:00
|
|
|
#if SU_HAVE_IN6
|
|
|
|
su_sockaddr_t su2[1];
|
|
|
|
#endif
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
#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) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: SIOCGIFINDEX failed: %s\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
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));
|
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
|
|
|
|
#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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2007-08-06 15:24:10 -04:00
|
|
|
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
|
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
#if defined(SIOCGIFFLAGS)
|
|
|
|
ifreq[0] = *ifr;
|
|
|
|
if (ioctl(s, SIOCGIFFLAGS, ifreq) < 0) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: SIOCGIFFLAGS failed: %s\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
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) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_9(("su_localinfo: if %s with index %d is down\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
if_name, if_index));
|
|
|
|
continue;
|
|
|
|
}
|
2007-05-08 15:14:10 -04:00
|
|
|
#elif defined(SIOCGIFACTIVECONF)
|
|
|
|
/* Handled above in SIOCGIFACTIVECONF vs. SIOCGIFCONF*/
|
2006-12-21 01:30:28 -05:00
|
|
|
#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) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: SIOCGIFADDR failed: %s\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2009-02-11 11:57:55 -05:00
|
|
|
li->li_ifname = if_name;
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2007-08-06 15:24:10 -04:00
|
|
|
#endif /* __APPLE_CC__ */
|
2006-12-21 01:30:28 -05:00
|
|
|
#else
|
|
|
|
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
|
2008-12-16 13:05:22 -05:00
|
|
|
socklen_t su_sockaddr_size =
|
2006-12-21 01:30:28 -05:00
|
|
|
(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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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);
|
2008-12-16 13:05:22 -05:00
|
|
|
su->su_family = li->li_family =
|
2006-12-21 01:30:28 -05:00
|
|
|
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);
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
else
|
2006-12-21 01:30:28 -05:00
|
|
|
#endif
|
|
|
|
memcpy(&su->su_sin.sin_addr.s_addr, h->h_addr_list[i], h->h_length);
|
2008-12-16 13:05:22 -05:00
|
|
|
if (li->li_flags & LI_IFNAME)
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
li->li_flags = hints->li_flags &
|
2006-12-21 01:30:28 -05:00
|
|
|
(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);
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
else
|
2006-12-21 01:30:28 -05:00
|
|
|
#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) {
|
2008-12-16 13:05:22 -05:00
|
|
|
free(li); li = NULL;
|
2006-12-21 01:30:28 -05:00
|
|
|
} else {
|
|
|
|
*lli = li; lli = &li->li_next; li = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*rresult = tbf;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (li) su_freelocalinfo(li);
|
|
|
|
su_freelocalinfo(tbf);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#if USE_LOCALINFO0 || !SU_HAVE_IN6 || SU_LOCALINFO_TEST
|
|
|
|
/* No localinfo6() */
|
2008-12-16 13:05:22 -05:00
|
|
|
#elif HAVE_PROC_NET_IF_INET6
|
2006-12-21 01:30:28 -05:00
|
|
|
/** Build a list of local IPv6 addresses and append it to *return_result. */
|
|
|
|
static
|
|
|
|
int localinfo6(su_localinfo_t const *hints, su_localinfo_t **return_result)
|
|
|
|
{
|
|
|
|
su_localinfo_t *li = NULL;
|
|
|
|
su_sockaddr_t su[1] = {{ 0 }}, *addr;
|
|
|
|
int error = ELI_NOADDRESS;
|
|
|
|
char *canonname = NULL;
|
|
|
|
char line[80];
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
if ((f = fopen("/proc/net/if_inet6", "r"))) {
|
|
|
|
for (;error;) {
|
|
|
|
struct in6_addr in6;
|
|
|
|
unsigned if_index, prefix_len, scope, flags;
|
|
|
|
int addrlen, if_namelen;
|
|
|
|
char ifname[16];
|
|
|
|
|
|
|
|
if (!fgets(line, sizeof(line), f)) {
|
|
|
|
if (feof(f))
|
|
|
|
error = ELI_NOERROR;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sscanf(line, "%08x%08x%08x%08x %2x %2x %2x %02x %016s\n",
|
|
|
|
&in6.s6_addr32[0],
|
|
|
|
&in6.s6_addr32[1],
|
|
|
|
&in6.s6_addr32[2],
|
2008-12-16 13:05:22 -05:00
|
|
|
&in6.s6_addr32[3],
|
2006-12-21 01:30:28 -05:00
|
|
|
&if_index, &prefix_len, &scope, &flags, ifname) != 9)
|
|
|
|
break;
|
|
|
|
|
|
|
|
flags = 0;
|
|
|
|
|
|
|
|
/* Fix global scope (it is 0) */
|
|
|
|
if (!scope) scope = LI_SCOPE_GLOBAL;
|
|
|
|
|
|
|
|
in6.s6_addr32[0] = htonl(in6.s6_addr32[0]);
|
|
|
|
in6.s6_addr32[1] = htonl(in6.s6_addr32[1]);
|
|
|
|
in6.s6_addr32[2] = htonl(in6.s6_addr32[2]);
|
|
|
|
in6.s6_addr32[3] = htonl(in6.s6_addr32[3]);
|
|
|
|
|
|
|
|
if (IN6_IS_ADDR_V4MAPPED(&in6) || IN6_IS_ADDR_V4COMPAT(&in6)) {
|
|
|
|
uint32_t ip4 = *(uint32_t *)(in6.s6_addr + 12);
|
|
|
|
scope = li_scope4(ip4);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((hints->li_scope && (hints->li_scope & scope) == 0) ||
|
|
|
|
(hints->li_index && hints->li_index != if_index) ||
|
|
|
|
(hints->li_ifname && strcmp(hints->li_ifname, ifname) != 0))
|
|
|
|
continue;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
su->su_family = AF_INET6;
|
2008-12-16 13:05:22 -05:00
|
|
|
su->su_sin6.sin6_addr = in6;
|
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
addrlen = su_sockaddr_size(su);
|
|
|
|
|
|
|
|
if ((error = li_name(hints, 0, su, &canonname)) < 0)
|
|
|
|
break;
|
|
|
|
else if (error > 0)
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
error = ELI_NOADDRESS;
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
if (canonname &&
|
2006-12-21 01:30:28 -05:00
|
|
|
(strchr(canonname, ':') ||
|
|
|
|
strspn(canonname, "0123456789.") == strlen(canonname)))
|
|
|
|
flags |= LI_NUMERIC;
|
|
|
|
|
|
|
|
if (hints->li_flags & LI_IFNAME)
|
|
|
|
if_namelen = strlen(ifname) + 1;
|
|
|
|
else
|
|
|
|
if_namelen = 0;
|
|
|
|
|
|
|
|
if ((li = calloc(1, sizeof *li + addrlen + if_namelen)) == NULL) {
|
|
|
|
error = ELI_MEMORY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
addr = (su_sockaddr_t*)memcpy((li + 1), su, addrlen);
|
|
|
|
*return_result = li; return_result = &li->li_next;
|
|
|
|
|
|
|
|
li->li_flags = flags;
|
|
|
|
li->li_family = AF_INET6;
|
|
|
|
li->li_scope = scope;
|
|
|
|
li->li_index = if_index;
|
|
|
|
li->li_addr = addr;
|
|
|
|
li->li_addrlen = addrlen;
|
|
|
|
li->li_canonname = canonname;
|
|
|
|
if (if_namelen)
|
|
|
|
li->li_ifname = memcpy(addrlen + (char *)addr, ifname, if_namelen);
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
canonname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
if (canonname)
|
2006-12-21 01:30:28 -05:00
|
|
|
free(canonname);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/* 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);
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-07-08 00:36:13 -04:00
|
|
|
if (su_inet_pton(AF_INET6, addr, &sa->su_sin6.sin6_addr) <= 0)
|
2006-12-21 01:30:28 -05:00
|
|
|
goto err;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
s = su_socket(AF_INET6, SOCK_DGRAM, 0);
|
|
|
|
if (s == -1) {
|
2008-12-16 13:05:22 -05:00
|
|
|
SU_DEBUG_1(("su_localinfo: su_socket failed: %s\n",
|
2006-12-21 01:30:28 -05:00
|
|
|
su_strerror(su_errno())));
|
|
|
|
return ELI_SYSTEM;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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())));
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
error = bind(s, (struct sockaddr *) sa, salen);
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
if (error < 0) {
|
|
|
|
SU_DEBUG_1(("%s: bind() failed: %s\n", __func__,
|
|
|
|
su_strerror(su_errno())));
|
|
|
|
goto err;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
su_close(s);
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
if ((error = li_name(hints, NI_NUMERICHOST, sa, &li->li_canonname)) < 0)
|
|
|
|
goto err;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-07-08 00:36:13 -04:00
|
|
|
if (su_inet_pton(AF_INET6, addr, &su->su_sin6.sin6_addr) <= 0)
|
2006-12-21 01:30:28 -05:00
|
|
|
goto err;
|
2008-12-16 13:05:22 -05:00
|
|
|
if (li->li_flags & LI_IFNAME)
|
2006-12-21 01:30:28 -05:00
|
|
|
li->li_ifname = ifname;
|
|
|
|
if ((error = li_name(hints, NI_NUMERICHOST, su, &li->li_canonname)) < 0)
|
|
|
|
goto err;
|
|
|
|
else if (error > 0) {
|
2008-12-16 13:05:22 -05:00
|
|
|
free(li); li = NULL;
|
2006-12-21 01:30:28 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*rresult = li;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (li) su_freelocalinfo(li);
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#if !USE_LOCALINFO0
|
|
|
|
/* no localinfo0() or bsd_localinfo() */
|
|
|
|
#elif HAVE_GETIFADDRS
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
#include <ifaddrs.h>
|
|
|
|
|
|
|
|
static
|
2008-12-16 13:05:22 -05:00
|
|
|
int bsd_localinfo(su_localinfo_t const hints[1],
|
2006-12-21 01:30:28 -05:00
|
|
|
su_localinfo_t **return_result)
|
|
|
|
{
|
|
|
|
struct ifaddrs *ifa, *results;
|
|
|
|
int error = 0;
|
2007-04-14 22:03:41 -04:00
|
|
|
#if SU_HAVE_IN6
|
2006-12-21 01:30:28 -05:00
|
|
|
int v4_mapped = (hints->li_flags & LI_V4MAPPED) != 0;
|
2007-04-14 22:03:41 -04:00
|
|
|
#endif
|
2006-12-21 01:30:28 -05:00
|
|
|
char *canonname = NULL;
|
|
|
|
|
|
|
|
if (getifaddrs(&results) < 0) {
|
|
|
|
if (errno == ENOMEM)
|
|
|
|
return ELI_MEMORY;
|
|
|
|
else
|
|
|
|
return ELI_SYSTEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ifa = results; ifa; ifa = ifa->ifa_next) {
|
|
|
|
su_localinfo_t *li;
|
2007-04-14 22:03:41 -04:00
|
|
|
su_sockaddr_t *su;
|
|
|
|
#if SU_HAVE_IN6
|
|
|
|
su_sockaddr_t su2[1];
|
|
|
|
#endif
|
2006-12-21 01:30:28 -05:00
|
|
|
socklen_t sulen;
|
|
|
|
int scope, flags = 0, gni_flags = 0, if_index = 0;
|
|
|
|
char const *ifname = 0;
|
|
|
|
size_t ifnamelen = 0;
|
|
|
|
|
|
|
|
/* no ip address from if that is down */
|
|
|
|
if ((ifa->ifa_flags & IFF_UP) == 0 && (hints->li_flags & LI_DOWN) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
su = (su_sockaddr_t *)ifa->ifa_addr;
|
|
|
|
|
|
|
|
if (!su)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (su->su_family == AF_INET) {
|
|
|
|
sulen = sizeof(su->su_sin);
|
|
|
|
scope = li_scope4(su->su_sin.sin_addr.s_addr);
|
2007-04-14 22:03:41 -04:00
|
|
|
#if SU_HAVE_IN6
|
2006-12-21 01:30:28 -05:00
|
|
|
if (v4_mapped)
|
|
|
|
sulen = sizeof(su->su_sin6);
|
2007-04-14 22:03:41 -04:00
|
|
|
#endif
|
2006-12-21 01:30:28 -05:00
|
|
|
}
|
2007-04-14 22:03:41 -04:00
|
|
|
#if SU_HAVE_IN6
|
2006-12-21 01:30:28 -05:00
|
|
|
else if (su->su_family == AF_INET6) {
|
|
|
|
if (IN6_IS_ADDR_MULTICAST(&su->su_sin6.sin6_addr))
|
|
|
|
continue;
|
|
|
|
sulen = sizeof(su->su_sin6);
|
|
|
|
scope = li_scope6(&su->su_sin6.sin6_addr);
|
|
|
|
}
|
2007-04-14 22:03:41 -04:00
|
|
|
#endif
|
2008-12-16 13:05:22 -05:00
|
|
|
else
|
2006-12-21 01:30:28 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (hints->li_flags & LI_IFNAME) {
|
|
|
|
ifname = ifa->ifa_name;
|
|
|
|
if (ifname)
|
|
|
|
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 && (!ifname || strcmp(hints->li_ifname, ifname))) ||
|
|
|
|
(hints->li_index && hints->li_index != if_index))
|
|
|
|
continue;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
if (scope == LI_SCOPE_HOST || scope == LI_SCOPE_LINK)
|
|
|
|
gni_flags = NI_NUMERICHOST;
|
|
|
|
|
2007-04-14 22:03:41 -04:00
|
|
|
#if SU_HAVE_IN6
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
|
|
|
}
|
2007-04-14 22:03:41 -04:00
|
|
|
#endif
|
2006-12-21 01:30:28 -05:00
|
|
|
|
|
|
|
if ((error = li_name(hints, gni_flags, su, &canonname)) < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (error > 0) {
|
|
|
|
error = 0;
|
|
|
|
continue;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
if (canonname)
|
|
|
|
if (strchr(canonname, ':') ||
|
|
|
|
canonname[strspn(canonname, "0123456789.")] == '\0')
|
|
|
|
flags |= LI_NUMERIC;
|
|
|
|
|
|
|
|
if (!(li = calloc(1, sizeof(*li) + sulen + ifnamelen))) {
|
|
|
|
SU_DEBUG_1(("su_getlocalinfo: memory exhausted\n"));
|
|
|
|
error = ELI_MEMORY;
|
|
|
|
break;
|
2008-12-16 13:05:22 -05:00
|
|
|
}
|
2006-12-21 01:30:28 -05:00
|
|
|
*return_result = li, return_result = &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);
|
|
|
|
}
|
|
|
|
|
|
|
|
canonname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (canonname)
|
|
|
|
free(canonname);
|
|
|
|
|
|
|
|
freeifaddrs(results);
|
|
|
|
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif USE_LOCALINFO0 && HAVE_IPHLPAPI_H && SU_HAVE_IN6
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
static
|
2006-12-21 01:30:28 -05:00
|
|
|
char const *ws2ifname(DWORD iftype)
|
|
|
|
{
|
|
|
|
switch (iftype) {
|
|
|
|
case IF_TYPE_ETHERNET_CSMACD: return "eth";
|
|
|
|
case IF_TYPE_IEEE80212: return "eth";
|
|
|
|
case IF_TYPE_FASTETHER: return "eth";
|
|
|
|
case IF_TYPE_GIGABITETHERNET: return "eth";
|
|
|
|
case IF_TYPE_ISO88025_TOKENRING: return "token";
|
|
|
|
case IF_TYPE_FDDI: return "fddi";
|
|
|
|
case IF_TYPE_PPP: return "ppp";
|
|
|
|
case IF_TYPE_SOFTWARE_LOOPBACK: return "lo";
|
|
|
|
case IF_TYPE_SLIP: return "sl";
|
|
|
|
case IF_TYPE_FRAMERELAY: return "fr";
|
|
|
|
case IF_TYPE_ATM: return "atm";
|
|
|
|
case IF_TYPE_HIPPI: return "hippi";
|
|
|
|
case IF_TYPE_ISDN: return "isdn";
|
|
|
|
case IF_TYPE_IEEE80211: return "wlan";
|
|
|
|
case IF_TYPE_ADSL: return "adsl";
|
|
|
|
case IF_TYPE_RADSL: return "radsl";
|
|
|
|
case IF_TYPE_SDSL: return "sdsl";
|
|
|
|
case IF_TYPE_VDSL: return "vdsl";
|
|
|
|
case IF_TYPE_TUNNEL: return "tunnel";
|
|
|
|
case IF_TYPE_IEEE1394: return "fw";
|
|
|
|
case IF_TYPE_OTHER:
|
|
|
|
default: return "other";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
int win_localinfo(su_localinfo_t const hints[1], su_localinfo_t **rresult)
|
|
|
|
{
|
|
|
|
/* This is Windows XP code, for both IPv6 and IPv4. */
|
2007-04-14 22:03:41 -04:00
|
|
|
ULONG iaa_size = 2048;
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
|
|
|
|
2007-04-14 22:03:41 -04:00
|
|
|
iaa0 = malloc((size_t)iaa_size);
|
2006-12-21 01:30:28 -05:00
|
|
|
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) {
|
2007-04-14 22:03:41 -04:00
|
|
|
char const *empty = "";
|
|
|
|
LPTSTR msg = empty;
|
|
|
|
|
|
|
|
if (error == ERROR_NO_DATA) {
|
|
|
|
error = ELI_NOADDRESS;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
2007-04-14 22:03:41 -04:00
|
|
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL,
|
|
|
|
error,
|
|
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
msg, 0, NULL))
|
|
|
|
msg = empty;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2007-04-14 22:03:41 -04:00
|
|
|
SU_DEBUG_1(("su_localinfo: GetAdaptersAddresses: %s (%d)\n", msg, error));
|
|
|
|
if (msg != empty) LocalFree((LPVOID)msg);
|
2006-12-21 01:30:28 -05:00
|
|
|
error = ELI_SYSTEM;
|
|
|
|
goto err;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
for (iaa = iaa0; iaa; iaa = iaa->Next) {
|
|
|
|
IP_ADAPTER_UNICAST_ADDRESS *ua;
|
|
|
|
IP_ADAPTER_UNICAST_ADDRESS lua[1];
|
|
|
|
int if_index = iaa->IfIndex;
|
2007-04-14 22:03:41 -04:00
|
|
|
size_t ifnamelen = 0;
|
2006-12-21 01:30:28 -05:00
|
|
|
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);
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
else
|
2006-12-21 01:30:28 -05:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (hints->li_flags & LI_IFNAME) {
|
2008-12-16 13:05:22 -05:00
|
|
|
snprintf(ifname, sizeof(ifname), "%s%u",
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
}
|
2006-12-21 01:30:28 -05:00
|
|
|
*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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif HAVE_SIO_ADDRESS_LIST_QUERY
|
2009-02-11 11:57:55 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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
|
2008-12-16 13:05:22 -05:00
|
|
|
INTERFACE_INFO_EX ii[1];
|
2006-12-21 01:30:28 -05:00
|
|
|
#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;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
if (canonname)
|
|
|
|
if (strchr(canonname, ':') ||
|
|
|
|
strspn(canonname, "0123456789.") == strlen(canonname))
|
|
|
|
flags |= LI_NUMERIC;
|
2008-12-16 13:05:22 -05:00
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
2008-12-16 13:05:22 -05:00
|
|
|
li->li_addr = (su_sockaddr_t *)(li + 1);
|
2006-12-21 01:30:28 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#if !SU_LOCALINFO_TEST
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
static
|
|
|
|
int li_name(su_localinfo_t const *hints,
|
2006-12-21 01:30:28 -05:00
|
|
|
int gni_flags,
|
2008-12-16 13:05:22 -05:00
|
|
|
su_sockaddr_t const *su,
|
2006-12-21 01:30:28 -05:00
|
|
|
char **ccanonname)
|
|
|
|
{
|
|
|
|
char name[SU_MAXHOST];
|
|
|
|
int error;
|
|
|
|
int flags = hints->li_flags;
|
|
|
|
|
|
|
|
*ccanonname = NULL;
|
|
|
|
|
|
|
|
if ((flags & LI_CANONNAME) || hints->li_canonname) {
|
|
|
|
if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
|
2008-12-16 13:05:22 -05:00
|
|
|
gni_flags |= NI_NAMEREQD;
|
2006-12-21 01:30:28 -05:00
|
|
|
if (flags & LI_NUMERIC)
|
|
|
|
gni_flags |= NI_NUMERICHOST;
|
|
|
|
|
2008-12-16 13:05:22 -05:00
|
|
|
error = su_getnameinfo(su, su_sockaddr_size(su),
|
2006-12-21 01:30:28 -05:00
|
|
|
name, sizeof(name), NULL, 0,
|
|
|
|
gni_flags);
|
|
|
|
if (error) {
|
|
|
|
if ((flags & LI_NAMEREQD) == LI_NAMEREQD)
|
|
|
|
return 1;
|
|
|
|
SU_DEBUG_7(("li_name: getnameinfo() failed\n"));
|
2007-12-11 05:45:05 -05:00
|
|
|
if (!su_inet_ntop(su->su_family, SU_ADDR(su), name, sizeof name))
|
2006-12-21 01:30:28 -05:00
|
|
|
return ELI_RESOLVER;
|
|
|
|
}
|
|
|
|
|
2009-02-11 11:45:51 -05:00
|
|
|
if (hints->li_canonname && !su_casematch(name, hints->li_canonname))
|
2006-12-21 01:30:28 -05:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (!(flags & LI_CANONNAME))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(*ccanonname = strdup(name)))
|
|
|
|
return ELI_MEMORY;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
void li_sort(su_localinfo_t *i, su_localinfo_t **rresult)
|
|
|
|
{
|
|
|
|
su_localinfo_t *li, **lli;
|
|
|
|
|
|
|
|
#define LI_MAPPED(li) \
|
|
|
|
((li)->li_family == AF_INET6 && \
|
|
|
|
(IN6_IS_ADDR_V4MAPPED(&(li)->li_addr->su_sin6.sin6_addr) || \
|
|
|
|
IN6_IS_ADDR_V4COMPAT(&(li)->li_addr->su_sin6.sin6_addr)))
|
|
|
|
|
|
|
|
/* Sort addresses according to scope (and mappedness) */
|
|
|
|
for (li = i; li; li = i) {
|
|
|
|
i = li->li_next;
|
|
|
|
for (lli = rresult; *lli; lli = &(*lli)->li_next) {
|
|
|
|
if ((*lli)->li_scope < li->li_scope)
|
|
|
|
break;
|
|
|
|
#if SU_HAVE_IN6
|
|
|
|
if (LI_MAPPED(*lli) > LI_MAPPED(li))
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
li->li_next = *lli;
|
|
|
|
*lli = li;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-11 11:57:55 -05:00
|
|
|
#endif
|
|
|
|
|
2006-12-21 01:30:28 -05:00
|
|
|
/**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;
|
|
|
|
}
|
2008-12-16 13:05:22 -05:00
|
|
|
else
|
2006-12-21 01:30:28 -05:00
|
|
|
return -1;
|
|
|
|
}
|