ss was printing the zone identifier in the wrong place. The zone identifier belongs to the address [1][2][3], and should thus be enclosed within the square brackets, not outside of it. [1] glibc (since about 2000) accepts "fe80::1%eth0" as an input to the `getaddrinfo` function. [2] Zone architecture specification (drafted 2003; released 2005): RFC 4007 §4: "The scope of an address is encoded as part of the address". [3] RFC 6874 §2 pg. 4: ABNF syntax showing where zones go in relation to square brackets. Signed-off-by: Jan Engelhardt --- misc/ss.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index b3566f6b..f242d761 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1484,10 +1484,23 @@ static void sock_details_print(struct sockstat *s) static void sock_addr_print(const char *addr, char *delim, const char *port, const char *ifname) { - if (ifname) - out("%s" "%%" "%s%s", addr, ifname, delim); - else - out("%s%s", addr, delim); + /* + * Numeric IPv6 addresses should be bracketed. + * Come to think of it, any address with a port delimiter character + * should be bracketed; otherwise, it would be impossible to tell if + * ":N" is the port or part of the address. + */ + if (strpbrk(addr, delim) != NULL) { + if (ifname) + out("[%s" "%%" "%s]%s", addr, ifname, delim); + else + out("[%s]%s", addr, delim); + } else { + if (ifname) + out("%s" "%%" "%s%s", addr, ifname, delim); + else + out("%s%s", addr, delim); + } field_next(); out("%s", port); @@ -1725,13 +1738,6 @@ static void inet_addr_print(const inet_prefix *a, int port, buf[1] = 0; } else { ap = format_host(a->family, 16, a->data); - - /* Numeric IPv6 addresses should be bracketed */ - if (strchr(ap, ':')) { - snprintf(buf, sizeof(buf), - "[%s]", ap); - ap = buf; - } } } -- 2.53.0