mirror of
https://github.com/libevent/libevent.git
synced 2025-01-31 09:12:55 +08:00
Parse IPv6 scope IDs.
This commit is contained in:
parent
4436287d12
commit
9fecb59a94
@ -966,6 +966,18 @@ add_event_library(event SOURCES ${SRC_CORE} ${SRC_EXTRA})
|
||||
|
||||
set(WIN32_GETOPT)
|
||||
if (WIN32)
|
||||
set(_TMPLIBS)
|
||||
if (${EVENT_LIBRARY_STATIC})
|
||||
list(APPEND _TMPLIBS event_core_static event_static)
|
||||
endif()
|
||||
if (${EVENT_LIBRARY_SHARED})
|
||||
list(APPEND _TMPLIBS event_core_shared event_shared)
|
||||
endif()
|
||||
foreach(lib ${_TMPLIBS})
|
||||
target_link_libraries(${lib} iphlpapi)
|
||||
endforeach()
|
||||
unset(_TMPLIBS)
|
||||
|
||||
list(APPEND WIN32_GETOPT
|
||||
WIN32-Code/getopt.c
|
||||
WIN32-Code/getopt_long.c)
|
||||
|
@ -270,11 +270,11 @@ AM_LDFLAGS = $(LIBEVENT_LDFLAGS)
|
||||
GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED) $(AM_LDFLAGS)
|
||||
|
||||
libevent_la_SOURCES = $(CORE_SRC) $(EXTRAS_SRC)
|
||||
libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
|
||||
libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) -liphlpapi
|
||||
libevent_la_LDFLAGS = $(GENERIC_LDFLAGS)
|
||||
|
||||
libevent_core_la_SOURCES = $(CORE_SRC)
|
||||
libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
|
||||
libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) -liphlpapi
|
||||
libevent_core_la_LDFLAGS = $(GENERIC_LDFLAGS)
|
||||
|
||||
if PTHREADS
|
||||
|
50
evutil.c
50
evutil.c
@ -44,6 +44,7 @@
|
||||
/* For structs needed by GetAdaptersAddresses */
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#include <iphlpapi.h>
|
||||
#include <netioapi.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
@ -77,6 +78,9 @@
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef _WIN32
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#ifdef EVENT__HAVE_IFADDRS_H
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
@ -1171,6 +1175,7 @@ evutil_getaddrinfo_common_(const char *nodename, const char *servname,
|
||||
struct evutil_addrinfo *hints, struct evutil_addrinfo **res, int *portnum)
|
||||
{
|
||||
int port = 0;
|
||||
unsigned int if_index;
|
||||
const char *pname;
|
||||
|
||||
if (nodename == NULL && servname == NULL)
|
||||
@ -1244,10 +1249,12 @@ evutil_getaddrinfo_common_(const char *nodename, const char *servname,
|
||||
if (hints->ai_family == PF_INET6 || hints->ai_family == PF_UNSPEC) {
|
||||
struct sockaddr_in6 sin6;
|
||||
memset(&sin6, 0, sizeof(sin6));
|
||||
if (1==evutil_inet_pton(AF_INET6, nodename, &sin6.sin6_addr)) {
|
||||
if (1 == evutil_inet_pton_scope(
|
||||
AF_INET6, nodename, &sin6.sin6_addr, &if_index)) {
|
||||
/* Got an ipv6 address. */
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_port = htons(port);
|
||||
sin6.sin6_scope_id = if_index;
|
||||
*res = evutil_new_addrinfo_((struct sockaddr*)&sin6,
|
||||
sizeof(sin6), hints);
|
||||
if (!*res)
|
||||
@ -2162,6 +2169,41 @@ evutil_inet_ntop(int af, const void *src, char *dst, size_t len)
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
evutil_inet_pton_scope(int af, const char *src, void *dst, unsigned *indexp)
|
||||
{
|
||||
int r;
|
||||
unsigned if_index;
|
||||
char *check, *cp, *tmp_src;
|
||||
|
||||
*indexp = 0; /* Reasonable default */
|
||||
|
||||
/* Bail out if not IPv6 */
|
||||
if (af != AF_INET6)
|
||||
return evutil_inet_pton(af, src, dst);
|
||||
|
||||
cp = strchr(src, '%');
|
||||
|
||||
/* Bail out if no zone ID */
|
||||
if (cp == NULL)
|
||||
return evutil_inet_pton(af, src, dst);
|
||||
|
||||
if_index = if_nametoindex(cp + 1);
|
||||
if (if_index == 0) {
|
||||
/* Could be numeric */
|
||||
if_index = strtoul(cp + 1, &check, 10);
|
||||
if (check[0] != '\0')
|
||||
return 0;
|
||||
}
|
||||
*indexp = if_index;
|
||||
tmp_src = mm_strdup(src);
|
||||
cp = strchr(tmp_src, '%');
|
||||
*cp = '\0';
|
||||
r = evutil_inet_pton(af, tmp_src, dst);
|
||||
free(tmp_src);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
evutil_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
@ -2278,6 +2320,7 @@ int
|
||||
evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *outlen)
|
||||
{
|
||||
int port;
|
||||
unsigned int if_index;
|
||||
char buf[128];
|
||||
const char *cp, *addr_part, *port_part;
|
||||
int is_ipv6;
|
||||
@ -2347,10 +2390,13 @@ evutil_parse_sockaddr_port(const char *ip_as_string, struct sockaddr *out, int *
|
||||
#endif
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_port = htons(port);
|
||||
if (1 != evutil_inet_pton(AF_INET6, addr_part, &sin6.sin6_addr))
|
||||
if (1 != evutil_inet_pton_scope(
|
||||
AF_INET6, addr_part, &sin6.sin6_addr, &if_index)) {
|
||||
return -1;
|
||||
}
|
||||
if ((int)sizeof(sin6) > *outlen)
|
||||
return -1;
|
||||
sin6.sin6_scope_id = if_index;
|
||||
memset(out, 0, *outlen);
|
||||
memcpy(out, &sin6, sizeof(sin6));
|
||||
*outlen = sizeof(sin6);
|
||||
|
@ -612,6 +612,12 @@ int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
|
||||
/** Replacement for inet_ntop for platforms which lack it. */
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
const char *evutil_inet_ntop(int af, const void *src, char *dst, size_t len);
|
||||
/** Variation of inet_pton that also parses IPv6 scopes. Public for
|
||||
unit tests. No reason to call this directly.
|
||||
*/
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
int evutil_inet_pton_scope(int af, const char *src, void *dst,
|
||||
unsigned *indexp);
|
||||
/** Replacement for inet_pton for platforms which lack it. */
|
||||
EVENT2_EXPORT_SYMBOL
|
||||
int evutil_inet_pton(int af, const char *src, void *dst);
|
||||
|
@ -215,6 +215,65 @@ regress_ipv6_parse(void *ptr)
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct ipv6_entry_scope {
|
||||
const char *addr;
|
||||
ev_uint32_t res[4];
|
||||
unsigned scope;
|
||||
enum entry_status status;
|
||||
} ipv6_entries_scope[] = {
|
||||
{ "2001:DB8::", { 0x20010db8, 0, 0 }, 0, NORMAL },
|
||||
{ "2001:DB8::%0", { 0x20010db8, 0, 0, 0 }, 0, NORMAL },
|
||||
{ "2001:DB8::%1", { 0x20010db8, 0, 0, 0 }, 1, NORMAL },
|
||||
{ "foobar.", { 0, 0, 0, 0 }, 0, BAD },
|
||||
{ "2001:DB8::%does-not-exist", { 0, 0, 0, 0 }, 0, BAD },
|
||||
{ NULL, { 0, 0, 0, 0, }, 0, BAD },
|
||||
};
|
||||
static void
|
||||
regress_ipv6_parse_scope(void *ptr)
|
||||
{
|
||||
#ifdef AF_INET6
|
||||
int i, j;
|
||||
unsigned if_scope;
|
||||
|
||||
for (i = 0; ipv6_entries_scope[i].addr; ++i) {
|
||||
struct ipv6_entry_scope *ent = &ipv6_entries_scope[i];
|
||||
struct in6_addr in6;
|
||||
int r;
|
||||
r = evutil_inet_pton_scope(AF_INET6, ent->addr, &in6,
|
||||
&if_scope);
|
||||
if (r == 0) {
|
||||
if (ent->status != BAD)
|
||||
TT_FAIL(("%s did not parse, but it's a good address!",
|
||||
ent->addr));
|
||||
continue;
|
||||
}
|
||||
if (ent->status == BAD) {
|
||||
TT_FAIL(("%s parsed, but we expected an error", ent->addr));
|
||||
continue;
|
||||
}
|
||||
for (j = 0; j < 4; ++j) {
|
||||
/* Can't use s6_addr32 here; some don't have it. */
|
||||
ev_uint32_t u =
|
||||
((ev_uint32_t)in6.s6_addr[j*4 ] << 24) |
|
||||
((ev_uint32_t)in6.s6_addr[j*4+1] << 16) |
|
||||
((ev_uint32_t)in6.s6_addr[j*4+2] << 8) |
|
||||
((ev_uint32_t)in6.s6_addr[j*4+3]);
|
||||
if (u != ent->res[j]) {
|
||||
TT_FAIL(("%s did not parse as expected.", ent->addr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (if_scope != ent->scope) {
|
||||
TT_FAIL(("%s did not parse as expected.", ent->addr));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
TT_BLATHER(("Skipping IPv6 address parsing."));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static struct sa_port_ent {
|
||||
const char *parse;
|
||||
int safamily;
|
||||
@ -1715,6 +1774,7 @@ end:
|
||||
struct testcase_t util_testcases[] = {
|
||||
{ "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
|
||||
{ "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
|
||||
{ "ipv6_parse_scope", regress_ipv6_parse_scope, 0, NULL, NULL },
|
||||
{ "sockaddr_port_parse", regress_sockaddr_port_parse, 0, NULL, NULL },
|
||||
{ "sockaddr_port_format", regress_sockaddr_port_format, 0, NULL, NULL },
|
||||
{ "sockaddr_predicates", test_evutil_sockaddr_predicates, 0,NULL,NULL },
|
||||
|
Loading…
x
Reference in New Issue
Block a user