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:
|
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
|
"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
|
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
|
The HTTP part violates RFC 7230 section 5.4 but the SNI part is accordance
|
||||||
with RFC 6066 section 3.
|
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
|
Our current approach allows a knowing client to send a custom HTTP header
|
||||||
with the dot added.
|
with the dot added.
|
||||||
|
|
||||||
It can also be noted that while adding a trailing dot to the host name in
|
In a few cases there is a difference in name resolving to IP addresses with
|
||||||
most (all?) cases will make the name resolve to the same set of IP addresses,
|
a trailing dot, but it can be noted that many HTTP servers will not happily
|
||||||
many HTTP servers will not happily accept the trailing dot there unless that
|
accept the trailing dot there unless that has been specifically configured
|
||||||
has been specifically configured to be a fine virtual host.
|
to be a fine virtual host.
|
||||||
|
|
||||||
If URLs with trailing dots for host names become more popular or even just
|
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
|
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"
|
#include "memdebug.h"
|
||||||
|
|
||||||
static void conn_free(struct connectdata *conn);
|
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);
|
static unsigned int get_protocol_family(unsigned int protocol);
|
||||||
|
|
||||||
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
|
/* 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->trailer);
|
||||||
Curl_safefree(conn->host.rawalloc); /* host name buffer */
|
Curl_safefree(conn->host.rawalloc); /* host name buffer */
|
||||||
Curl_safefree(conn->conn_to_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->secondaryhostname);
|
||||||
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
|
Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
|
||||||
Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks 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);
|
infof(data, "Closing connection %ld\n", conn->connection_id);
|
||||||
Curl_conncache_remove_conn(conn, TRUE);
|
Curl_conncache_remove_conn(conn, TRUE);
|
||||||
|
|
||||||
free_fixed_hostname(&conn->host);
|
free_idnconverted_hostname(&conn->host);
|
||||||
free_fixed_hostname(&conn->conn_to_host);
|
free_idnconverted_hostname(&conn->conn_to_host);
|
||||||
free_fixed_hostname(&conn->http_proxy.host);
|
free_idnconverted_hostname(&conn->http_proxy.host);
|
||||||
free_fixed_hostname(&conn->socks_proxy.host);
|
free_idnconverted_hostname(&conn->socks_proxy.host);
|
||||||
|
|
||||||
DEBUGASSERT(conn->data == data);
|
DEBUGASSERT(conn->data == data);
|
||||||
/* this assumes that the pointer is still there after the connection was
|
/* 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;
|
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;
|
struct Curl_easy *data = conn->data;
|
||||||
|
|
||||||
#ifndef USE_LIBIDN2
|
#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 */
|
/* set the name we use to display the host name */
|
||||||
host->dispname = 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 */
|
/* Check name for non-ASCII and convert hostname to ACE form if we can */
|
||||||
if(!is_ASCII_name(host->name)) {
|
if(!is_ASCII_name(host->name)) {
|
||||||
#ifdef USE_LIBIDN2
|
#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 defined(USE_LIBIDN2)
|
||||||
if(host->encalloc) {
|
if(host->encalloc) {
|
||||||
@ -3373,7 +3380,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
|
|||||||
*************************************************************/
|
*************************************************************/
|
||||||
if(conn->bits.reuse)
|
if(conn->bits.reuse)
|
||||||
/* We're reusing the connection - no need to resolve anything, and
|
/* 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. */
|
case. */
|
||||||
*async = FALSE;
|
*async = FALSE;
|
||||||
|
|
||||||
@ -3428,7 +3435,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
|
|||||||
conn->port = conn->remote_port;
|
conn->port = conn->remote_port;
|
||||||
|
|
||||||
/* Resolve target host right on */
|
/* 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);
|
&hostaddr, timeout_ms);
|
||||||
if(rc == CURLRESOLV_PENDING)
|
if(rc == CURLRESOLV_PENDING)
|
||||||
*async = TRUE;
|
*async = TRUE;
|
||||||
@ -3449,7 +3459,10 @@ static CURLcode resolve_server(struct Curl_easy *data,
|
|||||||
&conn->socks_proxy.host : &conn->http_proxy.host;
|
&conn->socks_proxy.host : &conn->http_proxy.host;
|
||||||
|
|
||||||
/* resolve proxy */
|
/* 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);
|
&hostaddr, timeout_ms);
|
||||||
|
|
||||||
if(rc == CURLRESOLV_PENDING)
|
if(rc == CURLRESOLV_PENDING)
|
||||||
@ -3479,8 +3492,8 @@ static CURLcode resolve_server(struct Curl_easy *data,
|
|||||||
static void reuse_conn(struct connectdata *old_conn,
|
static void reuse_conn(struct connectdata *old_conn,
|
||||||
struct connectdata *conn)
|
struct connectdata *conn)
|
||||||
{
|
{
|
||||||
free_fixed_hostname(&old_conn->http_proxy.host);
|
free_idnconverted_hostname(&old_conn->http_proxy.host);
|
||||||
free_fixed_hostname(&old_conn->socks_proxy.host);
|
free_idnconverted_hostname(&old_conn->socks_proxy.host);
|
||||||
|
|
||||||
free(old_conn->http_proxy.host.rawalloc);
|
free(old_conn->http_proxy.host.rawalloc);
|
||||||
free(old_conn->socks_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
|
/* host can change, when doing keepalive with a proxy or if the case is
|
||||||
different this time etc */
|
different this time etc */
|
||||||
free_fixed_hostname(&conn->host);
|
free_idnconverted_hostname(&conn->host);
|
||||||
free_fixed_hostname(&conn->conn_to_host);
|
free_idnconverted_hostname(&conn->conn_to_host);
|
||||||
Curl_safefree(conn->host.rawalloc);
|
Curl_safefree(conn->host.rawalloc);
|
||||||
Curl_safefree(conn->conn_to_host.rawalloc);
|
Curl_safefree(conn->conn_to_host.rawalloc);
|
||||||
conn->host = old_conn->host;
|
conn->host = old_conn->host;
|
||||||
conn->conn_to_host = old_conn->conn_to_host;
|
conn->conn_to_host = old_conn->conn_to_host;
|
||||||
conn->conn_to_port = old_conn->conn_to_port;
|
conn->conn_to_port = old_conn->conn_to_port;
|
||||||
conn->remote_port = old_conn->remote_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 */
|
/* persist connection info in session handle */
|
||||||
Curl_persistconninfo(conn);
|
Curl_persistconninfo(conn);
|
||||||
@ -3681,30 +3698,30 @@ static CURLcode create_conn(struct Curl_easy *data,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* IDN-fix the hostnames
|
* IDN-convert the hostnames
|
||||||
*************************************************************/
|
*************************************************************/
|
||||||
result = fix_hostname(conn, &conn->host);
|
result = idnconvert_hostname(conn, &conn->host);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
if(conn->bits.conn_to_host) {
|
if(conn->bits.conn_to_host) {
|
||||||
result = fix_hostname(conn, &conn->conn_to_host);
|
result = idnconvert_hostname(conn, &conn->conn_to_host);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(conn->bits.httpproxy) {
|
if(conn->bits.httpproxy) {
|
||||||
result = fix_hostname(conn, &conn->http_proxy.host);
|
result = idnconvert_hostname(conn, &conn->http_proxy.host);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(conn->bits.socksproxy) {
|
if(conn->bits.socksproxy) {
|
||||||
result = fix_hostname(conn, &conn->socks_proxy.host);
|
result = idnconvert_hostname(conn, &conn->socks_proxy.host);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Check whether the host and the "connect to host" are equal.
|
* 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 &&
|
if(conn->bits.conn_to_host &&
|
||||||
strcasecompare(conn->conn_to_host.name, conn->host.name)) {
|
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);
|
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:
|
out:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -828,6 +828,7 @@ struct connectdata {
|
|||||||
int socktype; /* SOCK_STREAM or SOCK_DGRAM */
|
int socktype; /* SOCK_STREAM or SOCK_DGRAM */
|
||||||
|
|
||||||
struct hostname host;
|
struct hostname host;
|
||||||
|
char *hostname_resolve; /* host name to resolve to address, allocated */
|
||||||
char *secondaryhostname; /* secondary socket host name (ftp) */
|
char *secondaryhostname; /* secondary socket host name (ftp) */
|
||||||
struct hostname conn_to_host; /* the host to connect to. valid only if
|
struct hostname conn_to_host; /* the host to connect to. valid only if
|
||||||
bits.conn_to_host is set */
|
bits.conn_to_host is set */
|
||||||
|
Loading…
Reference in New Issue
Block a user