diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2017-03-17 14:18:52 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2017-03-17 14:18:52 +0000 |
commit | 08a49957b3f06926744987207d542efa2631394d (patch) | |
tree | 2b20a72252d0cf0e939f01dff9e9694a5fafe4c5 /lib/libfetch/common.c | |
parent | ff17a6773e4785a8fb78c540de32a208c43162db (diff) | |
download | src-08a49957b3f06926744987207d542efa2631394d.tar.gz src-08a49957b3f06926744987207d542efa2631394d.zip |
r308996 broke IP literals by assuming that a colon could only occur as
a separator between host and port, and using strchr() to search for it.
Rewrite fetch_resolve() so it handles bracketed literals correctly, and
remove similar code elsewhere to avoid passing unbracketed literals to
fetch_resolve(). Remove #ifdef INET6 so we still parse IP literals
correctly even if we do not have the ability to connect to them.
While there, fix an off-by-one error which caused HTTP 400 errors to be
misinterpreted as redirects.
PR: 217723
MFC after: 1 week
Reported by: bapt, bz, cem, ngie
Notes
Notes:
svn path=/head/; revision=315455
Diffstat (limited to 'lib/libfetch/common.c')
-rw-r--r-- | lib/libfetch/common.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c index ba3217aa8a9c..78e214b0eb94 100644 --- a/lib/libfetch/common.c +++ b/lib/libfetch/common.c @@ -248,37 +248,51 @@ fetch_resolve(const char *addr, int port, int af) { char hbuf[256], sbuf[8]; struct addrinfo hints, *res; - const char *sep, *host, *service; + const char *hb, *he, *sep; + const char *host, *service; int err, len; - /* split address if necessary */ - err = EAI_SYSTEM; - if ((sep = strchr(addr, ':')) != NULL) { + /* first, check for a bracketed IPv6 address */ + if (*addr == '[') { + hb = addr + 1; + if ((sep = strchr(hb, ']')) == NULL) { + errno = EINVAL; + goto syserr; + } + he = sep++; + } else { + hb = addr; + sep = strchrnul(hb, ':'); + he = sep; + } + + /* see if we need to copy the host name */ + if (*he != '\0') { len = snprintf(hbuf, sizeof(hbuf), - "%.*s", (int)(sep - addr), addr); + "%.*s", (int)(he - hb), hb); if (len < 0) - return (NULL); + goto syserr; if (len >= (int)sizeof(hbuf)) { errno = ENAMETOOLONG; - fetch_syserr(); - return (NULL); + goto syserr; } host = hbuf; - service = sep + 1; - } else if (port != 0) { + } else { + host = hb; + } + + /* was it followed by a service name? */ + if (*sep == '\0' && port != 0) { if (port < 1 || port > 65535) { errno = EINVAL; - fetch_syserr(); - return (NULL); - } - if (snprintf(sbuf, sizeof(sbuf), "%d", port) < 0) { - fetch_syserr(); - return (NULL); + goto syserr; } - host = addr; + if (snprintf(sbuf, sizeof(sbuf), "%d", port) < 0) + goto syserr; service = sbuf; + } else if (*sep != '\0') { + service = sep; } else { - host = addr; service = NULL; } @@ -292,6 +306,9 @@ fetch_resolve(const char *addr, int port, int af) return (NULL); } return (res); +syserr: + fetch_syserr(); + return (NULL); } |