summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOded Engel <37329239+oengel@users.noreply.github.com>2021-12-29 01:30:19 +0200
committerGitHub <noreply@github.com>2021-12-28 15:30:19 -0800
commit67e52b1d70d094e1ad4a8d07ebf0243d019bc707 (patch)
tree3ac73cbd19eafe8d25e82e04338238c963301226
parent920add38113cd0f73c6eb8ec8d0cfd0d2a7ce0df (diff)
downloadnanomsg-67e52b1d70d094e1ad4a8d07ebf0243d019bc707.tar.gz
add IPv6 link-local support to nanomsg (#1055)
-rw-r--r--src/transports/utils/literal.c39
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);