From 849e5b07d982e7c0917a13d9ff22d447817dd7fe Mon Sep 17 00:00:00 2001 From: Sathish Yenna Date: Wed, 9 Dec 2015 16:26:34 -0600 Subject: [PATCH 1/2] Add missing support for IPv6 link local addresses (which include % followed by the interface name) --- src/socket_base.cpp | 6 ++++-- src/tcp_address.cpp | 26 ++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/socket_base.cpp b/src/socket_base.cpp index d6d5d4e3..a9ffc017 100644 --- a/src/socket_base.cpp +++ b/src/socket_base.cpp @@ -598,6 +598,8 @@ int zmq::socket_base_t::connect (const char *addr_) // Do some basic sanity checks on tcp:// address syntax // - hostname starts with digit or letter, with embedded '-' or '.' // - IPv6 address may contain hex chars and colons. + // - IPv6 link local address may contain % followed by interface name / zone_id + // (Reference: https://tools.ietf.org/html/rfc4007) // - IPv4 address may contain decimal digits and dots. // - Address must end in ":port" where port is *, or numeric // - Address may contain two parts separated by ':' @@ -608,8 +610,8 @@ int zmq::socket_base_t::connect (const char *addr_) check++; while (isalnum (*check) || isxdigit (*check) - || *check == '.' || *check == '-' || *check == ':'|| *check == ';' - || *check == ']') + || *check == '.' || *check == '-' || *check == ':' || *check == '%' + || *check == ';' || *check == ']') check++; } // Assume the worst, now look for success diff --git a/src/tcp_address.cpp b/src/tcp_address.cpp index c8689322..e694b13e 100644 --- a/src/tcp_address.cpp +++ b/src/tcp_address.cpp @@ -160,6 +160,7 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv6_, bool is_ && defined ZMQ_HAVE_IFADDRS) #include +#include // On these platforms, network interface name can be queried // using getifaddrs function. @@ -428,6 +429,23 @@ int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv6_, boo addr_str [addr_str.size () - 1] == ']') addr_str = addr_str.substr (1, addr_str.size () - 2); + // Test the '%' to know if we have an interface name / zone_id in the address + // Reference: https://tools.ietf.org/html/rfc4007 + std::size_t pos = addr_str.rfind("%"); + uint32_t zone_id = 0; + if (pos != std::string::npos) { + std::string if_str = addr_str.substr(pos + 1); + addr_str = addr_str.substr(0, pos); + if (isalpha (if_str.at (0))) + zone_id = if_nametoindex(if_str.c_str()); + else + zone_id = (uint32_t) atoi (if_str.c_str ()); + if (zone_id == 0) { + errno = EINVAL; + return -1; + } + } + // Allow 0 specifically, to detect invalid port error in atoi if not uint16_t port; if (port_str == "*" || port_str == "0") @@ -453,14 +471,18 @@ int zmq::tcp_address_t::resolve (const char *name_, bool local_, bool ipv6_, boo // Set the port into the address structure. if (is_src_) { - if (source_address.generic.sa_family == AF_INET6) + if (source_address.generic.sa_family == AF_INET6) { source_address.ipv6.sin6_port = htons (port); + source_address.ipv6.sin6_scope_id = zone_id; + } else source_address.ipv4.sin_port = htons (port); } else { - if (address.generic.sa_family == AF_INET6) + if (address.generic.sa_family == AF_INET6) { address.ipv6.sin6_port = htons (port); + address.ipv6.sin6_scope_id = zone_id; + } else address.ipv4.sin_port = htons (port); } From e8577bf1dda2e1a928770bb55d166346085fd31d Mon Sep 17 00:00:00 2001 From: Pieter Hintjens Date: Thu, 10 Dec 2015 08:56:18 +0100 Subject: [PATCH 2/2] Updated NEWS --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index 836aa2fc..a2e33828 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,8 @@ * Fixed #1644 - assertion failure in msg.cpp:390 on STREAM sockets. +* Fixed #1661 - does not handle IPv6 link local addresses. + 0MQ version 4.1.3 stable, released on 2015/08/17 ================================================