summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Homburg <phomburg@ripe.net>2019-10-29 15:48:53 +0100
committerAzat Khuzhin <azat@libevent.org>2019-11-06 21:07:16 +0300
commit9fecb59a94ef246088d7f3e0365c2fe80d0df2f4 (patch)
treeb09855726d8b43b510d1f73100a0b2f31c3c65f9
parent4436287d1247fb2e9c80560debf852a94657e485 (diff)
downloadlibevent-9fecb59a94ef246088d7f3e0365c2fe80d0df2f4.tar.gz
Parse IPv6 scope IDs.
-rw-r--r--CMakeLists.txt12
-rw-r--r--Makefile.am4
-rw-r--r--evutil.c50
-rw-r--r--include/event2/util.h6
-rw-r--r--test/regress_util.c60
5 files changed, 128 insertions, 4 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 897ddf6f..c98b619a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
diff --git a/Makefile.am b/Makefile.am
index 8211dc7f..c044e6a2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
diff --git a/evutil.c b/evutil.c
index 13631263..17962548 100644
--- a/evutil.c
+++ b/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)
@@ -2163,6 +2170,41 @@ evutil_inet_ntop(int af, const void *src, char *dst, size_t len)
}
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)
{
#if defined(EVENT__HAVE_INET_PTON) && !defined(USE_INTERNAL_PTON)
@@ -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);
diff --git a/include/event2/util.h b/include/event2/util.h
index 9ee6862f..4cedfc3f 100644
--- a/include/event2/util.h
+++ b/include/event2/util.h
@@ -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);
diff --git a/test/regress_util.c b/test/regress_util.c
index 9422cce8..1459387a 100644
--- a/test/regress_util.c
+++ b/test/regress_util.c
@@ -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 },