Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Mar 2017 14:18:52 +0000 (UTC)
From:      =?UTF-8?Q?Dag-Erling_Sm=c3=b8rgrav?= <des@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r315455 - head/lib/libfetch
Message-ID:  <201703171418.v2HEIqHO066929@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: des
Date: Fri Mar 17 14:18:52 2017
New Revision: 315455
URL: https://svnweb.freebsd.org/changeset/base/315455

Log:
  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

Modified:
  head/lib/libfetch/common.c
  head/lib/libfetch/fetch.c
  head/lib/libfetch/http.c

Modified: head/lib/libfetch/common.c
==============================================================================
--- head/lib/libfetch/common.c	Fri Mar 17 13:49:05 2017	(r315454)
+++ head/lib/libfetch/common.c	Fri Mar 17 14:18:52 2017	(r315455)
@@ -248,37 +248,51 @@ fetch_resolve(const char *addr, int port
 {
 	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
 		return (NULL);
 	}
 	return (res);
+syserr:
+	fetch_syserr();
+	return (NULL);
 }
 
 

Modified: head/lib/libfetch/fetch.c
==============================================================================
--- head/lib/libfetch/fetch.c	Fri Mar 17 13:49:05 2017	(r315454)
+++ head/lib/libfetch/fetch.c	Fri Mar 17 14:18:52 2017	(r315455)
@@ -386,18 +386,17 @@ fetchParseURL(const char *URL)
 	}
 
 	/* hostname */
-#ifdef INET6
 	if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
 	    (*++q == '\0' || *q == '/' || *q == ':')) {
-		if ((i = q - p - 2) > MAXHOSTNAMELEN)
+		if ((i = q - p) > MAXHOSTNAMELEN)
 			i = MAXHOSTNAMELEN;
-		strncpy(u->host, ++p, i);
+		strncpy(u->host, p, i);
 		p = q;
-	} else
-#endif
+	} else {
 		for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
 			if (i < MAXHOSTNAMELEN)
 				u->host[i++] = *p;
+	}
 
 	/* port */
 	if (*p == ':') {
@@ -444,12 +443,12 @@ nohost:
 	}
 
 	DEBUG(fprintf(stderr,
-		  "scheme:   [%s]\n"
-		  "user:     [%s]\n"
-		  "password: [%s]\n"
-		  "host:     [%s]\n"
-		  "port:     [%d]\n"
-		  "document: [%s]\n",
+		  "scheme:   \"%s\"\n"
+		  "user:     \"%s\"\n"
+		  "password: \"%s\"\n"
+		  "host:     \"%s\"\n"
+		  "port:     \"%d\"\n"
+		  "document: \"%s\"\n",
 		  u->scheme, u->user, u->pwd,
 		  u->host, u->port, u->doc));
 

Modified: head/lib/libfetch/http.c
==============================================================================
--- head/lib/libfetch/http.c	Fri Mar 17 13:49:05 2017	(r315454)
+++ head/lib/libfetch/http.c	Fri Mar 17 14:18:52 2017	(r315455)
@@ -118,7 +118,7 @@ __FBSDID("$FreeBSD$");
 			    || (xyz) == HTTP_USE_PROXY \
 			    || (xyz) == HTTP_SEE_OTHER)
 
-#define HTTP_ERROR(xyz) ((xyz) > 400 && (xyz) < 599)
+#define HTTP_ERROR(xyz) ((xyz) >= 400 && (xyz) <= 599)
 
 
 /*****************************************************************************
@@ -1604,20 +1604,11 @@ http_request_body(struct url *URL, const
 		if ((conn = http_connect(url, purl, flags)) == NULL)
 			goto ouch;
 
+		/* append port number only if necessary */
 		host = url->host;
-#ifdef INET6
-		if (strchr(url->host, ':')) {
-			snprintf(hbuf, sizeof(hbuf), "[%s]", url->host);
-			host = hbuf;
-		}
-#endif
 		if (url->port != fetch_default_port(url->scheme)) {
-			if (host != hbuf) {
-				strcpy(hbuf, host);
-				host = hbuf;
-			}
-			snprintf(hbuf + strlen(hbuf),
-			    sizeof(hbuf) - strlen(hbuf), ":%d", url->port);
+			snprintf(hbuf, sizeof(hbuf), "%s:%d", host, url->port);
+			host = hbuf;
 		}
 
 		/* send request */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703171418.v2HEIqHO066929>