mirror of
https://github.com/curl/curl.git
synced 2026-06-14 02:05:37 +03:00
ngtcp2: share common functionality
Share common functions/structs between ngtcp2 HTTP/3 and the proxy version. Fix bugs in proxy implementation when it comes to stream and pollset handling and transfer lifetimes. Curl_multi_xfer_sockbuf_borrow: work without multi When a connection gets shutdown by a share, the easy handle used is share->admin and it does not have a multi handle. In that case let Curl_multi_xfer_sockbuf_borrow() allocate a buffer to be freed on release. This happens when a TLS filter sends its last notify through a HTTP/3 proxy tunnel. Closes #21871
This commit is contained in:
parent
4fcf9c8f59
commit
f924489b25
43 changed files with 3254 additions and 4970 deletions
|
|
@ -125,6 +125,7 @@ LIB_VQUIC_CFILES = \
|
|||
vquic/capsule.c \
|
||||
vquic/cf-capsule.c \
|
||||
vquic/cf-ngtcp2.c \
|
||||
vquic/cf-ngtcp2-cmn.c \
|
||||
vquic/cf-ngtcp2-proxy.c \
|
||||
vquic/cf-quiche.c \
|
||||
vquic/vquic.c \
|
||||
|
|
@ -134,6 +135,7 @@ LIB_VQUIC_HFILES = \
|
|||
vquic/capsule.h \
|
||||
vquic/cf-capsule.h \
|
||||
vquic/cf-ngtcp2.h \
|
||||
vquic/cf-ngtcp2-cmn.h \
|
||||
vquic/cf-ngtcp2-proxy.h \
|
||||
vquic/cf-quiche.h \
|
||||
vquic/vquic.h \
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
struct transport_provider {
|
||||
cf_ip_connect_create *cf_create;
|
||||
uint8_t transport;
|
||||
bool tunnel_proxy;
|
||||
bool tunnel;
|
||||
};
|
||||
|
||||
static
|
||||
|
|
@ -88,12 +88,12 @@ struct transport_provider transport_providers[] = {
|
|||
};
|
||||
|
||||
static cf_ip_connect_create *get_cf_create(uint8_t transport,
|
||||
bool tunnel_proxy)
|
||||
bool tunnel)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) {
|
||||
if((transport == transport_providers[i].transport) &&
|
||||
(tunnel_proxy == transport_providers[i].tunnel_proxy))
|
||||
(tunnel == transport_providers[i].tunnel))
|
||||
return transport_providers[i].cf_create;
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -155,14 +155,17 @@ static bool cf_ai_iter_has_more(struct cf_ai_iter *iter,
|
|||
|
||||
struct cf_ip_attempt {
|
||||
struct cf_ip_attempt *next;
|
||||
struct Curl_peer *origin;
|
||||
struct Curl_peer *peer;
|
||||
struct Curl_peer *tunnel_peer;
|
||||
struct Curl_sockaddr_ex addr;
|
||||
struct Curl_cfilter *cf; /* current sub-cfilter connecting */
|
||||
cf_ip_connect_create *cf_create;
|
||||
struct curltime started; /* start of current attempt */
|
||||
CURLcode result;
|
||||
int ai_family;
|
||||
uint8_t transport_in;
|
||||
uint8_t transport_out;
|
||||
uint8_t transport_peer;
|
||||
uint8_t tunnel_transport;
|
||||
int error;
|
||||
BIT(connected); /* cf has connected */
|
||||
BIT(shutdown); /* cf has shutdown */
|
||||
|
|
@ -176,17 +179,23 @@ static void cf_ip_attempt_free(struct cf_ip_attempt *a,
|
|||
if(a) {
|
||||
if(a->cf)
|
||||
Curl_conn_cf_discard_chain(&a->cf, data);
|
||||
Curl_peer_unlink(&a->origin);
|
||||
Curl_peer_unlink(&a->peer);
|
||||
Curl_peer_unlink(&a->tunnel_peer);
|
||||
curlx_free(a);
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
int ai_family,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport,
|
||||
cf_ip_connect_create *cf_create)
|
||||
{
|
||||
struct Curl_cfilter *wcf;
|
||||
|
|
@ -198,16 +207,20 @@ static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa,
|
|||
if(!a)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
||||
Curl_peer_link(&a->origin, origin);
|
||||
Curl_peer_link(&a->peer, peer);
|
||||
a->transport_peer = transport_peer;
|
||||
Curl_peer_link(&a->tunnel_peer, tunnel_peer);
|
||||
a->tunnel_transport = tunnel_transport;
|
||||
a->addr = *addr;
|
||||
a->ai_family = ai_family;
|
||||
a->transport_in = transport_in;
|
||||
a->transport_out = transport_out;
|
||||
a->result = CURLE_OK;
|
||||
a->cf_create = cf_create;
|
||||
*pa = a;
|
||||
|
||||
result = a->cf_create(&a->cf, data, cf->conn, &a->addr,
|
||||
a->transport_in, a->transport_out);
|
||||
result = a->cf_create(&a->cf, data, a->origin, a->peer, a->transport_peer,
|
||||
cf->conn, &a->addr, a->tunnel_peer,
|
||||
a->tunnel_transport);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -256,14 +269,17 @@ struct cf_ip_ballers {
|
|||
#ifdef USE_IPV6
|
||||
struct cf_ai_iter ipv6_iter;
|
||||
#endif
|
||||
struct Curl_peer *origin;
|
||||
struct Curl_peer *peer;
|
||||
struct Curl_peer *tunnel_peer;
|
||||
cf_ip_connect_create *cf_create; /* for creating cf */
|
||||
struct curltime started;
|
||||
struct curltime last_attempt_started;
|
||||
timediff_t attempt_delay_ms;
|
||||
int last_attempt_ai_family;
|
||||
uint32_t max_concurrent;
|
||||
uint8_t transport_in;
|
||||
uint8_t transport_out;
|
||||
uint8_t transport_peer;
|
||||
uint8_t tunnel_transport;
|
||||
};
|
||||
|
||||
static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
|
||||
|
|
@ -281,8 +297,9 @@ static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
|
|||
a->inconclusive = FALSE;
|
||||
a->cf = NULL;
|
||||
|
||||
result = a->cf_create(&a->cf, data, cf->conn, &a->addr, a->transport_in,
|
||||
a->transport_out);
|
||||
result = a->cf_create(&a->cf, data, a->origin, a->peer, a->transport_peer,
|
||||
cf->conn, &a->addr,
|
||||
a->tunnel_peer, a->tunnel_transport);
|
||||
if(!result) {
|
||||
bool dummy;
|
||||
/* the new filter might have sub-filters */
|
||||
|
|
@ -295,11 +312,9 @@ static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a,
|
|||
return result;
|
||||
}
|
||||
|
||||
static void cf_ip_ballers_clear(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
static void cf_ip_ballers_clear(struct Curl_easy *data,
|
||||
struct cf_ip_ballers *bs)
|
||||
{
|
||||
(void)cf;
|
||||
while(bs->running) {
|
||||
struct cf_ip_attempt *a = bs->running;
|
||||
bs->running = a->next;
|
||||
|
|
@ -307,37 +322,36 @@ static void cf_ip_ballers_clear(struct Curl_cfilter *cf,
|
|||
}
|
||||
cf_ip_attempt_free(bs->winner, data);
|
||||
bs->winner = NULL;
|
||||
Curl_peer_unlink(&bs->origin);
|
||||
Curl_peer_unlink(&bs->peer);
|
||||
Curl_peer_unlink(&bs->tunnel_peer);
|
||||
}
|
||||
|
||||
static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs,
|
||||
struct Curl_cfilter *cf,
|
||||
cf_ip_connect_create *cf_create,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport,
|
||||
timediff_t attempt_delay_ms,
|
||||
uint32_t max_concurrent)
|
||||
{
|
||||
memset(bs, 0, sizeof(*bs));
|
||||
bs->cf_create = cf_create;
|
||||
bs->transport_in = transport_in;
|
||||
bs->transport_out = transport_out;
|
||||
bs->cf_create = get_cf_create(transport_peer, !!tunnel_peer);
|
||||
if(!bs->cf_create) {
|
||||
failf(data, "unsupported transport type %u%s",
|
||||
transport_peer, tunnel_peer ? "to proxy" : "");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
Curl_peer_link(&bs->origin, origin);
|
||||
Curl_peer_link(&bs->peer, peer);
|
||||
bs->transport_peer = transport_peer;
|
||||
Curl_peer_link(&bs->tunnel_peer, tunnel_peer);
|
||||
bs->tunnel_transport = tunnel_transport;
|
||||
bs->attempt_delay_ms = attempt_delay_ms;
|
||||
bs->max_concurrent = max_concurrent;
|
||||
bs->last_attempt_ai_family = AF_INET; /* so AF_INET6 is next */
|
||||
|
||||
if(transport_in == TRNSPRT_UNIX) {
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
cf_ai_iter_init(&bs->addr_iter, cf, AF_UNIX);
|
||||
#else
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
else { /* TCP/UDP/QUIC */
|
||||
#ifdef USE_IPV6
|
||||
cf_ai_iter_init(&bs->ipv6_iter, cf, AF_INET6);
|
||||
#endif
|
||||
cf_ai_iter_init(&bs->addr_iter, cf, AF_INET);
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
|
@ -473,12 +487,13 @@ evaluate:
|
|||
if(bs->max_concurrent)
|
||||
cf_ip_ballers_prune(bs, cf, data, bs->max_concurrent - 1);
|
||||
|
||||
result = Curl_socket_addr_from_ai(&addr, ai, bs->transport_out);
|
||||
result = Curl_socket_addr_from_ai(&addr, ai, bs->transport_peer);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
result = cf_ip_attempt_new(&a, cf, data, &addr, ai_family,
|
||||
bs->transport_in, bs->transport_out,
|
||||
result = cf_ip_attempt_new(&a, data, cf, bs->origin, bs->peer,
|
||||
bs->transport_peer, &addr, ai_family,
|
||||
bs->tunnel_peer, bs->tunnel_transport,
|
||||
bs->cf_create);
|
||||
CURL_TRC_CF(data, cf, "starting %s attempt for ipv%s -> %d",
|
||||
bs->running ? "next" : "first",
|
||||
|
|
@ -668,13 +683,10 @@ typedef enum {
|
|||
} cf_connect_state;
|
||||
|
||||
struct cf_ip_happy_ctx {
|
||||
struct Curl_peer *peer;
|
||||
cf_ip_connect_create *cf_create;
|
||||
cf_connect_state state;
|
||||
struct cf_ip_ballers ballers;
|
||||
struct curltime started;
|
||||
uint8_t transport_in;
|
||||
uint8_t transport_out;
|
||||
BIT(dns_resolved);
|
||||
};
|
||||
|
||||
|
|
@ -750,29 +762,39 @@ static CURLcode cf_ip_happy_init(struct Curl_cfilter *cf,
|
|||
return CURLE_OPERATION_TIMEDOUT;
|
||||
}
|
||||
|
||||
if(ctx->ballers.transport_peer == TRNSPRT_UNIX) {
|
||||
#ifdef USE_UNIX_SOCKETS
|
||||
cf_ai_iter_init(&ctx->ballers.addr_iter, cf, AF_UNIX);
|
||||
#else
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
#endif
|
||||
}
|
||||
else { /* TCP/UDP/QUIC */
|
||||
#ifdef USE_IPV6
|
||||
cf_ai_iter_init(&ctx->ballers.ipv6_iter, cf, AF_INET6);
|
||||
#endif
|
||||
cf_ai_iter_init(&ctx->ballers.addr_iter, cf, AF_INET);
|
||||
}
|
||||
|
||||
CURL_TRC_CF(data, cf, "init ip ballers for transport %u",
|
||||
ctx->transport_out);
|
||||
ctx->ballers.transport_peer);
|
||||
ctx->started = *Curl_pgrs_now(data);
|
||||
return cf_ip_ballers_init(&ctx->ballers, cf, ctx->cf_create,
|
||||
ctx->transport_in, ctx->transport_out,
|
||||
data->set.happy_eyeballs_timeout,
|
||||
IP_HE_MAX_CONCURRENT_ATTEMPTS);
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void cf_ip_happy_ctx_clear(struct Curl_cfilter *cf,
|
||||
static void cf_ip_happy_ctx_clear(struct cf_ip_happy_ctx *ctx,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = cf->ctx;
|
||||
|
||||
DEBUGASSERT(ctx);
|
||||
DEBUGASSERT(data);
|
||||
cf_ip_ballers_clear(cf, data, &ctx->ballers);
|
||||
if(ctx)
|
||||
cf_ip_ballers_clear(data, &ctx->ballers);
|
||||
}
|
||||
|
||||
static void cf_ip_happy_ctx_destroy(struct cf_ip_happy_ctx *ctx)
|
||||
static void cf_ip_happy_ctx_destroy(struct cf_ip_happy_ctx *ctx,
|
||||
struct Curl_easy *data)
|
||||
{
|
||||
if(ctx) {
|
||||
Curl_peer_unlink(&ctx->peer);
|
||||
cf_ip_happy_ctx_clear(ctx, data);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
|
@ -860,7 +882,7 @@ static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,
|
|||
cf->connected = TRUE;
|
||||
cf->next = ctx->ballers.winner->cf;
|
||||
ctx->ballers.winner->cf = NULL;
|
||||
cf_ip_happy_ctx_clear(cf, data);
|
||||
cf_ip_happy_ctx_clear(ctx, data);
|
||||
Curl_expire_done(data, EXPIRE_HAPPY_EYEBALLS);
|
||||
/* whatever errors where reported by ballers, clear our errorbuf */
|
||||
Curl_reset_fail(data);
|
||||
|
|
@ -943,8 +965,8 @@ static void cf_ip_happy_destroy(struct Curl_cfilter *cf,
|
|||
|
||||
CURL_TRC_CF(data, cf, "destroy");
|
||||
if(ctx) {
|
||||
cf_ip_happy_ctx_clear(cf, data);
|
||||
cf_ip_happy_ctx_destroy(ctx);
|
||||
cf_ip_happy_ctx_clear(ctx, data);
|
||||
cf_ip_happy_ctx_destroy(ctx, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -977,11 +999,12 @@ struct Curl_cftype Curl_cft_ip_happy = {
|
|||
*/
|
||||
static CURLcode cf_ip_happy_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
cf_ip_connect_create *cf_create,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out)
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
struct cf_ip_happy_ctx *ctx = NULL;
|
||||
CURLcode result;
|
||||
|
|
@ -994,42 +1017,39 @@ static CURLcode cf_ip_happy_create(struct Curl_cfilter **pcf,
|
|||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
ctx->transport_in = transport_in;
|
||||
ctx->transport_out = transport_out;
|
||||
ctx->cf_create = cf_create;
|
||||
Curl_peer_link(&ctx->peer, peer);
|
||||
result = cf_ip_ballers_init(&ctx->ballers, data,
|
||||
origin, peer, transport_peer,
|
||||
tunnel_peer, tunnel_transport,
|
||||
data->set.happy_eyeballs_timeout,
|
||||
IP_HE_MAX_CONCURRENT_ATTEMPTS);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
result = Curl_cf_create(pcf, &Curl_cft_ip_happy, ctx);
|
||||
|
||||
out:
|
||||
if(result) {
|
||||
curlx_safefree(*pcf);
|
||||
cf_ip_happy_ctx_destroy(ctx);
|
||||
cf_ip_happy_ctx_destroy(ctx, data);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out,
|
||||
bool tunnel_proxy)
|
||||
uint8_t transport_peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
cf_ip_connect_create *cf_create;
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
/* Need to be first */
|
||||
DEBUGASSERT(cf_at);
|
||||
cf_create = get_cf_create(transport_out, tunnel_proxy);
|
||||
if(!cf_create) {
|
||||
CURL_TRC_CF(data, cf_at, "unsupported transport type %u%s",
|
||||
transport_out, tunnel_proxy ? "to proxy" : "");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
result = cf_ip_happy_create(&cf, data, peer, cf_at->conn, cf_create,
|
||||
transport_in, transport_out);
|
||||
result = cf_ip_happy_create(&cf, data, origin, peer, transport_peer,
|
||||
cf_at->conn, tunnel_peer, tunnel_transport);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,15 @@ struct Curl_peer;
|
|||
struct Curl_sockaddr_ex;
|
||||
|
||||
/**
|
||||
* Create a cfilter for making an "ip" connection to the
|
||||
* given address, using parameters from `conn`. The "ip" connection
|
||||
* can be a TCP socket, a UDP socket or even a QUIC connection.
|
||||
*
|
||||
* It MUST use only the supplied `ai` for its connection attempt.
|
||||
* Create a cfilter for making an "ip" connect to a peer.
|
||||
* `pcf`: the filter created on success
|
||||
* `data`: the transfer initiating the connect
|
||||
* `peer`: the peer to connect to
|
||||
* `transport_peer': the transport used for the peer connect
|
||||
* `conn`: the connection that gets connected
|
||||
* `addr`: the socket address to connect to
|
||||
* `tunnel_peer`: NULL or the peer to tunnel through
|
||||
* `tunnel_transport`: the transport that goes through the tunnel
|
||||
*
|
||||
* Such a filter may be used in "happy eyeball" scenarios, and its
|
||||
* `connect` implementation needs to support non-blocking. Once connected,
|
||||
|
|
@ -45,26 +49,21 @@ struct Curl_sockaddr_ex;
|
|||
*/
|
||||
typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out);
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out,
|
||||
bool tunnel_proxy);
|
||||
|
||||
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) && \
|
||||
defined(USE_PROXY_HTTP3)
|
||||
/* For H3 proxy: create happy eyeballs that races IPv4/IPv6 using raw UDP
|
||||
sockets with TRNSPRT_QUIC transport so the socket is connected to the
|
||||
proxy peer. H3-PROXY manages its own ngtcp2 QUIC stack on top. */
|
||||
CURLcode cf_ip_happy_quic_udp_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data);
|
||||
#endif /* !CURL_DISABLE_HTTP && USE_HTTP3 && USE_PROXY_HTTP3 */
|
||||
uint8_t transport_peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_ip_happy;
|
||||
|
||||
|
|
|
|||
|
|
@ -906,7 +906,7 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
struct cf_socket_ctx {
|
||||
uint8_t transport;
|
||||
struct Curl_peer *peer;
|
||||
struct Curl_sockaddr_ex addr; /* address to connect to */
|
||||
curl_socket_t sock; /* current attempt socket */
|
||||
struct ip_quadruple ip; /* The IP quadruple 2x(addr+port) */
|
||||
|
|
@ -924,6 +924,7 @@ struct cf_socket_ctx {
|
|||
int rblock_percent; /* percent of reads doing EAGAIN */
|
||||
size_t recv_max; /* max enforced read size */
|
||||
#endif
|
||||
uint8_t transport;
|
||||
BIT(got_first_byte); /* if first byte was received */
|
||||
BIT(listening); /* socket is listening */
|
||||
BIT(accepted); /* socket was accepted, not connected */
|
||||
|
|
@ -932,10 +933,12 @@ struct cf_socket_ctx {
|
|||
};
|
||||
|
||||
static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
|
||||
struct Curl_peer *peer,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
Curl_peer_link(&ctx->peer, peer);
|
||||
ctx->sock = CURL_SOCKET_BAD;
|
||||
ctx->transport = transport;
|
||||
ctx->addr = *addr;
|
||||
|
|
@ -972,6 +975,14 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static void cf_socket_ctx_free(struct cf_socket_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
Curl_peer_unlink(&ctx->peer);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done)
|
||||
|
|
@ -1006,7 +1017,7 @@ static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||
cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
|
||||
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
|
||||
}
|
||||
curlx_free(ctx);
|
||||
cf_socket_ctx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1754,19 +1765,24 @@ struct Curl_cftype Curl_cft_tcp = {
|
|||
|
||||
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out)
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = NULL;
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
(void)origin;
|
||||
(void)conn;
|
||||
(void)transport_in;
|
||||
DEBUGASSERT(transport_out == TRNSPRT_TCP);
|
||||
(void)tunnel_peer;
|
||||
(void)tunnel_transport;
|
||||
DEBUGASSERT(transport_peer == TRNSPRT_TCP);
|
||||
if(!addr) {
|
||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
goto out;
|
||||
|
|
@ -1778,7 +1794,7 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
|||
goto out;
|
||||
}
|
||||
|
||||
result = cf_socket_ctx_init(ctx, addr, transport_out);
|
||||
result = cf_socket_ctx_init(ctx, peer, addr, transport_peer);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1788,7 +1804,7 @@ out:
|
|||
*pcf = (!result) ? cf : NULL;
|
||||
if(result) {
|
||||
curlx_safefree(cf);
|
||||
curlx_safefree(ctx);
|
||||
cf_socket_ctx_free(ctx);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -1921,26 +1937,31 @@ struct Curl_cftype Curl_cft_udp = {
|
|||
|
||||
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out)
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = NULL;
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
(void)origin;
|
||||
(void)conn;
|
||||
(void)transport_in;
|
||||
DEBUGASSERT(transport_out == TRNSPRT_UDP || transport_out == TRNSPRT_QUIC);
|
||||
(void)tunnel_peer;
|
||||
(void)tunnel_transport;
|
||||
DEBUGASSERT(transport_peer == TRNSPRT_UDP || transport_peer == TRNSPRT_QUIC);
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = cf_socket_ctx_init(ctx, addr, transport_out);
|
||||
result = cf_socket_ctx_init(ctx, peer, addr, transport_peer);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1950,7 +1971,7 @@ out:
|
|||
*pcf = (!result) ? cf : NULL;
|
||||
if(result) {
|
||||
curlx_safefree(cf);
|
||||
curlx_safefree(ctx);
|
||||
cf_socket_ctx_free(ctx);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -1975,27 +1996,32 @@ struct Curl_cftype Curl_cft_unix = {
|
|||
};
|
||||
|
||||
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out)
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
struct cf_socket_ctx *ctx = NULL;
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
(void)origin;
|
||||
(void)conn;
|
||||
(void)transport_in;
|
||||
DEBUGASSERT(transport_out == TRNSPRT_UNIX);
|
||||
(void)tunnel_peer;
|
||||
(void)tunnel_transport;
|
||||
DEBUGASSERT(transport_peer == TRNSPRT_UNIX);
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = cf_socket_ctx_init(ctx, addr, transport_out);
|
||||
result = cf_socket_ctx_init(ctx, peer, addr, transport_peer);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
|
|
@ -2005,7 +2031,7 @@ out:
|
|||
*pcf = (!result) ? cf : NULL;
|
||||
if(result) {
|
||||
curlx_safefree(cf);
|
||||
curlx_safefree(ctx);
|
||||
cf_socket_ctx_free(ctx);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
|||
|
|
@ -94,10 +94,13 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
|
|||
*/
|
||||
CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out);
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
/**
|
||||
* Creates a cfilter that opens a UDP socket to the given address
|
||||
|
|
@ -108,10 +111,13 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
|
|||
*/
|
||||
CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out);
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
/**
|
||||
* Creates a cfilter that opens a UNIX socket to the given address
|
||||
|
|
@ -122,10 +128,13 @@ CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
|
|||
*/
|
||||
CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out);
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
/**
|
||||
* Creates a cfilter that keeps a listening socket.
|
||||
|
|
|
|||
|
|
@ -413,7 +413,8 @@ static CURLcode cf_setup_add_http_proxy(struct Curl_cfilter *cf,
|
|||
#ifdef USE_SSL
|
||||
if(IS_HTTPS_PROXY(cf->conn->http_proxy.proxytype) &&
|
||||
!Curl_conn_is_ssl(cf->conn, cf->sockindex)) {
|
||||
result = Curl_cf_ssl_proxy_insert_after(cf, data);
|
||||
result = Curl_cf_ssl_proxy_insert_after(
|
||||
cf, data, cf->conn->http_proxy.peer);
|
||||
if(result) {
|
||||
CURL_TRC_CF(data, cf, "adding SSL filter for HTTP proxy failed -> %d",
|
||||
result);
|
||||
|
|
@ -424,10 +425,12 @@ static CURLcode cf_setup_add_http_proxy(struct Curl_cfilter *cf,
|
|||
#endif /* USE_SSL */
|
||||
|
||||
if(cf->conn->bits.tunnel_proxy) {
|
||||
struct Curl_peer *dest; /* where HTTP should tunnel to */
|
||||
dest = Curl_conn_get_destination(cf->conn, cf->sockindex);
|
||||
struct Curl_peer *peer = cf->conn->http_proxy.peer;
|
||||
struct Curl_peer *tunnel_peer; /* where HTTP should tunnel to */
|
||||
tunnel_peer = Curl_conn_get_destination(cf->conn, cf->sockindex);
|
||||
result = Curl_cf_http_proxy_insert_after(
|
||||
cf, data, dest, ctx->transport, cf->conn->http_proxy.proxytype);
|
||||
cf, data, peer, tunnel_peer,
|
||||
ctx->transport, cf->conn->http_proxy.proxytype);
|
||||
if(result) {
|
||||
CURL_TRC_CF(data, cf, "adding HTTP proxy tunnel filter failed -> %d",
|
||||
result);
|
||||
|
|
@ -449,41 +452,47 @@ static CURLcode cf_setup_add_ip_happy(struct Curl_cfilter *cf,
|
|||
CURLcode result = CURLE_OK;
|
||||
|
||||
if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) {
|
||||
/* What is the fist hop we directly connect to and what transport
|
||||
* do we use for it? Only on the first hop we can do Happy Eyeballs. */
|
||||
/* What is the first hop we directly connect to and what transport
|
||||
* do we use for it? Only on the first hop we can do Happy Eyeballs.
|
||||
* first_origin and first_peer differ on --connect-to. */
|
||||
struct Curl_peer *first_origin =
|
||||
Curl_conn_get_first_origin(cf->conn, cf->sockindex);
|
||||
struct Curl_peer *first_peer =
|
||||
Curl_conn_get_first_peer(cf->conn, cf->sockindex);
|
||||
struct Curl_peer *tunnel_peer = NULL;
|
||||
uint8_t first_transport = ctx->transport;
|
||||
bool tunnel_proxy = FALSE;
|
||||
|
||||
if(!first_peer)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
|
||||
if(cf->conn->bits.httpproxy && cf->conn->bits.tunnel_proxy) {
|
||||
first_transport =
|
||||
Curl_http_proxy_transport(cf->conn->http_proxy.proxytype);
|
||||
tunnel_peer = Curl_conn_get_destination(cf->conn, cf->sockindex);
|
||||
if((first_transport == TRNSPRT_QUIC) && (cf->conn->bits.socksproxy)) {
|
||||
failf(data, "HTTP/3 proxy not possible via SOCKS");
|
||||
return CURLE_UNSUPPORTED_PROTOCOL;
|
||||
}
|
||||
tunnel_proxy = TRUE;
|
||||
}
|
||||
#endif /* !CURL_DISABLE_PROXY && !CURL_DISABLE_HTTP */
|
||||
|
||||
result = cf_ip_happy_insert_after(cf, data, first_peer,
|
||||
ctx->transport, first_transport,
|
||||
tunnel_proxy);
|
||||
result = cf_ip_happy_insert_after(cf, data, first_origin, first_peer,
|
||||
first_transport,
|
||||
tunnel_peer, ctx->transport);
|
||||
if(result) {
|
||||
CURL_TRC_CF(data, cf, "adding happy eyeballs failed -> %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
if(tunnel_proxy && (first_transport == TRNSPRT_QUIC)) {
|
||||
if(tunnel_peer && (first_transport == TRNSPRT_QUIC)) {
|
||||
CURL_TRC_CF(data, cf, "happy eyeballing to HTTP/3 proxy %s:%u",
|
||||
first_peer->hostname, first_peer->port);
|
||||
ctx->state = CF_SETUP_CNNCT_HTTP_PROXY;
|
||||
}
|
||||
else {
|
||||
CURL_TRC_CF(data, cf, "happy eyeballing to %s %s:%u",
|
||||
tunnel_proxy ? "proxy" : "origin",
|
||||
tunnel_peer ? "proxy" : "origin",
|
||||
first_peer->hostname, first_peer->port);
|
||||
ctx->state = CF_SETUP_CNNCT_EYEBALLS;
|
||||
}
|
||||
|
|
@ -501,17 +510,22 @@ static CURLcode cf_setup_add_origin_filters(struct Curl_cfilter *cf,
|
|||
if(ctx->state < CF_SETUP_CNNCT_SSL) {
|
||||
#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) && \
|
||||
!defined(CURL_DISABLE_PROXY)
|
||||
|
||||
/* Wanting QUIC with a HTTP tunneling filter, we now need to add
|
||||
* the QUIC filter on top. Without tunneling, this has already
|
||||
* happened in the Happy Eyeball filter. */
|
||||
if(ctx->transport == TRNSPRT_QUIC && cf->conn->bits.httpproxy &&
|
||||
cf->conn->bits.tunnel_proxy) {
|
||||
struct Curl_peer *origin = Curl_conn_get_origin(cf->conn, cf->sockindex);
|
||||
struct Curl_peer *peer =
|
||||
Curl_conn_get_destination(cf->conn, cf->sockindex);
|
||||
|
||||
result = Curl_cf_capsule_insert_after(cf, data);
|
||||
if(result) {
|
||||
CURL_TRC_CF(data, cf, "adding capsule filter failed -> %d", result);
|
||||
return result;
|
||||
}
|
||||
result = Curl_cf_quic_insert_after(cf);
|
||||
result = Curl_cf_quic_insert_after(cf, origin, peer);
|
||||
if(result) {
|
||||
CURL_TRC_CF(data, cf, "adding QUIC filter failed -> %d", result);
|
||||
return result;
|
||||
|
|
@ -525,7 +539,13 @@ static CURLcode cf_setup_add_origin_filters(struct Curl_cfilter *cf,
|
|||
(ctx->ssl_mode != CURL_CF_SSL_DISABLE &&
|
||||
cf->conn->scheme->flags & PROTOPT_SSL)) && /* we want SSL */
|
||||
!Curl_conn_is_ssl(cf->conn, cf->sockindex)) { /* it is missing */
|
||||
result = Curl_cf_ssl_insert_after(cf, data);
|
||||
/* Another FTP quirk: when adding SSL verification, to a DATA
|
||||
* connection, always verify against the control's origin */
|
||||
struct Curl_peer *origin = Curl_conn_get_origin(cf->conn, FIRSTSOCKET);
|
||||
struct Curl_peer *peer =
|
||||
Curl_conn_get_destination(cf->conn, cf->sockindex);
|
||||
|
||||
result = Curl_cf_ssl_insert_after(cf, data, origin, peer);
|
||||
if(result) {
|
||||
CURL_TRC_CF(data, cf, "adding SSL filter for origin failed -> %d",
|
||||
result);
|
||||
|
|
@ -777,6 +797,13 @@ void Curl_conn_set_multiplex(struct connectdata *conn)
|
|||
}
|
||||
}
|
||||
|
||||
struct Curl_peer *Curl_conn_get_origin(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
return (sockindex == SECONDARYSOCKET) ?
|
||||
conn->origin2 : conn->origin;
|
||||
}
|
||||
|
||||
struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
|
|
@ -789,6 +816,18 @@ struct Curl_peer *Curl_conn_get_destination(struct connectdata *conn,
|
|||
(conn->via_peer ? conn->via_peer : conn->origin);
|
||||
}
|
||||
|
||||
struct Curl_peer *Curl_conn_get_first_origin(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->origin2 : conn->origin;
|
||||
}
|
||||
|
||||
struct Curl_peer *Curl_conn_get_first_peer(struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -126,12 +126,21 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
|
|||
/* Set conn to allow multiplexing. */
|
||||
void Curl_conn_set_multiplex(struct connectdata *conn);
|
||||
|
||||
/* Get the origin peer at sockindex. */
|
||||
struct Curl_peer *Curl_conn_get_origin(struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
/* 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 origin curl connects its socket to.
|
||||
* Can be origin or the first proxy. */
|
||||
struct Curl_peer *Curl_conn_get_first_origin(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,
|
||||
|
|
|
|||
10
lib/ftp.c
10
lib/ftp.c
|
|
@ -1390,10 +1390,13 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
|
|||
ftp_state(data, ftpc, FTP_STOP);
|
||||
}
|
||||
else {
|
||||
/* successfully set up the listen socket filter. SSL needed? */
|
||||
/* successfully set up the listen socket filter. SSL needed?
|
||||
* Use the control connections origin for cert verification. */
|
||||
if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
|
||||
!Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
|
||||
result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
|
||||
result = Curl_ssl_cfilter_add(
|
||||
data, Curl_conn_get_origin(conn, FIRSTSOCKET),
|
||||
conn, SECONDARYSOCKET);
|
||||
}
|
||||
conn->bits.do_more = FALSE;
|
||||
Curl_pgrsTime(data, TIMER_STARTACCEPT);
|
||||
|
|
@ -3196,7 +3199,8 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data,
|
|||
/* this was BLOCKING, keep it so for now */
|
||||
bool done;
|
||||
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
|
||||
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
|
||||
result = Curl_ssl_cfilter_add(
|
||||
data, Curl_conn_get_origin(conn, FIRSTSOCKET), conn, FIRSTSOCKET);
|
||||
if(result) {
|
||||
/* we failed and bail out */
|
||||
return CURLE_USE_SSL_FAILED;
|
||||
|
|
|
|||
|
|
@ -172,10 +172,11 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data,
|
|||
}
|
||||
|
||||
struct cf_proxy_ctx {
|
||||
struct Curl_peer *dest; /* tunnel destination */
|
||||
struct Curl_peer *peer; /* proxy */
|
||||
struct Curl_peer *tunnel_peer; /* tunnel destination */
|
||||
uint8_t proxytype;
|
||||
uint8_t tunnel_transport;
|
||||
BIT(sub_filter_installed);
|
||||
BIT(udp_tunnel);
|
||||
};
|
||||
|
||||
static int proxy_http_ver_major(proxy_http_ver ver)
|
||||
|
|
@ -556,9 +557,8 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
|
|||
{
|
||||
struct cf_proxy_ctx *ctx = cf->ctx;
|
||||
CURLcode result;
|
||||
const char *tunnel_type; /* Determine tunnel type once and reuse */
|
||||
|
||||
tunnel_type = ctx->udp_tunnel ? "CONNECT-UDP" : "CONNECT";
|
||||
bool udp_tunnel = TRNSPRT_IS_DGRAM(ctx->tunnel_transport);
|
||||
const char *tunnel_type = udp_tunnel ? "CONNECT-UDP" : "CONNECT";
|
||||
|
||||
if(cf->connected) {
|
||||
*done = TRUE;
|
||||
|
|
@ -606,8 +606,8 @@ connect_sub:
|
|||
|
||||
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,
|
||||
(bool)ctx->udp_tunnel);
|
||||
result = Curl_cf_h1_proxy_insert_after(cf, data, ctx->tunnel_peer, 10,
|
||||
udp_tunnel);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -615,16 +615,16 @@ connect_sub:
|
|||
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,
|
||||
(bool)ctx->udp_tunnel);
|
||||
result = Curl_cf_h1_proxy_insert_after(cf, data, ctx->tunnel_peer,
|
||||
httpversion, udp_tunnel);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
#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, ctx->dest,
|
||||
(bool)ctx->udp_tunnel);
|
||||
result = Curl_cf_h2_proxy_insert_after(cf, data, ctx->tunnel_peer,
|
||||
udp_tunnel);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -633,8 +633,9 @@ connect_sub:
|
|||
defined(USE_NGTCP2) && defined(USE_OPENSSL)
|
||||
else if(!strcmp(alpn, "h3")) {
|
||||
CURL_TRC_CF(data, cf, "installing subfilter for HTTP/3");
|
||||
result = Curl_cf_h3_proxy_insert_after(cf, data, ctx->dest,
|
||||
(bool)ctx->udp_tunnel);
|
||||
result = Curl_cf_h3_proxy_insert_after(cf, data, ctx->peer, ctx->peer,
|
||||
ctx->tunnel_peer,
|
||||
ctx->tunnel_transport);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -673,8 +674,8 @@ static CURLcode cf_http_proxy_query(struct Curl_cfilter *cf,
|
|||
struct cf_proxy_ctx *ctx = cf->ctx;
|
||||
switch(query) {
|
||||
case CF_QUERY_HOST_PORT:
|
||||
*pres1 = (int)ctx->dest->port;
|
||||
*((const char **)pres2) = ctx->dest->hostname;
|
||||
*pres1 = (int)ctx->tunnel_peer->port;
|
||||
*((const char **)pres2) = ctx->tunnel_peer->hostname;
|
||||
return CURLE_OK;
|
||||
case CF_QUERY_ALPN_NEGOTIATED: {
|
||||
const char **palpn = pres2;
|
||||
|
|
@ -693,7 +694,8 @@ static CURLcode cf_http_proxy_query(struct Curl_cfilter *cf,
|
|||
static void cf_https_proxy_ctx_free(struct cf_proxy_ctx *ctx)
|
||||
{
|
||||
if(ctx) {
|
||||
Curl_peer_unlink(&ctx->dest);
|
||||
Curl_peer_unlink(&ctx->peer);
|
||||
Curl_peer_unlink(&ctx->tunnel_peer);
|
||||
curlx_free(ctx);
|
||||
}
|
||||
}
|
||||
|
|
@ -727,8 +729,9 @@ struct Curl_cftype Curl_cft_http_proxy = {
|
|||
|
||||
CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
uint8_t transport,
|
||||
struct Curl_peer *peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport,
|
||||
uint8_t proxytype)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
|
|
@ -736,7 +739,7 @@ CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
|
|||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
if(!dest)
|
||||
if(!peer || !tunnel_peer)
|
||||
return CURLE_FAILED_INIT;
|
||||
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
|
|
@ -744,9 +747,10 @@ CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
|
|||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
Curl_peer_link(&ctx->dest, dest);
|
||||
Curl_peer_link(&ctx->peer, peer);
|
||||
Curl_peer_link(&ctx->tunnel_peer, tunnel_peer);
|
||||
ctx->proxytype = proxytype;
|
||||
ctx->udp_tunnel = (transport == TRNSPRT_QUIC);
|
||||
ctx->tunnel_transport = tunnel_transport;
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_http_proxy, ctx);
|
||||
if(result)
|
||||
|
|
|
|||
|
|
@ -68,8 +68,9 @@ CURLcode Curl_http_proxy_inspect_tunnel_response(
|
|||
|
||||
CURLcode Curl_cf_http_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
uint8_t transport,
|
||||
struct Curl_peer *peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport,
|
||||
uint8_t proxytype);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_http_proxy;
|
||||
|
|
|
|||
|
|
@ -555,7 +555,8 @@ static CURLcode imap_perform_upgrade_tls(struct Curl_easy *data,
|
|||
bool ssldone = FALSE;
|
||||
|
||||
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
|
||||
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
|
||||
result = Curl_ssl_cfilter_add(
|
||||
data, Curl_conn_get_origin(conn, FIRSTSOCKET), conn, FIRSTSOCKET);
|
||||
if(result)
|
||||
goto out;
|
||||
/* Change the connection handler */
|
||||
|
|
|
|||
20
lib/multi.c
20
lib/multi.c
|
|
@ -4074,11 +4074,12 @@ CURLcode Curl_multi_xfer_sockbuf_borrow(struct Curl_easy *data,
|
|||
size_t blen, char **pbuf)
|
||||
{
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->multi);
|
||||
*pbuf = NULL;
|
||||
if(!data->multi) {
|
||||
failf(data, "transfer has no multi handle");
|
||||
return CURLE_FAILED_INIT;
|
||||
/* When a SHARE gets destroyed and has a connection pool, we get
|
||||
* call with share->admin which does not have a multi handle. */
|
||||
*pbuf = curlx_malloc(blen);
|
||||
return *pbuf ? CURLE_OK : CURLE_OUT_OF_MEMORY;
|
||||
}
|
||||
if(data->multi->xfer_sockbuf_borrowed) {
|
||||
failf(data, "attempt to borrow xfer_sockbuf when already borrowed");
|
||||
|
|
@ -4107,11 +4108,16 @@ CURLcode Curl_multi_xfer_sockbuf_borrow(struct Curl_easy *data,
|
|||
|
||||
void Curl_multi_xfer_sockbuf_release(struct Curl_easy *data, char *buf)
|
||||
{
|
||||
(void)buf;
|
||||
DEBUGASSERT(data);
|
||||
DEBUGASSERT(data->multi);
|
||||
DEBUGASSERT(!buf || data->multi->xfer_sockbuf == buf);
|
||||
data->multi->xfer_sockbuf_borrowed = FALSE;
|
||||
if(!data->multi) {
|
||||
/* When a SHARE gets destroyed and has a connection pool, we get
|
||||
* call with share->admin which does not have a multi handle. */
|
||||
curlx_free(buf);
|
||||
}
|
||||
else {
|
||||
DEBUGASSERT(!buf || data->multi->xfer_sockbuf == buf);
|
||||
data->multi->xfer_sockbuf_borrowed = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void multi_xfer_bufs_free(struct Curl_multi *multi)
|
||||
|
|
|
|||
|
|
@ -900,7 +900,8 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
|
|||
result = oldap_perform_bind(data, OLDAP_BIND);
|
||||
break;
|
||||
}
|
||||
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
|
||||
result = Curl_ssl_cfilter_add(
|
||||
data, Curl_conn_get_origin(conn, FIRSTSOCKET), conn, FIRSTSOCKET);
|
||||
if(result)
|
||||
break;
|
||||
FALLTHROUGH();
|
||||
|
|
|
|||
|
|
@ -485,7 +485,8 @@ static CURLcode pop3_perform_upgrade_tls(struct Curl_easy *data,
|
|||
return CURLE_FAILED_INIT;
|
||||
|
||||
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
|
||||
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
|
||||
result = Curl_ssl_cfilter_add(
|
||||
data, Curl_conn_get_origin(conn, FIRSTSOCKET), conn, FIRSTSOCKET);
|
||||
if(result)
|
||||
goto out;
|
||||
/* Change the connection handler */
|
||||
|
|
|
|||
|
|
@ -689,7 +689,8 @@ static CURLcode smtp_perform_upgrade_tls(struct Curl_easy *data,
|
|||
|
||||
DEBUGASSERT(smtpc->state == SMTP_UPGRADETLS);
|
||||
if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
|
||||
result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
|
||||
result = Curl_ssl_cfilter_add(
|
||||
data, Curl_conn_get_origin(conn, FIRSTSOCKET), conn, FIRSTSOCKET);
|
||||
if(result)
|
||||
goto out;
|
||||
/* Change the connection handler and SMTP state */
|
||||
|
|
|
|||
|
|
@ -253,6 +253,8 @@ struct hostname {
|
|||
#define TRNSPRT_QUIC 5
|
||||
#define TRNSPRT_UNIX 6
|
||||
|
||||
#define TRNSPRT_IS_DGRAM(x) (((x) == TRNSPRT_UDP) || ((x) == TRNSPRT_QUIC))
|
||||
|
||||
struct ip_quadruple {
|
||||
char remote_ip[MAX_IPADR_LEN];
|
||||
char local_ip[MAX_IPADR_LEN];
|
||||
|
|
|
|||
1965
lib/vquic/cf-ngtcp2-cmn.c
Normal file
1965
lib/vquic/cf-ngtcp2-cmn.c
Normal file
File diff suppressed because it is too large
Load diff
239
lib/vquic/cf-ngtcp2-cmn.h
Normal file
239
lib/vquic/cf-ngtcp2-cmn.h
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
#ifndef HEADER_CURL_VQUIC_CF_NGTCP2_CMN_H
|
||||
#define HEADER_CURL_VQUIC_CF_NGTCP2_CMN_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
|
||||
*
|
||||
***************************************************************************/
|
||||
#include "curl_setup.h"
|
||||
|
||||
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGTCP2) && defined(USE_NGHTTP3)
|
||||
|
||||
#include <ngtcp2/ngtcp2.h>
|
||||
#include <ngtcp2/ngtcp2_crypto.h>
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
#include <openssl/err.h>
|
||||
#if defined(OPENSSL_IS_AWSLC) || defined(OPENSSL_IS_BORINGSSL)
|
||||
#include <ngtcp2/ngtcp2_crypto_boringssl.h>
|
||||
#elif defined(OPENSSL_QUIC_API2)
|
||||
#include <ngtcp2/ngtcp2_crypto_ossl.h>
|
||||
#else
|
||||
#include <ngtcp2/ngtcp2_crypto_quictls.h>
|
||||
#endif
|
||||
#include "vtls/openssl.h"
|
||||
#elif defined(USE_GNUTLS)
|
||||
#include <ngtcp2/ngtcp2_crypto_gnutls.h>
|
||||
#include "vtls/gtls.h"
|
||||
#elif defined(USE_WOLFSSL)
|
||||
#include <wolfssl/options.h>
|
||||
#include <wolfssl/ssl.h>
|
||||
#include <wolfssl/quic.h>
|
||||
#include <ngtcp2/ngtcp2_crypto_wolfssl.h>
|
||||
#include "vtls/wolfssl.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETINET_UDP_H
|
||||
#include <netinet/udp.h>
|
||||
#endif
|
||||
|
||||
#include <nghttp3/nghttp3.h>
|
||||
|
||||
#include "http1.h"
|
||||
#include "uint-hash.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "vquic/vquic_int.h"
|
||||
#include "vquic/vquic-tls.h"
|
||||
|
||||
struct Curl_cfilter;
|
||||
struct Curl_easy;
|
||||
struct cf_ngtcp2_ctx;
|
||||
struct cf_quic_ctx;
|
||||
|
||||
#define QUIC_MAX_STREAMS (256 * 1024)
|
||||
#define QUIC_HANDSHAKE_TIMEOUT (10 * NGTCP2_SECONDS)
|
||||
#define QUIC_TUNNEL_INBUF_SIZE (64 * 1024)
|
||||
|
||||
/* We announce a small window size in transport param to the server,
|
||||
* and grow that immediately to max when no rate limit is in place.
|
||||
* We need to start small as we are not able to decrease it. */
|
||||
#define H3_STREAM_WINDOW_SIZE_INITIAL (32 * 1024)
|
||||
#define H3_STREAM_WINDOW_SIZE_MAX (10 * 1024 * 1024)
|
||||
#define H3_CONN_WINDOW_SIZE_MAX (100 * H3_STREAM_WINDOW_SIZE_MAX)
|
||||
|
||||
#define H3_STREAM_CHUNK_SIZE (64 * 1024)
|
||||
#if H3_STREAM_CHUNK_SIZE < NGTCP2_MAX_UDP_PAYLOAD_SIZE
|
||||
#error H3_STREAM_CHUNK_SIZE smaller than NGTCP2_MAX_UDP_PAYLOAD_SIZE
|
||||
#endif
|
||||
/* The pool keeps spares around and half of a full stream window
|
||||
* seems good. More does not seem to improve performance.
|
||||
* The benefit of the pool is that stream buffers do not keep
|
||||
* spares. Memory consumption goes down when streams run empty,
|
||||
* have a large upload done, etc. */
|
||||
#define H3_STREAM_POOL_SPARES 2
|
||||
/* The max amount of un-acked upload data we keep around per stream */
|
||||
#define H3_STREAM_SEND_BUFFER_MAX (10 * 1024 * 1024)
|
||||
#define H3_STREAM_SEND_CHUNKS \
|
||||
(H3_STREAM_SEND_BUFFER_MAX / H3_STREAM_CHUNK_SIZE)
|
||||
#define QUIC_TUNNEL_INGRESS_PKT_LIMIT 1000
|
||||
|
||||
|
||||
void Curl_ngtcp2_ver(char *p, size_t len);
|
||||
|
||||
typedef CURLcode cf_ngtcp2_init_h3_conn(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct cf_ngtcp2_ctx *ctx);
|
||||
|
||||
struct cf_ngtcp2_ctx {
|
||||
struct cf_quic_ctx q;
|
||||
struct ssl_peer ssl_peer;
|
||||
struct curl_tls_ctx tls;
|
||||
#ifdef OPENSSL_QUIC_API2
|
||||
ngtcp2_crypto_ossl_ctx *ossl_ctx;
|
||||
#endif
|
||||
ngtcp2_path connected_path;
|
||||
ngtcp2_conn *qconn;
|
||||
ngtcp2_cid dcid;
|
||||
ngtcp2_cid scid;
|
||||
uint32_t version;
|
||||
ngtcp2_settings settings;
|
||||
ngtcp2_transport_params transport_params;
|
||||
ngtcp2_ccerr last_error;
|
||||
ngtcp2_crypto_conn_ref conn_ref;
|
||||
struct cf_call_data call_data;
|
||||
cf_ngtcp2_init_h3_conn *init_h3_conn_cb;
|
||||
nghttp3_conn *h3conn;
|
||||
nghttp3_settings h3settings;
|
||||
struct curltime started_at; /* time the current attempt started */
|
||||
struct curltime handshake_at; /* time connect handshake finished */
|
||||
struct bufc_pool stream_bufcp; /* chunk pool for streams */
|
||||
struct dynbuf scratch; /* temp buffer for header construction */
|
||||
struct uint_hash streams; /* hash data->mid to h3_stream_ctx */
|
||||
uint64_t used_bidi_streams; /* bidi streams we have opened */
|
||||
uint64_t max_bidi_streams; /* max bidi streams we can open */
|
||||
size_t earlydata_max; /* max amount of early data supported by
|
||||
server on session reuse */
|
||||
size_t earlydata_skip; /* sending bytes to skip when earlydata
|
||||
is accepted by peer */
|
||||
CURLcode tls_vrfy_result; /* result of TLS peer verification */
|
||||
int qlogfd;
|
||||
unsigned char *tunnel_inbuf; /* ingress buffer for tunneled packets */
|
||||
size_t tunnel_inbuf_len;
|
||||
BIT(initialized);
|
||||
BIT(tls_handshake_complete); /* TLS handshake is done */
|
||||
BIT(use_earlydata); /* Using 0RTT data */
|
||||
BIT(earlydata_accepted); /* 0RTT was accepted by server */
|
||||
BIT(shutdown_started); /* queued shutdown packets */
|
||||
};
|
||||
|
||||
/* How to access `call_data` from a cf_ngtcp2 filter */
|
||||
#undef CF_CTX_CALL_DATA
|
||||
#define CF_CTX_CALL_DATA(cf) ((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct ssl_primary_config *sslc,
|
||||
cf_ngtcp2_init_h3_conn *init_h3_conn_cb);
|
||||
void Curl_cf_ngtcp2_ctx_cleanup(struct cf_ngtcp2_ctx *ctx);
|
||||
void Curl_cf_ngtcp2_cmn_err_set(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, int code);
|
||||
|
||||
/**
|
||||
* All about the H3 internals of a stream
|
||||
*/
|
||||
struct h3_stream_ctx {
|
||||
int64_t id; /* HTTP/3 stream identifier */
|
||||
struct bufq sendbuf; /* h3 request body */
|
||||
struct h1_req_parser h1; /* h1 request parsing */
|
||||
size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
|
||||
uint64_t error3; /* HTTP/3 stream error code */
|
||||
curl_off_t upload_left; /* number of request bytes left to upload */
|
||||
curl_off_t rx_total; /* total number of bytes received */
|
||||
uint64_t rx_offset; /* current receive offset */
|
||||
uint64_t rx_offset_max; /* allowed receive offset */
|
||||
uint64_t window_size_max; /* max flow control window set for stream */
|
||||
int status_code; /* HTTP status code */
|
||||
CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
|
||||
BIT(resp_hds_complete); /* we have a complete, final response */
|
||||
BIT(closed); /* TRUE on stream close */
|
||||
BIT(reset); /* TRUE on stream reset */
|
||||
BIT(send_closed); /* stream is local closed */
|
||||
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
|
||||
};
|
||||
|
||||
void Curl_cf_ngtcp2_h3_stream_ctx_free(struct h3_stream_ctx *stream);
|
||||
void Curl_cf_ngtcp2_h3_err_set(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, int code);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_h3_init_ctrls(struct cf_ngtcp2_ctx *ctx,
|
||||
struct Curl_easy *data);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_cmn_connect(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *done);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_cmn_shutdown(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data, bool *done);
|
||||
void Curl_cf_ngtcp2_cmn_conn_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
struct cf_ngtcp2_io_ctx {
|
||||
struct Curl_cfilter *cf;
|
||||
struct Curl_easy *data;
|
||||
ngtcp2_tstamp ts;
|
||||
ngtcp2_path_storage ps;
|
||||
};
|
||||
|
||||
void Curl_cf_ngtcp2_io_ctx_init(struct cf_ngtcp2_io_ctx *io_ctx,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
void Curl_cf_ngtcp2_io_ctx_update_time(struct Curl_easy *data,
|
||||
struct cf_ngtcp2_io_ctx *pktx,
|
||||
struct Curl_cfilter *cf);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_progress_egress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct cf_ngtcp2_io_ctx *pktx);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_progress_ingress(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct cf_ngtcp2_io_ctx *pktx);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_cmn_set_expiry(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct cf_ngtcp2_io_ctx *pktx);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_h3_stream_setup(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
void Curl_cf_ngtcp2_h3_stream_close(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct h3_stream_ctx *stream);
|
||||
void Curl_cf_ngtcp2_h3_stream_done(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data);
|
||||
|
||||
bool Curl_cf_ngtcp2_cmn_conn_is_alive(struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
bool *input_pending);
|
||||
|
||||
#endif /* !CURL_DISABLE_HTTP && USE_NGTCP2 && USE_NGHTTP3 */
|
||||
|
||||
#endif /* HEADER_CURL_VQUIC_CF_NGTCP2_CMN_H */
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef HEADER_CURL_H3_PROXY_H
|
||||
#define HEADER_CURL_H3_PROXY_H
|
||||
#ifndef HEADER_CURL_VQUIC_CF_NGTCP2_PROXY_H
|
||||
#define HEADER_CURL_VQUIC_CF_NGTCP2_PROXY_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
|
|
@ -32,16 +32,21 @@
|
|||
|
||||
CURLcode Curl_cf_ngtcp2_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
bool udp_tunnel);
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_proxy_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out);
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_H3_PROXY_H */
|
||||
#endif /* HEADER_CURL_VQUIC_CF_NGTCP2_PROXY_H */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef HEADER_CURL_VQUIC_CURL_NGTCP2_H
|
||||
#define HEADER_CURL_VQUIC_CURL_NGTCP2_H
|
||||
#ifndef HEADER_CURL_VQUIC_CF_NGTCP2_H
|
||||
#define HEADER_CURL_VQUIC_CF_NGTCP2_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
|
|
@ -48,14 +48,16 @@ struct Curl_cfilter;
|
|||
|
||||
#include "urldata.h"
|
||||
|
||||
void Curl_ngtcp2_ver(char *p, size_t len);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr);
|
||||
|
||||
CURLcode Curl_cf_ngtcp2_insert_after(struct Curl_cfilter *cf_at);
|
||||
CURLcode Curl_cf_ngtcp2_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer);
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_VQUIC_CURL_NGTCP2_H */
|
||||
#endif /* HEADER_CURL_VQUIC_CF_NGTCP2_H */
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ void Curl_quiche_ver(char *p, size_t len)
|
|||
|
||||
struct cf_quiche_ctx {
|
||||
struct cf_quic_ctx q;
|
||||
struct ssl_peer peer;
|
||||
struct ssl_peer ssl_peer;
|
||||
struct curl_tls_ctx tls;
|
||||
quiche_conn *qconn;
|
||||
quiche_config *cfg;
|
||||
|
|
@ -106,7 +106,10 @@ static void quiche_debug_log(const char *line, void *argp)
|
|||
|
||||
static void h3_stream_hash_free(unsigned int id, void *stream);
|
||||
|
||||
static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
|
||||
static CURLcode cf_quiche_ctx_init(struct cf_quiche_ctx *ctx,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct ssl_primary_config *sslc)
|
||||
{
|
||||
DEBUGASSERT(!ctx->initialized);
|
||||
#ifdef DEBUG_QUICHE
|
||||
|
|
@ -121,6 +124,7 @@ static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
|
|||
BUFQ_OPT_SOFT_LIMIT);
|
||||
ctx->data_recvd = 0;
|
||||
ctx->initialized = TRUE;
|
||||
return Curl_vquic_tls_peer_init(origin, peer, sslc, &ctx->ssl_peer);
|
||||
}
|
||||
|
||||
static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
|
||||
|
|
@ -129,7 +133,7 @@ static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
|
|||
/* quiche freed it */
|
||||
ctx->tls.ossl.ssl = NULL;
|
||||
Curl_vquic_tls_cleanup(&ctx->tls);
|
||||
Curl_ssl_peer_cleanup(&ctx->peer);
|
||||
Curl_ssl_peer_cleanup(&ctx->ssl_peer);
|
||||
vquic_ctx_free(&ctx->q);
|
||||
Curl_uint32_hash_destroy(&ctx->streams);
|
||||
curlx_dyn_free(&ctx->h1hdr);
|
||||
|
|
@ -156,7 +160,7 @@ static void cf_quiche_ctx_close(struct cf_quiche_ctx *ctx)
|
|||
quiche_config_free(ctx->cfg);
|
||||
ctx->cfg = NULL;
|
||||
}
|
||||
Curl_ssl_peer_cleanup(&ctx->peer);
|
||||
Curl_ssl_peer_cleanup(&ctx->ssl_peer);
|
||||
}
|
||||
|
||||
static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
|
||||
|
|
@ -1291,7 +1295,7 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
|
|||
sizeof(QUICHE_H3_APPLICATION_PROTOCOL)
|
||||
- 1);
|
||||
|
||||
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
|
||||
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->ssl_peer,
|
||||
&ALPN_SPEC_H3, NULL, NULL, cf, NULL);
|
||||
if(result)
|
||||
return result;
|
||||
|
|
@ -1357,7 +1361,7 @@ static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf,
|
|||
struct Curl_easy *data)
|
||||
{
|
||||
struct cf_quiche_ctx *ctx = cf->ctx;
|
||||
return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
|
||||
return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->ssl_peer);
|
||||
}
|
||||
|
||||
static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
|
||||
|
|
@ -1629,6 +1633,8 @@ struct Curl_cftype Curl_cft_http3 = {
|
|||
|
||||
CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr)
|
||||
{
|
||||
|
|
@ -1641,15 +1647,15 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
|||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
cf_quiche_ctx_init(ctx);
|
||||
|
||||
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
||||
result = cf_quiche_ctx_init(ctx, origin, peer, &conn->ssl_config);
|
||||
if(!result)
|
||||
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
cf->conn = conn;
|
||||
|
||||
result = Curl_cf_udp_create(&cf->next, data, conn, addr,
|
||||
TRNSPRT_QUIC, TRNSPRT_QUIC);
|
||||
result = Curl_cf_udp_create(&cf->next, data, origin, peer, TRNSPRT_QUIC,
|
||||
conn, addr, NULL, TRNSPRT_QUIC);
|
||||
if(result)
|
||||
goto out;
|
||||
cf->next->conn = cf->conn;
|
||||
|
|
@ -1667,4 +1673,34 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_quiche_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer)
|
||||
{
|
||||
struct cf_quiche_ctx *ctx = NULL;
|
||||
struct Curl_cfilter *cf = NULL;
|
||||
CURLcode result;
|
||||
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
}
|
||||
result = cf_quiche_ctx_init(ctx, origin, peer, &cf_at->conn->ssl_config);
|
||||
if(!result)
|
||||
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
|
||||
if(result)
|
||||
goto out;
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
|
||||
out:
|
||||
if(result) {
|
||||
curlx_safefree(cf);
|
||||
if(ctx)
|
||||
cf_quiche_ctx_free(ctx);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef HEADER_CURL_VQUIC_CURL_QUICHE_H
|
||||
#define HEADER_CURL_VQUIC_CURL_QUICHE_H
|
||||
#ifndef HEADER_CURL_VQUIC_CF_QUICHE_H
|
||||
#define HEADER_CURL_VQUIC_CF_QUICHE_H
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
|
|
@ -37,9 +37,14 @@ void Curl_quiche_ver(char *p, size_t len);
|
|||
|
||||
CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr);
|
||||
CURLcode Curl_cf_quiche_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer);
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_VQUIC_CURL_QUICHE_H */
|
||||
#endif /* HEADER_CURL_VQUIC_CF_QUICHE_H */
|
||||
|
|
|
|||
|
|
@ -49,17 +49,12 @@
|
|||
#include "vtls/vtls_scache.h"
|
||||
#include "vquic/vquic-tls.h"
|
||||
|
||||
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct ssl_peer *peer,
|
||||
const struct alpn_spec *alpns,
|
||||
Curl_vquic_tls_ctx_setup *cb_setup,
|
||||
void *cb_user_data, void *ssl_user_data,
|
||||
Curl_vquic_session_reuse_cb *session_reuse_cb)
|
||||
CURLcode Curl_vquic_tls_peer_init(struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct ssl_primary_config *sslc,
|
||||
struct ssl_peer *ssl_peer)
|
||||
{
|
||||
char tls_id[80];
|
||||
CURLcode result;
|
||||
|
||||
#ifdef USE_OPENSSL
|
||||
Curl_ossl_version(tls_id, sizeof(tls_id));
|
||||
|
|
@ -71,24 +66,31 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
|||
#error "no TLS lib in used, should not happen"
|
||||
return CURLE_FAILED_INIT;
|
||||
#endif
|
||||
(void)session_reuse_cb;
|
||||
if(peer->dest)
|
||||
Curl_ssl_peer_cleanup(peer);
|
||||
result = Curl_ssl_peer_init(peer, cf, tls_id, TRNSPRT_QUIC);
|
||||
if(result)
|
||||
return result;
|
||||
if(ssl_peer->origin || ssl_peer->peer)
|
||||
Curl_ssl_peer_cleanup(ssl_peer);
|
||||
return Curl_ssl_peer_init(ssl_peer, origin, peer, sslc,
|
||||
tls_id, TRNSPRT_QUIC);
|
||||
}
|
||||
|
||||
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct ssl_peer *ssl_peer,
|
||||
const struct alpn_spec *alpns,
|
||||
Curl_vquic_tls_ctx_setup *cb_setup,
|
||||
void *cb_user_data, void *ssl_user_data,
|
||||
Curl_vquic_session_reuse_cb *session_reuse_cb)
|
||||
{
|
||||
#ifdef USE_OPENSSL
|
||||
(void)result;
|
||||
return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, alpns,
|
||||
return Curl_ossl_ctx_init(&ctx->ossl, cf, data, ssl_peer, alpns,
|
||||
cb_setup, cb_user_data, NULL, ssl_user_data,
|
||||
session_reuse_cb);
|
||||
#elif defined(USE_GNUTLS)
|
||||
return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer, alpns,
|
||||
return Curl_gtls_ctx_init(&ctx->gtls, cf, data, ssl_peer, alpns,
|
||||
cb_setup, cb_user_data, ssl_user_data,
|
||||
session_reuse_cb);
|
||||
#elif defined(USE_WOLFSSL)
|
||||
return Curl_wssl_ctx_init(&ctx->wssl, cf, data, peer, alpns,
|
||||
return Curl_wssl_ctx_init(&ctx->wssl, cf, data, ssl_peer, alpns,
|
||||
cb_setup, cb_user_data,
|
||||
ssl_user_data, session_reuse_cb);
|
||||
#else
|
||||
|
|
@ -180,7 +182,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->dest->hostname,
|
||||
(wolfSSL_X509_check_ip_asc(cert, peer->origin->hostname,
|
||||
0) == WOLFSSL_FAILURE))
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
wolfSSL_X509_free(cert);
|
||||
|
|
|
|||
|
|
@ -66,13 +66,18 @@ typedef CURLcode Curl_vquic_session_reuse_cb(struct Curl_cfilter *cf,
|
|||
struct Curl_ssl_session *scs,
|
||||
bool *do_early_data);
|
||||
|
||||
CURLcode Curl_vquic_tls_peer_init(struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct ssl_primary_config *sslc,
|
||||
struct ssl_peer *ssl_peer);
|
||||
|
||||
/**
|
||||
* Initialize the QUIC TLS instances based of the SSL configurations
|
||||
* for the connection filter, transfer and peer.
|
||||
* @param ctx the TLS context to initialize
|
||||
* @param cf the connection filter involved
|
||||
* @param data the transfer involved
|
||||
* @param peer the peer to be connected to
|
||||
* @param ssl_peer the SSL peer to be connected to
|
||||
* @param alpns the ALPN specifications to negotiate, may be NULL
|
||||
* @param cb_setup optional callback for early TLS config
|
||||
* @param cb_user_data user_data param for callback
|
||||
|
|
@ -82,7 +87,7 @@ typedef CURLcode Curl_vquic_session_reuse_cb(struct Curl_cfilter *cf,
|
|||
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
||||
struct Curl_cfilter *cf,
|
||||
struct Curl_easy *data,
|
||||
struct ssl_peer *peer,
|
||||
struct ssl_peer *ssl_peer,
|
||||
const struct alpn_spec *alpns,
|
||||
Curl_vquic_tls_ctx_setup *cb_setup,
|
||||
void *cb_user_data,
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@
|
|||
#include "curlx/fopen.h"
|
||||
#include "cfilters.h"
|
||||
#include "vquic/cf-ngtcp2.h"
|
||||
#include "vquic/cf-ngtcp2-cmn.h"
|
||||
#include "vquic/cf-ngtcp2-proxy.h"
|
||||
#include "vquic/cf-quiche.h"
|
||||
#include "multiif.h"
|
||||
|
|
@ -760,35 +761,49 @@ CURLcode Curl_qlogdir(struct Curl_easy *data,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_quic_insert_after(struct Curl_cfilter *cf_at)
|
||||
CURLcode Curl_cf_quic_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer)
|
||||
{
|
||||
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
|
||||
return Curl_cf_ngtcp2_insert_after(cf_at);
|
||||
return Curl_cf_ngtcp2_insert_after(cf_at, origin, peer);
|
||||
#elif defined(USE_QUICHE)
|
||||
return Curl_cf_quiche_insert_after(cf_at, origin, peer);
|
||||
#else
|
||||
(void)cf_at;
|
||||
(void)origin;
|
||||
(void)peer;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out)
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
(void)transport_in;
|
||||
(void)transport_out;
|
||||
DEBUGASSERT(transport_out == TRNSPRT_QUIC);
|
||||
(void)transport_peer;
|
||||
(void)tunnel_transport;
|
||||
(void)tunnel_peer;
|
||||
DEBUGASSERT(transport_peer == TRNSPRT_QUIC);
|
||||
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
|
||||
return Curl_cf_ngtcp2_create(pcf, data, conn, addr);
|
||||
return Curl_cf_ngtcp2_create(pcf, data, origin, peer, conn, addr);
|
||||
#elif defined(USE_QUICHE)
|
||||
return Curl_cf_quiche_create(pcf, data, conn, addr);
|
||||
return Curl_cf_quiche_create(pcf, data, origin, peer, conn, addr);
|
||||
#else
|
||||
*pcf = NULL;
|
||||
(void)data;
|
||||
(void)origin;
|
||||
(void)peer;
|
||||
(void)conn;
|
||||
(void)addr;
|
||||
(void)tunnel_peer;
|
||||
(void)tunnel_transport;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
|
@ -797,35 +812,49 @@ CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
|
|||
|
||||
CURLcode Curl_cf_h3_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
bool udp_tunnel)
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
|
||||
return Curl_cf_ngtcp2_proxy_insert_after(cf_at, data, dest, udp_tunnel);
|
||||
return Curl_cf_ngtcp2_proxy_insert_after(cf_at, data, origin, peer,
|
||||
tunnel_peer, tunnel_transport);
|
||||
#else
|
||||
(void)cf_at;
|
||||
(void)data;
|
||||
(void)origin;
|
||||
(void)peer;
|
||||
(void)tunnel_peer;
|
||||
(void)tunnel_transport;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_h3_proxy_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out)
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport)
|
||||
{
|
||||
(void)transport_in;
|
||||
(void)transport_out;
|
||||
DEBUGASSERT(transport_out == TRNSPRT_QUIC);
|
||||
DEBUGASSERT(transport_peer == TRNSPRT_QUIC);
|
||||
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
|
||||
return Curl_cf_ngtcp2_proxy_create(pcf, data, conn, addr,
|
||||
transport_in, transport_out);
|
||||
return Curl_cf_ngtcp2_proxy_create(pcf, data, origin, peer, transport_peer,
|
||||
conn, addr,
|
||||
tunnel_peer, tunnel_transport);
|
||||
#else
|
||||
*pcf = NULL;
|
||||
(void)data;
|
||||
(void)conn;
|
||||
(void)addr;
|
||||
(void)peer;
|
||||
(void)transport_peer;
|
||||
(void)tunnel_peer;
|
||||
(void)tunnel_transport;
|
||||
return CURLE_NOT_BUILT_IN;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,14 +39,19 @@ CURLcode Curl_qlogdir(struct Curl_easy *data,
|
|||
size_t scidlen,
|
||||
int *qlogfdp);
|
||||
|
||||
CURLcode Curl_cf_quic_insert_after(struct Curl_cfilter *cf_at);
|
||||
CURLcode Curl_cf_quic_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer);
|
||||
|
||||
CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out);
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_http3;
|
||||
|
||||
|
|
@ -54,15 +59,20 @@ extern struct Curl_cftype Curl_cft_http3;
|
|||
|
||||
CURLcode Curl_cf_h3_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *dest,
|
||||
bool udp_tunnel);
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
CURLcode Curl_cf_h3_proxy_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out);
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t tunnel_transport);
|
||||
|
||||
extern struct Curl_cftype Curl_cft_h3_proxy;
|
||||
|
||||
|
|
|
|||
|
|
@ -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->dest->hostname, kCFStringEncodingUTF8);
|
||||
peer->sni ? peer->sni : peer->origin->hostname, kCFStringEncodingUTF8);
|
||||
if(!host_str) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -1366,11 +1366,11 @@ static void gtls_msg_verify_result(struct Curl_easy *data,
|
|||
if(needs_verified) {
|
||||
failf(data, "SSL: certificate subject name (%s) does not match "
|
||||
"target hostname '%s'", certname,
|
||||
peer->dest->user_hostname);
|
||||
peer->origin->user_hostname);
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (does not match '%s')",
|
||||
certname, peer->dest->user_hostname);
|
||||
certname, peer->origin->user_hostname);
|
||||
}
|
||||
else
|
||||
infof(data, " common name: %s (matched)", certname);
|
||||
|
|
@ -1848,7 +1848,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->dest->hostname);
|
||||
peer->origin->hostname);
|
||||
result = (!rc && config->verifyhost) ?
|
||||
CURLE_PEER_FAILED_VERIFICATION : CURLE_OK;
|
||||
gtls_msg_verify_result(data, peer, x509_cert, rc, config->verifyhost);
|
||||
|
|
|
|||
|
|
@ -798,7 +798,7 @@ static CURLcode mbed_configure_ssl(struct Curl_cfilter *cf,
|
|||
char errorbuf[128];
|
||||
|
||||
infof(data, "mbedTLS: Connecting to %s:%d",
|
||||
connssl->peer.dest->hostname, connssl->peer.dest->port);
|
||||
connssl->peer.origin->hostname, connssl->peer.origin->port);
|
||||
|
||||
mbedtls_ssl_config_init(&backend->config);
|
||||
ret = mbedtls_ssl_config_defaults(&backend->config,
|
||||
|
|
@ -940,7 +940,7 @@ static CURLcode mbed_configure_ssl(struct Curl_cfilter *cf,
|
|||
|
||||
if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni ?
|
||||
connssl->peer.sni :
|
||||
connssl->peer.dest->hostname)) {
|
||||
connssl->peer.origin->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->dest->hostname);
|
||||
size_t hostlen = strlen(peer->origin->hostname);
|
||||
|
||||
(void)conn;
|
||||
switch(peer->type) {
|
||||
case CURL_SSL_PEER_IPV4:
|
||||
if(!curlx_inet_pton(AF_INET, peer->dest->hostname, &addr))
|
||||
if(!curlx_inet_pton(AF_INET, peer->origin->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->dest->hostname, &addr))
|
||||
if(!curlx_inet_pton(AF_INET6, peer->origin->hostname, &addr))
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
target = GEN_IPADD;
|
||||
addrlen = sizeof(struct in6_addr);
|
||||
|
|
@ -2116,10 +2116,10 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
|
|||
/* 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->dest->hostname, hostlen)) {
|
||||
peer->origin->hostname, hostlen)) {
|
||||
matched = TRUE;
|
||||
infof(data, " subjectAltName: \"%s\" matches cert's \"%.*s\"",
|
||||
peer->dest->user_hostname, (int)altlen, altptr);
|
||||
peer->origin->user_hostname, (int)altlen, altptr);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -2129,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->dest->user_hostname);
|
||||
peer->origin->user_hostname);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -2146,9 +2146,9 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
|
|||
(peer->type == CURL_SSL_PEER_IPV4) ?
|
||||
"ipv4 address" : "ipv6 address";
|
||||
infof(data, " subjectAltName does not match %s %s", tname,
|
||||
peer->dest->user_hostname);
|
||||
peer->origin->user_hostname);
|
||||
failf(data, "SSL: no alternative certificate subject name matches "
|
||||
"target %s '%s'", tname, peer->dest->user_hostname);
|
||||
"target %s '%s'", tname, peer->origin->user_hostname);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else {
|
||||
|
|
@ -2208,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->dest->hostname, hostlen)) {
|
||||
peer->origin->hostname, hostlen)) {
|
||||
failf(data, "SSL: certificate subject name '%s' does not match "
|
||||
"target hostname '%s'", cn, peer->dest->user_hostname);
|
||||
"target hostname '%s'", cn, peer->origin->user_hostname);
|
||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else {
|
||||
|
|
@ -3534,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->dest->hostname ? peer->dest->hostname : "NULL", outername);
|
||||
peer->origin->hostname ? peer->origin->hostname : "NULL", outername);
|
||||
result = SSL_ech_set1_server_names(octx->ssl,
|
||||
peer->dest->hostname, outername,
|
||||
peer->origin->hostname, outername,
|
||||
0 /* do send outer */);
|
||||
if(result != 1) {
|
||||
infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
|
||||
|
|
@ -4010,19 +4010,12 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
|||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
|
||||
char tls_id[80];
|
||||
BIO *bio;
|
||||
CURLcode result;
|
||||
|
||||
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
|
||||
DEBUGASSERT(octx);
|
||||
|
||||
if(!connssl->peer.dest) {
|
||||
Curl_ossl_version(tls_id, sizeof(tls_id));
|
||||
result = Curl_ssl_peer_init(&connssl->peer, cf, tls_id, TRNSPRT_TCP);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
DEBUGASSERT(connssl->peer.origin);
|
||||
|
||||
result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer,
|
||||
connssl->alpn, NULL, NULL,
|
||||
|
|
@ -4277,7 +4270,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.dest->hostname, connssl->peer.dest->port);
|
||||
connssl->peer.origin->hostname, connssl->peer.origin->port);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -4324,7 +4317,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.dest->hostname)) {
|
||||
inner && !strcmp(inner, connssl->peer.origin->hostname)) {
|
||||
VERBOSE(status = "bad name (tolerated without peer verification)");
|
||||
rv = SSL_ECH_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1102,7 +1102,7 @@ static CURLcode cr_init_backend(struct Curl_cfilter *cf,
|
|||
|
||||
DEBUGASSERT(!rconn);
|
||||
rr = rustls_client_connection_new(backend->config,
|
||||
connssl->peer.dest->hostname,
|
||||
connssl->peer.origin->hostname,
|
||||
&rconn);
|
||||
if(rr != RUSTLS_RESULT_OK) {
|
||||
rustls_failf(data, rr, "rustls_client_connection_new");
|
||||
|
|
|
|||
|
|
@ -849,7 +849,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.dest->hostname, connssl->peer.dest->port));
|
||||
connssl->peer.origin->hostname, connssl->peer.origin->port));
|
||||
|
||||
#ifdef HAS_ALPN_SCHANNEL
|
||||
backend->use_alpn = connssl->alpn && s_win_has_alpn;
|
||||
|
|
@ -902,7 +902,7 @@ 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.dest->hostname;
|
||||
connssl->peer.sni : connssl->peer.origin->hostname;
|
||||
backend->cred->sni_hostname = curlx_convert_UTF8_to_tchar(snihost);
|
||||
if(!backend->cred->sni_hostname)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
|
|
@ -1245,7 +1245,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.dest->hostname, connssl->peer.dest->port));
|
||||
connssl->peer.origin->hostname, connssl->peer.origin->port));
|
||||
|
||||
if(!backend->cred || !backend->ctxt)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
|
@ -1597,7 +1597,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.dest->hostname, connssl->peer.dest->port));
|
||||
connssl->peer.origin->hostname, connssl->peer.origin->port));
|
||||
|
||||
if(!backend->cred)
|
||||
return CURLE_SSL_CONNECT_ERROR;
|
||||
|
|
@ -2435,7 +2435,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.dest->hostname, connssl->peer.dest->port);
|
||||
connssl->peer.origin->hostname, connssl->peer.origin->port);
|
||||
}
|
||||
|
||||
if(!backend->ctxt || cf->shutdown) {
|
||||
|
|
|
|||
|
|
@ -480,7 +480,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.dest->hostname;
|
||||
const char *conn_hostname = connssl->peer.origin->hostname;
|
||||
size_t hostlen = strlen(conn_hostname);
|
||||
DWORD len = 0;
|
||||
DWORD actual_len = 0;
|
||||
|
|
|
|||
108
lib/vtls/vtls.c
108
lib/vtls/vtls.c
|
|
@ -869,7 +869,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);
|
||||
Curl_peer_unlink(&peer->origin);
|
||||
Curl_peer_unlink(&peer->peer);
|
||||
curlx_safefree(peer->sni);
|
||||
curlx_safefree(peer->scache_key);
|
||||
peer->transport = TRNSPRT_NONE;
|
||||
|
|
@ -908,62 +909,49 @@ static ssl_peer_type get_peer_type(const char *hostname)
|
|||
return CURL_SSL_PEER_DNS;
|
||||
}
|
||||
|
||||
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
|
||||
struct Curl_cfilter *cf,
|
||||
CURLcode Curl_ssl_peer_init(struct ssl_peer *ssl_peer,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct ssl_primary_config *sslc,
|
||||
const char *tls_id,
|
||||
uint8_t transport)
|
||||
{
|
||||
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->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,
|
||||
* the settings in cf->conn might change. We keep a copy of the hostname we
|
||||
* use for SNI.
|
||||
*/
|
||||
peer->transport = transport;
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
if(Curl_ssl_cf_is_proxy(cf)) {
|
||||
dest = cf->conn->http_proxy.peer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
dest = cf->conn->origin;
|
||||
if(!ssl_peer || !origin) {
|
||||
DEBUGASSERT(0);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
DEBUGASSERT(!ssl_peer->origin);
|
||||
DEBUGASSERT(!ssl_peer->peer);
|
||||
DEBUGASSERT(!ssl_peer->sni);
|
||||
ssl_peer->transport = transport;
|
||||
|
||||
/* hostname MUST exist and not be empty */
|
||||
if(!dest) {
|
||||
result = CURLE_FAILED_INIT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
Curl_peer_link(&peer->dest, dest);
|
||||
peer->type = get_peer_type(dest->hostname);
|
||||
if(peer->type == CURL_SSL_PEER_DNS) {
|
||||
Curl_peer_link(&ssl_peer->origin, origin);
|
||||
Curl_peer_link(&ssl_peer->peer, peer);
|
||||
ssl_peer->type = get_peer_type(origin->hostname);
|
||||
if(ssl_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(dest->hostname);
|
||||
if(len && (dest->hostname[len - 1] == '.'))
|
||||
size_t len = strlen(origin->hostname);
|
||||
if(len && (origin->hostname[len - 1] == '.'))
|
||||
len--;
|
||||
if(len < USHRT_MAX) {
|
||||
peer->sni = curlx_calloc(1, len + 1);
|
||||
if(!peer->sni)
|
||||
ssl_peer->sni = curlx_calloc(1, len + 1);
|
||||
if(!ssl_peer->sni)
|
||||
goto out;
|
||||
Curl_strntolower(peer->sni, dest->hostname, len);
|
||||
peer->sni[len] = 0;
|
||||
Curl_strntolower(ssl_peer->sni, origin->hostname, len);
|
||||
ssl_peer->sni[len] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
result = Curl_ssl_peer_key_make(cf, peer, tls_id, &peer->scache_key);
|
||||
result = Curl_ssl_peer_key_make(ssl_peer, sslc, tls_id,
|
||||
&ssl_peer->scache_key);
|
||||
|
||||
out:
|
||||
if(result)
|
||||
Curl_ssl_peer_cleanup(peer);
|
||||
Curl_ssl_peer_cleanup(ssl_peer);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -991,7 +979,7 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
|||
return CURLE_OK;
|
||||
}
|
||||
|
||||
if(!cf->next) {
|
||||
if(!cf->next || !connssl->peer.origin) {
|
||||
*done = FALSE;
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
|
@ -1016,14 +1004,6 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
|
|||
connssl->prefs_checked = TRUE;
|
||||
}
|
||||
|
||||
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);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = connssl->ssl_impl->do_connect(cf, data, done);
|
||||
|
||||
if(!result && *done) {
|
||||
|
|
@ -1406,28 +1386,53 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
static CURLcode cf_ssl_peer_init(struct Curl_cfilter *cf,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct ssl_primary_config *sslc)
|
||||
{
|
||||
struct ssl_connect_data *connssl = cf->ctx;
|
||||
char tls_id[80];
|
||||
connssl->ssl_impl->version(tls_id, sizeof(tls_id) - 1);
|
||||
return Curl_ssl_peer_init(&connssl->peer, origin, peer, sslc,
|
||||
tls_id, TRNSPRT_TCP);
|
||||
}
|
||||
|
||||
CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct connectdata *conn,
|
||||
int sockindex)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
struct Curl_peer *peer = (sockindex == SECONDARYSOCKET) ?
|
||||
conn->via_peer2 : conn->via_peer;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_ssl_create(&cf, data, conn);
|
||||
if(!result)
|
||||
result = cf_ssl_peer_init(cf, origin, peer, &conn->ssl_config);
|
||||
if(!result)
|
||||
Curl_conn_cf_add(data, conn, sockindex, cf);
|
||||
else if(cf)
|
||||
Curl_conn_cf_discard_chain(&cf, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_ssl_create(&cf, data, cf_at->conn);
|
||||
if(!result)
|
||||
result = cf_ssl_peer_init(cf, origin, peer, &cf_at->conn->ssl_config);
|
||||
if(!result)
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
else if(cf)
|
||||
Curl_conn_cf_discard_chain(&cf, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1467,14 +1472,19 @@ out:
|
|||
}
|
||||
|
||||
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data)
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *peer)
|
||||
{
|
||||
struct Curl_cfilter *cf;
|
||||
CURLcode result;
|
||||
|
||||
result = cf_ssl_proxy_create(&cf, data, cf_at->conn);
|
||||
if(!result)
|
||||
result = cf_ssl_peer_init(cf, peer, NULL, &cf_at->conn->proxy_ssl_config);
|
||||
if(!result)
|
||||
Curl_conn_cf_insert_after(cf_at, cf);
|
||||
else if(cf)
|
||||
Curl_conn_cf_discard_chain(&cf, data);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ typedef enum {
|
|||
} ssl_peer_type;
|
||||
|
||||
struct ssl_peer {
|
||||
struct Curl_peer *dest;
|
||||
struct Curl_peer *origin; /* the authority we talk to */
|
||||
struct Curl_peer *peer; /* the machine we are connected to */
|
||||
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 */
|
||||
|
|
@ -106,8 +107,10 @@ curl_sslbackend Curl_ssl_backend(void);
|
|||
/**
|
||||
* Init SSL peer information for filter. Can be called repeatedly.
|
||||
*/
|
||||
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
|
||||
struct Curl_cfilter *cf,
|
||||
CURLcode Curl_ssl_peer_init(struct ssl_peer *ssl_peer,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
struct ssl_primary_config *sslc,
|
||||
const char *tls_id,
|
||||
uint8_t transport);
|
||||
/**
|
||||
|
|
@ -174,18 +177,22 @@ CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
|
|||
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
|
||||
|
||||
CURLcode Curl_ssl_cfilter_add(struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct connectdata *conn,
|
||||
int sockindex);
|
||||
|
||||
CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data);
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer);
|
||||
|
||||
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
|
||||
int sockindex, bool send_shutdown);
|
||||
|
||||
#ifndef CURL_DISABLE_PROXY
|
||||
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
|
||||
struct Curl_easy *data);
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *peer);
|
||||
#endif /* !CURL_DISABLE_PROXY */
|
||||
|
||||
/**
|
||||
|
|
@ -225,7 +232,7 @@ extern struct Curl_cftype Curl_cft_ssl_proxy;
|
|||
#define Curl_ssl_random(x, y, z) ((void)(x), CURLE_NOT_BUILT_IN)
|
||||
#define Curl_ssl_cert_status_request() FALSE
|
||||
#define Curl_ssl_supports(a, b) FALSE
|
||||
#define Curl_ssl_cfilter_add(a, b, c) CURLE_NOT_BUILT_IN
|
||||
#define Curl_ssl_cfilter_add(a, b, c, d) CURLE_NOT_BUILT_IN
|
||||
#define Curl_ssl_cfilter_remove(a, b, c) CURLE_OK
|
||||
#define Curl_ssl_cf_get_config(a, b) NULL
|
||||
#define Curl_ssl_cf_get_primary_config(a) NULL
|
||||
|
|
|
|||
|
|
@ -177,11 +177,59 @@ static bool cf_ssl_peer_key_is_global(const char *peer_key)
|
|||
(peer_key[len - 2] == ':');
|
||||
}
|
||||
|
||||
CURLcode Curl_ssl_peer_key_build(struct ssl_primary_config *ssl,
|
||||
const struct ssl_peer *peer,
|
||||
const struct Curl_peer *via_peer,
|
||||
const char *tls_id,
|
||||
char **ppeer_key)
|
||||
static CURLcode ssl_peer_key_add_transport(struct dynbuf *buf,
|
||||
uint8_t transport)
|
||||
{
|
||||
switch(transport) {
|
||||
case TRNSPRT_TCP:
|
||||
return CURLE_OK;
|
||||
case TRNSPRT_UDP:
|
||||
return curlx_dyn_add(buf, ":UDP");
|
||||
case TRNSPRT_QUIC:
|
||||
return curlx_dyn_add(buf, ":QUIC");
|
||||
case TRNSPRT_UNIX:
|
||||
return curlx_dyn_add(buf, ":UNIX");
|
||||
default:
|
||||
return curlx_dyn_addf(buf, ":TRNSPRT-%d", transport);
|
||||
}
|
||||
}
|
||||
|
||||
static CURLcode ssl_peer_key_add_vrfy(struct dynbuf *buf,
|
||||
struct ssl_primary_config *ssl,
|
||||
const struct ssl_peer *peer)
|
||||
{
|
||||
CURLcode result;
|
||||
|
||||
if(!ssl->verifypeer) {
|
||||
result = curlx_dyn_add(buf, ":NO-VRFY-PEER");
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
if(!ssl->verifyhost) {
|
||||
result = curlx_dyn_add(buf, ":NO-VRFY-HOST");
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
if(ssl->verifystatus) {
|
||||
result = curlx_dyn_add(buf, ":VRFY-STATUS");
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
if((!ssl->verifypeer || !ssl->verifyhost) &&
|
||||
peer->peer && !Curl_peer_equal(peer->origin, peer->peer)) {
|
||||
result = curlx_dyn_addf(buf, ":CHOST-%s:CPORT-%u",
|
||||
peer->peer->hostname,
|
||||
peer->peer->port);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
static CURLcode ssl_peer_key_build(struct ssl_primary_config *ssl,
|
||||
const struct ssl_peer *peer,
|
||||
const char *tls_id,
|
||||
char **ppeer_key)
|
||||
{
|
||||
struct dynbuf buf;
|
||||
size_t key_len;
|
||||
|
|
@ -192,54 +240,15 @@ CURLcode Curl_ssl_peer_key_build(struct ssl_primary_config *ssl,
|
|||
curlx_dyn_init(&buf, 10 * 1024);
|
||||
|
||||
result = curlx_dyn_addf(&buf, "%s:%d",
|
||||
peer->dest->hostname, peer->dest->port);
|
||||
peer->origin->hostname, peer->origin->port);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
switch(peer->transport) {
|
||||
case TRNSPRT_TCP:
|
||||
break;
|
||||
case TRNSPRT_UDP:
|
||||
result = curlx_dyn_add(&buf, ":UDP");
|
||||
break;
|
||||
case TRNSPRT_QUIC:
|
||||
result = curlx_dyn_add(&buf, ":QUIC");
|
||||
break;
|
||||
case TRNSPRT_UNIX:
|
||||
result = curlx_dyn_add(&buf, ":UNIX");
|
||||
break;
|
||||
default:
|
||||
result = curlx_dyn_addf(&buf, ":TRNSPRT-%d", peer->transport);
|
||||
break;
|
||||
}
|
||||
result = ssl_peer_key_add_transport(&buf, peer->transport);
|
||||
if(result)
|
||||
goto out;
|
||||
result = ssl_peer_key_add_vrfy(&buf, ssl, peer);
|
||||
if(result)
|
||||
goto out;
|
||||
|
||||
if(!ssl->verifypeer) {
|
||||
result = curlx_dyn_add(&buf, ":NO-VRFY-PEER");
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
if(!ssl->verifyhost) {
|
||||
result = curlx_dyn_add(&buf, ":NO-VRFY-HOST");
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
if(ssl->verifystatus) {
|
||||
result = curlx_dyn_add(&buf, ":VRFY-STATUS");
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
if(!ssl->verifypeer || !ssl->verifyhost) {
|
||||
if(via_peer) {
|
||||
result = curlx_dyn_addf(&buf, ":CHOST-%s:CPORT-%u",
|
||||
via_peer->hostname,
|
||||
via_peer->port);
|
||||
if(result)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if(ssl->version || ssl->version_max) {
|
||||
result = curlx_dyn_addf(&buf, ":TLSVER-%d-%u", ssl->version,
|
||||
(ssl->version_max >> 16));
|
||||
|
|
@ -342,14 +351,12 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
|
||||
const struct ssl_peer *peer,
|
||||
CURLcode Curl_ssl_peer_key_make(const struct ssl_peer *peer,
|
||||
struct ssl_primary_config *sslc,
|
||||
const char *tls_id,
|
||||
char **ppeer_key)
|
||||
{
|
||||
struct ssl_primary_config *ssl = Curl_ssl_cf_get_primary_config(cf);
|
||||
return Curl_ssl_peer_key_build(ssl, peer, cf->conn->via_peer, tls_id,
|
||||
ppeer_key);
|
||||
return ssl_peer_key_build(sslc, peer, tls_id, ppeer_key);
|
||||
}
|
||||
|
||||
struct Curl_ssl_scache {
|
||||
|
|
|
|||
|
|
@ -54,34 +54,18 @@ void Curl_ssl_scache_destroy(struct Curl_ssl_scache *scache);
|
|||
* connection to the peer.
|
||||
* If the filter is a TLS proxy filter, it uses the proxy relevant
|
||||
* information.
|
||||
* @param cf the connection filter wanting to use it
|
||||
* @param peer the peer the filter wants to talk to
|
||||
* @param sslc the relevant ssl configuration
|
||||
* @param tls_id identifier of TLS implementation for sessions. Should
|
||||
* include full version if session data from other versions
|
||||
* is to be avoided.
|
||||
* @param ppeer_key on successful return, the key generated
|
||||
*/
|
||||
CURLcode Curl_ssl_peer_key_make(struct Curl_cfilter *cf,
|
||||
const struct ssl_peer *peer,
|
||||
CURLcode Curl_ssl_peer_key_make(const struct ssl_peer *peer,
|
||||
struct ssl_primary_config *sslc,
|
||||
const char *tls_id,
|
||||
char **ppeer_key);
|
||||
|
||||
/**
|
||||
* Like Curl_ssl_peer_key_make() but takes the primary config and peer
|
||||
* descriptors directly, without requiring a Curl_cfilter. Exposed for
|
||||
* unit testing.
|
||||
* @param ssl the primary SSL config to key on
|
||||
* @param peer the peer the filter wants to talk to
|
||||
* @param via_peer the connecting-through peer, or NULL
|
||||
* @param tls_id identifier of TLS implementation for sessions
|
||||
* @param ppeer_key on successful return, the key generated
|
||||
*/
|
||||
CURLcode Curl_ssl_peer_key_build(struct ssl_primary_config *ssl,
|
||||
const struct ssl_peer *peer,
|
||||
const struct Curl_peer *via_peer,
|
||||
const char *tls_id,
|
||||
char **ppeer_key);
|
||||
|
||||
/* Return if there is a session cache shall be used.
|
||||
* An SSL session might not be configured or not available for
|
||||
* "connect-only" transfers.
|
||||
|
|
|
|||
|
|
@ -1763,9 +1763,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.dest->hostname, 0);
|
||||
ret = wolfSSL_X509_check_ip_asc(cert, connssl->peer.origin->hostname, 0);
|
||||
CURL_TRC_CF(data, cf, "check peer certificate for IP match on %s -> %d",
|
||||
connssl->peer.dest->hostname, ret);
|
||||
connssl->peer.origin->hostname, ret);
|
||||
if(ret != WOLFSSL_SUCCESS)
|
||||
detail = DOMAIN_NAME_MISMATCH;
|
||||
wolfSSL_X509_free(cert);
|
||||
|
|
@ -1788,7 +1788,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.dest->hostname);
|
||||
connssl->peer.origin->hostname);
|
||||
return CURLE_PEER_FAILED_VERIFICATION;
|
||||
}
|
||||
else if(ASN_NO_SIGNER_E == detail) {
|
||||
|
|
|
|||
|
|
@ -214,3 +214,16 @@ class TestEyeballs:
|
|||
r.check_exit_code(0)
|
||||
r.check_response(count=1, http_status=200)
|
||||
assert r.stats[0]['http_version'] == '2'
|
||||
|
||||
# h3 download using --connect-to IPv6 address
|
||||
@pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support")
|
||||
@pytest.mark.skipif(condition=not Env.curl_has_feature('IPv6'), reason="no IPv6")
|
||||
def test_06_25_h3_connect_to(self, env: Env, httpd, nghttpx):
|
||||
curl = CurlClient(env=env, force_resolv=False)
|
||||
urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json'
|
||||
r = curl.http_download(urls=[urln], extra_args=[
|
||||
'--http3-only', '--connect-to',
|
||||
f'{env.authority_for(env.domain1, "h3")}:[::1]:{env.https_port}'
|
||||
])
|
||||
r.check_response(count=1, http_status=200)
|
||||
assert r.stats[0]['http_version'] == '3'
|
||||
|
|
|
|||
|
|
@ -113,8 +113,7 @@ static int test_idx;
|
|||
struct cf_test_ctx {
|
||||
int idx;
|
||||
int ai_family;
|
||||
uint8_t transport_in;
|
||||
uint8_t transport_out;
|
||||
uint8_t transport_peer;
|
||||
char id[16];
|
||||
struct curltime started;
|
||||
timediff_t fail_delay_ms;
|
||||
|
|
@ -166,10 +165,13 @@ static CURLcode cf_test_adjust_pollset(struct Curl_cfilter *cf,
|
|||
|
||||
static CURLcode cf_test_create(struct Curl_cfilter **pcf,
|
||||
struct Curl_easy *data,
|
||||
struct Curl_peer *origin,
|
||||
struct Curl_peer *peer,
|
||||
uint8_t transport_peer,
|
||||
struct connectdata *conn,
|
||||
struct Curl_sockaddr_ex *addr,
|
||||
uint8_t transport_in,
|
||||
uint8_t transport_out)
|
||||
struct Curl_peer *tunnel_peer,
|
||||
uint8_t transport_above)
|
||||
{
|
||||
static const struct Curl_cftype cft_test = {
|
||||
"TEST",
|
||||
|
|
@ -194,7 +196,11 @@ static CURLcode cf_test_create(struct Curl_cfilter **pcf,
|
|||
CURLcode result;
|
||||
|
||||
(void)data;
|
||||
(void)origin;
|
||||
(void)peer;
|
||||
(void)conn;
|
||||
(void)tunnel_peer;
|
||||
(void)transport_above;
|
||||
ctx = curlx_calloc(1, sizeof(*ctx));
|
||||
if(!ctx) {
|
||||
result = CURLE_OUT_OF_MEMORY;
|
||||
|
|
@ -202,8 +208,7 @@ static CURLcode cf_test_create(struct Curl_cfilter **pcf,
|
|||
}
|
||||
ctx->idx = test_idx++;
|
||||
ctx->ai_family = addr->family;
|
||||
ctx->transport_in = transport_in;
|
||||
ctx->transport_out = transport_out;
|
||||
ctx->transport_peer = transport_peer;
|
||||
ctx->started = curlx_now();
|
||||
current_tr->ongoing++;
|
||||
if(current_tr->ongoing > current_tr->max_concurrent)
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ static CURLcode test_unit3304(const char *arg)
|
|||
UNITTEST_BEGIN_SIMPLE
|
||||
|
||||
#ifdef USE_SSL
|
||||
struct Curl_peer dest;
|
||||
struct Curl_peer origin;
|
||||
struct ssl_peer peer;
|
||||
struct ssl_primary_config ssl;
|
||||
char *key1 = NULL;
|
||||
|
|
@ -60,12 +60,12 @@ static CURLcode test_unit3304(const char *arg)
|
|||
static char lc_ctype[] = "pem";
|
||||
static char lc_ktype[] = "pem";
|
||||
|
||||
memset(&dest, 0, sizeof(dest));
|
||||
dest.hostname = base_hostname;
|
||||
dest.port = 443;
|
||||
memset(&origin, 0, sizeof(origin));
|
||||
origin.hostname = base_hostname;
|
||||
origin.port = 443;
|
||||
|
||||
memset(&peer, 0, sizeof(peer));
|
||||
peer.dest = &dest;
|
||||
peer.origin = &origin;
|
||||
peer.transport = TRNSPRT_TCP;
|
||||
|
||||
memset(&ssl, 0, sizeof(ssl));
|
||||
|
|
@ -78,9 +78,9 @@ static CURLcode test_unit3304(const char *arg)
|
|||
ssl.key_type = base_ktype;
|
||||
|
||||
/* Baseline: same config produces same key. */
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key1),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key1),
|
||||
"peer key build failed");
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key2),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key2),
|
||||
"peer key build failed");
|
||||
fail_unless(key1 && key2 && !strcmp(key1, key2),
|
||||
"identical config should produce identical peer key");
|
||||
|
|
@ -89,10 +89,10 @@ static CURLcode test_unit3304(const char *arg)
|
|||
|
||||
/* key_passwd is NOT in the peer key: lookup uses timing-safe comparison
|
||||
* via cf_ssl_scache_match_auth(), same as SRP credentials. */
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key1),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key1),
|
||||
"peer key build failed");
|
||||
ssl.key_passwd = NULL;
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key2),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key2),
|
||||
"peer key build failed");
|
||||
fail_unless(key1 && key2 && !strcmp(key1, key2),
|
||||
"key_passwd must not affect the peer key");
|
||||
|
|
@ -101,10 +101,10 @@ static CURLcode test_unit3304(const char *arg)
|
|||
ssl.key_passwd = base_passwd;
|
||||
|
||||
/* Different key path must produce a different peer key. */
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key1),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key1),
|
||||
"peer key build failed");
|
||||
ssl.key = alt_key;
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key2),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key2),
|
||||
"peer key build failed");
|
||||
fail_unless(key1 && key2 && strcmp(key1, key2),
|
||||
"different key must produce different peer key");
|
||||
|
|
@ -113,10 +113,10 @@ static CURLcode test_unit3304(const char *arg)
|
|||
ssl.key = base_key;
|
||||
|
||||
/* Different key_type must produce a different peer key. */
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key1),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key1),
|
||||
"peer key build failed");
|
||||
ssl.key_type = alt_ktype;
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key2),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key2),
|
||||
"peer key build failed");
|
||||
fail_unless(key1 && key2 && strcmp(key1, key2),
|
||||
"different key_type must produce different peer key");
|
||||
|
|
@ -125,10 +125,10 @@ static CURLcode test_unit3304(const char *arg)
|
|||
ssl.key_type = base_ktype;
|
||||
|
||||
/* Different cert_type must produce a different peer key. */
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key1),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key1),
|
||||
"peer key build failed");
|
||||
ssl.cert_type = alt_ctype;
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key2),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key2),
|
||||
"peer key build failed");
|
||||
fail_unless(key1 && key2 && strcmp(key1, key2),
|
||||
"different cert_type must produce different peer key");
|
||||
|
|
@ -138,10 +138,10 @@ static CURLcode test_unit3304(const char *arg)
|
|||
|
||||
/* cert_type is case-insensitive: "PEM" and "pem" must produce the
|
||||
* same peer key, consistent with the conn-reuse comparison. */
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key1),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key1),
|
||||
"peer key build failed");
|
||||
ssl.cert_type = lc_ctype;
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key2),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key2),
|
||||
"peer key build failed");
|
||||
fail_unless(key1 && key2 && !strcmp(key1, key2),
|
||||
"cert_type case must not affect peer key");
|
||||
|
|
@ -151,10 +151,10 @@ static CURLcode test_unit3304(const char *arg)
|
|||
|
||||
/* key_type is case-insensitive: "PEM" and "pem" must produce the
|
||||
* same peer key. */
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key1),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key1),
|
||||
"peer key build failed");
|
||||
ssl.key_type = lc_ktype;
|
||||
fail_unless(!Curl_ssl_peer_key_build(&ssl, &peer, NULL, "test", &key2),
|
||||
fail_unless(!Curl_ssl_peer_key_make(&peer, &ssl, "test", &key2),
|
||||
"peer key build failed");
|
||||
fail_unless(key1 && key2 && !strcmp(key1, key2),
|
||||
"key_type case must not affect peer key");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue