socks: use dns filter for resolving
No binary (build failed)
—
(log yok)
| @@ -44,6 +44,7 @@ struct cf_dns_ctx { | |
| BIT(started); | |
| BIT(announced); | |
| BIT(abstract_unix_socket); | |
| + | BIT(complete_resolve); |
| char hostname[1]; | |
| }; | |
| @@ -52,6 +53,7 @@ static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data, | |
| const char *hostname, | |
| uint16_t port, uint8_t transport, | |
| bool abstract_unix_socket, | |
| + | bool complete_resolve, |
| struct Curl_dns_entry *dns) | |
| { | |
| struct cf_dns_ctx *ctx; | |
| @@ -65,11 +67,14 @@ static struct cf_dns_ctx *cf_dns_ctx_create(struct Curl_easy *data, | |
| ctx->dns_queries = dns_queries; | |
| ctx->transport = transport; | |
| ctx->abstract_unix_socket = abstract_unix_socket; | |
| + | ctx->complete_resolve = complete_resolve; |
| ctx->dns = Curl_dns_entry_link(data, dns); | |
| ctx->started = !!ctx->dns; | |
| if(hlen) | |
| memcpy(ctx->hostname, hostname, hlen); | |
| + | CURL_TRC_DNS(data, "created DNS filter for %s:%u, transport=%x, queries=%x", |
| + | ctx->hostname, ctx->port, ctx->transport, ctx->dns_queries); |
| return ctx; | |
| } | |
| @@ -240,20 +245,23 @@ static CURLcode cf_dns_connect(struct Curl_cfilter *cf, | |
| } | |
| if(cf->next && !cf->next->connected) { | |
| - | CURLcode result = Curl_conn_cf_connect(cf->next, data, done); |
| - | CURL_TRC_CF(data, cf, "connect subfilters -> %d, done=%d", result, *done); |
| - | if(result || !*done) |
| + | bool sub_done; |
| + | CURLcode result = Curl_conn_cf_connect(cf->next, data, &sub_done); |
| + | CURL_TRC_CF(data, cf, "connect subfilters -> %d, done=%d", |
| + | result, sub_done); |
| + | if(result || !sub_done) |
| return result; | |
| + | DEBUGASSERT(sub_done); |
| } | |
| - | /* sub filter chain is connected, so are we now. |
| - | * Unlink the DNS entry, it is no longer needed and if it |
| - | * came from a SHARE in `data`, we need to release it under |
| - | * that one's lock. */ |
| - | DEBUGASSERT(*done); |
| + | /* sub filter chain is connected */ |
| + | if(ctx->complete_resolve && !ctx->dns && !ctx->resolv_result) { |
| + | /* This filter only connects when it has resolved everything. */ |
| + | return CURLE_OK; |
| + | } |
| + | *done = TRUE; |
| cf->connected = TRUE; | |
| Curl_resolv_destroy(data, ctx->resolv_id); | |
| - | Curl_dns_entry_unlink(data, &ctx->dns); |
| return CURLE_OK; | |
| } | |
| @@ -336,6 +344,7 @@ static CURLcode cf_dns_create(struct Curl_cfilter **pcf, | |
| uint16_t port, | |
| uint8_t transport, | |
| bool abstract_unix_socket, | |
| + | bool complete_resolve, |
| struct Curl_dns_entry *dns) | |
| { | |
| struct Curl_cfilter *cf = NULL; | |
| @@ -344,7 +353,7 @@ static CURLcode cf_dns_create(struct Curl_cfilter **pcf, | |
| (void)data; | |
| ctx = cf_dns_ctx_create(data, dns_queries, hostname, port, transport, | |
| - | abstract_unix_socket, dns); |
| + | abstract_unix_socket, complete_resolve, dns); |
| if(!ctx) { | |
| result = CURLE_OUT_OF_MEMORY; | |
| goto out; | |
| @@ -365,6 +374,7 @@ static CURLcode cf_dns_conn_create(struct Curl_cfilter **pcf, | |
| struct Curl_easy *data, | |
| uint8_t dns_queries, | |
| uint8_t transport, | |
| + | bool complete_resolve, |
| struct Curl_dns_entry *dns) | |
| { | |
| struct connectdata *conn = data->conn; | |
| @@ -409,7 +419,7 @@ static CURLcode cf_dns_conn_create(struct Curl_cfilter **pcf, | |
| } | |
| return cf_dns_create(pcf, data, dns_queries, | |
| hostname, port, transport, | |
| - | abstract_unix_socket, dns); |
| + | abstract_unix_socket, complete_resolve, dns); |
| } | |
| /* Adds a "resolv" filter at the top of the connection's filter chain. | |
| @@ -430,11 +440,11 @@ CURLcode Curl_cf_dns_add(struct Curl_easy *data, | |
| DEBUGASSERT(data); | |
| if(sockindex == FIRSTSOCKET) | |
| - | result = cf_dns_conn_create(&cf, data, dns_queries, transport, dns); |
| + | result = cf_dns_conn_create(&cf, data, dns_queries, transport, FALSE, dns); |
| else if(dns) { | |
| result = cf_dns_create(&cf, data, dns_queries, | |
| dns->hostname, dns->port, transport, | |
| - | FALSE, dns); |
| + | FALSE, FALSE, dns); |
| } | |
| else { | |
| DEBUGASSERT(0); | |
| @@ -458,14 +468,15 @@ CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at, | |
| uint8_t dns_queries, | |
| const char *hostname, | |
| uint16_t port, | |
| - | uint8_t transport) |
| + | uint8_t transport, |
| + | bool complete_resolve) |
| { | |
| struct Curl_cfilter *cf; | |
| CURLcode result; | |
| result = cf_dns_create(&cf, data, dns_queries, | |
| hostname, port, transport, | |
| - | FALSE, NULL); |
| + | FALSE, complete_resolve, NULL); |
| if(result) | |
| return result; | |
| @@ -42,7 +42,8 @@ CURLcode Curl_cf_dns_insert_after(struct Curl_cfilter *cf_at, | |
| uint8_t dns_queries, | |
| const char *hostname, | |
| uint16_t port, | |
| - | uint8_t transport); |
| + | uint8_t transport, |
| + | bool complete_resolve); |
| CURLcode Curl_conn_dns_result(struct connectdata *conn, int sockindex); | |
| CURLcode Curl_cf_dns_result(struct Curl_cfilter *cf); | |
| @@ -38,6 +38,7 @@ | |
| #include "curl_trc.h" | |
| #include "select.h" | |
| #include "cfilters.h" | |
| + | #include "cf-dns.h" |
| #include "connect.h" | |
| #include "socks.h" | |
| #include "curlx/inet_pton.h" | |
| @@ -313,71 +314,54 @@ static CURLproxycode socks4_resolving(struct socks_state *sx, | |
| struct Curl_easy *data, | |
| bool *done) | |
| { | |
| - | struct Curl_dns_entry *dns = NULL; |
| - | struct Curl_addrinfo *hp = NULL; |
| + | const struct Curl_addrinfo *ai = NULL; |
| CURLcode result; | |
| size_t nwritten; | |
| + | bool dns_done; |
| *done = FALSE; | |
| if(sx->start_resolving) { | |
| /* need to resolve hostname to add destination address */ | |
| sx->start_resolving = FALSE; | |
| DEBUGASSERT(sx->hostname && *sx->hostname); | |
| - | |
| - | result = Curl_resolv(data, |
| - | Curl_resolv_dns_queries(data, cf->conn->ip_version), |
| - | sx->hostname, sx->remote_port, |
| - | Curl_conn_cf_get_transport(cf, data), |
| - | 0, &sx->resolv_id, &dns); |
| - | if(result == CURLE_AGAIN) { |
| - | CURL_TRC_CF(data, cf, "SOCKS4 non-blocking resolve of %s", sx->hostname); |
| - | return CURLPX_OK; |
| + | result = Curl_cf_dns_insert_after( |
| + | cf, data, Curl_resolv_dns_queries(data, cf->conn->ip_version), |
| + | sx->hostname, sx->remote_port, TRNSPRT_TCP, TRUE); |
| + | if(result) { |
| + | failf(data, "unable to create DNS filter for socks"); |
| + | return CURLPX_UNKNOWN_FAIL; |
| } | |
| - | else if(result) |
| - | return CURLPX_RESOLVE_HOST; |
| - | } |
| - | else { |
| - | /* check if we have the name resolved by now */ |
| - | result = Curl_resolv_take_result(data, sx->resolv_id, &dns); |
| - | if(!result && !dns) |
| - | return CURLPX_OK; |
| } | |
| - | if(result || !dns) { |
| - | failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", sx->hostname); |
| - | if(dns) |
| - | Curl_dns_entry_unlink(data, &dns); |
| + | /* resolve the hostname by connecting the DNS filter */ |
| + | result = Curl_conn_cf_connect(cf->next, data, &dns_done); |
| + | if(result) { |
| + | failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", |
| + | sx->hostname); |
| return CURLPX_RESOLVE_HOST; | |
| } | |
| + | else if(!dns_done) |
| + | return CURLPX_OK; |
| - | /* |
| - | * We cannot use 'hostent' as a struct that Curl_resolv() returns. It |
| - | * returns a Curl_addrinfo pointer that may not always look the same. |
| - | */ |
| - | /* scan for the first IPv4 address */ |
| - | hp = dns->addr; |
| - | while(hp && (hp->ai_family != AF_INET)) |
| - | hp = hp->ai_next; |
| - | |
| - | if(hp) { |
| + | ai = Curl_cf_dns_get_ai(cf->next, data, AF_INET, 0); |
| + | if(ai) { |
| struct sockaddr_in *saddr_in; | |
| char ipbuf[64]; | |
| - | Curl_printable_address(hp, ipbuf, sizeof(ipbuf)); |
| + | Curl_printable_address(ai, ipbuf, sizeof(ipbuf)); |
| CURL_TRC_CF(data, cf, "SOCKS4 connect to IPv4 %s (locally resolved)", | |
| ipbuf); | |
| - | saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; |
| + | saddr_in = (struct sockaddr_in *)(void *)ai->ai_addr; |
| result = Curl_bufq_write(&sx->iobuf, | |
| (unsigned char *)&saddr_in->sin_addr.s_addr, 4, | |
| &nwritten); | |
| - | Curl_dns_entry_unlink(data, &dns); /* not used anymore from now on */ |
| if(result || (nwritten != 4)) | |
| return CURLPX_SEND_REQUEST; | |
| } | |
| else { | |
| - | Curl_dns_entry_unlink(data, &dns); |
| + | /* No ipv4 address resolved */ |
| failf(data, "SOCKS4 connection to %s not supported", sx->hostname); | |
| return CURLPX_RESOLVE_HOST; | |
| } | |
| @@ -844,8 +828,7 @@ static CURLproxycode socks5_resolving(struct socks_state *sx, | |
| struct Curl_easy *data, | |
| bool *done) | |
| { | |
| - | struct Curl_dns_entry *dns = NULL; |
| - | struct Curl_addrinfo *hp = NULL; |
| + | const struct Curl_addrinfo *ai = NULL; |
| char dest[MAX_IPADR_LEN]; /* printable address */ | |
| const unsigned char *destination = NULL; | |
| unsigned char desttype = 1, destlen = 4; | |
| @@ -853,72 +836,61 @@ static CURLproxycode socks5_resolving(struct socks_state *sx, | |
| CURLcode result; | |
| CURLproxycode presult = CURLPX_OK; | |
| size_t nwritten; | |
| + | bool dns_done; |
| *done = FALSE; | |
| if(sx->start_resolving) { | |
| /* need to resolve hostname to add destination address */ | |
| sx->start_resolving = FALSE; | |
| DEBUGASSERT(sx->hostname && *sx->hostname); | |
| - | |
| - | result = Curl_resolv(data, |
| - | Curl_resolv_dns_queries(data, cf->conn->ip_version), |
| - | sx->hostname, sx->remote_port, |
| - | Curl_conn_cf_get_transport(cf, data), |
| - | 0, &sx->resolv_id, &dns); |
| - | if(result == CURLE_AGAIN) { |
| - | CURL_TRC_CF(data, cf, "SOCKS5 non-blocking resolve of %s", sx->hostname); |
| - | return CURLPX_OK; |
| + | result = Curl_cf_dns_insert_after( |
| + | cf, data, Curl_resolv_dns_queries(data, cf->conn->ip_version), |
| + | sx->hostname, sx->remote_port, TRNSPRT_TCP, TRUE); |
| + | if(result) { |
| + | failf(data, "unable to create DNS filter for socks"); |
| + | return CURLPX_UNKNOWN_FAIL; |
| } | |
| - | else if(result) |
| - | return CURLPX_RESOLVE_HOST; |
| - | } |
| - | else { |
| - | /* check if we have the name resolved by now */ |
| - | result = Curl_resolv_take_result(data, sx->resolv_id, &dns); |
| - | if(!result && !dns) |
| - | return CURLPX_OK; |
| } | |
| - | if(result || !dns) { |
| + | /* resolve the hostname by connecting the DNS filter */ |
| + | result = Curl_conn_cf_connect(cf->next, data, &dns_done); |
| + | if(result) { |
| failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", sx->hostname); | |
| - | presult = CURLPX_RESOLVE_HOST; |
| - | goto out; |
| + | return CURLPX_RESOLVE_HOST; |
| } | |
| + | else if(!dns_done) |
| + | return CURLPX_OK; |
| - | if(dns) |
| - | hp = dns->addr; |
| #ifdef USE_IPV6 | |
| - | if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) { |
| - | int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ? |
| - | AF_INET : AF_INET6; |
| - | /* scan for the first proper address */ |
| - | while(hp && (hp->ai_family != wanted_family)) |
| - | hp = hp->ai_next; |
| - | } |
| + | if(data->set.ipver != CURL_IPRESOLVE_V4) |
| + | ai = Curl_cf_dns_get_ai(cf->next, data, AF_INET6, 0); |
| #endif | |
| - | if(!hp) { |
| + | if(!ai) |
| + | ai = Curl_cf_dns_get_ai(cf->next, data, AF_INET, 0); |
| + | |
| + | if(!ai) { |
| failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.", sx->hostname); | |
| presult = CURLPX_RESOLVE_HOST; | |
| goto out; | |
| } | |
| - | Curl_printable_address(hp, dest, sizeof(dest)); |
| + | Curl_printable_address(ai, dest, sizeof(dest)); |
| - | if(hp->ai_family == AF_INET) { |
| + | if(ai->ai_family == AF_INET) { |
| struct sockaddr_in *saddr_in; | |
| desttype = 1; /* ATYP: IPv4 = 1 */ | |
| destlen = 4; | |
| - | saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; |
| + | saddr_in = (struct sockaddr_in *)(void *)ai->ai_addr; |
| destination = (const unsigned char *)&saddr_in->sin_addr.s_addr; | |
| CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%u (locally resolved)", | |
| dest, sx->remote_port); | |
| } | |
| #ifdef USE_IPV6 | |
| - | else if(hp->ai_family == AF_INET6) { |
| + | else if(ai->ai_family == AF_INET6) { |
| struct sockaddr_in6 *saddr_in6; | |
| desttype = 4; /* ATYP: IPv6 = 4 */ | |
| destlen = 16; | |
| - | saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; |
| + | saddr_in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr; |
| destination = (const unsigned char *)&saddr_in6->sin6_addr.s6_addr; | |
| CURL_TRC_CF(data, cf, "SOCKS5 connect to [%s]:%u (locally resolved)", | |
| dest, sx->remote_port); | |
| @@ -952,8 +924,6 @@ static CURLproxycode socks5_resolving(struct socks_state *sx, | |
| } | |
| out: | |
| - | if(dns) |
| - | Curl_dns_entry_unlink(data, &dns); |
| *done = (presult == CURLPX_OK); | |
| return presult; | |
| } | |