From 67e52b1d70d094e1ad4a8d07ebf0243d019bc707 Mon Sep 17 00:00:00 2001 From: Oded Engel <37329239+oengel@users.noreply.github.com> Date: Wed, 29 Dec 2021 01:30:19 +0200 Subject: add IPv6 link-local support to nanomsg (#1055) --- src/transports/utils/literal.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file 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 #include #ifndef NN_HAVE_WINDOWS @@ -32,6 +33,24 @@ #include #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); -- cgit v1.2.1