aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2019-04-30 16:59:08 +0200
committerDaniel Stenberg <daniel@haxx.se>2019-05-03 12:17:22 +0200
commitbdb2dbc1032e7ca33cfc161fd1d5bfbabdf65841 (patch)
treed9e4788e86e610c1a841e91fa6fcc1b3179c3d1c /lib
parent028126281901fb651819821f5c05caaf40976209 (diff)
urlapi: strip off scope id from numerical IPv6 addresses
... to make the host name "usable". Store the scope id and put it back when extracting a URL out of it. Also makes curl_url_set() syntax check CURLUPART_HOST. Fixes #3817 Closes #3822
Diffstat (limited to 'lib')
-rw-r--r--lib/urlapi.c63
1 files changed, 54 insertions, 9 deletions
diff --git a/lib/urlapi.c b/lib/urlapi.c
index 57f82cac5..c42dc737a 100644
--- a/lib/urlapi.c
+++ b/lib/urlapi.c
@@ -56,6 +56,7 @@ struct Curl_URL {
char *password;
char *options; /* IMAP only? */
char *host;
+ char *scopeid; /* for numerical IPv6 addresses */
char *port;
char *path;
char *query;
@@ -74,6 +75,7 @@ static void free_urlhandle(struct Curl_URL *u)
free(u->password);
free(u->options);
free(u->host);
+ free(u->scopeid);
free(u->port);
free(u->path);
free(u->query);
@@ -504,7 +506,7 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
portptr = &hostname[len];
else if('%' == endbracket) {
int zonelen = len;
- if(1 == sscanf(hostname + zonelen, "25%*[^]]%c%n", &endbracket, &len)) {
+ if(1 == sscanf(hostname + zonelen, "%*[^]]%c%n", &endbracket, &len)) {
if(']' != endbracket)
return CURLUE_MALFORMED_INPUT;
portptr = &hostname[--zonelen + len + 1];
@@ -587,25 +589,45 @@ static CURLUcode junkscan(char *part)
return CURLUE_OK;
}
-static CURLUcode hostname_check(char *hostname, unsigned int flags)
+static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
{
const char *l = NULL; /* accepted characters */
size_t len;
size_t hlen = strlen(hostname);
- (void)flags;
if(hostname[0] == '[') {
hostname++;
- l = "0123456789abcdefABCDEF::.%";
+ l = "0123456789abcdefABCDEF::.";
hlen -= 2;
}
if(l) {
/* only valid letters are ok */
len = strspn(hostname, l);
- if(hlen != len)
- /* hostname with bad content */
- return CURLUE_MALFORMED_INPUT;
+ if(hlen != len) {
+ /* this could now be '%[zone id]' */
+ char scopeid[16];
+ if(hostname[len] == '%') {
+ int i = 0;
+ char *h = &hostname[len + 1];
+ /* pass '25' if present and is a url encoded percent sign */
+ if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
+ h += 2;
+ while(*h && (*h != ']') && (i < 15))
+ scopeid[i++] = *h++;
+ if(!i || (']' != *h))
+ return CURLUE_MALFORMED_INPUT;
+ scopeid[i] = 0;
+ u->scopeid = strdup(scopeid);
+ if(!u->scopeid)
+ return CURLUE_OUT_OF_MEMORY;
+ hostname[len] = ']'; /* insert end bracket */
+ hostname[len + 1] = 0; /* terminate the hostname */
+ }
+ else
+ return CURLUE_MALFORMED_INPUT;
+ /* hostname is fine */
+ }
}
else {
/* letters from the second string is not ok */
@@ -856,7 +878,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
if(result)
return result;
- result = hostname_check(hostname, flags);
+ result = hostname_check(u, hostname);
if(result)
return result;
@@ -1021,6 +1043,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
char *scheme;
char *options = u->options;
char *port = u->port;
+ char *allochost = NULL;
if(u->scheme && strcasecompare("file", u->scheme)) {
url = aprintf("file://%s%s%s",
u->path,
@@ -1059,6 +1082,18 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
if(h && !(h->flags & PROTOPT_URLOPTIONS))
options = NULL;
+ if((u->host[0] == '[') && u->scopeid) {
+ /* make it '[ host %25 scopeid ]' */
+ size_t hostlen = strlen(u->host);
+ size_t alen = hostlen + 3 + strlen(u->scopeid) + 1;
+ allochost = malloc(alen);
+ if(!allochost)
+ return CURLUE_OUT_OF_MEMORY;
+ memcpy(allochost, u->host, hostlen - 1);
+ msnprintf(&allochost[hostlen - 1], alen - hostlen + 1,
+ "%%25%s]", u->scopeid);
+ }
+
url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
scheme,
u->user ? u->user : "",
@@ -1067,7 +1102,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
options ? ";" : "",
options ? options : "",
(u->user || u->password || options) ? "@": "",
- u->host,
+ allochost ? allochost : u->host,
port ? ":": "",
port ? port : "",
(u->path && (u->path[0] != '/')) ? "/": "",
@@ -1076,6 +1111,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
(u->query && u->query[0]) ? u->query : "",
u->fragment? "#": "",
u->fragment? u->fragment : "");
+ free(allochost);
}
if(!url)
return CURLUE_OUT_OF_MEMORY;
@@ -1191,6 +1227,8 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
break;
case CURLUPART_HOST:
storep = &u->host;
+ free(u->scopeid);
+ u->scopeid = NULL;
break;
case CURLUPART_PORT:
{
@@ -1370,6 +1408,13 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
}
+ if(what == CURLUPART_HOST) {
+ if(hostname_check(u, (char *)newp)) {
+ free((char *)newp);
+ return CURLUE_MALFORMED_INPUT;
+ }
+ }
+
free(*storep);
*storep = (char *)newp;
}