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 */
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to