diff --git a/src/standard.c b/src/standard.c index b5f4bf4046..969daf6b3f 100644 --- a/src/standard.c +++ b/src/standard.c @@ -620,6 +620,33 @@ const char *invalid_domainchar(const char *name) { struct sockaddr_storage *str2ip2(const char *str, struct sockaddr_storage *sa, int resolve) { struct hostent *he; + /* max IPv6 length, including brackets and terminating NULL */ + char tmpip[48]; + + /* check IPv6 with square brackets */ + if (str[0] == '[') { + size_t iplength = strlen(str); + + if (iplength < 4) { + /* minimal size is 4 when using brackets "[::]" */ + goto fail; + } + else if (iplength >= sizeof(tmpip)) { + /* IPv6 literal can not be larger than tmpip */ + goto fail; + } + else { + if (str[iplength - 1] != ']') { + /* if address started with bracket, it should end with bracket */ + goto fail; + } + else { + memcpy(tmpip, str + 1, iplength - 2); + tmpip[iplength - 2] = '\0'; + str = tmpip; + } + } + } /* Any IPv6 address */ if (str[0] == ':' && str[1] == ':' && !str[2]) { @@ -747,10 +774,12 @@ struct sockaddr_storage *str2ip2(const char *str, struct sockaddr_storage *sa, i * the first byte of the address. * - "fd@" => an integer must follow, and is a file descriptor number. * - * Also note that in order to avoid any ambiguity with IPv6 addresses, the ':' - * is mandatory after the IP address even when no port is specified. NULL is - * returned if the address cannot be parsed. The and ports are - * always initialized if non-null, even for non-IP families. + * IPv6 addresses can be declared with or without square brackets. When using + * square brackets for IPv6 addresses, the port separator (colon) is optional. + * If not using square brackets, and in order to avoid any ambiguity with + * IPv6 addresses, the last colon ':' is mandatory even when no port is specified. + * NULL is returned if the address cannot be parsed. The and ports + * are always initialized if non-null, even for non-IP families. * * If is non-null, it is used as a string prefix before any path-based * address (typically the path to a unix socket). @@ -855,12 +884,29 @@ struct sockaddr_storage *str2sa_range(const char *str, int *low, int *high, char } else { /* IPv4 and IPv6 */ int use_fqdn = 0; + char *end = str2 + strlen(str2); + char *chr; - port1 = strrchr(str2, ':'); - if (port1) - *port1++ = '\0'; - else + /* search for : or ] whatever comes first */ + for (chr = end-1; chr > str2; chr--) { + if (*chr == ']' || *chr == ':') + break; + } + + if (*chr == ':') { + /* Found a colon before a closing-bracket, must be a port separator. + * This guarantee backward compatibility. + */ + *chr++ = '\0'; + port1 = chr; + } + else { + /* Either no colon and no closing-bracket + * or directly ending with a closing-bracket. + * However, no port. + */ port1 = ""; + } if (str2ip2(str2, &ss, 0) == NULL) { use_fqdn = 1;