aboutsummaryrefslogtreecommitdiff
path: root/lib/libfetch/common.c
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2017-03-17 14:18:52 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2017-03-17 14:18:52 +0000
commit08a49957b3f06926744987207d542efa2631394d (patch)
tree2b20a72252d0cf0e939f01dff9e9694a5fafe4c5 /lib/libfetch/common.c
parentff17a6773e4785a8fb78c540de32a208c43162db (diff)
downloadsrc-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.c53
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);
}