mirror of
https://github.com/cuberite/libevent.git
synced 2025-09-10 04:50:37 -04:00
Merge branch '21_ifaddr'
This commit is contained in:
commit
56c6afe26a
@ -178,7 +178,7 @@ LIBEVENT_OPENSSL
|
|||||||
|
|
||||||
dnl Checks for header files.
|
dnl Checks for header files.
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_CHECK_HEADERS([fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in.h netinet/in6.h sys/socket.h sys/uio.h arpa/inet.h sys/eventfd.h sys/mman.h sys/sendfile.h sys/wait.h netdb.h])
|
AC_CHECK_HEADERS([fcntl.h stdarg.h inttypes.h stdint.h stddef.h poll.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in.h netinet/in6.h sys/socket.h sys/uio.h arpa/inet.h sys/eventfd.h sys/mman.h sys/sendfile.h sys/wait.h netdb.h ifaddrs.h])
|
||||||
AC_CHECK_HEADERS(sys/sysctl.h, [], [], [
|
AC_CHECK_HEADERS(sys/sysctl.h, [], [], [
|
||||||
#ifdef HAVE_SYS_PARAM_H
|
#ifdef HAVE_SYS_PARAM_H
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
@ -277,7 +277,7 @@ AC_HEADER_TIME
|
|||||||
|
|
||||||
dnl Checks for library functions.
|
dnl Checks for library functions.
|
||||||
AC_CHECK_FUNCS([gettimeofday vasprintf fcntl clock_gettime strtok_r strsep])
|
AC_CHECK_FUNCS([gettimeofday vasprintf fcntl clock_gettime strtok_r strsep])
|
||||||
AC_CHECK_FUNCS([getnameinfo strlcpy inet_ntop inet_pton signal sigaction strtoll inet_aton pipe eventfd sendfile mmap splice arc4random arc4random_buf issetugid geteuid getegid getprotobynumber setenv unsetenv putenv])
|
AC_CHECK_FUNCS([getnameinfo strlcpy inet_ntop inet_pton signal sigaction strtoll inet_aton pipe eventfd sendfile mmap splice arc4random arc4random_buf issetugid geteuid getegid getprotobynumber setenv unsetenv putenv getifaddrs])
|
||||||
|
|
||||||
AC_CACHE_CHECK(
|
AC_CACHE_CHECK(
|
||||||
[for getaddrinfo],
|
[for getaddrinfo],
|
||||||
|
176
evutil.c
176
evutil.c
@ -35,6 +35,10 @@
|
|||||||
#undef WIN32_LEAN_AND_MEAN
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
#undef _WIN32_WINNT
|
||||||
|
/* For structs needed by GetAdaptersAddresses */
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#include <iphlpapi.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
@ -69,6 +73,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#ifdef _EVENT_HAVE_IFADDRS_H
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "event2/util.h"
|
#include "event2/util.h"
|
||||||
#include "util-internal.h"
|
#include "util-internal.h"
|
||||||
@ -534,28 +541,149 @@ static int have_checked_interfaces, had_ipv4_address, had_ipv6_address;
|
|||||||
*/
|
*/
|
||||||
#define EVUTIL_V4ADDR_IS_CLASSD(addr) ((((addr)>>24) & 0xf0) == 0xe0)
|
#define EVUTIL_V4ADDR_IS_CLASSD(addr) ((((addr)>>24) & 0xf0) == 0xe0)
|
||||||
|
|
||||||
|
static void
|
||||||
|
evutil_found_ifaddr(const struct sockaddr *sa)
|
||||||
|
{
|
||||||
|
const char ZEROES[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||||
|
"\x00\x00\x00\x00\x00\x00\x00\x00";
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
printf("Sockaddr is %s\n", evutil_format_sockaddr_port(sa, buf, sizeof(buf)));
|
||||||
|
|
||||||
|
if (sa->sa_family == AF_INET) {
|
||||||
|
const struct sockaddr_in *sin = (struct sockaddr_in *)sa;
|
||||||
|
ev_uint32_t addr = ntohl(sin->sin_addr.s_addr);
|
||||||
|
if (addr == 0 ||
|
||||||
|
EVUTIL_V4ADDR_IS_LOCALHOST(addr) ||
|
||||||
|
EVUTIL_V4ADDR_IS_CLASSD(addr)) {
|
||||||
|
/* Not actually a usable external address. */
|
||||||
|
} else {
|
||||||
|
event_debug(("Detected an IPv4 interface"));
|
||||||
|
had_ipv4_address = 1;
|
||||||
|
}
|
||||||
|
} else if (sa->sa_family == AF_INET6) {
|
||||||
|
const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
|
||||||
|
const unsigned char *addr =
|
||||||
|
(unsigned char*)sin6->sin6_addr.s6_addr;
|
||||||
|
if (!memcmp(addr, ZEROES, 8) ||
|
||||||
|
((addr[0] & 0xfe) == 0xfc) ||
|
||||||
|
(addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
|
||||||
|
(addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
|
||||||
|
(addr[0] == 0xff)) {
|
||||||
|
/* This is a reserved, ipv4compat, ipv4map, loopback,
|
||||||
|
* link-local, multicast, or unspecified address. */
|
||||||
|
} else {
|
||||||
|
event_debug(("Detected an IPv6 interface"));
|
||||||
|
had_ipv6_address = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
evutil_check_ifaddrs(void)
|
||||||
|
{
|
||||||
|
#if defined(_EVENT_HAVE_GETIFADDRS)
|
||||||
|
/* Most free Unixy systems provide getifaddrs, which gives us a linked list
|
||||||
|
* of struct ifaddrs. */
|
||||||
|
struct ifaddrs *ifa = NULL;
|
||||||
|
const struct ifaddrs *i;
|
||||||
|
if (getifaddrs(&ifa) < 0) {
|
||||||
|
event_warn("Unable to call getifaddrs()");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = ifa; i; i = i->ifa_next) {
|
||||||
|
if (!i->ifa_addr)
|
||||||
|
continue;
|
||||||
|
evutil_found_ifaddr(i->ifa_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifa);
|
||||||
|
return 0;
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
/* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a
|
||||||
|
"GetAdaptersInfo", but that's deprecated; let's just try
|
||||||
|
GetAdaptersAddresses and fall back to connect+getsockname.
|
||||||
|
*/
|
||||||
|
HANDLE lib = evutil_load_windows_system_library(TEXT("ihplapi.dll"));
|
||||||
|
GetAdaptersAddresses_fn_t fn;
|
||||||
|
ULONG size, res;
|
||||||
|
IP_ADAPTER_ADDRESSES *addresses = NULL, *address;
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
#define FLAGS (GAA_FLAG_SKIP_ANYCAST | \
|
||||||
|
GAA_FLAG_SKIP_MULTICAST | \
|
||||||
|
GAA_FLAG_SKIP_DNS_SERVER)
|
||||||
|
|
||||||
|
if (!lib)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (!(fn = (GetAdaptersAddresses_fn_t) GetProcAddress(lib, "GetAdaptersAddresses")))
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* Guess how much space we need. */
|
||||||
|
size = 15*1024;
|
||||||
|
addresses = mm_malloc(size);
|
||||||
|
if (!addresses)
|
||||||
|
goto done;
|
||||||
|
res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
|
||||||
|
if (res == ERROR_BUFFER_OVERFLOW) {
|
||||||
|
/* we didn't guess that we needed enough space; try again */
|
||||||
|
mm_free(addresses);
|
||||||
|
addresses = tor_malloc(size);
|
||||||
|
if (!addresses)
|
||||||
|
goto done;
|
||||||
|
res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size);
|
||||||
|
}
|
||||||
|
if (res != NO_ERROR)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
result = smartlist_create();
|
||||||
|
for (address = addresses; address; address = address->Next) {
|
||||||
|
IP_ADAPTER_UNICAST_ADDRESS *a;
|
||||||
|
for (a = address->FirstUnicastAddress; a; a = a->Next) {
|
||||||
|
/* Yes, it's a linked list inside a linked list */
|
||||||
|
struct sockaddr *sa = a->Address.lpSockaddr;
|
||||||
|
evutil_found_ifaddr(sa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 0;
|
||||||
|
done:
|
||||||
|
if (lib)
|
||||||
|
FreeLibrary(lib);
|
||||||
|
if (addresses)
|
||||||
|
mm_free(addresses);
|
||||||
|
return result;
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Test whether we have an ipv4 interface and an ipv6 interface. Return 0 if
|
/* Test whether we have an ipv4 interface and an ipv6 interface. Return 0 if
|
||||||
* the test seemed successful. */
|
* the test seemed successful. */
|
||||||
static int
|
static int
|
||||||
evutil_check_interfaces(int force_recheck)
|
evutil_check_interfaces(int force_recheck)
|
||||||
{
|
{
|
||||||
const char ZEROES[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
|
|
||||||
"\x00\x00\x00\x00\x00\x00\x00\x00";
|
|
||||||
evutil_socket_t fd = -1;
|
evutil_socket_t fd = -1;
|
||||||
struct sockaddr_in sin, sin_out;
|
struct sockaddr_in sin, sin_out;
|
||||||
struct sockaddr_in6 sin6, sin6_out;
|
struct sockaddr_in6 sin6, sin6_out;
|
||||||
ev_socklen_t sin_out_len = sizeof(sin_out);
|
ev_socklen_t sin_out_len = sizeof(sin_out);
|
||||||
ev_socklen_t sin6_out_len = sizeof(sin6_out);
|
ev_socklen_t sin6_out_len = sizeof(sin6_out);
|
||||||
int r;
|
int r;
|
||||||
char buf[128];
|
|
||||||
if (have_checked_interfaces && !force_recheck)
|
if (have_checked_interfaces && !force_recheck)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* To check whether we have an interface open for a given protocol, we
|
if (evutil_check_ifaddrs() == 0) {
|
||||||
* try to make a UDP 'connection' to a remote host on the internet.
|
/* Use a nice sane interface, if this system has one. */
|
||||||
* We don't actually use it, so the address doesn't matter, but we
|
return 0;
|
||||||
* want to pick one that keep us from using a host- or link-local
|
}
|
||||||
* interface. */
|
|
||||||
|
/* Ugh. There was no nice sane interface. So to check whether we have
|
||||||
|
* an interface open for a given protocol, will try to make a UDP
|
||||||
|
* 'connection' to a remote host on the internet. We don't actually
|
||||||
|
* use it, so the address doesn't matter, but we want to pick one that
|
||||||
|
* keep us from using a host- or link-local interface. */
|
||||||
memset(&sin, 0, sizeof(sin));
|
memset(&sin, 0, sizeof(sin));
|
||||||
sin.sin_family = AF_INET;
|
sin.sin_family = AF_INET;
|
||||||
sin.sin_port = htons(53);
|
sin.sin_port = htons(53);
|
||||||
@ -576,21 +704,7 @@ evutil_check_interfaces(int force_recheck)
|
|||||||
connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
|
connect(fd, (struct sockaddr*)&sin, sizeof(sin)) == 0 &&
|
||||||
getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) {
|
getsockname(fd, (struct sockaddr*)&sin_out, &sin_out_len) == 0) {
|
||||||
/* We might have an IPv4 interface. */
|
/* We might have an IPv4 interface. */
|
||||||
ev_uint32_t addr = ntohl(sin_out.sin_addr.s_addr);
|
evutil_found_ifaddr((struct sockaddr*) &sin_out);
|
||||||
if (addr == 0 ||
|
|
||||||
EVUTIL_V4ADDR_IS_LOCALHOST(addr) ||
|
|
||||||
EVUTIL_V4ADDR_IS_CLASSD(addr)) {
|
|
||||||
evutil_inet_ntop(AF_INET, &sin_out.sin_addr,
|
|
||||||
buf, sizeof(buf));
|
|
||||||
/* This is a reserved, ipv4compat, ipv4map, loopback,
|
|
||||||
* link-local or unspecified address. The host should
|
|
||||||
* never have given it to us; it could never connect
|
|
||||||
* to sin. */
|
|
||||||
event_warnx("Got a strange local ipv4 address %s",buf);
|
|
||||||
} else {
|
|
||||||
event_debug(("Detected an IPv4 interface"));
|
|
||||||
had_ipv4_address = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
evutil_closesocket(fd);
|
evutil_closesocket(fd);
|
||||||
@ -599,21 +713,7 @@ evutil_check_interfaces(int force_recheck)
|
|||||||
connect(fd, (struct sockaddr*)&sin6, sizeof(sin6)) == 0 &&
|
connect(fd, (struct sockaddr*)&sin6, sizeof(sin6)) == 0 &&
|
||||||
getsockname(fd, (struct sockaddr*)&sin6_out, &sin6_out_len) == 0) {
|
getsockname(fd, (struct sockaddr*)&sin6_out, &sin6_out_len) == 0) {
|
||||||
/* We might have an IPv6 interface. */
|
/* We might have an IPv6 interface. */
|
||||||
const unsigned char *addr =
|
evutil_found_ifaddr((struct sockaddr*) &sin6_out);
|
||||||
(unsigned char*)sin6_out.sin6_addr.s6_addr;
|
|
||||||
if (!memcmp(addr, ZEROES, 8) ||
|
|
||||||
(addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80)) {
|
|
||||||
/* This is a reserved, ipv4compat, ipv4map, loopback,
|
|
||||||
* link-local or unspecified address. The host should
|
|
||||||
* never have given it to us; it could never connect
|
|
||||||
* to sin6. */
|
|
||||||
evutil_inet_ntop(AF_INET6, &sin6_out.sin6_addr,
|
|
||||||
buf, sizeof(buf));
|
|
||||||
event_warnx("Got a strange local ipv6 address %s",buf);
|
|
||||||
} else {
|
|
||||||
event_debug(("Detected an IPv4 interface"));
|
|
||||||
had_ipv6_address = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user