summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMichael Kaufmann <mail@michael-kaufmann.ch>2016-01-25 14:37:24 +0100
committerDaniel Stenberg <daniel@haxx.se>2016-04-17 23:50:59 +0200
commitcd8d23624594e21c37a0453459229a90a38ad471 (patch)
tree57afa8a5d73bffd4f3b08ef691d68ff2d03d4c7f /lib
parentf86f50f05a466f8960d94179ca46e9561458c567 (diff)
downloadcurl-cd8d23624594e21c37a0453459229a90a38ad471.tar.gz
news: CURLOPT_CONNECT_TO and --connect-to
Makes curl connect to the given host+port instead of the host+port found in the URL.
Diffstat (limited to 'lib')
-rw-r--r--lib/conncache.c13
-rw-r--r--lib/connect.c12
-rw-r--r--lib/http.c2
-rw-r--r--lib/http_proxy.c25
-rw-r--r--lib/multi.c8
-rw-r--r--lib/url.c331
-rw-r--r--lib/urldata.h21
-rw-r--r--lib/vtls/vtls.c29
8 files changed, 407 insertions, 34 deletions
diff --git a/lib/conncache.c b/lib/conncache.c
index 6e03caf3c..89086590a 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -132,9 +132,16 @@ void Curl_conncache_destroy(struct conncache *connc)
/* returns an allocated key to find a bundle for this connection */
static char *hashkey(struct connectdata *conn)
{
- return aprintf("%s:%d",
- conn->bits.proxy?conn->proxy.name:conn->host.name,
- conn->localport);
+ const char *hostname;
+
+ if(conn->bits.proxy)
+ hostname = conn->proxy.name;
+ else if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
+
+ return aprintf("%s:%d", hostname, conn->localport);
}
/* Look up the bundle with all the connections to the same host this
diff --git a/lib/connect.c b/lib/connect.c
index 567186a69..3f3d3f65f 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -841,6 +841,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
if(result) {
/* no more addresses to try */
+ const char* hostname;
+
/* if the first address family runs out of addresses to try before
the happy eyeball timeout, go ahead and try the next family now */
if(conn->tempaddr[1] == NULL) {
@@ -849,9 +851,15 @@ CURLcode Curl_is_connected(struct connectdata *conn,
return result;
}
+ if(conn->bits.proxy)
+ hostname = conn->proxy.name;
+ else if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
+
failf(data, "Failed to connect to %s port %ld: %s",
- conn->bits.proxy?conn->proxy.name:conn->host.name,
- conn->port, Curl_strerror(conn, error));
+ hostname, conn->port, Curl_strerror(conn, error));
}
return result;
diff --git a/lib/http.c b/lib/http.c
index 91ab8326d..1b1cd2235 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1832,6 +1832,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
data->state.first_host = strdup(conn->host.name);
if(!data->state.first_host)
return CURLE_OUT_OF_MEMORY;
+
+ data->state.first_remote_port = conn->remote_port;
}
http->writebytecount = http->readbytecount = 0;
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index e082ba291..676f0cb5d 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -49,6 +49,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
/* for [protocol] tunneled through HTTP proxy */
struct HTTP http_proxy;
void *prot_save;
+ const char *hostname;
+ int remote_port;
CURLcode result;
/* BLOCKING */
@@ -67,8 +69,16 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
memset(&http_proxy, 0, sizeof(http_proxy));
conn->data->req.protop = &http_proxy;
connkeep(conn, "HTTP proxy CONNECT");
- result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
- conn->host.name, conn->remote_port, FALSE);
+ if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
+ if(conn->bits.conn_to_port)
+ remote_port = conn->conn_to_port;
+ else
+ remote_port = conn->remote_port;
+ result = Curl_proxyCONNECT(conn, FIRSTSOCKET, hostname,
+ remote_port, FALSE);
conn->data->req.protop = prot_save;
if(CURLE_OK != result)
return result;
@@ -153,9 +163,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
const char *useragent="";
const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
"1.0" : "1.1";
- char *hostheader= /* host:port with IPv6 support */
- aprintf("%s%s%s:%hu", conn->bits.ipv6_ip?"[":"",
- hostname, conn->bits.ipv6_ip?"]":"",
+ bool ipv6_ip = conn->bits.ipv6_ip;
+ char *hostheader;
+
+ /* the hostname may be different */
+ if(hostname != conn->host.name)
+ ipv6_ip = (strchr(hostname, ':') != NULL);
+ hostheader= /* host:port with IPv6 support */
+ aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
remote_port);
if(!hostheader) {
Curl_add_buffer_free(req_buffer);
diff --git a/lib/multi.c b/lib/multi.c
index b1c1f5396..aec377d96 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -1464,9 +1464,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
{
struct Curl_dns_entry *dns = NULL;
struct connectdata *conn = data->easy_conn;
+ const char *hostname;
+
+ if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
/* check if we have the name resolved by now */
- dns = Curl_fetch_addr(conn, conn->host.name, (int)conn->port);
+ dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
if(dns) {
#ifdef CURLRES_ASYNCH
diff --git a/lib/url.c b/lib/url.c
index b597becb2..c93491582 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -2674,6 +2674,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
#endif
}
+ case CURLOPT_CONNECT_TO:
+ data->set.connect_to = va_arg(param, struct curl_slist *);
+ break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
@@ -2729,6 +2732,7 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->allocptr.rtsp_transport);
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->proxy.rawalloc); /* proxy name buffer */
Curl_safefree(conn->master_buffer);
@@ -2787,6 +2791,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
Curl_conncache_remove_conn(data->state.conn_cache, conn);
free_fixed_hostname(&conn->host);
+ free_fixed_hostname(&conn->conn_to_host);
free_fixed_hostname(&conn->proxy);
Curl_ssl_close(conn, FIRSTSOCKET);
@@ -3146,9 +3151,15 @@ ConnectionExists(struct SessionHandle *data,
max_pipeline_length(data->multi):0;
size_t best_pipe_len = max_pipe_len;
struct curl_llist_element *curr;
+ const char *hostname;
+
+ if(needle->bits.conn_to_host)
+ hostname = needle->conn_to_host.name;
+ else
+ hostname = needle->host.name;
infof(data, "Found bundle for host %s: %p [%s]\n",
- needle->host.name, (void *)bundle,
+ hostname, (void *)bundle,
(bundle->multiuse== BUNDLE_PIPELINING?
"can pipeline":
(bundle->multiuse== BUNDLE_MULTIPLEX?
@@ -3267,6 +3278,16 @@ ConnectionExists(struct SessionHandle *data,
/* don't do mixed proxy and non-proxy connections */
continue;
+ if(needle->bits.conn_to_host != check->bits.conn_to_host)
+ /* don't mix connections that use the "connect to host" feature and
+ * connections that don't use this feature */
+ continue;
+
+ if(needle->bits.conn_to_port != check->bits.conn_to_port)
+ /* don't mix connections that use the "connect to port" feature and
+ * connections that don't use this feature */
+ continue;
+
if(!canPipeline && check->inuse)
/* this request can't be pipelined but the checked connection is
already in use so we skip it */
@@ -3302,7 +3323,7 @@ ConnectionExists(struct SessionHandle *data,
}
}
- if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL ||
+ if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) ||
(needle->bits.httpproxy && check->bits.httpproxy &&
needle->bits.tunnel_proxy && check->bits.tunnel_proxy &&
Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
@@ -3313,6 +3334,10 @@ ConnectionExists(struct SessionHandle *data,
if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) ||
(get_protocol_family(check->handler->protocol) ==
needle->handler->protocol && check->tls_upgraded)) &&
+ (!needle->bits.conn_to_host || Curl_raw_equal(
+ needle->conn_to_host.name, check->conn_to_host.name)) &&
+ (!needle->bits.conn_to_port ||
+ needle->conn_to_port == check->conn_to_port) &&
Curl_raw_equal(needle->host.name, check->host.name) &&
needle->remote_port == check->remote_port) {
/* The schemes match or the the protocol family is the same and the
@@ -3490,16 +3515,27 @@ CURLcode Curl_connected_proxy(struct connectdata *conn,
case CURLPROXY_SOCKS5:
case CURLPROXY_SOCKS5_HOSTNAME:
return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd,
- conn->host.name, conn->remote_port,
+ conn->bits.conn_to_host ? conn->conn_to_host.name :
+ conn->host.name,
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port,
FIRSTSOCKET, conn);
case CURLPROXY_SOCKS4:
- return Curl_SOCKS4(conn->proxyuser, conn->host.name,
- conn->remote_port, FIRSTSOCKET, conn, FALSE);
+ return Curl_SOCKS4(conn->proxyuser,
+ conn->bits.conn_to_host ? conn->conn_to_host.name :
+ conn->host.name,
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port,
+ FIRSTSOCKET, conn, FALSE);
case CURLPROXY_SOCKS4A:
- return Curl_SOCKS4(conn->proxyuser, conn->host.name,
- conn->remote_port, FIRSTSOCKET, conn, TRUE);
+ return Curl_SOCKS4(conn->proxyuser,
+ conn->bits.conn_to_host ? conn->conn_to_host.name :
+ conn->host.name,
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port,
+ FIRSTSOCKET, conn, TRUE);
#endif /* CURL_DISABLE_PROXY */
case CURLPROXY_HTTP:
@@ -4373,11 +4409,6 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
was very likely already set to the proxy port */
conn->port = p->defport;
- /* only if remote_port was not already parsed off the URL we use the
- default port number */
- if(conn->remote_port < 0)
- conn->remote_port = (unsigned short)conn->given->defport;
-
return CURLE_OK;
}
@@ -4652,7 +4683,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
if(strncmp("%25", ptr, 3))
infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
ptr++;
- /* Allow unresered characters as defined in RFC 3986 */
+ /* Allow unreserved characters as defined in RFC 3986 */
while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
(*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
ptr++;
@@ -4679,7 +4710,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
/* now set the local port number */
port = strtol(prox_portno, &endp, 10);
if((endp && *endp && (*endp != '/') && (*endp != ' ')) ||
- (port >= 65536) ) {
+ (port < 0) || (port > 65535)) {
/* meant to detect for example invalid IPv6 numerical addresses without
brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only
because we then allow "URL style" with the number followed by a
@@ -4702,7 +4733,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
a slash so we strip everything from the first slash */
atsign = strchr(proxyptr, '/');
if(atsign)
- *atsign = 0x0; /* cut off path part from host name */
+ *atsign = '\0'; /* cut off path part from host name */
if(data->set.proxyport)
/* None given in the proxy string, then get the default one if it is
@@ -5106,6 +5137,12 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
use the default port. Firefox and Chrome both do that. */
*portptr = '\0';
}
+
+ /* only if remote_port was not already parsed off the URL we use the
+ default port number */
+ if(conn->remote_port < 0)
+ conn->remote_port = (unsigned short)conn->given->defport;
+
return CURLE_OK;
}
@@ -5211,6 +5248,214 @@ static CURLcode set_login(struct connectdata *conn,
return result;
}
+/*
+ * Parses a "host:port" string to connect to.
+ * The hostname and the port may be empty; in this case, NULL is returned for
+ * the hostname and -1 for the port.
+ */
+static CURLcode parse_connect_to_host_port(struct SessionHandle *data,
+ const char *host,
+ char **hostname_result,
+ int *port_result)
+{
+ char *host_dup;
+ char *hostptr;
+ char *host_portno;
+ char *portptr;
+ int port = -1;
+
+ *hostname_result = NULL;
+ *port_result = -1;
+
+ if(!host || !*host)
+ return CURLE_OK;
+
+ host_dup = strdup(host);
+ if(!host_dup)
+ return CURLE_OUT_OF_MEMORY;
+
+ hostptr = host_dup;
+
+ /* start scanning for port number at this point */
+ portptr = hostptr;
+
+ /* detect and extract RFC6874-style IPv6-addresses */
+ if(*hostptr == '[') {
+ char *ptr = ++hostptr; /* advance beyond the initial bracket */
+ while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
+ ptr++;
+ if(*ptr == '%') {
+ /* There might be a zone identifier */
+ if(strncmp("%25", ptr, 3))
+ infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
+ ptr++;
+ /* Allow unreserved characters as defined in RFC 3986 */
+ while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
+ (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
+ ptr++;
+ }
+ if(*ptr == ']')
+ /* yeps, it ended nicely with a bracket as well */
+ *ptr++ = '\0';
+ else
+ infof(data, "Invalid IPv6 address format\n");
+ portptr = ptr;
+ /* Note that if this didn't end with a bracket, we still advanced the
+ * hostptr first, but I can't see anything wrong with that as no host
+ * name nor a numeric can legally start with a bracket.
+ */
+ }
+
+ /* Get port number off server.com:1080 */
+ host_portno = strchr(portptr, ':');
+ if(host_portno) {
+ char *endp = NULL;
+ *host_portno = '\0'; /* cut off number from host name */
+ host_portno++;
+ if(*host_portno) {
+ long portparse = strtol(host_portno, &endp, 10);
+ if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
+ infof(data, "No valid port number in connect to host string (%s)\n",
+ host_portno);
+ hostptr = NULL;
+ port = -1;
+ }
+ else
+ port = (int)portparse; /* we know it will fit */
+ }
+ }
+
+ /* now, clone the cleaned host name */
+ if(hostptr) {
+ *hostname_result = strdup(hostptr);
+ if(!*hostname_result) {
+ free(host_dup);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ *port_result = port;
+
+ free(host_dup);
+ return CURLE_OK;
+}
+
+/*
+ * Parses one "connect to" string in the form:
+ * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
+ */
+static CURLcode parse_connect_to_string(struct SessionHandle *data,
+ struct connectdata *conn,
+ const char *conn_to_host,
+ char **host_result,
+ int *port_result)
+{
+ CURLcode result = CURLE_OK;
+ const char *ptr = conn_to_host;
+ int host_match = FALSE;
+ int port_match = FALSE;
+
+ if(*ptr == ':') {
+ /* an empty hostname always matches */
+ host_match = TRUE;
+ ptr++;
+ }
+ else {
+ /* check whether the URL's hostname matches */
+ size_t hostname_to_match_len;
+ char *hostname_to_match = aprintf("%s%s%s",
+ conn->bits.ipv6_ip ? "[" : "",
+ conn->host.name,
+ conn->bits.ipv6_ip ? "]" : "");
+ if(!hostname_to_match)
+ return CURLE_OUT_OF_MEMORY;
+ hostname_to_match_len = strlen(hostname_to_match);
+ host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len);
+ free(hostname_to_match);
+ ptr += hostname_to_match_len;
+
+ host_match = host_match && *ptr == ':';
+ ptr++;
+ }
+
+ if(host_match) {
+ if(*ptr == ':') {
+ /* an empty port always matches */
+ port_match = TRUE;
+ ptr++;
+ }
+ else {
+ /* check whether the URL's port matches */
+ char *ptr_next = strchr(ptr, ':');
+ if(ptr_next) {
+ char *endp = NULL;
+ long port_to_match = strtol(ptr, &endp, 10);
+ if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
+ port_match = TRUE;
+ ptr = ptr_next + 1;
+ }
+ }
+ }
+ }
+
+ if(host_match && port_match) {
+ /* parse the hostname and port to connect to */
+ result = parse_connect_to_host_port(data, ptr, host_result, port_result);
+ }
+
+ return result;
+}
+
+/*
+ * Processes all strings in the "connect to" slist, and uses the "connect
+ * to host" and "connect to port" of the first string that matches.
+ */
+static CURLcode parse_connect_to_slist(struct SessionHandle *data,
+ struct connectdata *conn,
+ struct curl_slist *conn_to_host)
+{
+ CURLcode result = CURLE_OK;
+ char *host = NULL;
+ int port = 0;
+
+ while(conn_to_host && !host) {
+ result = parse_connect_to_string(data, conn, conn_to_host->data,
+ &host, &port);
+ if(result)
+ return result;
+
+ if(host && *host) {
+ bool ipv6host;
+ conn->conn_to_host.rawalloc = host;
+ conn->conn_to_host.name = host;
+ conn->bits.conn_to_host = TRUE;
+
+ ipv6host = strchr(host, ':') != NULL;
+ infof(data, "Connecting to hostname: %s%s%s\n",
+ ipv6host ? "[" : "", host, ipv6host ? "]" : "");
+ }
+ else {
+ /* no "connect to host" */
+ conn->bits.conn_to_host = FALSE;
+ free(host);
+ }
+
+ if(port >= 0) {
+ conn->conn_to_port = port;
+ conn->bits.conn_to_port = TRUE;
+ infof(data, "Connecting to port: %d\n", port);
+ }
+ else {
+ /* no "connect to port" */
+ conn->bits.conn_to_port = FALSE;
+ }
+
+ conn_to_host = conn_to_host->next;
+ }
+
+ return result;
+}
+
/*************************************************************
* Resolve the address of the server or proxy
*************************************************************/
@@ -5262,12 +5507,21 @@ static CURLcode resolve_server(struct SessionHandle *data,
else
#endif
if(!conn->proxy.name || !*conn->proxy.name) {
+ struct hostname *connhost;
+ if(conn->bits.conn_to_host)
+ connhost = &conn->conn_to_host;
+ else
+ connhost = &conn->host;
+
/* If not connecting via a proxy, extract the port from the URL, if it is
* there, thus overriding any defaults that might have been set above. */
- conn->port = conn->remote_port; /* it is the same port */
+ if(conn->bits.conn_to_port)
+ conn->port = conn->conn_to_port;
+ else
+ conn->port = conn->remote_port; /* it is the same port */
/* Resolve target host right on */
- rc = Curl_resolv_timeout(conn, conn->host.name, (int)conn->port,
+ rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
@@ -5276,7 +5530,7 @@ static CURLcode resolve_server(struct SessionHandle *data,
result = CURLE_OPERATION_TIMEDOUT;
else if(!hostaddr) {
- failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
+ failf(data, "Couldn't resolve host '%s'", connhost->dispname);
result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
}
@@ -5351,8 +5605,14 @@ 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);
Curl_safefree(conn->host.rawalloc);
+ Curl_safefree(conn->conn_to_host.rawalloc);
conn->host=old_conn->host;
+ conn->bits.conn_to_host = old_conn->bits.conn_to_host;
+ conn->conn_to_host = old_conn->conn_to_host;
+ conn->bits.conn_to_port = old_conn->bits.conn_to_port;
+ conn->conn_to_port = old_conn->conn_to_port;
/* persist connection info in session handle */
Curl_persistconninfo(conn);
@@ -5661,13 +5921,48 @@ static CURLcode create_conn(struct SessionHandle *data,
goto out;
/*************************************************************
+ * Process the "connect to" linked list of hostname/port mappings.
+ * Do this after the remote port number has been fixed in the URL.
+ *************************************************************/
+ result = parse_connect_to_slist(data, conn, data->set.connect_to);
+ if(result)
+ goto out;
+
+ /*************************************************************
* IDN-fix the hostnames
*************************************************************/
fix_hostname(data, conn, &conn->host);
+ if(conn->bits.conn_to_host)
+ fix_hostname(data, conn, &conn->conn_to_host);
if(conn->proxy.name && *conn->proxy.name)
fix_hostname(data, conn, &conn->proxy);
/*************************************************************
+ * Check whether the host and the "connect to host" are equal.
+ * Do this after the hostnames have been IDN-fixed .
+ *************************************************************/
+ if(conn->bits.conn_to_host &&
+ Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) {
+ conn->bits.conn_to_host = FALSE;
+ }
+
+ /*************************************************************
+ * Check whether the port and the "connect to port" are equal.
+ * Do this after the remote port number has been fixed in the URL.
+ *************************************************************/
+ if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
+ conn->bits.conn_to_port = FALSE;
+ }
+
+ /*************************************************************
+ * If the "connect to" feature is used with an HTTP proxy,
+ * we set the tunnel_proxy bit.
+ *************************************************************/
+ if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
+ conn->bits.httpproxy)
+ conn->bits.tunnel_proxy = TRUE;
+
+ /*************************************************************
* Setup internals depending on protocol. Needs to be done after
* we figured out what/if proxy to use.
*************************************************************/
diff --git a/lib/urldata.h b/lib/urldata.h
index 0efb65160..aea688ced 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -375,10 +375,12 @@ struct ssl_config_data {
/* information stored about one single SSL session */
struct curl_ssl_session {
char *name; /* host name for which this ID was used */
+ char *conn_to_host; /* host name for the connection (may be NULL) */
void *sessionid; /* as returned from the SSL layer */
size_t idsize; /* if known, otherwise 0 */
long age; /* just a number, the higher the more recent */
- int remote_port; /* remote port to connect to */
+ int remote_port; /* remote port */
+ int conn_to_port; /* remote port for the connection (may be -1) */
struct ssl_config_data ssl_config; /* setup for this session */
};
@@ -490,6 +492,10 @@ struct ConnectBits {
/* always modify bits.close with the connclose() and connkeep() macros! */
bool close; /* if set, we close the connection after this request */
bool reuse; /* if set, this is a re-used connection */
+ bool conn_to_host; /* if set, this connection has a "connect to host"
+ that overrides the host in the URL */
+ bool conn_to_port; /* if set, this connection has a "connect to port"
+ that overrides the port in the URL (remote port) */
bool proxy; /* if set, this transfer is done through a proxy - any type */
bool httpproxy; /* if set, this transfer is done through a http proxy */
bool user_passwd; /* do we use user+password for this connection? */
@@ -874,10 +880,14 @@ struct connectdata {
int socktype; /* SOCK_STREAM or SOCK_DGRAM */
struct hostname host;
+ struct hostname conn_to_host; /* the host to connect to. valid only if
+ bits.conn_to_host is set */
struct hostname proxy;
long port; /* which port to use locally */
- int remote_port; /* what remote port to connect to, not the proxy port! */
+ int remote_port; /* the remote port, not the proxy port! */
+ int conn_to_port; /* the remote port to connect to. valid only if
+ bits.conn_to_port is set */
/* 'primary_ip' and 'primary_port' get filled with peer's numerical
ip address and port number whenever an outgoing connection is
@@ -1226,11 +1236,13 @@ struct UrlState {
bytes / second */
bool this_is_a_follow; /* this is a followed Location: request */
- char *first_host; /* if set, this should be the host name that we will
+ char *first_host; /* host name of the first (not followed) request.
+ if set, this should be the host name that we will
sent authorization to, no else. Used to make Location:
following not keep sending user+password... This is
strdup() data.
*/
+ int first_remote_port; /* remote port of the first (not followed) request */
struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
long sessionage; /* number of the most recent session */
char *tempwrite; /* allocated buffer to keep data in when a write
@@ -1528,6 +1540,8 @@ struct UserDefined {
struct curl_slist *telnet_options; /* linked list of telnet options */
struct curl_slist *resolve; /* list of names to add/remove from
DNS cache */
+ struct curl_slist *connect_to; /* list of host:port mappings to override
+ the hostname and port to connect to */
curl_TimeCond timecondition; /* kind of time/date comparison */
time_t timevalue; /* what time to compare with */
Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
@@ -1575,7 +1589,6 @@ struct UserDefined {
bool http_set_referer; /* is a custom referer used */
bool http_auto_referer; /* set "correct" referer when following location: */
bool opt_no_body; /* as set with CURLOPT_NOBODY */
- bool set_port; /* custom port number used */
bool upload; /* upload request */
enum CURL_NETRC_OPTION
use_netrc; /* defined in include/curl.h */
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index 36465a7f6..69fb70fc7 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -363,6 +363,12 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
/* not session ID means blank entry */
continue;
if(Curl_raw_equal(conn->host.name, check->name) &&
+ ((!conn->bits.conn_to_host && !check->conn_to_host) ||
+ (conn->bits.conn_to_host && check->conn_to_host &&
+ Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) &&
+ ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
+ (conn->bits.conn_to_port && check->conn_to_port != -1 &&
+ conn->conn_to_port == check->conn_to_port)) &&
(conn->remote_port == check->remote_port) &&
Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
/* yes, we have a session ID! */
@@ -400,6 +406,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session)
Curl_free_ssl_config(&session->ssl_config);
Curl_safefree(session->name);
+ Curl_safefree(session->conn_to_host);
}
}
@@ -442,6 +449,8 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
struct curl_ssl_session *store = &data->state.session[0];
long oldest_age=data->state.session[0].age; /* zero if unused */
char *clone_host;
+ char *clone_conn_to_host;
+ int conn_to_port;
long *general_age;
/* Even though session ID re-use might be disabled, that only disables USING
@@ -452,6 +461,21 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
if(!clone_host)
return CURLE_OUT_OF_MEMORY; /* bail out */
+ if(conn->bits.conn_to_host) {
+ clone_conn_to_host = strdup(conn->conn_to_host.name);
+ if(!clone_conn_to_host) {
+ free(clone_host);
+ return CURLE_OUT_OF_MEMORY; /* bail out */
+ }
+ }
+ else
+ clone_conn_to_host = NULL;
+
+ if(conn->bits.conn_to_port)
+ conn_to_port = conn->conn_to_port;
+ else
+ conn_to_port = -1;
+
/* Now we should add the session ID and the host name to the cache, (remove
the oldest if necessary) */
@@ -484,10 +508,12 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
store->age = *general_age; /* set current age */
/* free it if there's one already present */
free(store->name);
+ free(store->conn_to_host);
store->name = clone_host; /* clone host name */
+ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+ store->conn_to_port = conn_to_port; /* connect to port number */
store->remote_port = conn->remote_port; /* port number */
-
/* Unlock */
if(SSLSESSION_SHARED(data))
Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
@@ -495,6 +521,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {
store->sessionid = NULL; /* let caller free sessionid */
free(clone_host);
+ free(clone_conn_to_host);
return CURLE_OUT_OF_MEMORY;
}