mirror of
https://github.com/moparisthebest/curl
synced 2025-01-11 05:58:01 -05:00
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:
parent
2366697806
commit
5b4cce2e36
@ -167,7 +167,8 @@ problems may have been fixed or changed somewhat since this was written!
|
||||
When given a URL with a trailing dot for the host name part:
|
||||
"https://example.com./", libcurl will strip off the dot and use the name
|
||||
without a dot internally and send it dot-less in HTTP Host: headers and in
|
||||
the TLS SNI field.
|
||||
the TLS SNI field. For the purpose of resolving the name to an address
|
||||
the hostname is used as is without any change.
|
||||
|
||||
The HTTP part violates RFC 7230 section 5.4 but the SNI part is accordance
|
||||
with RFC 6066 section 3.
|
||||
@ -186,10 +187,10 @@ problems may have been fixed or changed somewhat since this was written!
|
||||
Our current approach allows a knowing client to send a custom HTTP header
|
||||
with the dot added.
|
||||
|
||||
It can also be noted that while adding a trailing dot to the host name in
|
||||
most (all?) cases will make the name resolve to the same set of IP addresses,
|
||||
many HTTP servers will not happily accept the trailing dot there unless that
|
||||
has been specifically configured to be a fine virtual host.
|
||||
In a few cases there is a difference in name resolving to IP addresses with
|
||||
a trailing dot, but it can be noted that many HTTP servers will not happily
|
||||
accept the trailing dot there unless that has been specifically configured
|
||||
to be a fine virtual host.
|
||||
|
||||
If URLs with trailing dots for host names become more popular or even just
|
||||
used more than for just plain fun experiments, I'm sure we will have reason
|
||||
|
82
lib/url.c
82
lib/url.c
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user