diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index f4084823d..b370855f9 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -2298,6 +2298,36 @@ This option requires that libcurl was built with a resolver backend that supports this operation. The c-ares backend is the only such one. (Added in 7.24.0) +.IP CURLOPT_DNS_INTERFACE +Pass a char * as parameter. Set the name of the network interface that +the DNS resolver should bind to. This must be an interface name (not an +address). Set this option to NULL to use the default setting (don't +bind to a specific interface). + +This option requires that libcurl was built with a resolver backend that +supports this operation. The c-ares backend is the only such one. + +(Added in 7.33.0) +.IP CURLOPT_DNS_LOCAL_IP4 +Set the local IPv4 address that the resolver should bind to. The argument +should be of type char * and contain a single IPv4 address as a string. +Set this option to NULL to use the default setting (don't +bind to a specific IP address). + +This option requires that libcurl was built with a resolver backend that +supports this operation. The c-ares backend is the only such one. + +(Added in 7.33.0) +.IP CURLOPT_DNS_LOCAL_IP6 +Set the local IPv6 address that the resolver should bind to. The argument +should be of type char * and contain a single IPv6 address as a string. +Set this option to NULL to use the default setting (don't +bind to a specific IP address). + +This option requires that libcurl was built with a resolver backend that +supports this operation. The c-ares backend is the only such one. + +(Added in 7.33.0) .IP CURLOPT_ACCEPTTIMEOUT_MS Pass a long telling libcurl the maximum number of milliseconds to wait for a server to connect back to libcurl when an active FTP connection is used. If no diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 3e20cd657..7c362cde7 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -332,6 +332,9 @@ CURLOPT_DEBUGDATA 7.9.6 CURLOPT_DEBUGFUNCTION 7.9.6 CURLOPT_DIRLISTONLY 7.17.0 CURLOPT_DNS_CACHE_TIMEOUT 7.9.3 +CURLOPT_DNS_INTERFACE 7.33.0 +CURLOPT_DNS_LOCAL_IP4 7.33.0 +CURLOPT_DNS_LOCAL_IP6 7.33.0 CURLOPT_DNS_SERVERS 7.24.0 CURLOPT_DNS_USE_GLOBAL_CACHE 7.9.3 7.11.1 CURLOPT_EGDSOCKET 7.7 diff --git a/include/curl/curl.h b/include/curl/curl.h index 239cecbf5..4e09cf728 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1556,6 +1556,19 @@ typedef enum { /* The XOAUTH2 bearer token */ CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220), + /* Set the interface string to use as outgoing network + * interface for DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_INTERFACE, OBJECTPOINT, 221), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP4, OBJECTPOINT, 222), + + /* Set the local IPv4 address to use for outgoing DNS requests. + * Only supported by the c-ares DNS backend */ + CINIT(DNS_LOCAL_IP6, OBJECTPOINT, 223), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index a9fee0c84..e8f1dff9a 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -265,6 +265,10 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, (option) == CURLOPT_RTSP_STREAM_URI || \ (option) == CURLOPT_RTSP_TRANSPORT || \ (option) == CURLOPT_XOAUTH2_BEARER || \ + (option) == CURLOPT_DNS_SERVERS || \ + (option) == CURLOPT_DNS_INTERFACE || \ + (option) == CURLOPT_DNS_LOCAL_IP4 || \ + (option) == CURLOPT_DNS_LOCAL_IP6 || \ 0) /* evaluates to true if option takes a curl_write_callback argument */ diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 081667dc3..fa12f21de 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -623,4 +623,65 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, #endif return result; } + +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interface) +{ +#if (ARES_VERSION >= 0x010704) + if(!interface) interface = ""; + ares_set_local_dev((ares_channel)data->state.resolver, interface); + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)interface; + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4) +{ +#if (ARES_VERSION >= 0x010704) + uint32_t a4; + + if((!local_ip4) || (local_ip4[0] == 0)) { + a4 = 0; /* disabled: do not bind to a specific address */ + } + else { + if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) { + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4)); + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6) +{ +#if (ARES_VERSION >= 0x010704) + unsigned char a6[INET6_ADDRSTRLEN]; + + if((!local_ip6) || (local_ip6[0] == 0)) { + /* disabled: do not bind to a specific address */ + memset(a6, 0, sizeof(a6)); + } + else { + if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) { + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + ares_set_local_ip6((ares_channel)data->state.resolver, a6); + return CURLE_OK; +#else /* c-ares version too old! */ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +#endif +} #endif /* CURLRES_ARES */ diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index 81d1d5d5d..206dcdb1f 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -635,4 +635,28 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, } +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interface) +{ + (void)data; + (void)interface; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4) +{ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +} + +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6) +{ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +} + #endif /* CURLRES_THREADED */ diff --git a/lib/hostip.h b/lib/hostip.h index a38f732a4..997800a88 100644 --- a/lib/hostip.h +++ b/lib/hostip.h @@ -200,6 +200,27 @@ extern sigjmp_buf curl_jmpenv; */ CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers); +/* + * Function provided by the resolver backend to set + * outgoing interface to use for DNS requests + */ +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interface); + +/* + * Function provided by the resolver backend to set + * local IPv4 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4); + +/* + * Function provided by the resolver backend to set + * local IPv6 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6); + /* * Clean off entries from the cache */ diff --git a/lib/hostsyn.c b/lib/hostsyn.c index 65a403545..24f8dd82c 100644 --- a/lib/hostsyn.c +++ b/lib/hostsyn.c @@ -72,4 +72,40 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, } +/* + * Function provided by the resolver backend to set + * outgoing interface to use for DNS requests + */ +CURLcode Curl_set_dns_interface(struct SessionHandle *data, + const char *interface) +{ + (void)data; + (void)interface; + return CURLE_NOT_BUILT_IN; +} + +/* + * Function provided by the resolver backend to set + * local IPv4 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, + const char *local_ip4) +{ + (void)data; + (void)local_ip4; + return CURLE_NOT_BUILT_IN; +} + +/* + * Function provided by the resolver backend to set + * local IPv6 address to use as source address for DNS requests + */ +CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, + const char *local_ip6) +{ + (void)data; + (void)local_ip6; + return CURLE_NOT_BUILT_IN; +} + #endif /* truly sync */ diff --git a/lib/url.c b/lib/url.c index 50ce80df4..c1672d08b 100644 --- a/lib/url.c +++ b/lib/url.c @@ -2455,6 +2455,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_DNS_SERVERS: result = Curl_set_dns_servers(data, va_arg(param, char *)); break; + case CURLOPT_DNS_INTERFACE: + result = Curl_set_dns_interface(data, va_arg(param, char *)); + break; + case CURLOPT_DNS_LOCAL_IP4: + result = Curl_set_dns_local_ip4(data, va_arg(param, char *)); + break; + case CURLOPT_DNS_LOCAL_IP6: + result = Curl_set_dns_local_ip6(data, va_arg(param, char *)); + break; case CURLOPT_TCP_KEEPALIVE: data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE;