diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst index 53bd09c8278..29680d285e7 100644 --- a/doc/admin-guide/files/records.config.en.rst +++ b/doc/admin-guide/files/records.config.en.rst @@ -2665,6 +2665,7 @@ HostDB of partitions .. ts:cv:: CONFIG proxy.config.hostdb.ip_resolve STRING NULL + :overridable: Set the host resolution style. diff --git a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst index 2af73e20b93..0d4a2e530b2 100644 --- a/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst +++ b/doc/developer-guide/api/functions/TSHttpOverridableConfig.en.rst @@ -186,6 +186,7 @@ TSOverridableConfigKey Value Configuratio :c:macro:`TS_CONFIG_SSL_CLIENT_CERT_FILENAME` :ts:cv:`proxy.config.ssl.client.cert.filename` :c:macro:`TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME` :ts:cv:`proxy.config.ssl.client.private_key.filename` :c:macro:`TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME` :ts:cv:`proxy.config.ssl.client.CA.cert.filename` +:c:macro:`TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE` :ts:cv:`proxy.config.hostdb.ip_resolve` ================================================================== ==================================================================== Examples diff --git a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst index d24b1a26152..a17c791a15c 100644 --- a/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst +++ b/doc/developer-guide/api/types/TSOverridableConfigKey.en.rst @@ -153,6 +153,7 @@ Enumeration Members .. c:macro:: TS_CONFIG_SSL_CLIENT_SNI_POLICY .. c:macro:: TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME .. c:macro:: TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME + .. c:macro:: TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE Description diff --git a/include/ts/apidefs.h.in b/include/ts/apidefs.h.in index 49f5a83cd0b..fe5f1012bd0 100644 --- a/include/ts/apidefs.h.in +++ b/include/ts/apidefs.h.in @@ -799,6 +799,7 @@ typedef enum { TS_CONFIG_SSL_CLIENT_SNI_POLICY, TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME, TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME, + TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE, TS_CONFIG_LAST_ENTRY } TSOverridableConfigKey; diff --git a/include/tscore/ink_resolver.h b/include/tscore/ink_resolver.h index 0969fa7dfa1..394e121824e 100644 --- a/include/tscore/ink_resolver.h +++ b/include/tscore/ink_resolver.h @@ -185,8 +185,6 @@ extern const char *const HOST_RES_STYLE_STRING[]; extern HostResStyle ats_host_res_from(int family, ///< Connection family HostResPreferenceOrder const & ///< Preference ordering. ); -/// Calculate the host resolution style to force a family match to @a addr. -extern HostResStyle ats_host_res_match(sockaddr const *addr); /** Parse a host resolution configuration string. */ @@ -194,6 +192,18 @@ extern void parse_host_res_preference(const char *value, ///< [in] Con HostResPreferenceOrder order /// [out] Order to update. ); +/// Configure the preference order to hold only what's from the client address. +/// @addr[in] client's address. +/// @order[out] Order to update +extern void ats_force_order_by_family(sockaddr const *addr, HostResPreferenceOrder order); + +// Domain resolution priority for origin. +struct HostResData { + HostResPreferenceOrder order; + // keep the configuration value to satisfy the API(TSHttpTxnConfigStringSet) + char *conf_value{nullptr}; +}; + #ifndef NS_GET16 #define NS_GET16(s, cp) \ do { \ diff --git a/plugins/lua/ts_lua_http_config.c b/plugins/lua/ts_lua_http_config.c index a926eb6cba8..72146aa10e2 100644 --- a/plugins/lua/ts_lua_http_config.c +++ b/plugins/lua/ts_lua_http_config.c @@ -136,6 +136,7 @@ typedef enum { TS_LUA_CONFIG_SSL_CLIENT_SNI_POLICY = TS_CONFIG_SSL_CLIENT_SNI_POLICY, TS_LUA_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME = TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME, TS_LUA_CONFIG_SSL_CLIENT_CA_CERT_FILENAME = TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME, + TS_LUA_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE = TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE, TS_LUA_CONFIG_LAST_ENTRY = TS_CONFIG_LAST_ENTRY, } TSLuaOverridableConfigKey; @@ -261,6 +262,7 @@ ts_lua_var_item ts_lua_http_config_vars[] = { TS_LUA_MAKE_VAR_ITEM(TS_CONFIG_SSL_CLIENT_SNI_POLICY), TS_LUA_MAKE_VAR_ITEM(TS_CONFIG_SSL_CLIENT_PRIVATE_KEY_FILENAME), TS_LUA_MAKE_VAR_ITEM(TS_CONFIG_SSL_CLIENT_CA_CERT_FILENAME), + TS_LUA_MAKE_VAR_ITEM(TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE), TS_LUA_MAKE_VAR_ITEM(TS_CONFIG_HTTP_SERVER_MIN_KEEP_ALIVE_CONNS), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_PER_SERVER_CONNECTION_MAX), TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_PER_SERVER_CONNECTION_MATCH), diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc index 0ec5251f968..4f00b34d69a 100644 --- a/proxy/http/HttpConfig.cc +++ b/proxy/http/HttpConfig.cc @@ -1583,6 +1583,9 @@ HttpConfig::reconfigure() params->negative_caching_list = m_master.negative_caching_list; + params->oride.host_res_data = m_master.oride.host_res_data; + params->oride.host_res_data.conf_value = ats_strdup(m_master.oride.host_res_data.conf_value); + m_id = configProcessor.set(m_id, params); } diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h index 978775dbfe9..ed0fcce2bfe 100644 --- a/proxy/http/HttpConfig.h +++ b/proxy/http/HttpConfig.h @@ -44,6 +44,7 @@ #include "tscore/ink_platform.h" #include "tscore/ink_inet.h" +#include "tscore/ink_resolver.h" #include "tscore/IpMap.h" #include "tscore/Regex.h" #include "string_view" @@ -681,6 +682,9 @@ struct OverridableHttpConfigParams { char *ssl_client_cert_filename = nullptr; char *ssl_client_private_key_filename = nullptr; char *ssl_client_ca_cert_filename = nullptr; + + // Host Resolution order + HostResData host_res_data; }; ///////////////////////////////////////////////////////////// @@ -859,6 +863,7 @@ inline HttpConfigParams::~HttpConfigParams() ats_free(reverse_proxy_no_host_redirect); ats_free(redirect_actions_string); ats_free(oride.ssl_client_sni_policy); + ats_free(oride.host_res_data.conf_value); delete connect_ports; delete redirect_actions_map; diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 9b47469b008..4a5f00a1e89 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -544,11 +544,15 @@ HttpSM::attach_client_session(ProxyTransaction *client_vc, IOBufferReader *buffe debug_on = true; } + t_state.setup_per_txn_configs(); + ink_assert(ua_txn->get_proxy_ssn()); ink_assert(ua_txn->get_proxy_ssn()->accept_options); - // default the upstream IP style host resolution from inbound - t_state.dns_info.host_res_style = - ats_host_res_from(netvc->get_local_addr()->sa_family, ua_txn->get_proxy_ssn()->accept_options->host_res_preference); + + // default the upstream IP style host resolution order from inbound + std::copy(std::begin(ua_txn->get_proxy_ssn()->accept_options->host_res_preference), + std::end(ua_txn->get_proxy_ssn()->accept_options->host_res_preference), + std::begin(t_state.my_txn_conf().host_res_data.order)); start_sub_sm(); @@ -2282,7 +2286,6 @@ int HttpSM::state_hostdb_lookup(int event, void *data) { STATE_ENTER(&HttpSM::state_hostdb_lookup, event); - // ink_assert (m_origin_server_vc == 0); // REQ_FLAVOR_SCHEDULED_UPDATE can be transformed into // REQ_FLAVOR_REVPROXY @@ -2305,7 +2308,7 @@ HttpSM::state_hostdb_lookup(int event, void *data) opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing) ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS : HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD; opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0; - opt.host_res_style = t_state.dns_info.host_res_style; + opt.host_res_style = ats_host_res_from(ua_txn->get_netvc()->get_local_addr()->sa_family, t_state.txn_conf->host_res_data.order); Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this, (cb_process_result_pfn)&HttpSM::process_hostdb_info, host_name, 0, opt); @@ -4123,8 +4126,9 @@ HttpSM::do_hostdb_lookup() t_state.hdr_info.client_request.port_get(); opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing) ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS : HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD; - opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0; - opt.host_res_style = t_state.dns_info.host_res_style; + opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0; + opt.host_res_style = + ats_host_res_from(ua_txn->get_netvc()->get_local_addr()->sa_family, t_state.txn_conf->host_res_data.order); Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this, (cb_process_result_pfn)&HttpSM::process_hostdb_info, host_name, 0, opt); @@ -4158,8 +4162,9 @@ HttpSM::do_hostdb_lookup() opt.port = server_port; opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing) ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS : HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD; - opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0; - opt.host_res_style = t_state.dns_info.host_res_style; + opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0; + + opt.host_res_style = ats_host_res_from(ua_txn->get_netvc()->get_local_addr()->sa_family, t_state.txn_conf->host_res_data.order); Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this, (cb_process_result_pfn)&HttpSM::process_hostdb_info, t_state.dns_info.lookup_name, 0, opt); diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc index 026870aa31e..138906ba6c1 100644 --- a/proxy/http/HttpTransact.cc +++ b/proxy/http/HttpTransact.cc @@ -46,6 +46,16 @@ #include "../IPAllow.h" #include "I_Machine.h" +// Support ip_resolve override. +const MgmtConverter HttpTransact::HOST_RES_CONV{[](const void *data) -> std::string_view { + const HostResData *host_res_data = static_cast(data); + return host_res_data->conf_value; + }, + [](void *data, std::string_view src) -> void { + HostResData *res_data = static_cast(data); + parse_host_res_preference(src.data(), res_data->order); + }}; + static char range_type[] = "multipart/byteranges; boundary=RANGE_SEPARATOR"; #define RANGE_NUMBERS_LENGTH 60 @@ -3749,7 +3759,7 @@ HttpTransact::handle_response_from_server(State *s) // Force host resolution to have the same family as the client. // Because this is a transparent connection, we can't switch address // families - that is locked in by the client source address. - s->dns_info.host_res_style = ats_host_res_match(&s->current.server->dst_addr.sa); + ats_force_order_by_family(&s->current.server->dst_addr.sa, s->my_txn_conf().host_res_data.order); return CallOSDNSLookup(s); } else if ((s->dns_info.srv_lookup_success || s->host_db_info.is_rr_elt()) && (s->txn_conf->connect_attempts_rr_retries > 0) && diff --git a/proxy/http/HttpTransact.h b/proxy/http/HttpTransact.h index e8d14156e10..0aaee1bc47b 100644 --- a/proxy/http/HttpTransact.h +++ b/proxy/http/HttpTransact.h @@ -41,6 +41,7 @@ #include "UrlMapping.h" #include "records/I_RecHttp.h" #include "ProxySession.h" +#include "MgmtDefs.h" #define HTTP_RELEASE_ASSERT(X) ink_release_assert(X) @@ -620,8 +621,7 @@ class HttpTransact OS_ADDR_USE_CLIENT ///< Use client target addr, no fallback. }; - OS_Addr os_addr_style = OS_Addr::OS_ADDR_TRY_DEFAULT; - HostResStyle host_res_style = HOST_RES_IPV4; + OS_Addr os_addr_style = OS_Addr::OS_ADDR_TRY_DEFAULT; bool lookup_success = false; char *lookup_name = nullptr; @@ -639,6 +639,9 @@ class HttpTransact _DNSLookupInfo() {} } DNSLookupInfo; + // Conversion handling for DNS host resolution type. + static const MgmtConverter HOST_RES_CONV; + typedef struct _HeaderInfo { HTTPHdr client_request; HTTPHdr client_response; diff --git a/src/shared/overridable_txn_vars.cc b/src/shared/overridable_txn_vars.cc index c38d8d4aeab..025e75d7ee6 100644 --- a/src/shared/overridable_txn_vars.cc +++ b/src/shared/overridable_txn_vars.cc @@ -159,4 +159,5 @@ const std::unordered_mapoutbound_conntrack.match; conv = &OutboundConnTrack::MATCH_CONV; break; + case TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE: + ret = &overridableHttpConfig->host_res_data; + conv = &HttpTransact::HOST_RES_CONV; + break; // This helps avoiding compiler warnings, yet detect unhandled enum members. case TS_CONFIG_NULL: case TS_CONFIG_LAST_ENTRY: @@ -8733,6 +8737,11 @@ TSHttpTxnConfigStringSet(TSHttpTxn txnp, TSOverridableConfigKey conf, const char case TS_CONFIG_SSL_CERT_FILEPATH: /* noop */ break; + case TS_CONFIG_HTTP_HOST_RESOLUTION_PREFERENCE: + if (value && length > 0) { + s->t_state.my_txn_conf().host_res_data.conf_value = const_cast(value); + } + [[fallthrough]]; default: { MgmtConverter const *conv; void *dest = _conf_to_memberp(conf, &(s->t_state.my_txn_conf()), conv); diff --git a/src/traffic_server/InkAPITest.cc b/src/traffic_server/InkAPITest.cc index 685da749bb1..e1273c28ce1 100644 --- a/src/traffic_server/InkAPITest.cc +++ b/src/traffic_server/InkAPITest.cc @@ -8660,7 +8660,8 @@ std::array SDK_Overridable_Configs = { "proxy.config.ssl.client.verify.server.properties", "proxy.config.ssl.client.sni_policy", "proxy.config.ssl.client.private_key.filename", - "proxy.config.ssl.client.CA.cert.filename"}}; + "proxy.config.ssl.client.CA.cert.filename", + "proxy.config.hostdb.ip_resolve"}}; REGRESSION_TEST(SDK_API_OVERRIDABLE_CONFIGS)(RegressionTest *test, int /* atype ATS_UNUSED */, int *pstatus) { diff --git a/src/tscore/ink_res_mkquery.cc b/src/tscore/ink_res_mkquery.cc index 7bfe95bd4cf..85af97fbd61 100644 --- a/src/tscore/ink_res_mkquery.cc +++ b/src/tscore/ink_res_mkquery.cc @@ -545,14 +545,16 @@ ats_host_res_from(int family, HostResPreferenceOrder const &order) return HOST_RES_NONE; } -HostResStyle -ats_host_res_match(sockaddr const *addr) +void +ats_force_order_by_family(sockaddr const *addr, HostResPreferenceOrder order) { - HostResStyle zret = HOST_RES_NONE; + int pos{0}; if (ats_is_ip6(addr)) { - zret = HOST_RES_IPV6_ONLY; + order[pos++] = HOST_RES_PREFER_IPV6; } else if (ats_is_ip4(addr)) { - zret = HOST_RES_IPV4_ONLY; + order[pos++] = HOST_RES_PREFER_IPV4; + } + for (; pos < N_HOST_RES_PREFERENCE_ORDER; pos++) { + order[pos] = HOST_RES_PREFER_NONE; } - return zret; } diff --git a/tests/gold_tests/remap/gold/remap-DNS-ipv6-200.gold b/tests/gold_tests/remap/gold/remap-DNS-ipv6-200.gold new file mode 100644 index 00000000000..8250185dfbe --- /dev/null +++ b/tests/gold_tests/remap/gold/remap-DNS-ipv6-200.gold @@ -0,0 +1,14 @@ +`` +> GET http://testDNS2.com`` +> Host: testDNS2.com`` +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 200 OK +< Date: `` +< Age: `` +< Transfer-Encoding: chunked +< Proxy-Connection: keep-alive +< Server: ATS/`` +< +`` diff --git a/tests/gold_tests/remap/gold/remap-ip-resolve.gold b/tests/gold_tests/remap/gold/remap-ip-resolve.gold new file mode 100644 index 00000000000..c83df3f4ca3 --- /dev/null +++ b/tests/gold_tests/remap/gold/remap-ip-resolve.gold @@ -0,0 +1,14 @@ +`` +> GET http://testDNS.com/`` +> Host: testDNS.com`` +> User-Agent: curl/`` +> Accept: */* +`` +< HTTP/1.1 200 OK +< Server: ATS/`` +< Date: `` +< Age: `` +< Transfer-Encoding: chunked +< Proxy-Connection: keep-alive +< +`` diff --git a/tests/gold_tests/remap/remap_ip_resolve.test.py b/tests/gold_tests/remap/remap_ip_resolve.test.py new file mode 100644 index 00000000000..a740275c141 --- /dev/null +++ b/tests/gold_tests/remap/remap_ip_resolve.test.py @@ -0,0 +1,79 @@ + +''' +''' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +Test.Summary = ''' +Test a basic ip_resolve override using an ipv6 server +''' + +Test.ContinueOnFail = True +# Define default ATS +ts = Test.MakeATSProcess("ts") +server = Test.MakeOriginServer("server") +server_v6 = Test.MakeOriginServer("server_v6", None, None, '::1', 0) + +dns = Test.MakeDNServer("dns") + +Test.testName = "" +request_header = {"headers": "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n", + "timestamp": "1469733493.993", "body": ""} +# expected response from the origin server +response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", + "timestamp": "1469733493.993", "body": ""} + +# add response to the server dictionary +server.addResponse("sessionfile.log", request_header, response_header) +server_v6.addResponse("sessionfile.log", request_header, response_header) +ts.Disk.records_config.update({ + 'proxy.config.diags.debug.enabled': 1, + 'proxy.config.diags.debug.tags': 'http.*|dns|conf_remap', + 'proxy.config.http.referer_filter': 1, + 'proxy.config.dns.nameservers': '127.0.0.1:{0}'.format(dns.Variables.Port), + 'proxy.config.dns.resolv_conf': 'NULL', + 'proxy.config.hostdb.ip_resolve': 'ipv4' +}) + + +ts.Disk.remap_config.AddLine( + 'map http://testDNS.com http://test.ipv4.only.com:{0} @plugin=conf_remap.so @pparam=proxy.config.hostdb.ip_resolve=ipv6;ipv4;client'.format(server.Variables.Port) +) +ts.Disk.remap_config.AddLine( + 'map http://testDNS2.com http://test.ipv6.only.com:{0} @plugin=conf_remap.so @pparam=proxy.config.hostdb.ip_resolve=ipv6;only'.format(server_v6.Variables.Port) +) + + +dns.addRecords(records={"test.ipv4.only.com.": ["127.0.0.1"]}) +dns.addRecords(records={"test.ipv6.only.com": ["127.0.0.1","::1"]}) + +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl --proxy 127.0.0.1:{0} "http://testDNS.com" --verbose'.format(ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 +tr.Processes.Default.StartBefore(server) +tr.Processes.Default.StartBefore(dns) +tr.Processes.Default.StartBefore(Test.Processes.ts) +tr.Processes.Default.Streams.stderr = "gold/remap-DNS-200.gold" +tr.StillRunningAfter=server + + +tr = Test.AddTestRun() +tr.Processes.Default.Command = 'curl --proxy 127.0.0.1:{0} "http://testDNS2.com" --verbose'.format(ts.Variables.port) +tr.Processes.Default.ReturnCode = 0 +tr.Processes.Default.StartBefore(server_v6) +tr.Processes.Default.Streams.stderr = "gold/remap-DNS-ipv6-200.gold" +tr.StillRunningAfter=server_v6 +