diff options
author | Oded Engel <37329239+oengel@users.noreply.github.com> | 2021-12-29 01:30:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-28 15:30:19 -0800 |
commit | 67e52b1d70d094e1ad4a8d07ebf0243d019bc707 (patch) | |
tree | 3ac73cbd19eafe8d25e82e04338238c963301226 | |
parent | 920add38113cd0f73c6eb8ec8d0cfd0d2a7ce0df (diff) | |
download | nanomsg-67e52b1d70d094e1ad4a8d07ebf0243d019bc707.tar.gz |
add IPv6 link-local support to nanomsg (#1055)
-rw-r--r-- | src/transports/utils/literal.c | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/src/transports/utils/literal.c b/src/transports/utils/literal.c index d329cdf..8184fae 100644 --- a/src/transports/utils/literal.c +++ b/src/transports/utils/literal.c @@ -25,6 +25,7 @@ #include "../../utils/err.h" #include "../../utils/fast.h" +#include <netdb.h> #include <string.h> #ifndef NN_HAVE_WINDOWS @@ -32,6 +33,24 @@ #include <netinet/in.h> #endif +void nn_literal_link_local_resolve(struct in6_addr *in6addr, int64_t *sin6_scope_id, char *addr) +{ + if (! IN6_IS_ADDR_LINKLOCAL(in6addr)) { + return; + } + struct addrinfo hints, *res; + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = 0; + hints.ai_flags = AI_NUMERICHOST; + int rc = getaddrinfo(addr, NULL, &hints, &res); + if (0 == rc && res) { + struct sockaddr_in6 * curr = ((struct sockaddr_in6 *) res->ai_addr); + // set scope_id + *sin6_scope_id = (int64_t) curr->sin6_scope_id; + } +} + int nn_literal_resolve (const char *addr, size_t addrlen, int ipv4only, struct sockaddr_storage *result, size_t *resultlen) { @@ -40,6 +59,8 @@ int nn_literal_resolve (const char *addr, size_t addrlen, INET6_ADDRSTRLEN : INET_ADDRSTRLEN]; struct in_addr inaddr; struct in6_addr in6addr; + int64_t sin6_scope_id = -1; + char *ifname_dindex = NULL; // pointer to ifname's delimiter, '%' /* Try to treat the address as a literal string. If the size of the address is larger than longest possible literal, skip the step. @@ -61,11 +82,25 @@ int nn_literal_resolve (const char *addr, size_t addrlen, /* Try to interpret the literal as an IPv6 address. */ if (!ipv4only) { - rc = inet_pton (AF_INET6, addrz, &in6addr); - if (rc == 1) { + // check if '%' exists in addrz (i.e. '$addr%$ifname') + ifname_dindex = strstr(addrz, "%"); + if (NULL == ifname_dindex) { + rc = inet_pton (AF_INET6, addrz, &in6addr); + } else { + // set addrz[index] = '\0', so that inet_pton won't fail + *ifname_dindex = '\0'; + rc = inet_pton (AF_INET6, addrz, &in6addr); + // re-add the '%' so we'll be able to get the scope_id for link-local IPv6 + *ifname_dindex = '%'; + } + if (1 == rc) { if (result) { + nn_literal_link_local_resolve(&in6addr, &sin6_scope_id, addrz); result->ss_family = AF_INET6; ((struct sockaddr_in6*) result)->sin6_addr = in6addr; + if (-1 < sin6_scope_id) { + ((struct sockaddr_in6*) result)->sin6_scope_id = (uint32_t) sin6_scope_id; + } } if (resultlen) *resultlen = sizeof (struct sockaddr_in6); |