mirror of
https://github.com/curl/curl.git
synced 2026-05-06 02:37:28 +03:00
lib: introduce Curl_peer
`struct Curl_peer` keeps information about a communication endpoint together. It will replace `conn->host` and `conn->conn_to_host` and proxyinfo host. It will also become part of `struct ssl_peer`. It has a reference counter, so an instance can be shared between connections and filters. Elminiates `conn->host` and `conn->connect_to_host`, used in the proxyinfo structures. Passed to DNS resolution and socks filters, etc. Pass peer to http proxy and socks tunnel filters. Use peer in dns filter and resolving. Make `Curl_peer` a member in the `struct ssl_peer`. Add `docs/internals/PEERS.md` for documentation. Closes #21472
This commit is contained in:
parent
9c9a4f3eab
commit
bc40e09f63
67 changed files with 1902 additions and 1295 deletions
|
|
@ -61,6 +61,7 @@ INTERNALDOCS = \
|
|||
internals/MQTT.md \
|
||||
internals/MULTI-EV.md \
|
||||
internals/NEW-PROTOCOL.md \
|
||||
internals/PEERS.md \
|
||||
internals/PORTING.md \
|
||||
internals/RATELIMITS.md \
|
||||
internals/README.md \
|
||||
|
|
|
|||
105
docs/internals/PEERS.md
Normal file
105
docs/internals/PEERS.md
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<!--
|
||||
Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
|
||||
SPDX-License-Identifier: curl
|
||||
-->
|
||||
|
||||
# curl peers
|
||||
|
||||
A `peer` in curl internals is represented by a `struct Curl_peer`. It has the following members:
|
||||
|
||||
* `scheme`: a `struct Curl_scheme` of the URL schemes known to curl
|
||||
* `user_hostname`: the hostname as supplied by the user/application
|
||||
* `hostname`: a *normalized* version of `user_hostname`
|
||||
* `port`: the network port
|
||||
* `ipv6`: if `hostname` is an IPv6 address
|
||||
* `unix_socket`: if `hostname` is a path to a `unix domain socket`
|
||||
* `user_ipv6zone`: user supplied IPv6 zone name or `NULL`
|
||||
* `ipv6scope_id`: IPv6 address scope or 0
|
||||
* `abstract`: (if `unix_socket`) if the socket is abstract
|
||||
|
||||
A peer, in short, is a communication endpoint.
|
||||
|
||||
## peers and connections
|
||||
|
||||
A network connection always goes *somewhere*. That *somewhere* is called
|
||||
the `origin` of the connection (e.g. the source of responses/downloads).
|
||||
It is kept in `conn->origin` and is always present in a connection.
|
||||
|
||||
The `origin` is *logical* endpoint a connection talks to.
|
||||
|
||||
For most connections, the `origin` is connected to *directly*. It
|
||||
can be directed to another peer, however.
|
||||
|
||||
### `connect-to`
|
||||
|
||||
With the command line option `--connect-to` or the `libcurl` option
|
||||
`CURLOPT_CONNECT_TO`, a connection can be told to make the network connection
|
||||
to another endpoint *while keeping the `origin` unchanged*.
|
||||
|
||||
This other endpoint is also a peer and is available as `conn->via_peer`.
|
||||
This may be a peer for a different hostname and port or it may be a
|
||||
`unix domain socket`.
|
||||
|
||||
### proxies
|
||||
|
||||
When a connection uses a proxy, the endpoint for contacting the proxy server
|
||||
is also represented as a peer and is kept at `conn->socks_proxy.peer` and/or
|
||||
`conn->http_proxy.peer`. `SOCKS` proxies always come first, so a connection
|
||||
might connect as:
|
||||
|
||||
```
|
||||
1. curl -------------------------------------------> conn->origin
|
||||
2. curl -------------------------------------------> conn->via_peer (acting as conn->origin)
|
||||
3. curl --> socks_proxy.peer ----------------------> conn->via_peer/origin
|
||||
4. curl -----------------------> http_proxy.peer --> conn->via_peer/origin
|
||||
5. curl --> socks_proxy.peer --> http_proxy.peer --> conn->via_peer/origin
|
||||
```
|
||||
|
||||
The connection filter `SETUP`, that assembles the filters for a connection,
|
||||
figures out which peer to pass to which filter in order to make it all work.
|
||||
The individual filters get passed a specific peer and do not need be concerned
|
||||
with the whole chain.
|
||||
|
||||
For example, IP connection goes to `origin`(1), `via_peer`(2),
|
||||
`socks_proxy.peer`(3+5), `http_proxy.peer`(4) and that is the peer that gets
|
||||
passed to the `DNS` and `HAPPY-EYEBALLS` filters.
|
||||
|
||||
### TLS
|
||||
|
||||
TLS filters' task is to verify the peer they talk to (unless that is
|
||||
switched off). They either talk to the `conn->origin` or the
|
||||
`conn->http_proxy.peer` (`SOCKS` does not have TLS). The `conn->via_peer` is
|
||||
irrelevant. A `via_peer` endpoint needs to present a certificate matching
|
||||
`conn->origin` or the connect must fail.
|
||||
|
||||
### `unix domain socket`s
|
||||
|
||||
Peers that represent a `unix domain socket` may be used in two places:
|
||||
|
||||
1. `via_peer`: curl can connect to an `origin` server via `unix domain socket`s.
|
||||
This disables any proxy settings a transfer might carry.
|
||||
2. `socks_proxy.peer`: a `SOCKS` proxy may be contacted over a `unix domain
|
||||
socket`.
|
||||
|
||||
It is not supported to contact an http proxy over `unix domain socket`s.
|
||||
|
||||
## peers and credentials
|
||||
|
||||
There have been several vulnerabilities by leaking credentials in requests
|
||||
where they should not appear. In future work we plan to tie credentials to
|
||||
`peers` and use them only when their `peer` still matches the current
|
||||
connection use.
|
||||
|
||||
## peers internals
|
||||
|
||||
A `struct Curl_peer` is allocated with space of the `user_hostname`.
|
||||
Only when the user supplied value needs conversions (removing `[]` or
|
||||
IDN encoding) is `hostname` an extra allocation. This keeps the number
|
||||
of allocations the same as before.
|
||||
|
||||
A `Curl_peer` is not expected to be modified after it has been created.
|
||||
However, each `Curl_peer` has a reference counter. Code needs to use
|
||||
`Curl_peer_link()` and `Curl_peer_unlink()` to keep/release references.
|
||||
This makes it safe and cheap to keep references to peers in connections
|
||||
and filters.
|
||||
|
|
@ -233,6 +233,7 @@ LIB_CFILES = \
|
|||
noproxy.c \
|
||||
openldap.c \
|
||||
parsedate.c \
|
||||
peer.c \
|
||||
pingpong.c \
|
||||
pop3.c \
|
||||
progress.c \
|
||||
|
|
@ -364,6 +365,7 @@ LIB_HFILES = \
|
|||
netrc.h \
|
||||
noproxy.h \
|
||||
parsedate.h \
|
||||
peer.h \
|
||||
pingpong.h \
|
||||
pop3.h \
|
||||
progress.h \
|
||||
|
|
|
|||
154
lib/cf-dns.c
154
lib/cf-dns.c
|
|
@ -37,48 +37,41 @@
|
|||
|
||||
struct cf_dns_ctx {
|
||||
struct Curl_dns_entry *dns;
|
||||
struct Curl_peer *peer;
|
||||
CURLcode resolv_result;
|
||||
uint32_t resolv_id;
|
||||
uint16_t port;
|
||||
uint8_t dns_queries;
|
||||
uint8_t transport;
|
||||
BIT(started);
|
||||
BIT(announced);
|
||||
BIT(abstract_unix_socket);
|
||||
BIT(complete_resolve);
|
||||
BIT(for_proxy);
|
||||
char hostname[1];
|
||||
};
|
||||
|
||||
static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t dns_queries,
|
||||
const char *hostname,
|
||||
uint16_t port, uint8_t transport,
|
||||
bool abstract_unix_socket,
|
||||
uint8_t transport,
|
||||
bool for_proxy,
|
||||
bool complete_resolve,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct cf_dns_ctx *ctx;
|
||||
size_t hlen = strlen(hostname);
|
||||
|
||||
ctx = curlx_calloc(1, sizeof(*ctx) + hlen);
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx)
|
||||
return NULL;
|
||||
|
||||
ctx->port = port;
|
||||
Curl_peer_link(&ctx->peer, peer);
|
||||
ctx->dns_queries = dns_queries;
|
||||
ctx->transport = transport;
|
||||
ctx->abstract_unix_socket = abstract_unix_socket;
|
||||
ctx->for_proxy = for_proxy;
|
||||
ctx->complete_resolve = complete_resolve;
|
||||
ctx->dns = Curl_dns_entry_link(data, dns);
|
||||
ctx->started = !!ctx->dns;
|
||||
if(hlen)
|
||||
memcpy(ctx->hostname, hostname, hlen);
|
||||
|
||||
CURL_TRC_DNS(data, "created DNS filter for %s:%u, transport=%x, queries=%x",
|
||||
ctx->hostname, ctx->port, ctx->transport, ctx->dns_queries);
|
||||
peer->hostname, peer->port, ctx->transport, ctx->dns_queries);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
|
@ -86,6 +79,7 @@ static void cf_dns_ctx_destroy(struct Curl_easy *data,
|
|||
struct cf_dns_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
Curl_peer_unlink(&ctx->peer);
|
||||
Curl_dns_entry_unlink(data, &ctx->dns);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
|
|
@ -131,16 +125,14 @@ static void cf_dns_report(struct Curl_cfilter *cf,
|
|||
!dns->hostname[0] || Curl_host_is_ipnum(dns->hostname))
|
||||
return;
|
||||
|
||||
switch(ctx->transport) {
|
||||
case TRNSPRT_UNIX:
|
||||
if(ctx->peer->unix_socket) {
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
CURL_TRC_CF(data, cf, "resolved unix domain %s",
|
||||
Curl_conn_get_unix_path(data->conn));
|
||||
CURL_TRC_CF(data, cf, "resolved unix://%s", ctx->peer->hostname);
|
||||
#else
|
||||
DEBUGASSERT(0);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
}
|
||||
else {
|
||||
curlx_dyn_init(&tmp, 1024);
|
||||
infof(data, "Host %s:%u was resolved.", dns->hostname, dns->port);
|
||||
#ifdef CURLRES_IPV6
|
||||
|
|
@ -161,7 +153,6 @@ static void cf_dns_report(struct Curl_cfilter *cf,
|
|||
}
|
||||
#endif
|
||||
curlx_dyn_free(&tmp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
@ -181,24 +172,19 @@ static CURLcode cf_dns_start(struct Curl_cfilter *cf,
|
|||
|
||||
*pdns = NULL;
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(ctx->transport == TRNSPRT_UNIX) {
|
||||
CURL_TRC_CF(data, cf, "resolve unix socket %s", ctx->hostname);
|
||||
return Curl_resolv_unix(data, ctx->hostname,
|
||||
(bool)cf->conn->bits.abstract_unix_socket, pdns);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Resolve target host right on */
|
||||
CURL_TRC_CF(data, cf, "cf_dns_start host %s:%u", ctx->hostname, ctx->port);
|
||||
if(Curl_is_ipv4addr(ctx->hostname))
|
||||
CURL_TRC_CF(data, cf, "cf_dns_start %s %s:%u",
|
||||
ctx->peer->unix_socket ? "unix-domain-socket" : "host",
|
||||
ctx->peer->hostname, ctx->peer->port);
|
||||
if(ctx->peer->unix_socket)
|
||||
ctx->dns_queries = 0;
|
||||
else if(Curl_is_ipv4addr(ctx->peer->hostname))
|
||||
ctx->dns_queries |= CURL_DNSQ_A;
|
||||
#ifdef USE_IPV6
|
||||
else if(Curl_is_ipaddr(ctx->hostname)) /* not ipv4, must be ipv6 then */
|
||||
else if(ctx->peer->ipv6)
|
||||
ctx->dns_queries |= CURL_DNSQ_AAAA;
|
||||
#endif
|
||||
result = Curl_resolv(data, ctx->dns_queries,
|
||||
ctx->hostname, ctx->port, ctx->transport,
|
||||
|
||||
result = Curl_resolv(data, ctx->peer, ctx->dns_queries, ctx->transport,
|
||||
(bool)ctx->for_proxy, timeout_ms,
|
||||
&ctx->resolv_id, pdns);
|
||||
DEBUGASSERT(!result || !*pdns);
|
||||
|
|
@ -211,14 +197,14 @@ static CURLcode cf_dns_start(struct Curl_cfilter *cf,
|
|||
}
|
||||
else if(result == CURLE_OPERATION_TIMEDOUT) { /* took too long */
|
||||
failf(data, "Failed to resolve '%s' with timeout after %"
|
||||
FMT_TIMEDIFF_T " ms", ctx->hostname,
|
||||
FMT_TIMEDIFF_T " ms", ctx->peer->hostname,
|
||||
curlx_ptimediff_ms(Curl_pgrs_now(data),
|
||||
&data->progress.t_startsingle));
|
||||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(result);
|
||||
failf(data, "Could not resolve: %s", ctx->hostname);
|
||||
failf(data, "Could not resolve: %s", ctx->peer->hostname);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
@ -393,11 +379,9 @@ struct Curl_cftype Curl_cft_dns = {
|
|||
|
||||
static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t dns_queries,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t transport,
|
||||
bool abstract_unix_socket,
|
||||
bool for_proxy,
|
||||
bool complete_resolve,
|
||||
struct Curl_dns_entry *dns)
|
||||
|
|
@ -407,9 +391,8 @@ static CURLcode cf_dns_create(struct Curl_cfilter **pcf,
|
|||
CURLcode result = CURLE_OK;
|
||||
|
||||
(void)data;
|
||||
ctx = cf_dns_ctx_create(data, dns_queries, hostname, port, transport,
|
||||
abstract_unix_socket, for_proxy,
|
||||
complete_resolve, dns);
|
||||
ctx = cf_dns_ctx_create(data, peer, dns_queries, transport,
|
||||
for_proxy, complete_resolve, dns);
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
|
|
@ -424,60 +407,6 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
/* Create a "resolv" filter for the transfer's connection. Figures
|
||||
* out the hostname/path and port where to connect to. */
|
||||
static CURLcode cf_dns_conn_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
uint8_t dns_queries,
|
||||
uint8_t transport,
|
||||
bool complete_resolve,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
const char *hostname = NULL;
|
||||
uint16_t port = 0;
|
||||
bool abstract_unix_socket = FALSE, for_proxy = FALSE;
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
{
|
||||
const char *unix_path = Curl_conn_get_unix_path(conn);
|
||||
if(unix_path) {
|
||||
DEBUGASSERT(transport == TRNSPRT_UNIX);
|
||||
hostname = unix_path;
|
||||
abstract_unix_socket = (bool)conn->bits.abstract_unix_socket;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(!hostname && conn->bits.proxy) {
|
||||
for_proxy = TRUE;
|
||||
hostname = conn->bits.socksproxy ?
|
||||
conn->socks_proxy.host.name : conn->http_proxy.host.name;
|
||||
port = conn->bits.socksproxy ?
|
||||
conn->socks_proxy.port : conn->http_proxy.port;
|
||||
}
|
||||
#endif
|
||||
if(!hostname) {
|
||||
struct hostname *ehost;
|
||||
ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &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. */
|
||||
hostname = ehost->name;
|
||||
port = conn->bits.conn_to_port ?
|
||||
conn->conn_to_port : (uint16_t)conn->remote_port;
|
||||
}
|
||||
|
||||
if(!hostname) {
|
||||
DEBUGASSERT(0);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
return cf_dns_create(pcf, data, dns_queries,
|
||||
hostname, port, transport,
|
||||
abstract_unix_socket, for_proxy,
|
||||
complete_resolve, dns);
|
||||
}
|
||||
|
||||
/* Adds a "resolv" filter at the top of the connection's filter chain.
|
||||
* For FIRSTSOCKET, the `dns` parameter may be NULL. The filter will
|
||||
* figure out hostname and port to connect to and start the DNS resolve
|
||||
|
|
@ -487,25 +416,24 @@ static CURLcode cf_dns_conn_create(struct Curl_cfilter **pcf,
|
|||
CURLcode Curl_cf_dns_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t dns_queries,
|
||||
uint8_t transport,
|
||||
struct Curl_dns_entry *dns)
|
||||
{
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
bool for_proxy = FALSE;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
if(sockindex == FIRSTSOCKET)
|
||||
result = cf_dns_conn_create(&cf, data, dns_queries, transport, FALSE, dns);
|
||||
else if(dns) {
|
||||
result = cf_dns_create(&cf, data, dns_queries,
|
||||
dns->hostname, dns->port, transport,
|
||||
FALSE, FALSE, FALSE, dns);
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(0);
|
||||
result = CURLE_FAILED_INIT;
|
||||
}
|
||||
if(!peer)
|
||||
return CURLE_FAILED_INIT;
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
for_proxy = (peer == conn->socks_proxy.peer) ||
|
||||
(peer == conn->http_proxy.peer);
|
||||
#endif
|
||||
|
||||
result = cf_dns_create(&cf, data, peer, dns_queries, transport,
|
||||
for_proxy, FALSE, dns);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
|
|
@ -514,7 +442,7 @@ out:
|
|||
}
|
||||
|
||||
/* Insert a new "resolv" filter directly after `cf`. It will
|
||||
* start a DNS resolve for the given hostnmae and port on the
|
||||
* start a DNS resolve for the given peer on the
|
||||
* first connect attempt.
|
||||
* See socks.c on how this is used to make a non-blocking DNS
|
||||
* resolve during connect.
|
||||
|
|
@ -522,17 +450,15 @@ out:
|
|||
CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
uint8_t dns_queries,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport,
|
||||
bool complete_resolve)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_dns_create(&cf, data, dns_queries,
|
||||
hostname, port, transport,
|
||||
FALSE, FALSE, complete_resolve, NULL);
|
||||
result = cf_dns_create(&cf, data, peer, dns_queries, transport,
|
||||
FALSE, complete_resolve, NULL);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,12 @@ struct Curl_easy;
|
|||
struct connectdata;
|
||||
struct Curl_dns_entry;
|
||||
struct Curl_addrinfo;
|
||||
struct Curl_peer;
|
||||
|
||||
CURLcode Curl_cf_dns_add(struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
int sockindex,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t dns_queries,
|
||||
uint8_t transport,
|
||||
struct Curl_dns_entry *dns);
|
||||
|
|
@ -40,8 +42,7 @@ CURLcode Curl_cf_dns_add(struct Curl_easy *data,
|
|||
CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
uint8_t dns_queries,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport,
|
||||
bool complete_resolve);
|
||||
|
||||
|
|
|
|||
|
|
@ -52,11 +52,13 @@ typedef enum {
|
|||
|
||||
/* struct for HTTP CONNECT tunneling */
|
||||
struct h1_tunnel_state {
|
||||
struct Curl_peer *dest;
|
||||
struct dynbuf rcvbuf;
|
||||
struct dynbuf request_data;
|
||||
size_t nsent;
|
||||
size_t headerlines;
|
||||
struct Curl_chunker ch;
|
||||
int httpversion;
|
||||
enum keeponval {
|
||||
KEEPON_DONE,
|
||||
KEEPON_CONNECT,
|
||||
|
|
@ -177,17 +179,26 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
|
|||
}
|
||||
}
|
||||
|
||||
static void tunnel_free(struct Curl_cfilter *cf,
|
||||
static void tunnel_free(struct h1_tunnel_state *ts,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(ts) {
|
||||
Curl_peer_unlink(&ts->dest);
|
||||
curlx_dyn_free(&ts->rcvbuf);
|
||||
curlx_dyn_free(&ts->request_data);
|
||||
Curl_httpchunk_free(data, &ts->ch);
|
||||
curlx_free(ts);
|
||||
}
|
||||
}
|
||||
|
||||
static void cf_tunnel_free(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(cf) {
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
if(ts) {
|
||||
h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
|
||||
curlx_dyn_free(&ts->rcvbuf);
|
||||
curlx_dyn_free(&ts->request_data);
|
||||
Curl_httpchunk_free(data, &ts->ch);
|
||||
curlx_free(ts);
|
||||
tunnel_free(ts, data);
|
||||
cf->ctx = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -210,7 +221,8 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
|
|||
and we do not really use the newly cloned URL here then. Free it. */
|
||||
curlx_safefree(data->req.newurl);
|
||||
|
||||
result = Curl_http_proxy_create_CONNECT(&req, cf, data, 1);
|
||||
result = Curl_http_proxy_create_CONNECT(&req, cf, data,
|
||||
ts->dest, ts->httpversion);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -219,7 +231,7 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
|
|||
curlx_dyn_reset(&ts->request_data);
|
||||
ts->nsent = 0;
|
||||
ts->headerlines = 0;
|
||||
http_minor = (cf->conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? 0 : 1;
|
||||
http_minor = ts->httpversion % 10;
|
||||
|
||||
result = Curl_h1_req_write_head(req, http_minor, &ts->request_data);
|
||||
if(!result)
|
||||
|
|
@ -701,7 +713,7 @@ out:
|
|||
Curl_client_reset(data);
|
||||
Curl_pgrsReset(data);
|
||||
|
||||
tunnel_free(cf, data);
|
||||
cf_tunnel_free(cf, data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -737,7 +749,7 @@ static void cf_h1_proxy_destroy(struct Curl_cfilter *cf,
|
|||
struct Curl_easy *data)
|
||||
{
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
tunnel_free(cf, data);
|
||||
cf_tunnel_free(cf, data);
|
||||
}
|
||||
|
||||
static void cf_h1_proxy_close(struct Curl_cfilter *cf,
|
||||
|
|
@ -754,6 +766,30 @@ static void cf_h1_proxy_close(struct Curl_cfilter *cf,
|
|||
}
|
||||
}
|
||||
|
||||
static CURLcode cf_h1_proxy_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2)
|
||||
{
|
||||
struct h1_tunnel_state *ts = cf->ctx;
|
||||
switch(query) {
|
||||
case CF_QUERY_HOST_PORT:
|
||||
*pres1 = (int)ts->dest->port;
|
||||
*((const char **)pres2) = ts->dest->hostname;
|
||||
return CURLE_OK;
|
||||
case CF_QUERY_ALPN_NEGOTIATED: {
|
||||
const char **palpn = pres2;
|
||||
DEBUGASSERT(palpn);
|
||||
*palpn = NULL;
|
||||
return CURLE_OK;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return cf->next ?
|
||||
cf->next->cft->query(cf->next, data, query, pres1, pres2) :
|
||||
CURLE_UNKNOWN_OPTION;
|
||||
}
|
||||
|
||||
struct Curl_cftype Curl_cft_h1_proxy = {
|
||||
"H1-PROXY",
|
||||
CF_TYPE_IP_CONNECT | CF_TYPE_PROXY,
|
||||
|
|
@ -769,19 +805,43 @@ struct Curl_cftype Curl_cft_h1_proxy = {
|
|||
Curl_cf_def_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
Curl_cf_http_proxy_query,
|
||||
cf_h1_proxy_query,
|
||||
};
|
||||
|
||||
CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
int httpversion)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
struct h1_tunnel_state *ts;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
result = Curl_cf_create(&cf, &Curl_cft_h1_proxy, NULL);
|
||||
if(!result)
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
if(!dest)
|
||||
return CURLE_FAILED_INIT;
|
||||
if((httpversion < 10) || (httpversion >= 20))
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
ts = curlx_calloc(1, sizeof(*ts));
|
||||
if(!ts) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
Curl_peer_link(&ts->dest, dest);
|
||||
ts->httpversion = httpversion;
|
||||
curlx_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
|
||||
curlx_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
|
||||
Curl_httpchunk_init(data, &ts->ch, TRUE);
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_h1_proxy, ts);
|
||||
if(result)
|
||||
goto out;
|
||||
ts = NULL;
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
|
||||
out:
|
||||
tunnel_free(ts, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,12 @@
|
|||
|
||||
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
|
||||
|
||||
struct Curl_peer;
|
||||
|
||||
CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data);
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
int httpversion);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_h1_proxy;
|
||||
|
||||
|
|
|
|||
|
|
@ -76,24 +76,20 @@ struct tunnel_stream {
|
|||
BIT(reset);
|
||||
};
|
||||
|
||||
static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
|
||||
struct tunnel_stream *ts)
|
||||
static CURLcode tunnel_stream_init(struct tunnel_stream *ts,
|
||||
struct Curl_peer *dest)
|
||||
{
|
||||
const char *hostname;
|
||||
uint16_t port;
|
||||
bool ipv6_ip;
|
||||
|
||||
ts->state = H2_TUNNEL_INIT;
|
||||
ts->stream_id = -1;
|
||||
Curl_bufq_init2(&ts->recvbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS,
|
||||
BUFQ_OPT_SOFT_LIMIT);
|
||||
Curl_bufq_init(&ts->sendbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS);
|
||||
|
||||
Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip);
|
||||
|
||||
/* host:port with IPv6 support */
|
||||
ts->authority = curl_maprintf("%s%s%s:%u", ipv6_ip ? "[" : "", hostname,
|
||||
ipv6_ip ? "]" : "", port);
|
||||
ts->authority = curl_maprintf("%s%s%s:%u", dest->ipv6 ? "[" : "",
|
||||
dest->hostname,
|
||||
dest->ipv6 ? "]" : "",
|
||||
dest->port);
|
||||
if(!ts->authority)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
|
|
@ -171,6 +167,7 @@ struct cf_h2_proxy_ctx {
|
|||
struct bufq inbufq; /* network receive buffer */
|
||||
struct bufq outbufq; /* network send buffer */
|
||||
|
||||
struct Curl_peer *dest; /* where to tunnel to */
|
||||
struct tunnel_stream tunnel; /* our tunnel CONNECT stream */
|
||||
int32_t goaway_error;
|
||||
int32_t last_stream_id;
|
||||
|
|
@ -202,6 +199,7 @@ static void cf_h2_proxy_ctx_free(struct cf_h2_proxy_ctx *ctx)
|
|||
{
|
||||
if(ctx) {
|
||||
cf_h2_proxy_ctx_clear(ctx);
|
||||
Curl_peer_unlink(&ctx->dest);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
|
@ -750,7 +748,7 @@ static CURLcode submit_CONNECT(struct Curl_cfilter *cf,
|
|||
CURLcode result;
|
||||
struct httpreq *req = NULL;
|
||||
|
||||
result = Curl_http_proxy_create_CONNECT(&req, cf, data, 2);
|
||||
result = Curl_http_proxy_create_CONNECT(&req, cf, data, ctx->dest, 20);
|
||||
if(result)
|
||||
goto out;
|
||||
result = Curl_creader_set_null(data);
|
||||
|
|
@ -896,7 +894,7 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
|
|||
Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
|
||||
Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
|
||||
|
||||
if(tunnel_stream_init(cf, &ctx->tunnel))
|
||||
if(tunnel_stream_init(&ctx->tunnel, ctx->dest))
|
||||
goto out;
|
||||
|
||||
rc = nghttp2_session_callbacks_new(&cbs);
|
||||
|
|
@ -1410,8 +1408,8 @@ static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf,
|
|||
|
||||
switch(query) {
|
||||
case CF_QUERY_HOST_PORT:
|
||||
*pres1 = (int)cf->conn->http_proxy.port;
|
||||
*((const char **)pres2) = cf->conn->http_proxy.host.name;
|
||||
*pres1 = (int)ctx->dest->port;
|
||||
*((const char **)pres2) = ctx->dest->hostname;
|
||||
return CURLE_OK;
|
||||
case CF_QUERY_NEED_FLUSH: {
|
||||
if(!Curl_bufq_is_empty(&ctx->outbufq) ||
|
||||
|
|
@ -1477,7 +1475,8 @@ struct Curl_cftype Curl_cft_h2_proxy = {
|
|||
};
|
||||
|
||||
CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest)
|
||||
{
|
||||
struct Curl_cfilter *cf_h2_proxy = NULL;
|
||||
struct cf_h2_proxy_ctx *ctx;
|
||||
|
|
@ -1487,17 +1486,16 @@ CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
|
|||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx)
|
||||
goto out;
|
||||
Curl_peer_link(&ctx->dest, dest);
|
||||
|
||||
result = Curl_cf_create(&cf_h2_proxy, &Curl_cft_h2_proxy, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
ctx = NULL;
|
||||
Curl_conn_cf_insert_after(cf, cf_h2_proxy);
|
||||
result = CURLE_OK;
|
||||
|
||||
out:
|
||||
if(result)
|
||||
cf_h2_proxy_ctx_free(ctx);
|
||||
cf_h2_proxy_ctx_free(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@
|
|||
#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY)
|
||||
|
||||
CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_h2_proxy;
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "urldata.h"
|
||||
#include "cfilters.h"
|
||||
#include "cf-haproxy.h"
|
||||
#include "connect.h"
|
||||
#include "curl_addrinfo.h"
|
||||
#include "curl_trc.h"
|
||||
#include "select.h"
|
||||
|
|
@ -78,7 +79,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter *cf,
|
|||
DEBUGASSERT(ctx);
|
||||
DEBUGASSERT(ctx->state == HAPROXY_INIT);
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(cf->conn->unix_domain_socket)
|
||||
if(Curl_conn_get_first_peer(cf->conn, cf->sockindex)->unix_socket)
|
||||
/* the buffer is large enough to hold this! */
|
||||
result = curlx_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -674,40 +674,38 @@ static CURLcode is_connected(struct Curl_cfilter *cf,
|
|||
if(!result)
|
||||
return CURLE_OK;
|
||||
else {
|
||||
const char *hostname, *proxy_name = NULL;
|
||||
struct Curl_peer *peer = NULL, *proxy_peer = NULL;
|
||||
char viamsg[160];
|
||||
|
||||
peer = Curl_conn_get_first_peer(conn, cf->sockindex);
|
||||
if(!conn->origin || !peer)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(conn->bits.socksproxy)
|
||||
proxy_name = conn->socks_proxy.host.name;
|
||||
proxy_peer = conn->socks_proxy.peer;
|
||||
else if(conn->bits.httpproxy)
|
||||
proxy_name = conn->http_proxy.host.name;
|
||||
proxy_peer = conn->http_proxy.peer;
|
||||
#endif
|
||||
hostname = conn->bits.conn_to_host ? conn->conn_to_host.name :
|
||||
conn->host.name;
|
||||
|
||||
viamsg[0] = 0;
|
||||
if((peer != conn->origin) && (peer != proxy_peer)) {
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(conn->unix_domain_socket)
|
||||
curl_msnprintf(viamsg, sizeof(viamsg), "over %s",
|
||||
conn->unix_domain_socket);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
uint16_t port;
|
||||
if(cf->sockindex == SECONDARYSOCKET)
|
||||
port = conn->secondary_port;
|
||||
else if(cf->conn->bits.conn_to_port)
|
||||
port = conn->conn_to_port;
|
||||
if(peer->unix_socket)
|
||||
curl_msnprintf(viamsg, sizeof(viamsg), " over unix://%s",
|
||||
peer->hostname);
|
||||
else
|
||||
port = conn->remote_port;
|
||||
curl_msnprintf(viamsg, sizeof(viamsg), "port %d", port);
|
||||
#endif
|
||||
curl_msnprintf(viamsg, sizeof(viamsg), " via %s:%u",
|
||||
peer->hostname, peer->port);
|
||||
}
|
||||
|
||||
failf(data, "Failed to connect to %s %s %s%s%safter "
|
||||
failf(data, "Failed to connect to %s:%u%s %s%s%safter "
|
||||
"%" FMT_TIMEDIFF_T " ms: %s",
|
||||
hostname, viamsg,
|
||||
proxy_name ? "via " : "",
|
||||
proxy_name ? proxy_name : "",
|
||||
proxy_name ? " " : "",
|
||||
conn->origin->hostname, conn->origin->port, viamsg,
|
||||
proxy_peer ? "over proxy " : "",
|
||||
proxy_peer ? proxy_peer->hostname : "",
|
||||
proxy_peer ? " " : "",
|
||||
curlx_ptimediff_ms(Curl_pgrs_now(data),
|
||||
&data->progress.t_startsingle),
|
||||
curl_easy_strerror(result));
|
||||
|
|
|
|||
|
|
@ -1549,7 +1549,7 @@ static void cf_socket_update_data(struct Curl_cfilter *cf,
|
|||
struct cf_socket_ctx *ctx = cf->ctx;
|
||||
data->info.primary = ctx->ip;
|
||||
/* not sure if this is redundant... */
|
||||
data->info.conn_remote_port = cf->conn->remote_port;
|
||||
data->info.conn_remote_port = cf->conn->origin->port;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,29 +117,28 @@ CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
|
|||
}
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
static void conn_trc_filters(struct Curl_easy *data,
|
||||
int sockindex,
|
||||
const char *info)
|
||||
void Curl_conn_trc_filters(struct Curl_easy *data,
|
||||
int sockindex, const char *info)
|
||||
{
|
||||
if(CURL_TRC_M_is_verbose(data) && data->conn) {
|
||||
struct Curl_cfilter *cf = data->conn->cfilter[sockindex];
|
||||
|
||||
if(cf) {
|
||||
struct dynbuf msg;
|
||||
CURLcode result = CURLE_OK;
|
||||
char msg[256], *buf;
|
||||
int blen, n;
|
||||
|
||||
curlx_dyn_init(&msg, 1024);
|
||||
result = curlx_dyn_addf(&msg, "%s [%d]", info, sockindex);
|
||||
for(; cf && !result; cf = cf->next) {
|
||||
result = curlx_dyn_addf(&msg, "[%s%s]",
|
||||
cf->connected ? "" : "!", cf->cft->name);
|
||||
buf = msg;
|
||||
blen = sizeof(msg) - 1;
|
||||
n = curl_msnprintf(buf, blen, "%s [%d]", info, sockindex);
|
||||
buf += n;
|
||||
blen -= n;
|
||||
for(; cf && blen; cf = cf->next) {
|
||||
n = curl_msnprintf(buf, blen, "[%s%s]",
|
||||
cf->connected ? "" : "!", cf->cft->name);
|
||||
buf += n;
|
||||
blen -= n;
|
||||
}
|
||||
if(!result)
|
||||
CURL_TRC_M(data, "%s", curlx_dyn_ptr(&msg));
|
||||
else
|
||||
CURL_TRC_M(data, "%s [%d] error %d tracing chain",
|
||||
info, sockindex, result);
|
||||
curlx_dyn_free(&msg);
|
||||
CURL_TRC_M(data, "%s%s", msg, blen ? "" : "...");
|
||||
}
|
||||
else
|
||||
CURL_TRC_M(data, "%s [%d][-]", info, sockindex);
|
||||
|
|
@ -591,14 +590,14 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
|
|||
conn_report_connect_stats(cf, data);
|
||||
data->conn->keepalive = *Curl_pgrs_now(data);
|
||||
VERBOSE(result = cf_verboseconnect(data, cf));
|
||||
VERBOSE(conn_trc_filters(data, sockindex, "connected"));
|
||||
VERBOSE(Curl_conn_trc_filters(data, sockindex, "connected"));
|
||||
conn_remove_setup_filters(data, sockindex);
|
||||
VERBOSE(conn_trc_filters(data, sockindex, "reduced to"));
|
||||
VERBOSE(Curl_conn_trc_filters(data, sockindex, "reduced to"));
|
||||
goto out;
|
||||
}
|
||||
else if(result) {
|
||||
CURL_TRC_CF(data, cf, "Curl_conn_connect(), filter returned %d", result);
|
||||
VERBOSE(conn_trc_filters(data, sockindex, "failed to connect"));
|
||||
VERBOSE(Curl_conn_trc_filters(data, sockindex, "failed to connect"));
|
||||
conn_report_connect_stats(cf, data);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -953,8 +952,8 @@ void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
|
|||
&portarg, CURL_UNCONST(phost))) {
|
||||
/* Everything connected or query unsuccessful, the overall
|
||||
* connection's destination is the answer */
|
||||
*phost = data->conn->host.name;
|
||||
portarg = data->conn->remote_port;
|
||||
*phost = data->conn->origin->hostname;
|
||||
portarg = data->conn->origin->port;
|
||||
}
|
||||
if(pport)
|
||||
*pport = portarg;
|
||||
|
|
|
|||
|
|
@ -582,7 +582,7 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
|
|||
* Get the remote hostname and port that the connection is currently
|
||||
* talking to (or will talk to).
|
||||
* Once connected or before connect starts,
|
||||
* it is `conn->host.name` and `conn->remote_port`.
|
||||
* it is `conn->origin->hostname` and `conn->origin->port`.
|
||||
* During connect, when tunneling proxies are involved (http or socks),
|
||||
* it will be the name and port the proxy currently negotiates with.
|
||||
*/
|
||||
|
|
@ -604,6 +604,11 @@ int Curl_conn_get_stream_error(struct Curl_easy *data,
|
|||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
#ifdef CURLVERBOSE
|
||||
void Curl_conn_trc_filters(struct Curl_easy *data,
|
||||
int sockindex, const char *info);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the index of the given socket in the connection's sockets.
|
||||
* Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
|
||||
|
|
|
|||
|
|
@ -355,6 +355,7 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf,
|
|||
|
||||
/* connect current sub-chain */
|
||||
connect_sub_chain:
|
||||
VERBOSE(Curl_conn_trc_filters(data, cf->sockindex, "cf_setup_connect"));
|
||||
|
||||
if(cf->next && !cf->next->connected) {
|
||||
result = Curl_conn_cf_connect(cf->next, data, done);
|
||||
|
|
@ -374,27 +375,23 @@ connect_sub_chain:
|
|||
/* sub-chain connected, do we need to add more? */
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(ctx->state < CF_SETUP_CNNCT_SOCKS && cf->conn->bits.socksproxy) {
|
||||
/* for the secondary socket (FTP), use the "connect to host"
|
||||
* but ignore the "connect to port" (use the secondary port)
|
||||
*/
|
||||
const char *hostname =
|
||||
cf->conn->bits.httpproxy ?
|
||||
cf->conn->http_proxy.host.name :
|
||||
cf->conn->bits.conn_to_host ?
|
||||
cf->conn->conn_to_host.name :
|
||||
cf->sockindex == SECONDARYSOCKET ?
|
||||
cf->conn->secondaryhostname : cf->conn->host.name;
|
||||
uint16_t port =
|
||||
cf->conn->bits.httpproxy ? cf->conn->http_proxy.port :
|
||||
cf->sockindex == SECONDARYSOCKET ? cf->conn->secondary_port :
|
||||
cf->conn->bits.conn_to_port ? cf->conn->conn_to_port :
|
||||
cf->conn->remote_port;
|
||||
const char *user = cf->conn->socks_proxy.user;
|
||||
const char *passwd = cf->conn->socks_proxy.passwd;
|
||||
struct Curl_peer *dest; /* where SOCKS should tunnel to */
|
||||
|
||||
if(cf->conn->bits.httpproxy)
|
||||
dest = cf->conn->http_proxy.peer;
|
||||
else
|
||||
dest = Curl_conn_get_destination(cf->conn, cf->sockindex);
|
||||
if(!dest)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
result = Curl_cf_socks_proxy_insert_after(
|
||||
cf, data, hostname, port, cf->conn->ip_version,
|
||||
cf->conn->socks_proxy.proxytype, user, passwd);
|
||||
cf, data, dest, cf->conn->ip_version,
|
||||
cf->conn->socks_proxy.proxytype,
|
||||
cf->conn->socks_proxy.user,
|
||||
cf->conn->socks_proxy.passwd);
|
||||
|
||||
CURL_TRC_CF(data, cf, "added SOCKS filter to %s:%u -> %d",
|
||||
dest->hostname, dest->port, result);
|
||||
if(result)
|
||||
return result;
|
||||
ctx->state = CF_SETUP_CNNCT_SOCKS;
|
||||
|
|
@ -414,7 +411,10 @@ connect_sub_chain:
|
|||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if(cf->conn->bits.tunnel_proxy) {
|
||||
result = Curl_cf_http_proxy_insert_after(cf, data);
|
||||
struct Curl_peer *dest; /* where HTTP should tunnel to */
|
||||
dest = Curl_conn_get_destination(cf->conn, cf->sockindex);
|
||||
result = Curl_cf_http_proxy_insert_after(
|
||||
cf, data, dest, cf->conn->http_proxy.proxytype);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
|
@ -580,12 +580,16 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
|||
int ssl_mode)
|
||||
{
|
||||
CURLcode result = CURLE_OK;
|
||||
struct Curl_peer *peer = Curl_conn_get_first_peer(conn, sockindex);
|
||||
uint8_t dns_queries;
|
||||
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(conn->scheme);
|
||||
DEBUGASSERT(!conn->cfilter[sockindex]);
|
||||
|
||||
if(!peer)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
#ifndef CURL_DISABLE_HTTP
|
||||
if(!conn->cfilter[sockindex] &&
|
||||
conn->scheme->protocol == CURLPROTO_HTTPS) {
|
||||
|
|
@ -609,29 +613,13 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
|||
if(sockindex == FIRSTSOCKET)
|
||||
dns_queries |= CURL_DNSQ_HTTPS;
|
||||
#endif
|
||||
result = Curl_cf_dns_add(data, conn, sockindex, dns_queries,
|
||||
result = Curl_cf_dns_add(data, conn, sockindex, peer, dns_queries,
|
||||
conn->transport_wanted, dns);
|
||||
DEBUGASSERT(conn->cfilter[sockindex]);
|
||||
out:
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
const char *Curl_conn_get_unix_path(struct connectdata *conn)
|
||||
{
|
||||
const char *unix_path = conn->unix_domain_socket;
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(!unix_path && conn->bits.proxy && conn->socks_proxy.host.name &&
|
||||
!strncmp(UNIX_SOCKET_PREFIX "/",
|
||||
conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
|
||||
unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
|
||||
#endif
|
||||
|
||||
return unix_path;
|
||||
}
|
||||
#endif /* USE_UNIX_SOCKETS */
|
||||
|
||||
void Curl_conn_set_multiplex(struct connectdata *conn)
|
||||
{
|
||||
if(!conn->bits.multiplex) {
|
||||
|
|
@ -641,3 +629,29 @@ void Curl_conn_set_multiplex(struct connectdata *conn)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(conn->http_proxy.peer && !conn->bits.tunnel_proxy)
|
||||
return conn->http_proxy.peer;
|
||||
#endif
|
||||
return (sockindex == SECONDARYSOCKET) ?
|
||||
(conn->via_peer2 ? conn->via_peer2 : conn->origin2) :
|
||||
(conn->via_peer ? conn->via_peer : conn->origin);
|
||||
}
|
||||
|
||||
struct Curl_peer *Curl_conn_get_first_peer(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(conn->socks_proxy.peer)
|
||||
return conn->socks_proxy.peer;
|
||||
if(conn->http_proxy.peer)
|
||||
return conn->http_proxy.peer;
|
||||
#endif
|
||||
return (sockindex == SECONDARYSOCKET) ?
|
||||
(conn->via_peer2 ? conn->via_peer2 : conn->origin2) :
|
||||
(conn->via_peer ? conn->via_peer : conn->origin);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
struct Curl_dns_entry;
|
||||
struct ip_quadruple;
|
||||
struct Curl_peer;
|
||||
struct Curl_str;
|
||||
|
||||
enum alpnid Curl_alpn2alpnid(const unsigned char *name, size_t len);
|
||||
|
|
@ -126,14 +127,16 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
|||
/* Set conn to allow multiplexing. */
|
||||
void Curl_conn_set_multiplex(struct connectdata *conn);
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
#define UNIX_SOCKET_PREFIX "localhost"
|
||||
#endif
|
||||
const char *Curl_conn_get_unix_path(struct connectdata *conn);
|
||||
#else
|
||||
#define Curl_conn_get_unix_path(c) NULL
|
||||
#endif
|
||||
/* Get the peer the connection actually connects to at sockindex.
|
||||
* Often the same as "origin", but can be redirected via "connect-to"
|
||||
* or "alt-svc". May tunnel through proxies. */
|
||||
struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
/* Get the peer curl connects its socket to.
|
||||
* Can be origin, "connect-to" or the first proxy. */
|
||||
struct Curl_peer *Curl_conn_get_first_peer(struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_setup;
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "curl_addrinfo.h"
|
||||
#include "fake_addrinfo.h"
|
||||
#include "curlx/inet_pton.h"
|
||||
#include "curlx/strparse.h"
|
||||
|
||||
/*
|
||||
* Curl_freeaddrinfo()
|
||||
|
|
@ -443,6 +444,48 @@ bool Curl_is_ipaddr(const char *address)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
bool Curl_looks_like_ipv6(const char *s, size_t len, bool maybe_url_encoded,
|
||||
struct Curl_str *host, struct Curl_str *zone)
|
||||
{
|
||||
const char *zonep = NULL;
|
||||
size_t i = 0, hlen = 0, zlen = 0;
|
||||
|
||||
if(host)
|
||||
memset(host, 0, sizeof(*host));
|
||||
if(zone)
|
||||
memset(zone, 0, sizeof(*zone));
|
||||
|
||||
for(i = 0; i < len; ++i, ++hlen) {
|
||||
if(!s[i] || !(ISXDIGIT(s[i]) || (s[i] == ':') || (s[i] == '.')))
|
||||
break;
|
||||
}
|
||||
|
||||
if((i < len) && (s[i] == '%')) { /* address followed by a zone? */
|
||||
i += 1;
|
||||
if(maybe_url_encoded && !strncmp("25", s + i, 2))
|
||||
i += 2;
|
||||
zonep = s + i;
|
||||
for(; i < len; ++i, ++zlen) {
|
||||
/* Allow unreserved characters as defined in RFC 3986 */
|
||||
if(!s[i] || !(ISALPHA(s[i]) || ISXDIGIT(s[i]) || (s[i] == '-') ||
|
||||
(s[i] == '.') || (s[i] == '_') || (s[i] == '~')))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i != len)
|
||||
return FALSE; /* invalid chars in zone */
|
||||
if(host && hlen) {
|
||||
host->str = s;
|
||||
host->len = hlen;
|
||||
}
|
||||
if(zone && zlen) {
|
||||
zone->str = zonep;
|
||||
zone->len = zlen;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
/**
|
||||
* Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
# include <inet.h>
|
||||
#endif
|
||||
|
||||
struct Curl_str;
|
||||
|
||||
/*
|
||||
* Curl_addrinfo is our internal struct definition that we use to allow
|
||||
* consistent internal handling of this data. We use this even when the system
|
||||
|
|
@ -73,6 +75,9 @@ struct Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port);
|
|||
|
||||
bool Curl_is_ipv4addr(const char *address);
|
||||
bool Curl_is_ipaddr(const char *address);
|
||||
bool Curl_looks_like_ipv6(const char *s, size_t len, bool maybe_url_encoded,
|
||||
struct Curl_str *host, struct Curl_str *zone);
|
||||
|
||||
CURLcode Curl_str2addr(const char *dotted, uint16_t port,
|
||||
struct Curl_addrinfo **addrp);
|
||||
|
||||
|
|
|
|||
|
|
@ -332,7 +332,8 @@ static bool sasl_choose_krb5(struct Curl_easy *data, struct sasl_ctx *sctx)
|
|||
sctx->result = !krb5 ? CURLE_OUT_OF_MEMORY :
|
||||
Curl_auth_create_gssapi_user_message(data, sctx->conn->user,
|
||||
sctx->conn->passwd,
|
||||
service, sctx->conn->host.name,
|
||||
service,
|
||||
sctx->conn->origin->hostname,
|
||||
(bool)sctx->sasl->mutual_auth,
|
||||
NULL, krb5, &sctx->resp);
|
||||
}
|
||||
|
|
@ -711,7 +712,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
|
|||
struct kerberos5data *krb5 = Curl_auth_krb5_get(conn);
|
||||
result = !krb5 ? CURLE_OUT_OF_MEMORY :
|
||||
Curl_auth_create_gssapi_user_message(data, conn->user, conn->passwd,
|
||||
service, conn->host.name,
|
||||
service, conn->origin->hostname,
|
||||
(bool)sasl->mutual_auth, NULL,
|
||||
krb5, &resp);
|
||||
newstate = SASL_GSSAPI_TOKEN;
|
||||
|
|
|
|||
46
lib/ftp.c
46
lib/ftp.c
|
|
@ -2020,7 +2020,7 @@ static CURLcode ftp_control_addr_dup(struct Curl_easy *data, char **newhostp)
|
|||
not the ftp host. */
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
|
||||
*newhostp = curlx_strdup(conn->host.name);
|
||||
*newhostp = curlx_strdup(conn->origin->hostname);
|
||||
else
|
||||
#endif
|
||||
if(!Curl_conn_get_ip_info(data, conn, FIRSTSOCKET, &is_ipv6, &ipquad) &&
|
||||
|
|
@ -2060,7 +2060,6 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
|||
struct connectdata *conn = data->conn;
|
||||
CURLcode result;
|
||||
struct Curl_dns_entry *dns = NULL;
|
||||
unsigned short connectport; /* the local port connect() should use! */
|
||||
const struct pingpong *pp = &ftpc->pp;
|
||||
char *newhost = NULL;
|
||||
unsigned short newport = 0;
|
||||
|
|
@ -2125,7 +2124,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
|||
/* told to ignore the remotely given IP but instead use the host we used
|
||||
for the control connection */
|
||||
infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead",
|
||||
ip[0], ip[1], ip[2], ip[3], conn->host.name);
|
||||
ip[0], ip[1], ip[2], ip[3], conn->origin->hostname);
|
||||
result = ftp_control_addr_dup(data, &newhost);
|
||||
if(result)
|
||||
return result;
|
||||
|
|
@ -2154,8 +2153,13 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
|||
* expired now, instead we remake the lookup here and now! */
|
||||
struct ip_quadruple ipquad;
|
||||
bool is_ipv6;
|
||||
const char * const host_name = conn->bits.socksproxy ?
|
||||
conn->socks_proxy.host.name : conn->http_proxy.host.name;
|
||||
const struct Curl_peer *dest = conn->bits.socksproxy ?
|
||||
conn->socks_proxy.peer : conn->http_proxy.peer;
|
||||
|
||||
if(!dest) {
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = Curl_conn_get_ip_info(data, data->conn, FIRSTSOCKET,
|
||||
&is_ipv6, &ipquad);
|
||||
|
|
@ -2164,13 +2168,12 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
|||
|
||||
(void)Curl_resolv_blocking(
|
||||
data, is_ipv6 ? CURL_DNSQ_AAAA : CURL_DNSQ_A,
|
||||
host_name, ipquad.remote_port, Curl_conn_get_transport(data, conn),
|
||||
dest->hostname, dest->port, Curl_conn_get_transport(data, conn),
|
||||
&dns);
|
||||
/* we connect to the proxy's port */
|
||||
connectport = (unsigned short)ipquad.remote_port;
|
||||
|
||||
if(!dns) {
|
||||
failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport);
|
||||
failf(data, "cannot resolve proxy host %s:%hu",
|
||||
dest->hostname, dest->port);
|
||||
result = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -2192,20 +2195,31 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
|||
(void)Curl_resolv_blocking(
|
||||
data, Curl_resolv_dns_queries(data, conn->ip_version),
|
||||
newhost, newport, Curl_conn_get_transport(data, conn), &dns);
|
||||
connectport = newport; /* we connect to the remote port */
|
||||
|
||||
if(!dns) {
|
||||
failf(data, "cannot resolve new host %s:%hu", newhost, connectport);
|
||||
failf(data, "cannot resolve new host %s:%hu", newhost, newport);
|
||||
result = CURLE_FTP_CANT_GET_HOST;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGASSERT(newhost);
|
||||
curlx_free(conn->secondaryhostname);
|
||||
conn->secondary_port = newport;
|
||||
conn->secondaryhostname = newhost;
|
||||
newhost = NULL;
|
||||
Curl_peer_unlink(&conn->origin2);
|
||||
result = Curl_peer_create(data, conn->scheme, newhost, newport,
|
||||
&conn->origin2);
|
||||
if(result)
|
||||
goto error;
|
||||
|
||||
/* If FIRSTSOCKET goes via another peer, SECONDARY needs as well,
|
||||
* but with its new port. */
|
||||
if(conn->via_peer) {
|
||||
Curl_peer_unlink(&conn->via_peer2);
|
||||
result = Curl_peer_create(data, conn->via_peer->scheme,
|
||||
conn->via_peer->hostname, newport,
|
||||
&conn->via_peer2);
|
||||
if(result)
|
||||
goto error;
|
||||
}
|
||||
|
||||
result = Curl_conn_setup(data, conn, SECONDARYSOCKET, dns,
|
||||
conn->bits.ftp_use_data_ssl ?
|
||||
|
|
@ -2233,7 +2247,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
|
|||
char buf[256];
|
||||
Curl_printable_address(dns->addr, buf, sizeof(buf));
|
||||
infof(data, "Connecting to %s (%s) port %d",
|
||||
conn->secondaryhostname, buf, connectport);
|
||||
conn->origin2->hostname, buf, conn->origin2->port);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
23
lib/hostip.c
23
lib/hostip.c
|
|
@ -956,16 +956,14 @@ clean_up:
|
|||
* any other CURLcode error, *pdns == NULL
|
||||
*/
|
||||
CURLcode Curl_resolv(struct Curl_easy *data,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t dns_queries,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t transport,
|
||||
bool for_proxy,
|
||||
timediff_t timeout_ms,
|
||||
uint32_t *presolv_id,
|
||||
struct Curl_dns_entry **pdns)
|
||||
{
|
||||
DEBUGASSERT(hostname && *hostname);
|
||||
*presolv_id = 0;
|
||||
*pdns = NULL;
|
||||
|
||||
|
|
@ -975,14 +973,24 @@ CURLcode Curl_resolv(struct Curl_easy *data,
|
|||
else if(!timeout_ms)
|
||||
timeout_ms = CURL_TIMEOUT_RESOLVE_MS;
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(peer->unix_socket)
|
||||
return Curl_resolv_unix(data, peer->hostname, (bool)peer->abstract_uds,
|
||||
pdns);
|
||||
#else
|
||||
if(peer->unix_socket)
|
||||
return hostip_resolv_failed(data, peer->hostname, for_proxy);
|
||||
#endif
|
||||
|
||||
#ifdef USE_ALARM_TIMEOUT
|
||||
if(timeout_ms && data->set.no_signal) {
|
||||
/* Cannot use ALARM when signals are disabled */
|
||||
timeout_ms = 0;
|
||||
}
|
||||
if(timeout_ms && !Curl_doh_wanted(data)) {
|
||||
return resolv_alarm_timeout(data, dns_queries, hostname, port, transport,
|
||||
for_proxy, timeout_ms, presolv_id, pdns);
|
||||
return resolv_alarm_timeout(data, dns_queries, peer->hostname, peer->port,
|
||||
transport, for_proxy, timeout_ms, presolv_id,
|
||||
pdns);
|
||||
}
|
||||
#endif /* !USE_ALARM_TIMEOUT */
|
||||
|
||||
|
|
@ -991,8 +999,9 @@ CURLcode Curl_resolv(struct Curl_easy *data,
|
|||
infof(data, "timeout on name lookup is not supported");
|
||||
#endif
|
||||
|
||||
return hostip_resolv(data, dns_queries, hostname, port, transport,
|
||||
for_proxy, timeout_ms, TRUE, presolv_id, pdns);
|
||||
return hostip_resolv(data, dns_queries, peer->hostname, peer->port,
|
||||
transport, for_proxy, timeout_ms, TRUE, presolv_id,
|
||||
pdns);
|
||||
}
|
||||
|
||||
#ifdef USE_CURL_ASYNC
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ struct easy_pollset;
|
|||
struct Curl_https_rrinfo;
|
||||
struct Curl_multi;
|
||||
struct Curl_dns_entry;
|
||||
struct Curl_peer;
|
||||
|
||||
/* DNS query types */
|
||||
#define CURL_DNSQ_A (1U << 0)
|
||||
|
|
@ -96,9 +97,8 @@ void Curl_printable_address(const struct Curl_addrinfo *ai,
|
|||
* - other: the operation failed, `*pdns` is NULL, `*presolv_id` is 0.
|
||||
*/
|
||||
CURLcode Curl_resolv(struct Curl_easy *data,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t dns_queries,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
uint8_t transport,
|
||||
bool for_proxy,
|
||||
timediff_t timeout_ms,
|
||||
|
|
|
|||
|
|
@ -610,6 +610,12 @@ CURLcode Curl_hsts_loadfiles(struct Curl_easy *data)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool Curl_hsts_applies(struct hsts *h, const struct Curl_peer *dest)
|
||||
{
|
||||
return !!Curl_hsts(h, dest->hostname,
|
||||
strlen(dest->hostname), TRUE);
|
||||
}
|
||||
|
||||
#if defined(DEBUGBUILD) || defined(UNITTESTS)
|
||||
#undef time
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
|
||||
#include "llist.h"
|
||||
|
||||
struct Curl_peer;
|
||||
|
||||
#define MAX_HSTS_ENTRIES 10000
|
||||
|
||||
#if defined(DEBUGBUILD) || defined(UNITTESTS)
|
||||
|
|
@ -61,6 +63,9 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
|
|||
CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
|
||||
struct hsts *h);
|
||||
CURLcode Curl_hsts_loadfiles(struct Curl_easy *data);
|
||||
|
||||
bool Curl_hsts_applies(struct hsts *h, const struct Curl_peer *dest);
|
||||
|
||||
#else
|
||||
#define Curl_hsts_cleanup(x)
|
||||
#define Curl_hsts_loadcb(x, y) CURLE_OK
|
||||
|
|
|
|||
42
lib/http.c
42
lib/http.c
|
|
@ -2005,17 +2005,9 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
|
|||
struct dynamically_allocated_data *aptr = &data->state.aptr;
|
||||
const char *ptr;
|
||||
|
||||
if(!data->state.this_is_a_follow) {
|
||||
/* Free to avoid leaking memory on multiple requests */
|
||||
curlx_free(data->state.first_host);
|
||||
if(!data->state.this_is_a_follow)
|
||||
Curl_peer_link(&data->state.first_origin, conn->origin);
|
||||
|
||||
data->state.first_host = curlx_strdup(conn->host.name);
|
||||
if(!data->state.first_host)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
data->state.first_remote_port = conn->remote_port;
|
||||
data->state.first_remote_protocol = conn->scheme->protocol;
|
||||
}
|
||||
curlx_safefree(aptr->host);
|
||||
#ifndef CURL_DISABLE_COOKIES
|
||||
curlx_safefree(data->req.cookiehost);
|
||||
|
|
@ -2023,7 +2015,7 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
|
|||
|
||||
ptr = Curl_checkheaders(data, STRCONST("Host"));
|
||||
if(ptr && (!data->state.this_is_a_follow ||
|
||||
curl_strequal(data->state.first_host, conn->host.name))) {
|
||||
Curl_peer_equal(data->state.first_origin, conn->origin))) {
|
||||
#ifndef CURL_DISABLE_COOKIES
|
||||
/* If we have a given custom Host: header, we extract the hostname in
|
||||
order to possibly use it for cookie reasons later on. We only allow the
|
||||
|
|
@ -2068,17 +2060,17 @@ static CURLcode http_set_aptr_host(struct Curl_easy *data)
|
|||
else {
|
||||
/* Use the hostname as present in the URL if it was IPv6. */
|
||||
char *host = (data->state.up.hostname[0] == '[') ?
|
||||
data->state.up.hostname : conn->host.name;
|
||||
data->state.up.hostname : conn->origin->hostname;
|
||||
|
||||
if(((conn->given->protocol & (CURLPROTO_HTTPS | CURLPROTO_WSS)) &&
|
||||
(conn->remote_port == PORT_HTTPS)) ||
|
||||
(conn->origin->port == PORT_HTTPS)) ||
|
||||
((conn->given->protocol & (CURLPROTO_HTTP | CURLPROTO_WS)) &&
|
||||
(conn->remote_port == PORT_HTTP)))
|
||||
(conn->origin->port == PORT_HTTP)))
|
||||
/* if(HTTPS on port 443) OR (HTTP on port 80) then do not include
|
||||
the port number in the host string */
|
||||
aptr->host = curl_maprintf("Host: %s\r\n", host);
|
||||
else
|
||||
aptr->host = curl_maprintf("Host: %s:%d\r\n", host, conn->remote_port);
|
||||
aptr->host = curl_maprintf("Host: %s:%d\r\n", host, conn->origin->port);
|
||||
|
||||
if(!aptr->host)
|
||||
/* without Host: we cannot make a nice request */
|
||||
|
|
@ -2120,8 +2112,8 @@ static CURLcode http_target(struct Curl_easy *data,
|
|||
if(!h)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
if(conn->host.dispname != conn->host.name) {
|
||||
uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
|
||||
if(conn->origin->user_hostname != conn->origin->hostname) {
|
||||
uc = curl_url_set(h, CURLUPART_HOST, conn->origin->hostname, 0);
|
||||
if(uc) {
|
||||
curl_url_cleanup(h);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
|
@ -2551,7 +2543,7 @@ static CURLcode http_cookies(struct Curl_easy *data,
|
|||
if(data->cookies && data->state.cookie_engine) {
|
||||
bool okay;
|
||||
const char *host = data->req.cookiehost ?
|
||||
data->req.cookiehost : data->conn->host.name;
|
||||
data->req.cookiehost : data->conn->origin->hostname;
|
||||
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
|
||||
result = Curl_cookie_getlist(data, data->conn, &okay, host, &list);
|
||||
if(!result && okay) {
|
||||
|
|
@ -2966,10 +2958,10 @@ static CURLcode http_add_hd(struct Curl_easy *data,
|
|||
|
||||
#ifndef CURL_DISABLE_ALTSVC
|
||||
case H1_HD_ALT_USED:
|
||||
if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used")))
|
||||
if(conn->bits.altused && conn->via_peer &&
|
||||
!Curl_checkheaders(data, STRCONST("Alt-Used")))
|
||||
result = curlx_dyn_addf(req, "Alt-Used: %s:%u\r\n",
|
||||
conn->conn_to_host.name,
|
||||
conn->conn_to_port);
|
||||
conn->via_peer->hostname, conn->via_peer->port);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
|
@ -3224,8 +3216,8 @@ static CURLcode http_header_a(struct Curl_easy *data,
|
|||
struct SingleRequest *k = &data->req;
|
||||
enum alpnid id = (k->httpversion == 30) ? ALPN_h3 :
|
||||
(k->httpversion == 20) ? ALPN_h2 : ALPN_h1;
|
||||
return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
|
||||
curlx_uitous((unsigned int)conn->remote_port));
|
||||
return Curl_altsvc_parse(data, data->asi, v, id, conn->origin->hostname,
|
||||
curlx_uitous((unsigned int)conn->origin->port));
|
||||
}
|
||||
#else
|
||||
(void)data;
|
||||
|
|
@ -3552,7 +3544,7 @@ static CURLcode http_header_s(struct Curl_easy *data,
|
|||
/* If there is a custom-set Host: name, use it here, or else use
|
||||
* real peer hostname. */
|
||||
const char *host = data->req.cookiehost ?
|
||||
data->req.cookiehost : conn->host.name;
|
||||
data->req.cookiehost : conn->origin->hostname;
|
||||
const bool secure_context = Curl_secure_context(conn, host);
|
||||
CURLcode result;
|
||||
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
|
||||
|
|
@ -3576,7 +3568,7 @@ static CURLcode http_header_s(struct Curl_easy *data,
|
|||
) ? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
|
||||
if(v) {
|
||||
CURLcode result =
|
||||
Curl_hsts_parse(data->hsts, conn->host.name, v);
|
||||
Curl_hsts_parse(data->hsts, conn->origin->hostname, v);
|
||||
if(result) {
|
||||
if(result == CURLE_OUT_OF_MEMORY)
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -1438,14 +1438,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
|
|||
!strncmp(HTTP_PSEUDO_AUTHORITY, (const char *)name, namelen)) {
|
||||
/* pseudo headers are lower case */
|
||||
int rc = 0;
|
||||
char *check = curl_maprintf("%s:%d", cf->conn->host.name,
|
||||
cf->conn->remote_port);
|
||||
char *check = curl_maprintf("%s:%d", cf->conn->origin->hostname,
|
||||
cf->conn->origin->port);
|
||||
if(!check)
|
||||
/* no memory */
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
if(!curl_strequal(check, (const char *)value) &&
|
||||
((cf->conn->remote_port != cf->conn->given->defport) ||
|
||||
!curl_strequal(cf->conn->host.name, (const char *)value))) {
|
||||
((cf->conn->origin->port != cf->conn->given->defport) ||
|
||||
!curl_strequal(cf->conn->origin->hostname, (const char *)value))) {
|
||||
/* This is push is not for the same authority that was asked for in
|
||||
* the URL. RFC 7540 section 8.2 says: "A client MUST treat a
|
||||
* PUSH_PROMISE for which the server is not authoritative as a stream
|
||||
|
|
|
|||
|
|
@ -827,7 +827,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
|
|||
struct Curl_str provider1;
|
||||
struct Curl_str region = { NULL, 0 };
|
||||
struct Curl_str service = { NULL, 0 };
|
||||
const char *hostname = conn->host.name;
|
||||
const char *hostname = conn->origin->hostname;
|
||||
time_t clock;
|
||||
struct tm tm;
|
||||
char timestamp[TIMESTAMP_SIZE];
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
|
|||
passwdp = conn->http_proxy.passwd;
|
||||
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
|
||||
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
|
||||
host = conn->http_proxy.host.name;
|
||||
host = conn->http_proxy.peer->hostname;
|
||||
state = conn->proxy_negotiate_state;
|
||||
#else
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
|
|
@ -79,7 +79,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
|
|||
passwdp = conn->passwd;
|
||||
service = data->set.str[STRING_SERVICE_NAME] ?
|
||||
data->set.str[STRING_SERVICE_NAME] : "HTTP";
|
||||
host = conn->host.name;
|
||||
host = conn->origin->hostname;
|
||||
state = conn->http_negotiate_state;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
|
|||
passwdp = data->state.aptr.proxypasswd;
|
||||
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
|
||||
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
|
||||
hostname = conn->http_proxy.host.name;
|
||||
hostname = conn->http_proxy.peer->hostname;
|
||||
state = &conn->proxy_ntlm_state;
|
||||
authp = &data->state.authproxy;
|
||||
#else
|
||||
|
|
@ -157,7 +157,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
|
|||
passwdp = data->state.aptr.passwd;
|
||||
service = data->set.str[STRING_SERVICE_NAME] ?
|
||||
data->set.str[STRING_SERVICE_NAME] : "HTTP";
|
||||
hostname = conn->host.name;
|
||||
hostname = conn->origin->hostname;
|
||||
state = &conn->http_ntlm_state;
|
||||
authp = &data->state.authhost;
|
||||
}
|
||||
|
|
|
|||
132
lib/http_proxy.c
132
lib/http_proxy.c
|
|
@ -162,52 +162,27 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
void Curl_http_proxy_get_destination(struct Curl_cfilter *cf,
|
||||
const char **phostname,
|
||||
uint16_t *pport, bool *pipv6_ip)
|
||||
{
|
||||
DEBUGASSERT(cf);
|
||||
DEBUGASSERT(cf->conn);
|
||||
|
||||
if(cf->conn->bits.conn_to_host)
|
||||
*phostname = cf->conn->conn_to_host.name;
|
||||
else if(cf->sockindex == SECONDARYSOCKET)
|
||||
*phostname = cf->conn->secondaryhostname;
|
||||
else
|
||||
*phostname = cf->conn->host.name;
|
||||
|
||||
if(cf->sockindex == SECONDARYSOCKET)
|
||||
*pport = cf->conn->secondary_port;
|
||||
else if(cf->conn->bits.conn_to_port)
|
||||
*pport = cf->conn->conn_to_port;
|
||||
else
|
||||
*pport = cf->conn->remote_port;
|
||||
|
||||
*pipv6_ip = (strchr(*phostname, ':') != NULL);
|
||||
}
|
||||
|
||||
struct cf_proxy_ctx {
|
||||
int httpversion; /* HTTP version used to CONNECT */
|
||||
struct Curl_peer *dest; /* tunnel destination */
|
||||
uint8_t proxytype;
|
||||
BIT(sub_filter_installed);
|
||||
};
|
||||
|
||||
CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int http_version_major)
|
||||
struct Curl_peer *dest,
|
||||
int httpversion)
|
||||
{
|
||||
struct cf_proxy_ctx *ctx = cf->ctx;
|
||||
const char *hostname = NULL;
|
||||
char *authority = NULL;
|
||||
uint16_t port;
|
||||
bool ipv6_ip;
|
||||
CURLcode result;
|
||||
struct httpreq *req = NULL;
|
||||
|
||||
Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip);
|
||||
|
||||
authority = curl_maprintf("%s%s%s:%u", ipv6_ip ? "[" : "", hostname,
|
||||
ipv6_ip ? "]" : "", port);
|
||||
authority = curl_maprintf("%s%s%s:%u",
|
||||
dest->ipv6 ? "[" : "",
|
||||
dest->hostname,
|
||||
dest->ipv6 ? "]" : "",
|
||||
dest->port);
|
||||
if(!authority) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
|
|
@ -226,7 +201,7 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
|
|||
goto out;
|
||||
|
||||
/* If user is not overriding Host: header, we add for HTTP/1.x */
|
||||
if(http_version_major == 1 &&
|
||||
if(httpversion < 20 &&
|
||||
!Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) {
|
||||
result = Curl_dynhds_cadd(&req->headers, "Host", authority);
|
||||
if(result)
|
||||
|
|
@ -248,14 +223,14 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
|
|||
goto out;
|
||||
}
|
||||
|
||||
if(http_version_major == 1 &&
|
||||
if(httpversion < 20 &&
|
||||
!Curl_checkProxyheaders(data, cf->conn, STRCONST("Proxy-Connection"))) {
|
||||
result = Curl_dynhds_cadd(&req->headers, "Proxy-Connection", "Keep-Alive");
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = dynhds_add_custom(data, TRUE, ctx->httpversion, &req->headers);
|
||||
result = dynhds_add_custom(data, TRUE, httpversion, &req->headers);
|
||||
|
||||
out:
|
||||
if(result && req) {
|
||||
|
|
@ -287,36 +262,46 @@ connect_sub:
|
|||
|
||||
*done = FALSE;
|
||||
if(!ctx->sub_filter_installed) {
|
||||
int httpversion = 0;
|
||||
const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data);
|
||||
|
||||
if(alpn)
|
||||
infof(data, "CONNECT: '%s' negotiated", alpn);
|
||||
else
|
||||
else if(!alpn) {
|
||||
/* No ALPN, proxytype rules. Fake ALPN */
|
||||
infof(data, "CONNECT: no ALPN negotiated");
|
||||
|
||||
if(alpn && !strcmp(alpn, "http/1.0")) {
|
||||
CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.0");
|
||||
result = Curl_cf_h1_proxy_insert_after(cf, data);
|
||||
if(result)
|
||||
goto out;
|
||||
httpversion = 10;
|
||||
switch(ctx->proxytype) {
|
||||
case CURLPROXY_HTTP_1_0:
|
||||
alpn = "http/1.0";
|
||||
break;
|
||||
case CURLPROXY_HTTPS2:
|
||||
alpn = "h2";
|
||||
break;
|
||||
default:
|
||||
alpn = "http/1.1";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(!alpn || !strcmp(alpn, "http/1.1")) {
|
||||
CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.1");
|
||||
result = Curl_cf_h1_proxy_insert_after(cf, data);
|
||||
|
||||
if(!strcmp(alpn, "http/1.0")) {
|
||||
CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.0");
|
||||
result = Curl_cf_h1_proxy_insert_after(cf, data, ctx->dest, 10);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
else if(!strcmp(alpn, "http/1.1")) {
|
||||
int httpversion = (ctx->proxytype == CURLPROXY_HTTP_1_0) ? 10 : 11;
|
||||
CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.%d",
|
||||
httpversion % 10);
|
||||
result = Curl_cf_h1_proxy_insert_after(cf, data, ctx->dest, httpversion);
|
||||
if(result)
|
||||
goto out;
|
||||
/* Assume that without an ALPN, we are talking to an ancient one */
|
||||
httpversion = 11;
|
||||
}
|
||||
#ifdef USE_NGHTTP2
|
||||
else if(!strcmp(alpn, "h2")) {
|
||||
CURL_TRC_CF(data, cf, "installing subfilter for HTTP/2");
|
||||
result = Curl_cf_h2_proxy_insert_after(cf, data);
|
||||
result = Curl_cf_h2_proxy_insert_after(cf, data, ctx->dest);
|
||||
if(result)
|
||||
goto out;
|
||||
httpversion = 20;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
|
|
@ -326,7 +311,6 @@ connect_sub:
|
|||
}
|
||||
|
||||
ctx->sub_filter_installed = TRUE;
|
||||
ctx->httpversion = httpversion;
|
||||
/* after we installed the filter "below" us, we call connect
|
||||
* on out sub-chain again.
|
||||
*/
|
||||
|
|
@ -348,14 +332,15 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2)
|
||||
static CURLcode cf_http_proxy_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2)
|
||||
{
|
||||
struct cf_proxy_ctx *ctx = cf->ctx;
|
||||
switch(query) {
|
||||
case CF_QUERY_HOST_PORT:
|
||||
*pres1 = (int)cf->conn->http_proxy.port;
|
||||
*((const char **)pres2) = cf->conn->http_proxy.host.name;
|
||||
*pres1 = (int)ctx->dest->port;
|
||||
*((const char **)pres2) = ctx->dest->hostname;
|
||||
return CURLE_OK;
|
||||
case CF_QUERY_ALPN_NEGOTIATED: {
|
||||
const char **palpn = pres2;
|
||||
|
|
@ -371,13 +356,22 @@ CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf,
|
|||
CURLE_UNKNOWN_OPTION;
|
||||
}
|
||||
|
||||
static void cf_https_proxy_ctx_free(struct cf_proxy_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
Curl_peer_unlink(&ctx->dest);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_proxy_ctx *ctx = cf->ctx;
|
||||
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
curlx_free(ctx);
|
||||
if(ctx) {
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
cf_https_proxy_ctx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static void http_proxy_cf_close(struct Curl_cfilter *cf,
|
||||
|
|
@ -404,22 +398,30 @@ struct Curl_cftype Curl_cft_http_proxy = {
|
|||
Curl_cf_def_cntrl,
|
||||
Curl_cf_def_conn_is_alive,
|
||||
Curl_cf_def_conn_keep_alive,
|
||||
Curl_cf_http_proxy_query,
|
||||
cf_http_proxy_query,
|
||||
};
|
||||
|
||||
CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
uint8_t proxytype)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
struct cf_proxy_ctx *ctx = NULL;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
if(!dest)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
Curl_peer_link(&ctx->dest, dest);
|
||||
ctx->proxytype = proxytype;
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_http_proxy, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
|
|
@ -427,7 +429,7 @@ CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
|
|||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
|
||||
out:
|
||||
curlx_free(ctx);
|
||||
cf_https_proxy_ctx_free(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,24 +35,19 @@ enum Curl_proxy_use {
|
|||
HEADER_CONNECT /* sending CONNECT to a proxy */
|
||||
};
|
||||
|
||||
void Curl_http_proxy_get_destination(struct Curl_cfilter *cf,
|
||||
const char **phostname,
|
||||
uint16_t *pport, bool *pipv6_ip);
|
||||
|
||||
CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int http_version_major);
|
||||
struct Curl_peer *dest,
|
||||
int httpversion);
|
||||
|
||||
/* Default proxy timeout in milliseconds */
|
||||
#define PROXY_TIMEOUT (3600 * 1000)
|
||||
|
||||
CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
int query, int *pres1, void *pres2);
|
||||
|
||||
CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data);
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
uint8_t proxytype);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_http_proxy;
|
||||
|
||||
|
|
|
|||
|
|
@ -251,7 +251,7 @@ bool Curl_httpsrr_applicable(struct Curl_easy *data,
|
|||
return FALSE;
|
||||
return (!rr->target || !rr->target[0] ||
|
||||
(rr->target[0] == '.' && !rr->target[1])) &&
|
||||
(!rr->port_set || rr->port == data->conn->remote_port);
|
||||
(!rr->port_set || rr->port == data->conn->origin->port);
|
||||
}
|
||||
|
||||
#ifdef USE_ARES
|
||||
|
|
|
|||
26
lib/idn.c
26
lib/idn.c
|
|
@ -27,6 +27,7 @@
|
|||
#include "curl_setup.h"
|
||||
|
||||
#include "urldata.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "idn.h"
|
||||
|
||||
#ifdef USE_LIBIDN2
|
||||
|
|
@ -222,15 +223,24 @@ static CURLcode win32_ascii_to_idn(const char *in, char **out)
|
|||
*/
|
||||
bool Curl_is_ASCII_name(const char *hostname)
|
||||
{
|
||||
/* get an UNSIGNED local version of the pointer */
|
||||
const unsigned char *ch = (const unsigned char *)hostname;
|
||||
if(hostname) {
|
||||
struct Curl_str s;
|
||||
s.str = hostname;
|
||||
s.len = strlen(hostname);
|
||||
return Curl_is_ASCII_str(&s);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if(!hostname) /* bad input, consider it ASCII! */
|
||||
return TRUE;
|
||||
|
||||
while(*ch) {
|
||||
if(*ch++ & 0x80)
|
||||
return FALSE;
|
||||
bool Curl_is_ASCII_str(struct Curl_str *s)
|
||||
{
|
||||
if(s && s->len) {
|
||||
const unsigned char *ch = (const unsigned char *)s->str;
|
||||
size_t i;
|
||||
for(i = 0; i < s->len; ++i) {
|
||||
if(ch[i] & 0x80)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,21 @@
|
|||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
struct Curl_str;
|
||||
|
||||
bool Curl_is_ASCII_name(const char *hostname);
|
||||
bool Curl_is_ASCII_str(struct Curl_str *s);
|
||||
|
||||
#ifdef HEADER_CURL_URLDATA_H /* HACK */
|
||||
CURLcode Curl_idnconvert_hostname(struct hostname *host);
|
||||
#endif
|
||||
|
||||
#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
|
||||
#define USE_IDN
|
||||
#ifdef HEADER_CURL_URLDATA_H /* HACK */
|
||||
void Curl_free_idnconverted_hostname(struct hostname *host);
|
||||
#endif
|
||||
CURLcode Curl_idn_decode(const char *input, char **output);
|
||||
CURLcode Curl_idn_encode(const char *puny, char **output);
|
||||
#else
|
||||
|
|
|
|||
14
lib/ldap.c
14
lib/ldap.c
|
|
@ -284,14 +284,14 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
|
|||
ldap_ssl ? "encrypted" : "cleartext");
|
||||
|
||||
#ifdef USE_WIN32_LDAP
|
||||
host = curlx_convert_UTF8_to_tchar(conn->host.name);
|
||||
host = curlx_convert_UTF8_to_tchar(conn->origin->hostname);
|
||||
if(!host) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
|
||||
goto quit;
|
||||
}
|
||||
#else
|
||||
host = conn->host.name;
|
||||
host = conn->origin->hostname;
|
||||
#endif
|
||||
|
||||
if(data->state.aptr.user) {
|
||||
|
|
@ -307,7 +307,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
|
|||
server = ldap_init(host, (curl_ldap_num_t)ipquad.remote_port);
|
||||
if(!server) {
|
||||
failf(data, "LDAP: cannot setup connect to %s:%u",
|
||||
conn->host.dispname, ipquad.remote_port);
|
||||
conn->origin->user_hostname, ipquad.remote_port);
|
||||
result = CURLE_COULDNT_CONNECT;
|
||||
goto quit;
|
||||
}
|
||||
|
|
@ -681,8 +681,8 @@ static size_t num_entries(const char *s)
|
|||
* Syntax:
|
||||
* ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
|
||||
*
|
||||
* <hostname> already known from 'conn->host.name'.
|
||||
* <port> already known from 'conn->remote_port'.
|
||||
* <hostname> already known from 'conn->origin->hostname'.
|
||||
* <port> already known from 'conn->origin->port'.
|
||||
* extract the rest from 'data->state.path+1'. All fields are optional.
|
||||
* e.g.
|
||||
* ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
|
||||
|
|
@ -708,8 +708,8 @@ static curl_ldap_num_t ldap_url_parse2_low(struct Curl_easy *data,
|
|||
return LDAP_INVALID_SYNTAX;
|
||||
|
||||
ludp->lud_scope = LDAP_SCOPE_BASE;
|
||||
ludp->lud_port = conn->remote_port;
|
||||
ludp->lud_host = conn->host.name;
|
||||
ludp->lud_port = conn->origin->port;
|
||||
ludp->lud_host = conn->origin->hostname;
|
||||
|
||||
/* Duplicate the path */
|
||||
p = path = curlx_strdup(data->state.up.path + 1);
|
||||
|
|
|
|||
|
|
@ -617,8 +617,8 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
|
|||
hosturl = curl_maprintf("%s://%s:%d",
|
||||
conn->scheme->name,
|
||||
(data->state.up.hostname[0] == '[') ?
|
||||
data->state.up.hostname : conn->host.name,
|
||||
conn->remote_port);
|
||||
data->state.up.hostname : conn->origin->hostname,
|
||||
conn->origin->port);
|
||||
if(!hosturl) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
|
|
|
|||
712
lib/peer.c
Normal file
712
lib/peer.c
Normal file
|
|
@ -0,0 +1,712 @@
|
|||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
/*
|
||||
* IDN conversions
|
||||
*/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#ifdef HAVE_NETDB_H
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_IF_H
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
#ifdef HAVE_IPHLPAPI_H
|
||||
#include <Iphlpapi.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef __VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_IF_NAMETOINDEX) && defined(USE_WINSOCK)
|
||||
#if defined(__MINGW32__) && (__MINGW64_VERSION_MAJOR <= 5)
|
||||
#include <wincrypt.h> /* workaround for old mingw-w64 missing to include it */
|
||||
#endif
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#include "curl_addrinfo.h"
|
||||
#include "curl_trc.h"
|
||||
#include "protocol.h"
|
||||
#include "http_proxy.h"
|
||||
#include "idn.h"
|
||||
#include "curlx/strdup.h"
|
||||
#include "curlx/strparse.h"
|
||||
#include "peer.h"
|
||||
#include "urldata.h"
|
||||
#include "url.h"
|
||||
#include "vtls/vtls.h"
|
||||
|
||||
struct peer_parse {
|
||||
const struct Curl_scheme *scheme;
|
||||
struct Curl_str host_user;
|
||||
struct Curl_str host;
|
||||
struct Curl_str zoneid;
|
||||
char *tmp_host_user;
|
||||
char *tmp_host;
|
||||
char *tmp_zoneid;
|
||||
uint32_t scopeid;
|
||||
uint16_t port;
|
||||
bool ipv6;
|
||||
bool unix_socket;
|
||||
bool abstract_uds;
|
||||
};
|
||||
|
||||
static void peer_parse_clear(struct peer_parse *pp)
|
||||
{
|
||||
curlx_free(pp->tmp_host_user);
|
||||
curlx_free(pp->tmp_host);
|
||||
curlx_free(pp->tmp_zoneid);
|
||||
memset(pp, 0, sizeof(*pp));
|
||||
}
|
||||
|
||||
static CURLcode peer_create(struct peer_parse *pp,
|
||||
struct Curl_peer **ppeer)
|
||||
{
|
||||
struct Curl_peer *peer = NULL;
|
||||
CURLcode result = CURLE_OK;
|
||||
size_t zone_alen = 0, host_alen = 0;
|
||||
|
||||
if(!pp || !pp->scheme)
|
||||
return CURLE_FAILED_INIT;
|
||||
if(!pp->host.len && !(pp->scheme->flags & PROTOPT_NONETWORK))
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if((pp->host.str != pp->host_user.str) ||
|
||||
(pp->host.len != pp->host_user.len)) {
|
||||
host_alen = pp->host.len + 1;
|
||||
}
|
||||
zone_alen = pp->zoneid.len ? (pp->zoneid.len + 1) : 0;
|
||||
|
||||
/* NUL terminator already part of struct */
|
||||
peer = curlx_calloc(1, sizeof(*peer) +
|
||||
pp->host_user.len + host_alen + zone_alen);
|
||||
if(!peer) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
peer->refcount = 1;
|
||||
peer->scheme = pp->scheme;
|
||||
peer->hostname = peer->user_hostname;
|
||||
peer->port = pp->port;
|
||||
peer->scopeid = pp->scopeid;
|
||||
peer->ipv6 = pp->ipv6;
|
||||
peer->unix_socket = pp->unix_socket;
|
||||
peer->abstract_uds = pp->abstract_uds;
|
||||
|
||||
if(pp->host_user.len)
|
||||
memcpy(peer->user_hostname, pp->host_user.str, pp->host_user.len);
|
||||
|
||||
if(host_alen) {
|
||||
peer->hostname = peer->user_hostname + pp->host_user.len + 1;
|
||||
memcpy(peer->hostname, pp->host.str, pp->host.len);
|
||||
}
|
||||
|
||||
if(zone_alen) {
|
||||
peer->zoneid = peer->user_hostname + pp->host_user.len + 1 + host_alen;
|
||||
memcpy(peer->zoneid, pp->zoneid.str, pp->zoneid.len);
|
||||
#ifdef USE_IPV6
|
||||
/* Determine scope_id if not already provided */
|
||||
if(!peer->scopeid) {
|
||||
const char *p = peer->zoneid;
|
||||
curl_off_t scope;
|
||||
if(!curlx_str_number(&p, &scope, UINT_MAX)) {
|
||||
/* A plain number, use it directly as a scope id. */
|
||||
peer->scopeid = (uint32_t)scope;
|
||||
}
|
||||
#ifdef HAVE_IF_NAMETOINDEX
|
||||
else {
|
||||
/* Zone identifier is not numeric */
|
||||
unsigned int idx = 0;
|
||||
idx = if_nametoindex(peer->zoneid);
|
||||
if(idx) {
|
||||
peer->scopeid = (uint32_t)idx;
|
||||
}
|
||||
else {
|
||||
/* Do we want to return an error here? */
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_IF_NAMETOINDEX */
|
||||
}
|
||||
#endif /* USE_IPV6 */
|
||||
}
|
||||
|
||||
out:
|
||||
if(!result)
|
||||
*ppeer = peer;
|
||||
else
|
||||
Curl_peer_unlink(&peer);
|
||||
return result;
|
||||
}
|
||||
|
||||
static CURLcode peer_parse_host(struct Curl_easy *data,
|
||||
struct peer_parse *pp,
|
||||
bool scan_for_ipv6)
|
||||
{
|
||||
if(!pp || !pp->host_user.str || !pp->host_user.len)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(pp->host_user.str[0] == '[') {
|
||||
const char *s = pp->host_user.str + 1;
|
||||
struct Curl_str tmp;
|
||||
if(curlx_str_until(&s, &tmp, pp->host_user.len - 1, ']'))
|
||||
return CURLE_URL_MALFORMAT;
|
||||
|
||||
if(!Curl_looks_like_ipv6(tmp.str, tmp.len, TRUE,
|
||||
&pp->host, &pp->zoneid)) {
|
||||
failf(data, "Invalid IPv6 address format in '%.*s'",
|
||||
(int)pp->host_user.len, pp->host_user.str);
|
||||
return CURLE_URL_MALFORMAT;
|
||||
}
|
||||
pp->ipv6 = TRUE;
|
||||
}
|
||||
else {
|
||||
#ifdef USE_IDN
|
||||
if(!Curl_is_ASCII_str(&pp->host_user)) {
|
||||
CURLcode result;
|
||||
if(!pp->tmp_host_user) {
|
||||
/* need a null-terminated string for IDN */
|
||||
pp->tmp_host_user = curlx_memdup0(pp->host_user.str,
|
||||
pp->host_user.len);
|
||||
if(!pp->tmp_host_user)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
result = Curl_idn_decode(pp->tmp_host_user, &pp->tmp_host);
|
||||
if(result)
|
||||
return result;
|
||||
pp->host.str = pp->tmp_host;
|
||||
pp->host.len = strlen(pp->host.str);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(scan_for_ipv6 &&
|
||||
Curl_looks_like_ipv6(pp->host_user.str, pp->host_user.len, TRUE,
|
||||
&pp->host, &pp->zoneid)) {
|
||||
pp->ipv6 = TRUE;
|
||||
}
|
||||
else
|
||||
pp->host = pp->host_user;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_peer_create(struct Curl_easy *data,
|
||||
const struct Curl_scheme *scheme,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
struct Curl_peer **ppeer)
|
||||
{
|
||||
struct peer_parse pp;
|
||||
CURLcode result;
|
||||
|
||||
Curl_peer_unlink(ppeer);
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
pp.scheme = scheme;
|
||||
pp.host_user.str = hostname;
|
||||
pp.host_user.len = strlen(hostname);
|
||||
pp.port = port;
|
||||
|
||||
result = peer_parse_host(data, &pp, TRUE);
|
||||
if(!result)
|
||||
result = peer_create(&pp, ppeer);
|
||||
|
||||
peer_parse_clear(&pp);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
CURLcode Curl_peer_uds_create(const struct Curl_scheme *scheme,
|
||||
const char *path,
|
||||
bool abstract_unix_socket,
|
||||
struct Curl_peer **ppeer)
|
||||
{
|
||||
struct peer_parse pp;
|
||||
size_t pathlen = path ? strlen(path) : 0;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
Curl_peer_unlink(ppeer);
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
if(!scheme)
|
||||
return CURLE_FAILED_INIT;
|
||||
if(!pathlen)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
pp.scheme = scheme;
|
||||
pp.host_user.str = pp.host.str = path;
|
||||
pp.host_user.len = pp.host.len = pathlen;
|
||||
pp.unix_socket = TRUE;
|
||||
pp.abstract_uds = abstract_unix_socket;
|
||||
|
||||
result = peer_create(&pp, ppeer);
|
||||
peer_parse_clear(&pp);
|
||||
return result;
|
||||
}
|
||||
#endif /* USE_UNIX_SOCKETS */
|
||||
|
||||
void Curl_peer_link(struct Curl_peer **pdest, struct Curl_peer *src)
|
||||
{
|
||||
if(*pdest != src) {
|
||||
Curl_peer_unlink(pdest);
|
||||
*pdest = src;
|
||||
if(src) {
|
||||
DEBUGASSERT(src->refcount < UINT32_MAX);
|
||||
src->refcount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_peer_unlink(struct Curl_peer **ppeer)
|
||||
{
|
||||
if(*ppeer) {
|
||||
struct Curl_peer *peer = *ppeer;
|
||||
|
||||
DEBUGASSERT(peer->refcount);
|
||||
*ppeer = NULL;
|
||||
if(peer->refcount)
|
||||
peer->refcount--;
|
||||
if(!peer->refcount) {
|
||||
curlx_free(peer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Curl_peer_equal(struct Curl_peer *p1, struct Curl_peer *p2)
|
||||
{
|
||||
return (p1 == p2) ||
|
||||
(p1 && p2 &&
|
||||
(p1->scheme == p2->scheme) &&
|
||||
Curl_peer_same_destination(p1, p2));
|
||||
}
|
||||
|
||||
bool Curl_peer_same_destination(struct Curl_peer *p1, struct Curl_peer *p2)
|
||||
{
|
||||
return (p1 == p2) ||
|
||||
(p1 && p2 &&
|
||||
(p1->port == p2->port) &&
|
||||
curl_strequal(p1->hostname, p2->hostname) &&
|
||||
(p1->ipv6 == p2->ipv6) &&
|
||||
(p1->unix_socket == p2->unix_socket) &&
|
||||
(p1->abstract_uds == p2->abstract_uds) &&
|
||||
(p1->scopeid == p2->scopeid) &&
|
||||
(p1->scopeid || curl_strequal(p1->zoneid, p2->zoneid)));
|
||||
}
|
||||
|
||||
CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data,
|
||||
uint16_t port_override,
|
||||
uint32_t scopeid_override,
|
||||
struct urlpieces *up,
|
||||
struct Curl_peer **ppeer)
|
||||
{
|
||||
struct peer_parse pp;
|
||||
char *zoneid = NULL;
|
||||
CURLUcode uc;
|
||||
CURLcode result;
|
||||
|
||||
Curl_peer_unlink(ppeer);
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
|
||||
curlx_safefree(up->scheme);
|
||||
uc = curl_url_get(uh, CURLUPART_SCHEME, &up->scheme, 0);
|
||||
if(uc)
|
||||
return Curl_uc_to_curlcode(uc);
|
||||
pp.scheme = Curl_get_scheme(up->scheme);
|
||||
if(!pp.scheme) {
|
||||
failf(data, "Protocol \"%s\" not supported%s", up->scheme,
|
||||
data->state.this_is_a_follow ? " (in redirect)" : "");
|
||||
result = CURLE_UNSUPPORTED_PROTOCOL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
curlx_safefree(up->hostname);
|
||||
uc = curl_url_get(uh, CURLUPART_HOST, &up->hostname, 0);
|
||||
if(uc) {
|
||||
if((uc == CURLUE_NO_HOST) && (pp.scheme->flags & PROTOPT_NONETWORK))
|
||||
; /* acceptable */
|
||||
else {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if(strlen(up->hostname) > MAX_URL_LEN) {
|
||||
failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN);
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pp.host_user.str = up->hostname ? up->hostname : "";
|
||||
pp.host_user.len = strlen(pp.host_user.str);
|
||||
if(pp.host_user.len) {
|
||||
result = peer_parse_host(data, &pp, FALSE);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
pp.host = pp.host_user;
|
||||
|
||||
curlx_safefree(up->port);
|
||||
if(port_override) {
|
||||
/* if set, we use this instead of the port possibly given in the URL */
|
||||
char portbuf[16];
|
||||
curl_msnprintf(portbuf, sizeof(portbuf), "%d", port_override);
|
||||
uc = curl_url_set(uh, CURLUPART_PORT, portbuf, 0);
|
||||
if(uc) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
pp.port = port_override;
|
||||
}
|
||||
else {
|
||||
uc = curl_url_get(uh, CURLUPART_PORT, &up->port, CURLU_DEFAULT_PORT);
|
||||
if(uc) {
|
||||
if(uc == CURLUE_OUT_OF_MEMORY) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
else if(!(pp.scheme->flags & PROTOPT_NONETWORK)) {
|
||||
result = CURLE_URL_MALFORMAT;
|
||||
goto out;
|
||||
}
|
||||
/* no port ok when not a network scheme */
|
||||
}
|
||||
else {
|
||||
const char *p = up->port;
|
||||
curl_off_t offt;
|
||||
if(curlx_str_number(&p, &offt, 0xffff))
|
||||
return CURLE_URL_MALFORMAT;
|
||||
pp.port = (uint16_t)offt;
|
||||
}
|
||||
}
|
||||
|
||||
if(scopeid_override)
|
||||
/* Override any scope id from an url zone. */
|
||||
pp.scopeid = scopeid_override;
|
||||
else {
|
||||
if(curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0) ==
|
||||
CURLUE_OUT_OF_MEMORY) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
if(zoneid) {
|
||||
pp.zoneid.str = zoneid;
|
||||
pp.zoneid.len = strlen(zoneid);
|
||||
}
|
||||
}
|
||||
|
||||
result = peer_create(&pp, ppeer);
|
||||
if(result)
|
||||
failf(data, "Error %d creating peer for %s:%u",
|
||||
result, pp.host_user.str, pp.port);
|
||||
|
||||
out:
|
||||
peer_parse_clear(&pp);
|
||||
curlx_free(zoneid);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Parse a "host:port" string to connect to into a peer.
|
||||
* IPv6 addresses might appear in brackets or without them. */
|
||||
CURLcode Curl_peer_from_connect_to(struct Curl_easy *data,
|
||||
const struct Curl_peer *dest,
|
||||
const char *connect_to,
|
||||
struct Curl_peer **ppeer)
|
||||
{
|
||||
struct peer_parse pp;
|
||||
const char *portstr = NULL;
|
||||
CURLcode result;
|
||||
|
||||
Curl_peer_unlink(ppeer);
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
if(!connect_to || !*connect_to)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
pp.scheme = dest->scheme;
|
||||
|
||||
/* detect and extract RFC6874-style IPv6-addresses */
|
||||
if(connect_to[0] == '[') {
|
||||
const char *s = strchr(connect_to + 1, ']');
|
||||
if(!s) {
|
||||
failf(data, "Invalid IPv6 address format in '%s'", connect_to);
|
||||
result = CURLE_SETOPT_OPTION_SYNTAX;
|
||||
goto out;
|
||||
}
|
||||
portstr = strchr(s, ':');
|
||||
pp.host_user.str = connect_to;
|
||||
pp.host_user.len = s - pp.host_user.str + 1;
|
||||
pp.ipv6 = TRUE;
|
||||
}
|
||||
else {
|
||||
portstr = strchr(connect_to, ':');
|
||||
pp.host_user.str = connect_to;
|
||||
pp.host_user.len = portstr ?
|
||||
(size_t)(portstr - connect_to) : strlen(connect_to);
|
||||
}
|
||||
|
||||
if(!pp.host_user.len) { /* no hostname found, only port switch */
|
||||
pp.host_user.str = dest->user_hostname;
|
||||
pp.host_user.len = strlen(dest->user_hostname);
|
||||
}
|
||||
|
||||
result = peer_parse_host(data, &pp, FALSE);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
if(portstr && portstr[1]) {
|
||||
const char *p = portstr + 1;
|
||||
curl_off_t portparse;
|
||||
if(curlx_str_number(&p, &portparse, 0xffff)) {
|
||||
failf(data, "No valid port number in '%s'", connect_to);
|
||||
result = CURLE_SETOPT_OPTION_SYNTAX;
|
||||
goto out;
|
||||
}
|
||||
pp.port = (uint16_t)portparse; /* we know it will fit */
|
||||
}
|
||||
else
|
||||
pp.port = dest->port;
|
||||
|
||||
#ifndef USE_IPV6
|
||||
if(pp.ipv6) {
|
||||
failf(data, "Use of IPv6 in *_CONNECT_TO without IPv6 support built-in");
|
||||
result = CURLE_NOT_BUILT_IN;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = peer_create(&pp, ppeer);
|
||||
CURL_TRC_M(data, "connect-to peer_create2 -> %d", result);
|
||||
|
||||
out:
|
||||
CURL_TRC_M(data, "parse connect_to peer: %s -> %d", connect_to, result);
|
||||
peer_parse_clear(&pp);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
#define UNIX_SOCKET_PREFIX "localhost"
|
||||
#endif
|
||||
|
||||
CURLcode Curl_peer_from_proxy_url(CURLU *uh,
|
||||
struct Curl_easy *data,
|
||||
const char *url,
|
||||
uint8_t proxytype,
|
||||
struct Curl_peer **ppeer,
|
||||
uint8_t *pproxytype)
|
||||
{
|
||||
struct peer_parse pp;
|
||||
char *scheme = NULL;
|
||||
char *portptr = NULL;
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
bool is_socks = FALSE;
|
||||
#endif
|
||||
CURLUcode uc;
|
||||
CURLcode result = CURLE_OK;
|
||||
|
||||
Curl_peer_unlink(ppeer);
|
||||
memset(&pp, 0, sizeof(pp));
|
||||
pp.port = CURL_DEFAULT_PROXY_PORT;
|
||||
uc = curl_url_get(uh, CURLUPART_SCHEME, &scheme,
|
||||
CURLU_NON_SUPPORT_SCHEME | CURLU_NO_GUESS_SCHEME);
|
||||
if(uc) {
|
||||
if(uc == CURLUE_OUT_OF_MEMORY) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
/* url came without scheme, the passed `proxytype` determines it */
|
||||
switch(proxytype) {
|
||||
case CURLPROXY_HTTP:
|
||||
case CURLPROXY_HTTP_1_0:
|
||||
pp.scheme = &Curl_scheme_http;
|
||||
break;
|
||||
case CURLPROXY_HTTPS:
|
||||
case CURLPROXY_HTTPS2:
|
||||
pp.scheme = &Curl_scheme_https;
|
||||
break;
|
||||
case CURLPROXY_SOCKS4:
|
||||
pp.scheme = &Curl_scheme_socks4;
|
||||
break;
|
||||
case CURLPROXY_SOCKS4A:
|
||||
pp.scheme = &Curl_scheme_socks4a;
|
||||
break;
|
||||
case CURLPROXY_SOCKS5:
|
||||
pp.scheme = &Curl_scheme_socks5;
|
||||
break;
|
||||
case CURLPROXY_SOCKS5_HOSTNAME:
|
||||
pp.scheme = &Curl_scheme_socks5h;
|
||||
break;
|
||||
default:
|
||||
failf(data, "Unsupported proxy type %u for \'%s\'", proxytype, url);
|
||||
result = CURLE_COULDNT_RESOLVE_PROXY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pp.scheme = Curl_get_scheme(scheme);
|
||||
if(pp.scheme == &Curl_scheme_https) {
|
||||
proxytype = (proxytype != CURLPROXY_HTTPS2) ?
|
||||
CURLPROXY_HTTPS : CURLPROXY_HTTPS2;
|
||||
}
|
||||
else if(pp.scheme == &Curl_scheme_socks5h)
|
||||
proxytype = CURLPROXY_SOCKS5_HOSTNAME;
|
||||
else if(pp.scheme == &Curl_scheme_socks5)
|
||||
proxytype = CURLPROXY_SOCKS5;
|
||||
else if(pp.scheme == &Curl_scheme_socks4a)
|
||||
proxytype = CURLPROXY_SOCKS4A;
|
||||
else if((pp.scheme == &Curl_scheme_socks4) ||
|
||||
(pp.scheme == &Curl_scheme_socks))
|
||||
proxytype = CURLPROXY_SOCKS4;
|
||||
else if(pp.scheme == &Curl_scheme_http) {
|
||||
proxytype = (uint8_t)((proxytype != CURLPROXY_HTTP_1_0) ?
|
||||
CURLPROXY_HTTP : CURLPROXY_HTTP_1_0);
|
||||
}
|
||||
else {
|
||||
/* Any other xxx:// reject! */
|
||||
failf(data, "Unsupported proxy scheme for \'%s\'", url);
|
||||
result = CURLE_COULDNT_CONNECT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
DEBUGASSERT(pp.scheme);
|
||||
|
||||
if(IS_HTTPS_PROXY(proxytype) &&
|
||||
!Curl_ssl_supports(data, SSLSUPP_HTTPS_PROXY)) {
|
||||
failf(data, "Unsupported proxy \'%s\', libcurl is built without the "
|
||||
"HTTPS-proxy support.", url);
|
||||
result = CURLE_NOT_BUILT_IN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch(pp.scheme->family) {
|
||||
case CURLPROTO_SOCKS:
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
is_socks = TRUE;
|
||||
#endif
|
||||
break;
|
||||
case CURLPROTO_HTTP:
|
||||
break;
|
||||
default:
|
||||
failf(data, "Unsupported proxy protocol for \'%s\'", url);
|
||||
result = CURLE_COULDNT_CONNECT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uc = curl_url_get(uh, CURLUPART_PORT, &portptr, CURLU_NO_DEFAULT_PORT);
|
||||
if(uc == CURLUE_OUT_OF_MEMORY) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
if(portptr) {
|
||||
curl_off_t num;
|
||||
const char *p = portptr;
|
||||
if(!curlx_str_number(&p, &num, UINT16_MAX))
|
||||
pp.port = (uint16_t)num;
|
||||
/* Should we not error out when the port number is invalid? */
|
||||
curlx_free(portptr);
|
||||
}
|
||||
else {
|
||||
/* No port in url, take the set one or the scheme's default */
|
||||
if(data->set.proxyport)
|
||||
pp.port = data->set.proxyport;
|
||||
else
|
||||
pp.port = pp.scheme->defport;
|
||||
}
|
||||
|
||||
/* now, clone the proxy hostname */
|
||||
uc = curl_url_get(uh, CURLUPART_HOST, &pp.tmp_host_user, CURLU_URLDECODE);
|
||||
if(uc) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
pp.host_user.str = pp.tmp_host_user;
|
||||
pp.host_user.len = strlen(pp.tmp_host_user);
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
if(is_socks && curl_strequal(UNIX_SOCKET_PREFIX, pp.tmp_host_user)) {
|
||||
uc = curl_url_get(uh, CURLUPART_PATH, &pp.tmp_host, CURLU_URLDECODE);
|
||||
if(uc) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
/* path will be "/", if no path was found */
|
||||
if(strcmp("/", pp.tmp_host)) {
|
||||
pp.host.str = pp.tmp_host;
|
||||
pp.host.len = strlen(pp.tmp_host);
|
||||
pp.unix_socket = TRUE;
|
||||
}
|
||||
else {
|
||||
pp.host = pp.host_user;
|
||||
}
|
||||
}
|
||||
#endif /* USE_UNIX_SOCKETS */
|
||||
|
||||
if(!pp.host.len) {
|
||||
result = peer_parse_host(data, &pp, FALSE);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
||||
uc = curl_url_get(uh, CURLUPART_ZONEID, &pp.tmp_zoneid, 0);
|
||||
if(uc == CURLUE_OUT_OF_MEMORY) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
if(pp.tmp_zoneid) {
|
||||
pp.zoneid.str = pp.tmp_zoneid;
|
||||
pp.zoneid.len = strlen(pp.tmp_zoneid);
|
||||
}
|
||||
|
||||
*pproxytype = proxytype;
|
||||
result = peer_create(&pp, ppeer);
|
||||
|
||||
out:
|
||||
peer_parse_clear(&pp);
|
||||
curlx_free(scheme);
|
||||
#ifdef DEBUGBUILD
|
||||
if(!result)
|
||||
DEBUGASSERT(*ppeer);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
105
lib/peer.h
Normal file
105
lib/peer.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
#ifndef HEADER_CURL_PEER_H
|
||||
#define HEADER_CURL_PEER_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* This software is licensed as described in the file COPYING, which
|
||||
* you should have received as part of this distribution. The terms
|
||||
* are also available at https://curl.se/docs/copyright.html.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the COPYING file.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* SPDX-License-Identifier: curl
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
struct Curl_scheme;
|
||||
struct urlpieces;
|
||||
|
||||
/* if peer hostname starts with this, the peer is a unix domain socket
|
||||
* path, e.g. the remainder after 'localhost'. */
|
||||
#define CURL_PEER_UDS_PREFIX "localhost/"
|
||||
|
||||
struct Curl_peer {
|
||||
const struct Curl_scheme *scheme; /* url scheme */
|
||||
char *hostname; /* normalized hostname (IDN decoded when supported) */
|
||||
char *zoneid; /* NULL or ipv6 zone identifier */
|
||||
uint32_t refcount; /* created with 1, freed when dropping to 0 */
|
||||
uint32_t scopeid; /* != 0, ipv6 scope to use */
|
||||
uint16_t port;
|
||||
BIT(unix_socket); /* hostname is a UDS path without the prefix */
|
||||
BIT(abstract_uds); /* only TRUE when `unix_socket` also TRUE */
|
||||
BIT(ipv6); /* hostname is an IPv6 address stripped of '[]' */
|
||||
char user_hostname[1]; /* hostname supplied by user/url */
|
||||
};
|
||||
|
||||
/* Create a new peer:
|
||||
* - `peer->user_hostname` is the passed `hostname`
|
||||
* - `peer->hostname` is the normalized `hostname` via
|
||||
* + IDN conversion if it has non-ASCII characters
|
||||
* + stripping of surrounding '[]' for URL formatted ipv6 addresses
|
||||
* + the path alone in case of a unix domain socket, e.g. hostname
|
||||
* starts with CURL_PEER_UDS_PREFIX and is longer
|
||||
* Will scam for IPv6 addresses even without surrounding '[]'.
|
||||
* - `zoneid` ipv6 zone identifier or NULL
|
||||
* - `scopeid` ipv6 scopeid of zoneid, when known.
|
||||
*/
|
||||
CURLcode Curl_peer_create(struct Curl_easy *data,
|
||||
const struct Curl_scheme *scheme,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
struct Curl_peer **ppeer);
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
CURLcode Curl_peer_uds_create(const struct Curl_scheme *scheme,
|
||||
const char *path,
|
||||
bool abstract_unix_socket,
|
||||
struct Curl_peer **ppeer);
|
||||
#endif
|
||||
|
||||
/* Unlink any peer in `*pdest`, assign src, increase src
|
||||
* refcount when not NULL. */
|
||||
void Curl_peer_link(struct Curl_peer **pdest, struct Curl_peer *src);
|
||||
|
||||
/* Drop a reference, peer may be passed as NULL */
|
||||
void Curl_peer_unlink(struct Curl_peer **ppeer);
|
||||
|
||||
/* TRUE if both peers are NULL or have completely same properties. */
|
||||
bool Curl_peer_equal(struct Curl_peer *p1, struct Curl_peer *p2);
|
||||
|
||||
/* TRUE if both peers are NULL or have properties except the scheme. */
|
||||
bool Curl_peer_same_destination(struct Curl_peer *p1, struct Curl_peer *p2);
|
||||
|
||||
CURLcode Curl_peer_from_url(CURLU *uh, struct Curl_easy *data,
|
||||
uint16_t port_override,
|
||||
uint32_t scopeid_override,
|
||||
struct urlpieces *up,
|
||||
struct Curl_peer **ppeer);
|
||||
|
||||
CURLcode Curl_peer_from_connect_to(struct Curl_easy *data,
|
||||
const struct Curl_peer *dest,
|
||||
const char *connect_to,
|
||||
struct Curl_peer **ppeer);
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
|
||||
CURLcode Curl_peer_from_proxy_url(CURLU *uh,
|
||||
struct Curl_easy *data,
|
||||
const char *url,
|
||||
uint8_t proxytype,
|
||||
struct Curl_peer **ppeer,
|
||||
uint8_t *pproxytype);
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
|
||||
#endif /* HEADER_CURL_PEER_H */
|
||||
108
lib/protocol.c
108
lib/protocol.c
|
|
@ -361,6 +361,51 @@ const struct Curl_scheme Curl_scheme_smtps = {
|
|||
PORT_SMTPS, /* defport */
|
||||
};
|
||||
|
||||
const struct Curl_scheme Curl_scheme_socks = {
|
||||
"socks", /* scheme */
|
||||
ZERO_NULL,
|
||||
CURLPROTO_SOCKS, /* protocol */
|
||||
CURLPROTO_SOCKS, /* family */
|
||||
PROTOPT_NO_TRANSFER, /* flags */
|
||||
PORT_SOCKS, /* defport */
|
||||
};
|
||||
|
||||
const struct Curl_scheme Curl_scheme_socks4 = {
|
||||
"socks4", /* scheme */
|
||||
ZERO_NULL,
|
||||
CURLPROTO_SOCKS, /* protocol */
|
||||
CURLPROTO_SOCKS, /* family */
|
||||
PROTOPT_NO_TRANSFER, /* flags */
|
||||
PORT_SOCKS, /* defport */
|
||||
};
|
||||
|
||||
const struct Curl_scheme Curl_scheme_socks4a = {
|
||||
"socks4a", /* scheme */
|
||||
ZERO_NULL,
|
||||
CURLPROTO_SOCKS, /* protocol */
|
||||
CURLPROTO_SOCKS, /* family */
|
||||
PROTOPT_NO_TRANSFER, /* flags */
|
||||
PORT_SOCKS, /* defport */
|
||||
};
|
||||
|
||||
const struct Curl_scheme Curl_scheme_socks5 = {
|
||||
"socks5", /* scheme */
|
||||
ZERO_NULL,
|
||||
CURLPROTO_SOCKS, /* protocol */
|
||||
CURLPROTO_SOCKS, /* family */
|
||||
PROTOPT_NO_TRANSFER, /* flags */
|
||||
PORT_SOCKS, /* defport */
|
||||
};
|
||||
|
||||
const struct Curl_scheme Curl_scheme_socks5h = {
|
||||
"socks5h", /* scheme */
|
||||
ZERO_NULL,
|
||||
CURLPROTO_SOCKS, /* protocol */
|
||||
CURLPROTO_SOCKS, /* family */
|
||||
PROTOPT_NO_TRANSFER, /* flags */
|
||||
PORT_SOCKS, /* defport */
|
||||
};
|
||||
|
||||
const struct Curl_scheme Curl_scheme_telnet = {
|
||||
"telnet", /* scheme */
|
||||
#ifdef CURL_DISABLE_TELNET
|
||||
|
|
@ -430,49 +475,54 @@ const struct Curl_scheme *Curl_getn_scheme(const char *scheme, size_t len)
|
|||
6. make sure this function uses the same hash function that worked for
|
||||
schemetable.c
|
||||
*/
|
||||
static const struct Curl_scheme * const all_schemes[47] = {
|
||||
&Curl_scheme_mqtt,
|
||||
&Curl_scheme_smtp,
|
||||
&Curl_scheme_tftp,
|
||||
&Curl_scheme_imap, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
&Curl_scheme_ldaps,
|
||||
&Curl_scheme_dict, NULL,
|
||||
&Curl_scheme_file, NULL,
|
||||
&Curl_scheme_pop3s,
|
||||
&Curl_scheme_ftp,
|
||||
&Curl_scheme_scp,
|
||||
&Curl_scheme_mqtts,
|
||||
&Curl_scheme_imaps,
|
||||
&Curl_scheme_ldap,
|
||||
&Curl_scheme_http,
|
||||
&Curl_scheme_smb, NULL, NULL,
|
||||
&Curl_scheme_telnet,
|
||||
&Curl_scheme_https,
|
||||
&Curl_scheme_gopher,
|
||||
&Curl_scheme_rtsp, NULL, NULL,
|
||||
&Curl_scheme_wss, NULL,
|
||||
&Curl_scheme_gophers,
|
||||
static const struct Curl_scheme * const all_schemes[59] = { NULL,
|
||||
&Curl_scheme_pop3, NULL,
|
||||
&Curl_scheme_smtps,
|
||||
&Curl_scheme_pop3,
|
||||
&Curl_scheme_ws, NULL, NULL,
|
||||
&Curl_scheme_socks,
|
||||
&Curl_scheme_socks4,
|
||||
&Curl_scheme_socks5, NULL, NULL,
|
||||
&Curl_scheme_gophers,
|
||||
&Curl_scheme_ws,
|
||||
&Curl_scheme_sftp,
|
||||
&Curl_scheme_ftps, NULL,
|
||||
&Curl_scheme_smbs, NULL,
|
||||
&Curl_scheme_socks4a,
|
||||
&Curl_scheme_scp,
|
||||
&Curl_scheme_rtsp,
|
||||
&Curl_scheme_dict, NULL, NULL,
|
||||
&Curl_scheme_gopher, NULL, NULL, NULL,
|
||||
&Curl_scheme_wss, NULL,
|
||||
&Curl_scheme_smb, NULL,
|
||||
&Curl_scheme_ldap,
|
||||
&Curl_scheme_ldaps,
|
||||
&Curl_scheme_imap, NULL, NULL, NULL,
|
||||
&Curl_scheme_imaps,
|
||||
&Curl_scheme_https,
|
||||
&Curl_scheme_tftp,
|
||||
&Curl_scheme_telnet, NULL, NULL, NULL,
|
||||
&Curl_scheme_file,
|
||||
&Curl_scheme_smtp, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
&Curl_scheme_ftp,
|
||||
&Curl_scheme_mqtt, NULL,
|
||||
&Curl_scheme_socks5h,
|
||||
&Curl_scheme_http,
|
||||
&Curl_scheme_pop3s, NULL,
|
||||
&Curl_scheme_mqtts, NULL,
|
||||
&Curl_scheme_smbs,
|
||||
&Curl_scheme_ftps,
|
||||
};
|
||||
|
||||
if(len && (len <= 7)) {
|
||||
const char *s = scheme;
|
||||
size_t l = len;
|
||||
const struct Curl_scheme *h;
|
||||
unsigned int c = 792;
|
||||
unsigned int c = 443;
|
||||
while(l) {
|
||||
c <<= 4;
|
||||
c <<= 5;
|
||||
c += (unsigned int)Curl_raw_tolower(*s);
|
||||
s++;
|
||||
l--;
|
||||
}
|
||||
|
||||
h = all_schemes[c % 47];
|
||||
h = all_schemes[c % 59];
|
||||
if(h && curl_strnequal(scheme, h->name, len) && !h->name[len])
|
||||
return h;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ struct easy_pollset;
|
|||
#define PORT_SMTPS 465 /* sometimes called SSMTP */
|
||||
#define PORT_RTSP 554
|
||||
#define PORT_GOPHER 70
|
||||
#define PORT_SOCKS 1080
|
||||
#define PORT_MQTT 1883
|
||||
#define PORT_MQTTS 8883
|
||||
|
||||
|
|
@ -62,6 +63,7 @@ struct easy_pollset;
|
|||
#define CURLPROTO_WS (1L << 30)
|
||||
#define CURLPROTO_WSS ((curl_prot_t)1 << 31)
|
||||
#define CURLPROTO_MQTTS (1LL << 32)
|
||||
#define CURLPROTO_SOCKS (1LL << 33)
|
||||
|
||||
#define CURLPROTO_64ALL ((uint64_t)0xffffffffffffffff)
|
||||
|
||||
|
|
@ -224,6 +226,7 @@ struct Curl_protocol {
|
|||
SSL connection in the same family
|
||||
without having PROTOPT_SSL. */
|
||||
#define PROTOPT_CONN_REUSE (1 << 16) /* this protocol can reuse connections */
|
||||
#define PROTOPT_NO_TRANSFER (1 << 17) /* this protocol is not for transfers */
|
||||
|
||||
/* Everything about a URI scheme. */
|
||||
struct Curl_scheme {
|
||||
|
|
@ -268,6 +271,11 @@ extern const struct Curl_scheme Curl_scheme_smb;
|
|||
extern const struct Curl_scheme Curl_scheme_smbs;
|
||||
extern const struct Curl_scheme Curl_scheme_smtp;
|
||||
extern const struct Curl_scheme Curl_scheme_smtps;
|
||||
extern const struct Curl_scheme Curl_scheme_socks;
|
||||
extern const struct Curl_scheme Curl_scheme_socks4;
|
||||
extern const struct Curl_scheme Curl_scheme_socks4a;
|
||||
extern const struct Curl_scheme Curl_scheme_socks5;
|
||||
extern const struct Curl_scheme Curl_scheme_socks5h;
|
||||
extern const struct Curl_scheme Curl_scheme_telnet;
|
||||
extern const struct Curl_scheme Curl_scheme_tftp;
|
||||
extern const struct Curl_scheme Curl_scheme_ws;
|
||||
|
|
|
|||
10
lib/rtsp.c
10
lib/rtsp.c
|
|
@ -304,14 +304,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
|
|||
/* Setup the first_* fields to allow auth details get sent
|
||||
to this origin */
|
||||
|
||||
if(!data->state.first_host) {
|
||||
data->state.first_host = curlx_strdup(conn->host.name);
|
||||
if(!data->state.first_host)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
data->state.first_remote_port = conn->remote_port;
|
||||
data->state.first_remote_protocol = conn->scheme->protocol;
|
||||
}
|
||||
if(!data->state.first_origin)
|
||||
Curl_peer_link(&data->state.first_origin, conn->origin);
|
||||
|
||||
/* Setup the 'p_request' pointer to the proper p_request string
|
||||
* Since all RTSP requests are included here, there is no need to
|
||||
|
|
|
|||
|
|
@ -500,7 +500,7 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
|
|||
}
|
||||
else {
|
||||
smbc->user = conn->user;
|
||||
smbc->domain = curlx_strdup(conn->host.name);
|
||||
smbc->domain = curlx_strdup(conn->origin->hostname);
|
||||
if(!smbc->domain)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
|
@ -720,7 +720,8 @@ static CURLcode smb_send_tree_connect(struct Curl_easy *data,
|
|||
struct smb_tree_connect msg;
|
||||
struct connectdata *conn = data->conn;
|
||||
char *p = msg.bytes;
|
||||
const size_t byte_count = strlen(conn->host.name) + strlen(smbc->share) +
|
||||
const size_t byte_count = strlen(conn->origin->hostname) +
|
||||
strlen(smbc->share) +
|
||||
strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */
|
||||
|
||||
if(byte_count > sizeof(msg.bytes))
|
||||
|
|
@ -735,7 +736,7 @@ static CURLcode smb_send_tree_connect(struct Curl_easy *data,
|
|||
"\\\\%s\\" /* hostname */
|
||||
"%s%c" /* share */
|
||||
"%s", /* service */
|
||||
conn->host.name, smbc->share, 0, SERVICENAME);
|
||||
conn->origin->hostname, smbc->share, 0, SERVICENAME);
|
||||
p++; /* count the final null-termination */
|
||||
DEBUGASSERT(byte_count == (size_t)(p - msg.bytes));
|
||||
msg.byte_count = smb_swap16((unsigned short)byte_count);
|
||||
|
|
|
|||
77
lib/socks.c
77
lib/socks.c
|
|
@ -98,7 +98,7 @@ static const char * const cf_socks_statename[] = {
|
|||
struct socks_ctx {
|
||||
enum socks_state_t state;
|
||||
struct bufq iobuf;
|
||||
uint16_t remote_port;
|
||||
struct Curl_peer *dest;
|
||||
const char *user;
|
||||
const char *passwd;
|
||||
CURLproxycode presult;
|
||||
|
|
@ -109,7 +109,6 @@ struct socks_ctx {
|
|||
BIT(resolve_local);
|
||||
BIT(start_resolving);
|
||||
BIT(socks4a);
|
||||
char hostname[1];
|
||||
};
|
||||
|
||||
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
|
||||
|
|
@ -273,8 +272,8 @@ static CURLproxycode socks4_req_add_hd(struct socks_ctx *sx,
|
|||
(void)data;
|
||||
buf[0] = 4; /* version (SOCKS4) */
|
||||
buf[1] = 1; /* connect */
|
||||
buf[2] = (unsigned char)((sx->remote_port >> 8) & 0xffU); /* MSB */
|
||||
buf[3] = (unsigned char)(sx->remote_port & 0xffU); /* LSB */
|
||||
buf[2] = (unsigned char)((sx->dest->port >> 8) & 0xffU); /* MSB */
|
||||
buf[3] = (unsigned char)(sx->dest->port & 0xffU); /* LSB */
|
||||
|
||||
result = Curl_bufq_write(&sx->iobuf, buf, 4, &nwritten);
|
||||
if(result || (nwritten != 4))
|
||||
|
|
@ -329,7 +328,7 @@ static CURLproxycode socks4_resolving(struct socks_ctx *sx,
|
|||
sx->start_resolving = FALSE;
|
||||
result = Curl_cf_dns_insert_after(
|
||||
cf, data, Curl_resolv_dns_queries(data, sx->ip_version),
|
||||
sx->hostname, sx->remote_port, TRNSPRT_TCP, TRUE);
|
||||
sx->dest, TRNSPRT_TCP, TRUE);
|
||||
if(result) {
|
||||
failf(data, "unable to create DNS filter for socks");
|
||||
return CURLPX_UNKNOWN_FAIL;
|
||||
|
|
@ -340,7 +339,7 @@ static CURLproxycode socks4_resolving(struct socks_ctx *sx,
|
|||
result = Curl_conn_cf_connect(cf->next, data, &dns_done);
|
||||
if(result) {
|
||||
failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
|
||||
sx->hostname);
|
||||
sx->dest->hostname);
|
||||
return CURLPX_RESOLVE_HOST;
|
||||
}
|
||||
else if(!dns_done)
|
||||
|
|
@ -365,7 +364,7 @@ static CURLproxycode socks4_resolving(struct socks_ctx *sx,
|
|||
}
|
||||
else {
|
||||
/* No ipv4 address resolved */
|
||||
failf(data, "SOCKS4 connection to %s not supported", sx->hostname);
|
||||
failf(data, "SOCKS4 connection to %s not supported", sx->dest->hostname);
|
||||
return CURLPX_RESOLVE_HOST;
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +486,8 @@ process_state:
|
|||
/* SOCKS4 can only do IPv4, insist! */
|
||||
sx->ip_version = CURL_IPRESOLVE_V4;
|
||||
CURL_TRC_CF(data, cf, "SOCKS4%s connecting to %s:%u",
|
||||
sx->socks4a ? "a" : "", sx->hostname, sx->remote_port);
|
||||
sx->socks4a ? "a" : "",
|
||||
sx->dest->hostname, sx->dest->port);
|
||||
|
||||
/*
|
||||
* Compose socks4 request
|
||||
|
|
@ -508,7 +508,7 @@ process_state:
|
|||
/* socks4a, not resolving locally, sends the hostname.
|
||||
* add an invalid address + user + hostname */
|
||||
unsigned char buf[4] = { 0, 0, 0, 1 };
|
||||
size_t hlen = strlen(sx->hostname) + 1; /* including NUL */
|
||||
size_t hlen = strlen(sx->dest->hostname) + 1; /* including NUL */
|
||||
|
||||
if(hlen > 255) {
|
||||
failf(data, "SOCKS4: too long hostname");
|
||||
|
|
@ -520,7 +520,8 @@ process_state:
|
|||
presult = socks4_req_add_user(sx, data);
|
||||
if(presult)
|
||||
return socks_failed(sx, cf, data, presult);
|
||||
result = Curl_bufq_cwrite(&sx->iobuf, sx->hostname, hlen, &nwritten);
|
||||
result = Curl_bufq_cwrite(&sx->iobuf, sx->dest->hostname, hlen,
|
||||
&nwritten);
|
||||
if(result || (nwritten != hlen))
|
||||
return socks_failed(sx, cf, data, CURLPX_SEND_REQUEST);
|
||||
/* request complete */
|
||||
|
|
@ -591,7 +592,7 @@ static CURLproxycode socks5_req0_init(struct Curl_cfilter *cf,
|
|||
|
||||
(void)cf;
|
||||
/* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
|
||||
if(!sx->resolve_local && strlen(sx->hostname) > 255) {
|
||||
if(!sx->resolve_local && strlen(sx->dest->hostname) > 255) {
|
||||
failf(data, "SOCKS5: the destination hostname is too long to be "
|
||||
"resolved remotely by the proxy.");
|
||||
return CURLPX_LONG_HOSTNAME;
|
||||
|
|
@ -779,28 +780,28 @@ static CURLproxycode socks5_req1_init(struct socks_ctx *sx,
|
|||
|
||||
/* remote resolving, send what type+addr/string to resolve */
|
||||
#ifdef USE_IPV6
|
||||
if(strchr(sx->hostname, ':')) {
|
||||
if(strchr(sx->dest->hostname, ':')) {
|
||||
desttype = 4;
|
||||
destination = ipbuf;
|
||||
destlen = 16;
|
||||
if(curlx_inet_pton(AF_INET6, sx->hostname, ipbuf) != 1)
|
||||
if(curlx_inet_pton(AF_INET6, sx->dest->hostname, ipbuf) != 1)
|
||||
return CURLPX_BAD_ADDRESS_TYPE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if(curlx_inet_pton(AF_INET, sx->hostname, ipbuf) == 1) {
|
||||
if(curlx_inet_pton(AF_INET, sx->dest->hostname, ipbuf) == 1) {
|
||||
desttype = 1;
|
||||
destination = ipbuf;
|
||||
destlen = 4;
|
||||
}
|
||||
else {
|
||||
const size_t hostname_len = strlen(sx->hostname);
|
||||
const size_t hostname_len = strlen(sx->dest->hostname);
|
||||
/* socks5_req0_init() already rejects hostnames longer than 255 bytes, so
|
||||
this cast to unsigned char is safe. Assert to guard against future
|
||||
refactoring that might remove or reorder that earlier check. */
|
||||
DEBUGASSERT(hostname_len <= 255);
|
||||
desttype = 3;
|
||||
destination = (const unsigned char *)sx->hostname;
|
||||
destination = (const unsigned char *)sx->dest->hostname;
|
||||
destlen = (unsigned char)hostname_len; /* one byte length */
|
||||
}
|
||||
|
||||
|
|
@ -814,13 +815,13 @@ static CURLproxycode socks5_req1_init(struct socks_ctx *sx,
|
|||
if(result || (nwritten != destlen))
|
||||
return CURLPX_SEND_REQUEST;
|
||||
/* PORT MSB+LSB */
|
||||
req[0] = (unsigned char)((sx->remote_port >> 8) & 0xff);
|
||||
req[1] = (unsigned char)(sx->remote_port & 0xff);
|
||||
req[0] = (unsigned char)((sx->dest->port >> 8) & 0xff);
|
||||
req[1] = (unsigned char)(sx->dest->port & 0xff);
|
||||
result = Curl_bufq_write(&sx->iobuf, req, 2, &nwritten);
|
||||
if(result || (nwritten != 2))
|
||||
return CURLPX_SEND_REQUEST;
|
||||
CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%u (remotely resolved)",
|
||||
sx->hostname, sx->remote_port);
|
||||
sx->dest->hostname, sx->dest->port);
|
||||
return CURLPX_OK;
|
||||
}
|
||||
|
||||
|
|
@ -845,7 +846,7 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx,
|
|||
sx->start_resolving = FALSE;
|
||||
result = Curl_cf_dns_insert_after(
|
||||
cf, data, Curl_resolv_dns_queries(data, sx->ip_version),
|
||||
sx->hostname, sx->remote_port, TRNSPRT_TCP, TRUE);
|
||||
sx->dest, TRNSPRT_TCP, TRUE);
|
||||
if(result) {
|
||||
failf(data, "unable to create DNS filter for socks");
|
||||
return CURLPX_UNKNOWN_FAIL;
|
||||
|
|
@ -855,7 +856,8 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx,
|
|||
/* resolve the hostname by connecting the DNS filter */
|
||||
result = Curl_conn_cf_connect(cf->next, data, &dns_done);
|
||||
if(result) {
|
||||
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", sx->hostname);
|
||||
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
|
||||
sx->dest->hostname);
|
||||
return CURLPX_RESOLVE_HOST;
|
||||
}
|
||||
else if(!dns_done)
|
||||
|
|
@ -869,7 +871,8 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx,
|
|||
ai = Curl_cf_dns_get_ai(cf->next, data, AF_INET, 0);
|
||||
|
||||
if(!ai) {
|
||||
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", sx->hostname);
|
||||
failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
|
||||
sx->dest->hostname);
|
||||
presult = CURLPX_RESOLVE_HOST;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -883,7 +886,7 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx,
|
|||
saddr_in = (struct sockaddr_in *)(void *)ai->ai_addr;
|
||||
destination = (const unsigned char *)&saddr_in->sin_addr.s_addr;
|
||||
CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%u (locally resolved)",
|
||||
dest, sx->remote_port);
|
||||
dest, sx->dest->port);
|
||||
}
|
||||
#ifdef USE_IPV6
|
||||
else if(ai->ai_family == AF_INET6) {
|
||||
|
|
@ -893,7 +896,7 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx,
|
|||
saddr_in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
|
||||
destination = (const unsigned char *)&saddr_in6->sin6_addr.s6_addr;
|
||||
CURL_TRC_CF(data, cf, "SOCKS5 connect to [%s]:%u (locally resolved)",
|
||||
dest, sx->remote_port);
|
||||
dest, sx->dest->port);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -915,8 +918,8 @@ static CURLproxycode socks5_resolving(struct socks_ctx *sx,
|
|||
goto out;
|
||||
}
|
||||
/* PORT MSB+LSB */
|
||||
req[0] = (unsigned char)((sx->remote_port >> 8) & 0xffU);
|
||||
req[1] = (unsigned char)(sx->remote_port & 0xffU);
|
||||
req[0] = (unsigned char)((sx->dest->port >> 8) & 0xffU);
|
||||
req[1] = (unsigned char)(sx->dest->port & 0xffU);
|
||||
result = Curl_bufq_write(&sx->iobuf, req, 2, &nwritten);
|
||||
if(result || (nwritten != 2)) {
|
||||
presult = CURLPX_SEND_REQUEST;
|
||||
|
|
@ -971,7 +974,7 @@ static CURLproxycode socks5_recv_resp1(struct socks_ctx *sx,
|
|||
CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
|
||||
int code = resp[1];
|
||||
failf(data, "cannot complete SOCKS5 connection to %s. (%d)",
|
||||
sx->hostname, code);
|
||||
sx->dest->hostname, code);
|
||||
if(code < 9) {
|
||||
/* RFC 1928 section 6 lists: */
|
||||
static const CURLproxycode lookup[] = {
|
||||
|
|
@ -1043,7 +1046,7 @@ process_state:
|
|||
|
||||
case SOCKS5_ST_START:
|
||||
CURL_TRC_CF(data, cf, "SOCKS5: connecting to %s:%u",
|
||||
sx->hostname, sx->remote_port);
|
||||
sx->dest->hostname, sx->dest->port);
|
||||
presult = socks5_req0_init(cf, sx, data);
|
||||
if(presult)
|
||||
return socks_failed(sx, cf, data, presult);
|
||||
|
|
@ -1181,6 +1184,7 @@ process_state:
|
|||
static void socks_proxy_ctx_free(struct socks_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
Curl_peer_unlink(&ctx->dest);
|
||||
Curl_bufq_free(&ctx->iobuf);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
|
|
@ -1244,7 +1248,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
|
|||
"(via %s port %u)",
|
||||
(cf->sockindex == SECONDARYSOCKET) ? "2nd " : "",
|
||||
ipquad.local_ip, ipquad.local_port,
|
||||
ctx->hostname, ctx->remote_port,
|
||||
ctx->dest->hostname, ctx->dest->port,
|
||||
ipquad.remote_ip, ipquad.remote_port);
|
||||
else
|
||||
infof(data, "Opened %sSOCKS connection",
|
||||
|
|
@ -1315,8 +1319,8 @@ static CURLcode socks_cf_query(struct Curl_cfilter *cf,
|
|||
switch(query) {
|
||||
case CF_QUERY_HOST_PORT:
|
||||
if(sx) {
|
||||
*pres1 = sx->remote_port;
|
||||
*((const char **)pres2) = sx->hostname;
|
||||
*pres1 = sx->dest->port;
|
||||
*((const char **)pres2) = sx->dest->hostname;
|
||||
return CURLE_OK;
|
||||
}
|
||||
break;
|
||||
|
|
@ -1354,8 +1358,7 @@ struct Curl_cftype Curl_cft_socks_proxy = {
|
|||
|
||||
CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
struct Curl_peer *dest,
|
||||
uint8_t ip_version,
|
||||
uint8_t proxy_type,
|
||||
const char *user,
|
||||
|
|
@ -1363,10 +1366,9 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
|
|||
{
|
||||
struct Curl_cfilter *cf;
|
||||
struct socks_ctx *ctx;
|
||||
size_t hostlen = hostname ? strlen(hostname) : 0;
|
||||
CURLcode result;
|
||||
|
||||
if(!hostlen)
|
||||
if(!dest)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
switch(proxy_type) {
|
||||
|
|
@ -1381,13 +1383,12 @@ CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
|
|||
}
|
||||
|
||||
/* NUL byte already part of struct size */
|
||||
ctx = curlx_calloc(1, sizeof(*ctx) + hostlen);
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
memcpy(ctx->hostname, hostname, hostlen);
|
||||
ctx->remote_port = port;
|
||||
Curl_peer_link(&ctx->dest, dest);
|
||||
ctx->ip_version = ip_version;
|
||||
ctx->proxy_type = proxy_type;
|
||||
ctx->user = user;
|
||||
|
|
|
|||
11
lib/socks.h
11
lib/socks.h
|
|
@ -26,6 +26,9 @@
|
|||
#include "curl_setup.h"
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
|
||||
struct Curl_peer;
|
||||
|
||||
/*
|
||||
* Helper read-from-socket functions. Does the same as Curl_read() but it
|
||||
* blocks until all bytes amount of buffersize will be read. No more, no less.
|
||||
|
|
@ -46,15 +49,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
|
|||
struct Curl_easy *data);
|
||||
#endif
|
||||
|
||||
/* Insert a SOCKS filter after `cf_at` for connecting to `hostname`
|
||||
* and `port` with optional credentials.
|
||||
* Credentials are NOT duplicated and are
|
||||
/* Insert a SOCKS filter after `cf_at` for connecting to `dest`.
|
||||
* Credentials are optional and NOT duplicated and are
|
||||
* expected to exist during connect phase.
|
||||
*/
|
||||
CURLcode Curl_cf_socks_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
struct Curl_peer *dest,
|
||||
uint8_t ip_version,
|
||||
uint8_t proxy_type,
|
||||
const char *user,
|
||||
|
|
|
|||
|
|
@ -141,8 +141,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
|
|||
(gss_OID)GSS_C_NULL_OID, &server);
|
||||
}
|
||||
else {
|
||||
service.value = curl_maprintf("%s@%s",
|
||||
serviceptr, conn->socks_proxy.host.name);
|
||||
service.value = curl_maprintf("%s@%s", serviceptr,
|
||||
conn->socks_proxy.peer->hostname);
|
||||
if(!service.value)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
service.length = strlen(service.value);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ static CURLcode socks5_sspi_setup(struct Curl_cfilter *cf,
|
|||
*service_namep = curlx_strdup(service);
|
||||
else
|
||||
*service_namep = curl_maprintf("%s/%s",
|
||||
service, conn->socks_proxy.host.name);
|
||||
service, conn->socks_proxy.peer->hostname);
|
||||
if(!*service_namep)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@
|
|||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
/* Reject URLs exceeding this length */
|
||||
#define MAX_URL_LEN 0xffff
|
||||
|
||||
/*
|
||||
* Prototypes for library-wide functions
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@
|
|||
#include "http_chunks.h" /* for the structs and enum stuff */
|
||||
#include "hostip.h"
|
||||
#include "hash.h"
|
||||
#include "peer.h"
|
||||
#include "splay.h"
|
||||
#include "curlx/dynbuf.h"
|
||||
#include "bufref.h"
|
||||
|
|
@ -259,10 +260,6 @@ struct ConnectBits {
|
|||
BIT(close); /* if set, we close the connection after this request */
|
||||
BIT(reuse); /* if set, this is a reused connection */
|
||||
BIT(altused); /* this is an alt-svc "redirect" */
|
||||
BIT(conn_to_host); /* if set, this connection has a "connect to host"
|
||||
that overrides the host in the URL */
|
||||
BIT(conn_to_port); /* if set, this connection has a "connect to port"
|
||||
that overrides the port in the URL (remote port) */
|
||||
BIT(ipv6); /* we communicate with a site using an IPv6 address */
|
||||
BIT(do_more); /* this is set TRUE if the ->curl_do_more() function is
|
||||
supposed to be called, after ->curl_do() */
|
||||
|
|
@ -289,9 +286,6 @@ struct ConnectBits {
|
|||
BIT(multiplex); /* connection is multiplexed */
|
||||
BIT(tcp_fastopen); /* use TCP Fast Open */
|
||||
BIT(tls_enable_alpn); /* TLS ALPN extension? */
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
BIT(abstract_unix_socket);
|
||||
#endif
|
||||
BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with
|
||||
accept() */
|
||||
BIT(parallel_connect); /* set TRUE when a parallel connect attempt has
|
||||
|
|
@ -334,8 +328,7 @@ struct ip_quadruple {
|
|||
((x)->transport == TRNSPRT_QUIC))
|
||||
|
||||
struct proxy_info {
|
||||
struct hostname host;
|
||||
uint16_t port;
|
||||
struct Curl_peer *peer; /* proxy to this peer */
|
||||
uint8_t proxytype; /* what kind of proxy that is in use */
|
||||
char *user; /* proxy username string, allocated */
|
||||
char *passwd; /* proxy password string, allocated */
|
||||
|
|
@ -369,10 +362,11 @@ struct connectdata {
|
|||
* the connection is cleaned up (see Curl_hash_add2()).*/
|
||||
struct Curl_hash meta_hash;
|
||||
|
||||
struct hostname host;
|
||||
char *secondaryhostname; /* secondary socket hostname (ftp) */
|
||||
struct hostname conn_to_host; /* the host to connect to. valid only if
|
||||
bits.conn_to_host is set */
|
||||
/* Who the connection is talking to, ultimately */
|
||||
struct Curl_peer *origin; /* connection ultimately talks to this */
|
||||
struct Curl_peer *via_peer; /* if set, connection really talks to this */
|
||||
struct Curl_peer *origin2; /* origin of SECONDARYSOCKET */
|
||||
struct Curl_peer *via_peer2; /* peer of SECONDARYSOCKET */
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
struct proxy_info socks_proxy;
|
||||
struct proxy_info http_proxy;
|
||||
|
|
@ -438,10 +432,6 @@ struct connectdata {
|
|||
curlnegotiate proxy_negotiate_state;
|
||||
#endif
|
||||
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
char *unix_domain_socket;
|
||||
#endif
|
||||
|
||||
/* When this connection is created, store the conditions for the local end
|
||||
bind. This is stored before the actual bind and before any connection is
|
||||
made and will serve the purpose of being used for comparison reasons so
|
||||
|
|
@ -456,14 +446,8 @@ struct connectdata {
|
|||
#ifdef USE_IPV6
|
||||
uint32_t scope_id; /* Scope id for IPv6 */
|
||||
#endif
|
||||
/* The field below gets set in connect.c:connecthost() */
|
||||
uint16_t remote_port; /* the remote port, not the proxy port! */
|
||||
uint16_t conn_to_port; /* the remote port to connect to. valid only if
|
||||
bits.conn_to_port is set */
|
||||
uint16_t localportrange;
|
||||
uint16_t localport;
|
||||
uint16_t secondary_port; /* secondary socket remote port to connect to
|
||||
(ftp) */
|
||||
uint8_t transport_wanted; /* one of the TRNSPRT_* defines. Not necessarily
|
||||
the transport the connection ends using due to Alt-Svc and happy
|
||||
eyeballing. Use Curl_conn_get_transport() for actual value once the
|
||||
|
|
@ -477,14 +461,13 @@ struct connectdata {
|
|||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
#define CURL_CONN_HOST_DISPNAME(c) \
|
||||
((c)->bits.socksproxy ? (c)->socks_proxy.host.dispname : \
|
||||
(c)->bits.httpproxy ? (c)->http_proxy.host.dispname : \
|
||||
(c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \
|
||||
(c)->host.dispname)
|
||||
((c)->bits.socksproxy ? (c)->socks_proxy.peer->user_hostname : \
|
||||
(c)->bits.httpproxy ? (c)->http_proxy.peer->user_hostname : \
|
||||
(c)->via_peer ? (c)->via_peer->user_hostname : \
|
||||
(c)->origin->user_hostname)
|
||||
#else
|
||||
#define CURL_CONN_HOST_DISPNAME(c) \
|
||||
(c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \
|
||||
(c)->host.dispname
|
||||
((c)->via_peer ? (c)->via_peer->user_hostname : (c)->origin->user_hostname)
|
||||
#endif
|
||||
|
||||
/* The end of connectdata. */
|
||||
|
|
@ -692,13 +675,11 @@ struct UrlState {
|
|||
curl_off_t current_speed; /* the ProgressShow() function sets this,
|
||||
bytes / second */
|
||||
|
||||
/* hostname, port number and protocol of the first (not followed) request.
|
||||
if set, this should be the hostname that we will sent authorization to,
|
||||
no else. Used to make Location: following not keep sending user+password.
|
||||
This is strdup()ed data. */
|
||||
char *first_host;
|
||||
int first_remote_port;
|
||||
curl_prot_t first_remote_protocol;
|
||||
/* origin of the first (not followed) request.
|
||||
if set, this is the origin we sent authorization to, none else.
|
||||
Used to make Location: following not keep sending user+password. */
|
||||
struct Curl_peer *first_origin;
|
||||
|
||||
int os_errno; /* filled in with errno whenever an error occurs */
|
||||
int requests; /* request counter: redirects + authentication retakes */
|
||||
#ifdef HAVE_SIGNAL
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
|
|||
curl_msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
|
||||
|
||||
/* Generate our SPN */
|
||||
spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
|
||||
spn = Curl_auth_build_spn(service, data->conn->origin->hostname, NULL);
|
||||
if(!spn)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
|
|||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* Generate our SPN */
|
||||
spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
|
||||
spn = Curl_auth_build_spn(service, data->conn->origin->hostname, NULL);
|
||||
if(!spn) {
|
||||
curlx_free(output_token);
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
|
|
|||
|
|
@ -137,13 +137,10 @@ bool Curl_auth_user_contains_domain(const char *user)
|
|||
*/
|
||||
bool Curl_auth_allowed_to_host(struct Curl_easy *data)
|
||||
{
|
||||
struct connectdata *conn = data->conn;
|
||||
return !data->state.this_is_a_follow ||
|
||||
data->set.allow_auth_to_other_hosts ||
|
||||
(data->state.first_host &&
|
||||
curl_strequal(data->state.first_host, conn->host.name) &&
|
||||
(data->state.first_remote_port == conn->remote_port) &&
|
||||
(data->state.first_remote_protocol == conn->scheme->protocol));
|
||||
(data->state.first_origin &&
|
||||
Curl_peer_equal(data->state.first_origin, data->conn->origin));
|
||||
}
|
||||
|
||||
#ifdef USE_NTLM
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
|
|||
NULL) == WOLFSSL_FAILURE))
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
else if(!peer->sni &&
|
||||
(wolfSSL_X509_check_ip_asc(cert, peer->hostname,
|
||||
(wolfSSL_X509_check_ip_asc(cert, peer->dest->hostname,
|
||||
0) == WOLFSSL_FAILURE))
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
wolfSSL_X509_free(cert);
|
||||
|
|
|
|||
|
|
@ -2551,7 +2551,7 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
|
|||
|
||||
rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_HOST,
|
||||
(data->state.up.hostname[0] == '[') ?
|
||||
data->state.up.hostname : conn->host.name);
|
||||
data->state.up.hostname : conn->origin->hostname);
|
||||
|
||||
if(rc != SSH_OK) {
|
||||
failf(data, "Could not set remote host");
|
||||
|
|
@ -2595,9 +2595,9 @@ static CURLcode myssh_connect(struct Curl_easy *data, bool *done)
|
|||
}
|
||||
}
|
||||
|
||||
if(conn->remote_port) {
|
||||
if(conn->origin->port) {
|
||||
rc = ssh_options_set(sshc->ssh_session, SSH_OPTIONS_PORT,
|
||||
&conn->remote_port);
|
||||
&conn->origin->port);
|
||||
if(rc != SSH_OK) {
|
||||
failf(data, "Could not set remote port");
|
||||
return CURLE_FAILED_INIT;
|
||||
|
|
|
|||
|
|
@ -361,9 +361,9 @@ static CURLcode ssh_knownhost(struct Curl_easy *data,
|
|||
rc = CURLKHSTAT_REJECT;
|
||||
else {
|
||||
keycheck = libssh2_knownhost_checkp(sshc->kh,
|
||||
conn->host.name,
|
||||
(conn->remote_port != PORT_SSH) ?
|
||||
conn->remote_port : -1,
|
||||
conn->origin->hostname,
|
||||
(conn->origin->port != PORT_SSH) ?
|
||||
conn->origin->port : -1,
|
||||
remotekey, keylen,
|
||||
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
|
||||
LIBSSH2_KNOWNHOST_KEYENC_RAW|
|
||||
|
|
@ -427,14 +427,14 @@ static CURLcode ssh_knownhost(struct Curl_easy *data,
|
|||
/* the found host+key did not match but has been told to be fine
|
||||
anyway so we add it in memory */
|
||||
int addrc = libssh2_knownhost_add(sshc->kh,
|
||||
conn->host.name, NULL,
|
||||
conn->origin->hostname, NULL,
|
||||
remotekey, keylen,
|
||||
LIBSSH2_KNOWNHOST_TYPE_PLAIN|
|
||||
LIBSSH2_KNOWNHOST_KEYENC_RAW|
|
||||
keybit, NULL);
|
||||
if(addrc)
|
||||
infof(data, "WARNING: adding the known host %s failed",
|
||||
conn->host.name);
|
||||
conn->origin->hostname);
|
||||
else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE ||
|
||||
rc == CURLKHSTAT_FINE_REPLACE) {
|
||||
/* now we write the entire in-memory list of known hosts to the
|
||||
|
|
@ -642,16 +642,16 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data,
|
|||
}
|
||||
p = kh_name_end + 2; /* start of port number */
|
||||
if(!curlx_str_number(&p, &port, 0xffff) &&
|
||||
(kh_name_end && (port == conn->remote_port))) {
|
||||
(kh_name_end && (port == conn->origin->port))) {
|
||||
kh_name_size = strlen(store->name) - 1 - strlen(kh_name_end);
|
||||
if(strncmp(store->name + 1,
|
||||
conn->host.name, kh_name_size) == 0) {
|
||||
conn->origin->hostname, kh_name_size) == 0) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(strcmp(store->name, conn->host.name) == 0) {
|
||||
else if(strcmp(store->name, conn->origin->hostname) == 0) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
|
@ -667,7 +667,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data,
|
|||
int rc;
|
||||
const char *hostkey_method = NULL;
|
||||
infof(data, "Found host %s in %s",
|
||||
conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
|
||||
conn->origin->hostname, data->set.str[STRING_SSH_KNOWNHOSTS]);
|
||||
|
||||
switch(store->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) {
|
||||
case LIBSSH2_KNOWNHOST_KEY_ED25519:
|
||||
|
|
@ -710,7 +710,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data,
|
|||
}
|
||||
else {
|
||||
infof(data, "Did not find host %s in %s",
|
||||
conn->host.name, data->set.str[STRING_SSH_KNOWNHOSTS]);
|
||||
conn->origin->hostname, data->set.str[STRING_SSH_KNOWNHOSTS]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ CURLcode Curl_vtls_apple_verify(struct Curl_cfilter *cf,
|
|||
|
||||
if(conn_config->verifyhost) {
|
||||
host_str = CFStringCreateWithCString(NULL,
|
||||
peer->sni ? peer->sni : peer->hostname, kCFStringEncodingUTF8);
|
||||
peer->sni ? peer->sni : peer->dest->hostname, kCFStringEncodingUTF8);
|
||||
if(!host_str) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -1361,11 +1361,12 @@ static void gtls_msg_verify_result(struct Curl_easy *data,
|
|||
if(!was_verified) {
|
||||
if(needs_verified) {
|
||||
failf(data, "SSL: certificate subject name (%s) does not match "
|
||||
"target hostname '%s'", certname, peer->dispname);
|
||||
"target hostname '%s'", certname,
|
||||
peer->dest->user_hostname);
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (does not match '%s')",
|
||||
certname, peer->dispname);
|
||||
certname, peer->dest->user_hostname);
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (matched)", certname);
|
||||
|
|
@ -1821,7 +1822,7 @@ CURLcode Curl_gtls_verifyserver(struct Curl_cfilter *cf,
|
|||
IP addresses) */
|
||||
rc = (int)gnutls_x509_crt_check_hostname(x509_cert,
|
||||
peer->sni ? peer->sni :
|
||||
peer->hostname);
|
||||
peer->dest->hostname);
|
||||
result = (!rc && config->verifyhost) ?
|
||||
CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
|
||||
gtls_msg_verify_result(data, peer, x509_cert, rc, config->verifyhost);
|
||||
|
|
|
|||
|
|
@ -791,7 +791,7 @@ static CURLcode mbed_configure_ssl(struct Curl_cfilter *cf,
|
|||
char errorbuf[128];
|
||||
|
||||
infof(data, "mbedTLS: Connecting to %s:%d",
|
||||
connssl->peer.hostname, connssl->peer.port);
|
||||
connssl->peer.dest->hostname, connssl->peer.dest->port);
|
||||
|
||||
mbedtls_ssl_config_init(&backend->config);
|
||||
ret = mbedtls_ssl_config_defaults(&backend->config,
|
||||
|
|
@ -932,7 +932,8 @@ static CURLcode mbed_configure_ssl(struct Curl_cfilter *cf,
|
|||
}
|
||||
|
||||
if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni ?
|
||||
connssl->peer.sni : connssl->peer.hostname)) {
|
||||
connssl->peer.sni :
|
||||
connssl->peer.dest->hostname)) {
|
||||
/* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
|
||||
the name to set in the SNI extension. Thus even if curl connects to
|
||||
a host specified as an IP address, this function must be used. */
|
||||
|
|
|
|||
|
|
@ -2042,19 +2042,19 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
|
|||
CURLcode result = CURLE_OK;
|
||||
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
|
||||
bool iPAddress = FALSE; /* if an iPAddress field exists in the cert */
|
||||
size_t hostlen = strlen(peer->hostname);
|
||||
size_t hostlen = strlen(peer->dest->hostname);
|
||||
|
||||
(void)conn;
|
||||
switch(peer->type) {
|
||||
case CURL_SSL_PEER_IPV4:
|
||||
if(!curlx_inet_pton(AF_INET, peer->hostname, &addr))
|
||||
if(!curlx_inet_pton(AF_INET, peer->dest->hostname, &addr))
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
target = GEN_IPADD;
|
||||
addrlen = sizeof(struct in_addr);
|
||||
break;
|
||||
#ifdef USE_IPV6
|
||||
case CURL_SSL_PEER_IPV6:
|
||||
if(!curlx_inet_pton(AF_INET6, peer->hostname, &addr))
|
||||
if(!curlx_inet_pton(AF_INET6, peer->dest->hostname, &addr))
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
target = GEN_IPADD;
|
||||
addrlen = sizeof(struct in6_addr);
|
||||
|
|
@ -2115,10 +2115,11 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
|
|||
if((altlen == strlen(altptr)) &&
|
||||
/* if this is not true, there was an embedded zero in the name
|
||||
string and we cannot match it. */
|
||||
Curl_cert_hostcheck(altptr, altlen, peer->hostname, hostlen)) {
|
||||
Curl_cert_hostcheck(altptr, altlen,
|
||||
peer->dest->hostname, hostlen)) {
|
||||
matched = TRUE;
|
||||
infof(data, " subjectAltName: \"%s\" matches cert's \"%.*s\"",
|
||||
peer->dispname, (int)altlen, altptr);
|
||||
peer->dest->user_hostname, (int)altlen, altptr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2128,7 +2129,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
|
|||
if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
|
||||
matched = TRUE;
|
||||
infof(data, " subjectAltName: \"%s\" matches cert's IP address!",
|
||||
peer->dispname);
|
||||
peer->dest->user_hostname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -2144,9 +2145,10 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
|
|||
const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "hostname" :
|
||||
(peer->type == CURL_SSL_PEER_IPV4) ?
|
||||
"ipv4 address" : "ipv6 address";
|
||||
infof(data, " subjectAltName does not match %s %s", tname, peer->dispname);
|
||||
infof(data, " subjectAltName does not match %s %s", tname,
|
||||
peer->dest->user_hostname);
|
||||
failf(data, "SSL: no alternative certificate subject name matches "
|
||||
"target %s '%s'", tname, peer->dispname);
|
||||
"target %s '%s'", tname, peer->dest->user_hostname);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else {
|
||||
|
|
@ -2206,9 +2208,9 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
|
|||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else if(!Curl_cert_hostcheck((const char *)cn, cnlen,
|
||||
peer->hostname, hostlen)) {
|
||||
peer->dest->hostname, hostlen)) {
|
||||
failf(data, "SSL: certificate subject name '%s' does not match "
|
||||
"target hostname '%s'", cn, peer->dispname);
|
||||
"target hostname '%s'", cn, peer->dest->user_hostname);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else {
|
||||
|
|
@ -3532,9 +3534,9 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx,
|
|||
#else
|
||||
if(trying_ech_now && outername) {
|
||||
infof(data, "ECH: inner: '%s', outer: '%s'",
|
||||
peer->hostname ? peer->hostname : "NULL", outername);
|
||||
peer->dest->hostname ? peer->dest->hostname : "NULL", outername);
|
||||
result = SSL_ech_set1_server_names(octx->ssl,
|
||||
peer->hostname, outername,
|
||||
peer->dest->hostname, outername,
|
||||
0 /* do send outer */);
|
||||
if(result != 1) {
|
||||
infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
|
||||
|
|
@ -4263,7 +4265,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
|
|||
curlx_strerror(sockerr, extramsg, sizeof(extramsg));
|
||||
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
|
||||
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
|
||||
connssl->peer.hostname, connssl->peer.port);
|
||||
connssl->peer.dest->hostname, connssl->peer.dest->port);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -4310,7 +4312,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
|
|||
struct ssl_primary_config *conn_config =
|
||||
Curl_ssl_cf_get_primary_config(cf);
|
||||
if(!conn_config->verifypeer && !conn_config->verifyhost &&
|
||||
inner && !strcmp(inner, connssl->peer.hostname)) {
|
||||
inner && !strcmp(inner, connssl->peer.dest->hostname)) {
|
||||
VERBOSE(status = "bad name (tolerated without peer verification)");
|
||||
rv = SSL_ECH_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1095,7 +1095,7 @@ static CURLcode cr_init_backend(struct Curl_cfilter *cf,
|
|||
|
||||
DEBUGASSERT(rconn == NULL);
|
||||
rr = rustls_client_connection_new(backend->config,
|
||||
connssl->peer.hostname,
|
||||
connssl->peer.dest->hostname,
|
||||
&rconn);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "rustls_client_connection_new");
|
||||
|
|
|
|||
|
|
@ -843,7 +843,7 @@ static CURLcode schannel_connect_step1(struct Curl_cfilter *cf,
|
|||
|
||||
DEBUGASSERT(backend);
|
||||
DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %d (step 1/3)",
|
||||
connssl->peer.hostname, connssl->peer.port));
|
||||
connssl->peer.dest->hostname, connssl->peer.dest->port));
|
||||
|
||||
#ifdef HAS_ALPN_SCHANNEL
|
||||
backend->use_alpn = connssl->alpn && s_win_has_alpn;
|
||||
|
|
@ -895,7 +895,8 @@ static CURLcode schannel_connect_step1(struct Curl_cfilter *cf,
|
|||
|
||||
/* A hostname associated with the credential is needed by
|
||||
InitializeSecurityContext for SNI and other reasons. */
|
||||
snihost = connssl->peer.sni ? connssl->peer.sni : connssl->peer.hostname;
|
||||
snihost = connssl->peer.sni ?
|
||||
connssl->peer.sni : connssl->peer.dest->hostname;
|
||||
backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
|
||||
if(!backend->cred->sni_hostname)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
|
@ -1238,7 +1239,7 @@ static CURLcode schannel_connect_step2(struct Curl_cfilter *cf,
|
|||
connssl->io_need = CURL_SSL_IO_NEED_NONE;
|
||||
|
||||
DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %d (step 2/3)",
|
||||
connssl->peer.hostname, connssl->peer.port));
|
||||
connssl->peer.dest->hostname, connssl->peer.dest->port));
|
||||
|
||||
if(!backend->cred || !backend->ctxt)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
|
@ -1590,7 +1591,7 @@ static CURLcode schannel_connect_step3(struct Curl_cfilter *cf,
|
|||
DEBUGASSERT(backend);
|
||||
|
||||
DEBUGF(infof(data, "schannel: SSL/TLS connection with %s port %d (step 3/3)",
|
||||
connssl->peer.hostname, connssl->peer.port));
|
||||
connssl->peer.dest->hostname, connssl->peer.dest->port));
|
||||
|
||||
if(!backend->cred)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
|
@ -2428,7 +2429,7 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
|
|||
*done = FALSE;
|
||||
if(backend->ctxt) {
|
||||
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
|
||||
connssl->peer.hostname, connssl->peer.port);
|
||||
connssl->peer.dest->hostname, connssl->peer.dest->port);
|
||||
}
|
||||
|
||||
if(!backend->ctxt || cf->shutdown) {
|
||||
|
|
|
|||
|
|
@ -509,7 +509,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
SECURITY_STATUS sspi_status;
|
||||
TCHAR *cert_hostname_buff = NULL;
|
||||
size_t cert_hostname_buff_index = 0;
|
||||
const char *conn_hostname = connssl->peer.hostname;
|
||||
const char *conn_hostname = connssl->peer.dest->hostname;
|
||||
size_t hostlen = strlen(conn_hostname);
|
||||
DWORD len = 0;
|
||||
DWORD actual_len = 0;
|
||||
|
|
|
|||
|
|
@ -1180,11 +1180,8 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
|
|||
|
||||
void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
|
||||
{
|
||||
Curl_peer_unlink(&peer->dest);
|
||||
curlx_safefree(peer->sni);
|
||||
if(peer->dispname != peer->hostname)
|
||||
curlx_free(peer->dispname);
|
||||
peer->dispname = NULL;
|
||||
curlx_safefree(peer->hostname);
|
||||
curlx_safefree(peer->scache_key);
|
||||
peer->type = CURL_SSL_PEER_DNS;
|
||||
}
|
||||
|
|
@ -1224,13 +1221,12 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
|
|||
const char *tls_id,
|
||||
uint8_t transport)
|
||||
{
|
||||
const char *ehostname, *edispname;
|
||||
struct Curl_peer *dest = NULL;
|
||||
CURLcode result = CURLE_OUT_OF_MEMORY;
|
||||
|
||||
/* We expect a clean struct, e.g. called only ONCE */
|
||||
DEBUGASSERT(peer);
|
||||
DEBUGASSERT(!peer->hostname);
|
||||
DEBUGASSERT(!peer->dispname);
|
||||
DEBUGASSERT(!peer->dest);
|
||||
DEBUGASSERT(!peer->sni);
|
||||
/* We need the hostname for SNI negotiation. Once handshaked, this remains
|
||||
* the SNI hostname for the TLS connection. When the connection is reused,
|
||||
|
|
@ -1240,46 +1236,33 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
|
|||
peer->transport = transport;
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(Curl_ssl_cf_is_proxy(cf)) {
|
||||
ehostname = cf->conn->http_proxy.host.name;
|
||||
edispname = cf->conn->http_proxy.host.dispname;
|
||||
peer->port = cf->conn->http_proxy.port;
|
||||
dest = cf->conn->http_proxy.peer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ehostname = cf->conn->host.name;
|
||||
edispname = cf->conn->host.dispname;
|
||||
peer->port = (uint16_t)cf->conn->remote_port;
|
||||
dest = cf->conn->origin;
|
||||
}
|
||||
|
||||
/* hostname MUST exist and not be empty */
|
||||
if(!ehostname || !ehostname[0]) {
|
||||
if(!dest) {
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
peer->hostname = curlx_strdup(ehostname);
|
||||
if(!peer->hostname)
|
||||
goto out;
|
||||
if(!edispname || !strcmp(ehostname, edispname))
|
||||
peer->dispname = peer->hostname;
|
||||
else {
|
||||
peer->dispname = curlx_strdup(edispname);
|
||||
if(!peer->dispname)
|
||||
goto out;
|
||||
}
|
||||
peer->type = get_peer_type(peer->hostname);
|
||||
Curl_peer_link(&peer->dest, dest);
|
||||
peer->type = get_peer_type(dest->hostname);
|
||||
if(peer->type == CURL_SSL_PEER_DNS) {
|
||||
/* not an IP address, normalize according to RCC 6066 ch. 3,
|
||||
* max len of SNI is 2^16-1, no trailing dot */
|
||||
size_t len = strlen(peer->hostname);
|
||||
if(len && (peer->hostname[len - 1] == '.'))
|
||||
size_t len = strlen(dest->hostname);
|
||||
if(len && (dest->hostname[len - 1] == '.'))
|
||||
len--;
|
||||
if(len < USHRT_MAX) {
|
||||
peer->sni = curlx_calloc(1, len + 1);
|
||||
if(!peer->sni)
|
||||
goto out;
|
||||
Curl_strntolower(peer->sni, peer->hostname, len);
|
||||
Curl_strntolower(peer->sni, dest->hostname, len);
|
||||
peer->sni[len] = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1353,7 +1336,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
|||
connssl->prefs_checked = TRUE;
|
||||
}
|
||||
|
||||
if(!connssl->peer.hostname) {
|
||||
if(!connssl->peer.dest) {
|
||||
char tls_id[80];
|
||||
connssl->ssl_impl->version(tls_id, sizeof(tls_id) - 1);
|
||||
result = Curl_ssl_peer_init(&connssl->peer, cf, tls_id, TRNSPRT_TCP);
|
||||
|
|
|
|||
|
|
@ -91,12 +91,10 @@ typedef enum {
|
|||
} ssl_peer_type;
|
||||
|
||||
struct ssl_peer {
|
||||
char *hostname; /* hostname for verification */
|
||||
char *dispname; /* display version of hostname */
|
||||
struct Curl_peer *dest;
|
||||
char *sni; /* SNI version of hostname or NULL if not usable */
|
||||
char *scache_key; /* for lookups in session cache */
|
||||
ssl_peer_type type; /* type of the peer information */
|
||||
uint16_t port; /* port we are talking to */
|
||||
uint8_t transport; /* one of TRNSPRT_* defines */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,8 @@ CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
|
|||
*ppeer_key = NULL;
|
||||
curlx_dyn_init(&buf, 10 * 1024);
|
||||
|
||||
r = curlx_dyn_addf(&buf, "%s:%d", peer->hostname, peer->port);
|
||||
r = curlx_dyn_addf(&buf, "%s:%d",
|
||||
peer->dest->hostname, peer->dest->port);
|
||||
if(r)
|
||||
goto out;
|
||||
|
||||
|
|
@ -187,13 +188,10 @@ CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
|
|||
goto out;
|
||||
}
|
||||
if(!ssl->verifypeer || !ssl->verifyhost) {
|
||||
if(cf->conn->bits.conn_to_host) {
|
||||
r = curlx_dyn_addf(&buf, ":CHOST-%s", cf->conn->conn_to_host.name);
|
||||
if(r)
|
||||
goto out;
|
||||
}
|
||||
if(cf->conn->bits.conn_to_port) {
|
||||
r = curlx_dyn_addf(&buf, ":CPORT-%d", cf->conn->conn_to_port);
|
||||
if(cf->conn->via_peer) {
|
||||
r = curlx_dyn_addf(&buf, ":CHOST-%s:CPORT-%u",
|
||||
cf->conn->via_peer->hostname,
|
||||
cf->conn->via_peer->port);
|
||||
if(r)
|
||||
goto out;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1765,9 +1765,9 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
failf(data, "unable to get peer certificate");
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
ret = wolfSSL_X509_check_ip_asc(cert, connssl->peer.hostname, 0);
|
||||
ret = wolfSSL_X509_check_ip_asc(cert, connssl->peer.dest->hostname, 0);
|
||||
CURL_TRC_CF(data, cf, "check peer certificate for IP match on %s -> %d",
|
||||
connssl->peer.hostname, ret);
|
||||
connssl->peer.dest->hostname, ret);
|
||||
if(ret != WOLFSSL_SUCCESS)
|
||||
detail = DOMAIN_NAME_MISMATCH;
|
||||
wolfSSL_X509_free(cert);
|
||||
|
|
@ -1790,7 +1790,7 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
* This enables the override of both mismatching SubjectAltNames
|
||||
* as also mismatching CN fields */
|
||||
failf(data, " subject alt name(s) or common name do not match \"%s\"",
|
||||
connssl->peer.dispname);
|
||||
connssl->peer.dest->hostname);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else if(ASN_NO_SIGNER_E == detail) {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,11 @@ static const char *scheme[] = {
|
|||
"smbs",
|
||||
"smtp",
|
||||
"smtps",
|
||||
"socks",
|
||||
"socks4",
|
||||
"socks4a",
|
||||
"socks5",
|
||||
"socks5h",
|
||||
"telnet",
|
||||
"tftp",
|
||||
"ws",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue