host names: allow trailing dot in name resolve, then strip it

Delays stripping of trailing dots to after resolving the hostname.

Fixes #3022
Closes #3222
This commit is contained in:
Tobias Hintze 2018-11-02 21:24:14 +01:00 committed by Daniel Stenberg
parent 2366697806
commit 5b4cce2e36
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
3 changed files with 61 additions and 33 deletions

View file

@ -127,7 +127,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "memdebug.h"
static void conn_free(struct connectdata *conn);
static void free_fixed_hostname(struct hostname *host);
static void free_idnconverted_hostname(struct hostname *host);
static unsigned int get_protocol_family(unsigned int protocol);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@ -708,6 +708,7 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->trailer);
Curl_safefree(conn->host.rawalloc); /* host name buffer */
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
@ -788,10 +789,10 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
infof(data, "Closing connection %ld\n", conn->connection_id);
Curl_conncache_remove_conn(conn, TRUE);
free_fixed_hostname(&conn->host);
free_fixed_hostname(&conn->conn_to_host);
free_fixed_hostname(&conn->http_proxy.host);
free_fixed_hostname(&conn->socks_proxy.host);
free_idnconverted_hostname(&conn->host);
free_idnconverted_hostname(&conn->conn_to_host);
free_idnconverted_hostname(&conn->http_proxy.host);
free_idnconverted_hostname(&conn->socks_proxy.host);
DEBUGASSERT(conn->data == data);
/* this assumes that the pointer is still there after the connection was
@ -1679,11 +1680,23 @@ static bool is_ASCII_name(const char *hostname)
}
/*
* Perform any necessary IDN conversion of hostname
* Strip single trailing dot in the hostname,
* primarily for SNI and http host header.
*/
static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
static void strip_trailing_dot(struct hostname *host)
{
size_t len;
len = strlen(host->name);
if(len && (host->name[len-1] == '.'))
host->name[len-1] = 0;
}
/*
* Perform any necessary IDN conversion of hostname
*/
static CURLcode idnconvert_hostname(struct connectdata *conn,
struct hostname *host)
{
struct Curl_easy *data = conn->data;
#ifndef USE_LIBIDN2
@ -1696,12 +1709,6 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
/* set the name we use to display the host name */
host->dispname = host->name;
len = strlen(host->name);
if(len && (host->name[len-1] == '.'))
/* strip off a single trailing dot if present, primarily for SNI but
there's no use for it */
host->name[len-1] = 0;
/* Check name for non-ASCII and convert hostname to ACE form if we can */
if(!is_ASCII_name(host->name)) {
#ifdef USE_LIBIDN2
@ -1756,9 +1763,9 @@ static CURLcode fix_hostname(struct connectdata *conn, struct hostname *host)
}
/*
* Frees data allocated by fix_hostname()
* Frees data allocated by idnconvert_hostname()
*/
static void free_fixed_hostname(struct hostname *host)
static void free_idnconverted_hostname(struct hostname *host)
{
#if defined(USE_LIBIDN2)
if(host->encalloc) {
@ -3373,7 +3380,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
*************************************************************/
if(conn->bits.reuse)
/* We're reusing the connection - no need to resolve anything, and
fix_hostname() was called already in create_conn() for the re-use
idnconvert_hostname() was called already in create_conn() for the re-use
case. */
*async = FALSE;
@ -3428,7 +3435,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
conn->port = conn->remote_port;
/* Resolve target host right on */
rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
conn->hostname_resolve = strdup(connhost->name);
if(!conn->hostname_resolve)
return CURLE_OUT_OF_MEMORY;
rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
@ -3449,7 +3459,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
&conn->socks_proxy.host : &conn->http_proxy.host;
/* resolve proxy */
rc = Curl_resolv_timeout(conn, host->name, (int)conn->port,
conn->hostname_resolve = strdup(host->name);
if(!conn->hostname_resolve)
return CURLE_OUT_OF_MEMORY;
rc = Curl_resolv_timeout(conn, conn->hostname_resolve, (int)conn->port,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
@ -3479,8 +3492,8 @@ static CURLcode resolve_server(struct Curl_easy *data,
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
free_fixed_hostname(&old_conn->http_proxy.host);
free_fixed_hostname(&old_conn->socks_proxy.host);
free_idnconverted_hostname(&old_conn->http_proxy.host);
free_idnconverted_hostname(&old_conn->socks_proxy.host);
free(old_conn->http_proxy.host.rawalloc);
free(old_conn->socks_proxy.host.rawalloc);
@ -3524,14 +3537,18 @@ static void reuse_conn(struct connectdata *old_conn,
/* host can change, when doing keepalive with a proxy or if the case is
different this time etc */
free_fixed_hostname(&conn->host);
free_fixed_hostname(&conn->conn_to_host);
free_idnconverted_hostname(&conn->host);
free_idnconverted_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->conn_to_host.rawalloc);
conn->host = old_conn->host;
conn->conn_to_host = old_conn->conn_to_host;
conn->conn_to_port = old_conn->conn_to_port;
conn->remote_port = old_conn->remote_port;
Curl_safefree(conn->hostname_resolve);
conn->hostname_resolve = old_conn->hostname_resolve;
old_conn->hostname_resolve = NULL;
/* persist connection info in session handle */
Curl_persistconninfo(conn);
@ -3681,30 +3698,30 @@ static CURLcode create_conn(struct Curl_easy *data,
goto out;
/*************************************************************
* IDN-fix the hostnames
* IDN-convert the hostnames
*************************************************************/
result = fix_hostname(conn, &conn->host);
result = idnconvert_hostname(conn, &conn->host);
if(result)
goto out;
if(conn->bits.conn_to_host) {
result = fix_hostname(conn, &conn->conn_to_host);
result = idnconvert_hostname(conn, &conn->conn_to_host);
if(result)
goto out;
}
if(conn->bits.httpproxy) {
result = fix_hostname(conn, &conn->http_proxy.host);
result = idnconvert_hostname(conn, &conn->http_proxy.host);
if(result)
goto out;
}
if(conn->bits.socksproxy) {
result = fix_hostname(conn, &conn->socks_proxy.host);
result = idnconvert_hostname(conn, &conn->socks_proxy.host);
if(result)
goto out;
}
/*************************************************************
* Check whether the host and the "connect to host" are equal.
* Do this after the hostnames have been IDN-fixed.
* Do this after the hostnames have been IDN-converted.
*************************************************************/
if(conn->bits.conn_to_host &&
strcasecompare(conn->conn_to_host.name, conn->host.name)) {
@ -4032,6 +4049,15 @@ static CURLcode create_conn(struct Curl_easy *data,
*************************************************************/
result = resolve_server(data, conn, async);
/* Strip trailing dots. resolve_server copied the name. */
strip_trailing_dot(&conn->host);
if(conn->bits.httpproxy)
strip_trailing_dot(&conn->http_proxy.host);
if(conn->bits.socksproxy)
strip_trailing_dot(&conn->socks_proxy.host);
if(conn->bits.conn_to_host)
strip_trailing_dot(&conn->conn_to_host);
out:
return result;
}

View file

@ -828,6 +828,7 @@ struct connectdata {
int socktype; /* SOCK_STREAM or SOCK_DGRAM */
struct hostname host;
char *hostname_resolve; /* host name to resolve to address, allocated */
char *secondaryhostname; /* secondary socket host name (ftp) */
struct hostname conn_to_host; /* the host to connect to. valid only if
bits.conn_to_host is set */