This is an automated email from the ASF dual-hosted git repository. cmcfarlen pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit a9a4f29c9ce9be0059ae29bd456154d3114470b4 Author: Leif Hedstrom <[email protected]> AuthorDate: Thu Aug 21 16:12:06 2025 -0600 HRW: Adds %{INBOUND:SERVER-CERT} and %{INBOUND:CLIENT-CERT} conds (#12363) * Adds a %{CERT} and %{CLIENT-CERT} cond * Moved certificates to INBOUND: condition (cherry picked from commit 938b4913d5b76509306553016421777c1fddbf5e) (cherry picked from commit 0b6ea0e625f5cac9edac732a604468ad39f3ef45) --- doc/admin-guide/plugins/header_rewrite.en.rst | 40 ++++- include/cripts/Transaction.hpp | 2 - plugins/header_rewrite/CMakeLists.txt | 5 + plugins/header_rewrite/conditions.cc | 223 ++++++++++++++++++++------ plugins/header_rewrite/conditions.h | 9 +- plugins/header_rewrite/header_rewrite.cc | 28 ++-- plugins/header_rewrite/operators.cc | 111 ++++++------- plugins/header_rewrite/resources.cc | 49 +++++- plugins/header_rewrite/resources.h | 67 +++++--- plugins/header_rewrite/statement.h | 26 ++- plugins/header_rewrite/value.cc | 8 +- plugins/header_rewrite/value.h | 4 +- 12 files changed, 416 insertions(+), 156 deletions(-) diff --git a/doc/admin-guide/plugins/header_rewrite.en.rst b/doc/admin-guide/plugins/header_rewrite.en.rst index 540bd9598c..91e4811138 100644 --- a/doc/admin-guide/plugins/header_rewrite.en.rst +++ b/doc/admin-guide/plugins/header_rewrite.en.rst @@ -454,7 +454,7 @@ INBOUND ~~~~~~~ :: - cond %{INBOUND:TLS} /./ + cond %{INBOUND:TLS} ="" [NOT] This condition provides access to information about the inbound (client, user agent) connection to ATS. The data that can be checked is :: @@ -482,7 +482,7 @@ will be true for *non*-TLS connections because it will be true when ``%{INBOUND: string. This happens because the default matching is equality and the default value the empty string. Therefore the condition is treated as if it were :: - cond %{INBOUND:TLS}="" + cond %{INBOUND:TLS} ="" which is true when the connection is not TLS. The arguments ``H2``, ``IPV4``, and ``IPV6`` work the same way. @@ -497,6 +497,42 @@ As a special matcher, the inbound IP addresses can be matched against a list of and the configuration parser will error out. The format here is very specific, in particular no white spaces are allowed between the ranges. +If |ATS| is built with :ref:`Cripts <developer-guide-cripts>` support, a number of additional +qualifiers are available exclusively on TLS sessions, for X509 certificate introspection. +The client certificate (for mutual TLS) is accessed with qualifier prefix of ``CLIENT-CERT:`` +and the server certificate with a prefix qualifier of ``SERVER-CERT:``. The X509 naming of the +specific fields are the same for the two certificates:: + + PEM The PEM-encoded certificate, as a string. + SIG The signature of the certificate. + SUBJECT The subject of the certificate. + ISSUER The issuer of the certificate. + SERIAL The serial number of the certificate. + NOT_BEFORE The date and time when the certificate becomes valid. + NOT_AFTER The date and time when the certificate expires. + VERSION The version of the certificate. + SAN:DNS The Subject Alternative Name (SAN) DNS entries. + SAN:IP The Subject Alternative Name (SAN) IP addresses. + SAN:EMAIL The Subject Alternative Name (SAN) email addresses. + SAN:URI The Subject Alternative Name (SAN) URIs. + +These conditions and qualifiers can be used in conditions of course, but more importantly, +are also very useful when adding or modifying headers. For example, you can add some +client certificate and server subject to the response headers, so that the client can see it +as part of the response :: + + cond %{SEND_RESPONSE_HDR_HOOK} [AND] + cond %{INBOUND:TLS} ="" [NOT] + set-header X-Client-Cert "%{INBOUND:CLIENT-CERT:PEM}" + set-header X-Client-Cert-Subject "%{INBOUND:CLIENT-CERT:SUBJECT}" + set-header X-Client-Cert-Issuer "%{INBOUND:CLIENT-CERT:ISSUER}" + set-header X-Server-Cert-Subject "%{INBOUND:SERVER-CERT:SUBJECT}"" + +The ``SAN:`` fields will return a semicolon-separated list of the respective +values, there can be zero, one or many of each SAN type. Example :: + + cond %{CLIENT-CERT:SAN:DNS} /example\.com/ + IP ~~ :: diff --git a/include/cripts/Transaction.hpp b/include/cripts/Transaction.hpp index 9bcdb83d33..1831406b1e 100644 --- a/include/cripts/Transaction.hpp +++ b/include/cripts/Transaction.hpp @@ -17,8 +17,6 @@ */ #pragma once -#include <fmt/core.h> - #include "ts/ts.h" #include "cripts/Error.hpp" diff --git a/plugins/header_rewrite/CMakeLists.txt b/plugins/header_rewrite/CMakeLists.txt index e1a8ef7bc6..7527a1efd3 100644 --- a/plugins/header_rewrite/CMakeLists.txt +++ b/plugins/header_rewrite/CMakeLists.txt @@ -42,6 +42,11 @@ target_link_libraries( PUBLIC libswoc::libswoc ) +if(ENABLE_CRIPTS) + target_link_libraries(header_rewrite PRIVATE ts::cripts) + target_compile_definitions(header_rewrite PRIVATE TS_HAS_CRIPTS=1) +endif() + if(maxminddb_FOUND) target_compile_definitions(header_rewrite PUBLIC TS_USE_HRW_MAXMINDDB=1) target_sources(header_rewrite PRIVATE conditions_geo_maxmind.cc) diff --git a/plugins/header_rewrite/conditions.cc b/plugins/header_rewrite/conditions.cc index 4cd109fa9e..522a60bc69 100644 --- a/plugins/header_rewrite/conditions.cc +++ b/plugins/header_rewrite/conditions.cc @@ -36,6 +36,10 @@ static const sockaddr *getClientAddr(TSHttpTxn txnp, int txn_private_slot); +#if TS_HAS_CRIPTS +#include "cripts/Certs.hpp" +#endif + // ConditionStatus void ConditionStatus::initialize(Parser &p) @@ -280,7 +284,7 @@ ConditionUrl::append_value(std::string &s, const Resources &res) if (_type == CLIENT) { // CLIENT always uses the pristine URL Dbg(pi_dbg_ctl, " Using the pristine url"); - if (TSHttpTxnPristineUrlGet(res.txnp, &bufp, &url) != TS_SUCCESS) { + if (TSHttpTxnPristineUrlGet(res.state.txnp, &bufp, &url) != TS_SUCCESS) { TSError("[%s] Error getting the pristine URL", PLUGIN_NAME); return; } @@ -503,7 +507,7 @@ ConditionCookie::eval(const Resources &res) bool ConditionInternalTxn::eval(const Resources &res) { - bool ret = (0 != TSHttpTxnIsInternal(res.txnp)); + bool ret = (0 != TSHttpTxnIsInternal(res.state.txnp)); Dbg(pi_dbg_ctl, "Evaluating INTERNAL-TRANSACTION() -> %d", ret); return ret; @@ -555,16 +559,16 @@ ConditionIp::eval(const Resources &res) switch (_ip_qual) { case IP_QUAL_CLIENT: - addr = getClientAddr(res.txnp, _txn_private_slot); + addr = getClientAddr(res.state.txnp, _txn_private_slot); break; case IP_QUAL_INBOUND: - addr = TSHttpTxnIncomingAddrGet(res.txnp); + addr = TSHttpTxnIncomingAddrGet(res.state.txnp); break; case IP_QUAL_SERVER: - addr = TSHttpTxnServerAddrGet(res.txnp); + addr = TSHttpTxnServerAddrGet(res.state.txnp); break; case IP_QUAL_OUTBOUND: - addr = TSHttpTxnOutgoingAddrGet(res.txnp); + addr = TSHttpTxnOutgoingAddrGet(res.state.txnp); break; } @@ -593,17 +597,17 @@ ConditionIp::append_value(std::string &s, const Resources &res) switch (_ip_qual) { case IP_QUAL_CLIENT: - ip_set = (nullptr != getIP(getClientAddr(res.txnp, _txn_private_slot), ip)); + ip_set = (nullptr != getIP(getClientAddr(res.state.txnp, _txn_private_slot), ip)); break; case IP_QUAL_INBOUND: - ip_set = (nullptr != getIP(TSHttpTxnIncomingAddrGet(res.txnp), ip)); + ip_set = (nullptr != getIP(TSHttpTxnIncomingAddrGet(res.state.txnp), ip)); break; case IP_QUAL_SERVER: - ip_set = (nullptr != getIP(TSHttpTxnServerAddrGet(res.txnp), ip)); + ip_set = (nullptr != getIP(TSHttpTxnServerAddrGet(res.state.txnp), ip)); break; case IP_QUAL_OUTBOUND: Dbg(pi_dbg_ctl, "Requesting output ip"); - ip_set = (nullptr != getIP(TSHttpTxnOutgoingAddrGet(res.txnp), ip)); + ip_set = (nullptr != getIP(TSHttpTxnOutgoingAddrGet(res.state.txnp), ip)); break; } @@ -627,10 +631,8 @@ ConditionTransactCount::initialize(Parser &p) bool ConditionTransactCount::eval(const Resources &res) { - TSHttpSsn ssn = TSHttpTxnSsnGet(res.txnp); - - if (ssn) { - int n = TSHttpSsnTransactionCount(ssn); + if (res.state.ssnp) { + int n = TSHttpSsnTransactionCount(res.state.ssnp); Dbg(pi_dbg_ctl, "Evaluating TXN-COUNT()"); return static_cast<MatcherType *>(_matcher)->test(n, res); @@ -643,11 +645,9 @@ ConditionTransactCount::eval(const Resources &res) void ConditionTransactCount::append_value(std::string &s, Resources const &res) { - TSHttpSsn ssn = TSHttpTxnSsnGet(res.txnp); - - if (ssn) { + if (res.state.ssnp) { char value[32]; // enough for UINT64_MAX - int count = TSHttpSsnTransactionCount(ssn); + int count = TSHttpSsnTransactionCount(res.state.ssnp); int length = ink_fast_itoa(count, value, sizeof(value)); if (length > 0) { @@ -673,7 +673,7 @@ ConditionNow::get_now_qualified(NowQualifiers qual, const Resources &resources) struct tm res; PrivateSlotData private_data; - private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(resources.txnp, _txn_private_slot)); + private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(resources.state.txnp, _txn_private_slot)); if (private_data.timezone == 1) { gmtime_r(&now, &res); } else { @@ -826,9 +826,9 @@ void ConditionGeo::append_value(std::string &s, const Resources &res) { if (is_int_type()) { - s += std::to_string(get_geo_int(getClientAddr(res.txnp, _txn_private_slot))); + s += std::to_string(get_geo_int(getClientAddr(res.state.txnp, _txn_private_slot))); } else { - s += get_geo_string(getClientAddr(res.txnp, _txn_private_slot)); + s += get_geo_string(getClientAddr(res.state.txnp, _txn_private_slot)); } Dbg(pi_dbg_ctl, "Appending GEO() to evaluation value -> %s", s.c_str()); } @@ -840,7 +840,7 @@ ConditionGeo::eval(const Resources &res) Dbg(pi_dbg_ctl, "Evaluating GEO()"); if (is_int_type()) { - int64_t geo = get_geo_int(getClientAddr(res.txnp, _txn_private_slot)); + int64_t geo = get_geo_int(getClientAddr(res.state.txnp, _txn_private_slot)); ret = static_cast<const Matchers<int64_t> *>(_matcher)->test(geo, res); } else { @@ -899,7 +899,7 @@ ConditionId::append_value(std::string &s, const Resources &res ATS_UNUSED) { switch (_id_qual) { case ID_QUAL_REQUEST: { - s += std::to_string(TSHttpTxnIdGet(res.txnp)); + s += std::to_string(TSHttpTxnIdGet(res.state.txnp)); } break; case ID_QUAL_PROCESS: { TSUuid process = TSProcessUuidGet(); @@ -911,7 +911,7 @@ ConditionId::append_value(std::string &s, const Resources &res ATS_UNUSED) case ID_QUAL_UNIQUE: { char uuid[TS_CRUUID_STRING_LEN + 1]; - if (TS_SUCCESS == TSClientRequestUuidGet(res.txnp, uuid)) { + if (TS_SUCCESS == TSClientRequestUuidGet(res.state.txnp, uuid)) { s += uuid; } } break; @@ -923,7 +923,7 @@ bool ConditionId::eval(const Resources &res) { if (_id_qual == ID_QUAL_REQUEST) { - uint64_t id = TSHttpTxnIdGet(res.txnp); + uint64_t id = TSHttpTxnIdGet(res.state.txnp); Dbg(pi_dbg_ctl, "Evaluating GEO() -> %" PRIu64, id); return static_cast<const Matchers<uint64_t> *>(_matcher)->test(id, res); @@ -997,7 +997,7 @@ ConditionCidr::eval(const Resources &res) void ConditionCidr::append_value(std::string &s, const Resources &res) { - struct sockaddr const *addr = getClientAddr(res.txnp, _txn_private_slot); + struct sockaddr const *addr = getClientAddr(res.state.txnp, _txn_private_slot); if (addr) { switch (addr->sa_family) { @@ -1057,6 +1057,17 @@ ConditionInbound::initialize(Parser &p) match->set(p.get_arg(), mods()); _matcher = match; } + +#if TS_HAS_CRIPTS + if (_net_qual >= NET_QUAL_CERT_PEM && _net_qual <= NET_QUAL_CERT_SAN_URI) { + if (_mtls_cert) { + require_resources(RSRC_MTLS_CERTIFICATE); + } else { + require_resources(RSRC_SERVER_CERTIFICATE); + } + require_resources(RSRC_CLIENT_CONNECTION); + } +#endif } void @@ -1086,6 +1097,68 @@ ConditionInbound::set_qualifier(const std::string &q) _net_qual = NET_QUAL_IP_FAMILY; } else if (q == "STACK") { _net_qual = NET_QUAL_STACK; +#if TS_HAS_CRIPTS + } else if (q == "SERVER-CERT:PEM") { + _net_qual = NET_QUAL_CERT_PEM; + } else if (q == "SERVER-CERT:SIG") { + _net_qual = NET_QUAL_CERT_SIG; + } else if (q == "SERVER-CERT:SUBJECT") { + _net_qual = NET_QUAL_CERT_SUBJECT; + } else if (q == "SERVER-CERT:ISSUER") { + _net_qual = NET_QUAL_CERT_ISSUER; + } else if (q == "SERVER-CERT:SERIAL") { + _net_qual = NET_QUAL_CERT_SERIAL; + } else if (q == "SERVER-CERT:NOT_BEFORE") { + _net_qual = NET_QUAL_CERT_NOT_BEFORE; + } else if (q == "SERVER-CERT:NOT_AFTER") { + _net_qual = NET_QUAL_CERT_NOT_AFTER; + } else if (q == "SERVER-CERT:VERSION") { + _net_qual = NET_QUAL_CERT_VERSION; + } else if (q == "SERVER-CERT:SAN:DNS") { + _net_qual = NET_QUAL_CERT_SAN_DNS; + } else if (q == "SERVER-CERT:SAN:IP") { + _net_qual = NET_QUAL_CERT_SAN_IP; + } else if (q == "SERVER-CERT:SAN:EMAIL") { + _net_qual = NET_QUAL_CERT_SAN_EMAIL; + } else if (q == "SERVER-CERT:SAN:URI") { + _net_qual = NET_QUAL_CERT_SAN_URI; + } else if (q == "CLIENT-CERT:PEM") { + _net_qual = NET_QUAL_CERT_PEM; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:SIG") { + _net_qual = NET_QUAL_CERT_SIG; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:SUBJECT") { + _net_qual = NET_QUAL_CERT_SUBJECT; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:ISSUER") { + _net_qual = NET_QUAL_CERT_ISSUER; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:SERIAL") { + _net_qual = NET_QUAL_CERT_SERIAL; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:NOT_BEFORE") { + _net_qual = NET_QUAL_CERT_NOT_BEFORE; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:NOT_AFTER") { + _net_qual = NET_QUAL_CERT_NOT_AFTER; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:VERSION") { + _net_qual = NET_QUAL_CERT_VERSION; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:SAN:DNS") { + _net_qual = NET_QUAL_CERT_SAN_DNS; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:SAN:IP") { + _net_qual = NET_QUAL_CERT_SAN_IP; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:SAN:EMAIL") { + _net_qual = NET_QUAL_CERT_SAN_EMAIL; + _mtls_cert = true; + } else if (q == "CLIENT-CERT:SAN:URI") { + _net_qual = NET_QUAL_CERT_SAN_URI; + _mtls_cert = true; +#endif } else { TSError("[%s] Unknown %s() qualifier: %s", PLUGIN_NAME, TAG, q.c_str()); } @@ -1100,10 +1173,10 @@ ConditionInbound::eval(const Resources &res) switch (_net_qual) { case NET_QUAL_LOCAL_ADDR: - addr = TSHttpTxnIncomingAddrGet(res.txnp); + addr = TSHttpTxnIncomingAddrGet(res.state.txnp); break; case NET_QUAL_REMOTE_ADDR: - addr = getClientAddr(res.txnp, _txn_private_slot); + addr = getClientAddr(res.state.txnp, _txn_private_slot); break; default: // Only support actual IP addresses of course... @@ -1140,43 +1213,59 @@ ConditionInbound::append_value(std::string &s, const Resources &res, NetworkSess const char *zret = nullptr; char text[INET6_ADDRSTRLEN]; +#if TS_HAS_CRIPTS + detail::CertBase *cert = nullptr; + + if (_net_qual >= NET_QUAL_CERT_PEM && _net_qual <= NET_QUAL_CERT_SAN_URI) { + if (_mtls_cert) { + cert = static_cast<detail::CertBase *>(res.mtls_cert); + } else { + cert = static_cast<detail::CertBase *>(res.server_cert); + } + + if (!cert) { + return; + } + } +#endif + switch (qual) { case NET_QUAL_LOCAL_ADDR: { - zret = getIP(TSHttpTxnIncomingAddrGet(res.txnp), text); + zret = getIP(TSHttpTxnIncomingAddrGet(res.state.txnp), text); } break; case NET_QUAL_LOCAL_PORT: { - uint16_t port = getPort(TSHttpTxnIncomingAddrGet(res.txnp)); + uint16_t port = getPort(TSHttpTxnIncomingAddrGet(res.state.txnp)); snprintf(text, sizeof(text), "%d", port); zret = text; } break; case NET_QUAL_REMOTE_ADDR: { - zret = getIP(getClientAddr(res.txnp, _txn_private_slot), text); + zret = getIP(getClientAddr(res.state.txnp, _txn_private_slot), text); } break; case NET_QUAL_REMOTE_PORT: { - uint16_t port = getPort(getClientAddr(res.txnp, _txn_private_slot)); + uint16_t port = getPort(getClientAddr(res.state.txnp, _txn_private_slot)); snprintf(text, sizeof(text), "%d", port); zret = text; } break; case NET_QUAL_TLS: - zret = TSHttpTxnClientProtocolStackContains(res.txnp, "tls/"); + zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "tls/"); break; case NET_QUAL_H2: - zret = TSHttpTxnClientProtocolStackContains(res.txnp, "h2"); + zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "h2"); break; case NET_QUAL_IPV4: - zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ipv4"); + zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "ipv4"); break; case NET_QUAL_IPV6: - zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ipv6"); + zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "ipv6"); break; case NET_QUAL_IP_FAMILY: - zret = TSHttpTxnClientProtocolStackContains(res.txnp, "ip"); + zret = TSHttpTxnClientProtocolStackContains(res.state.txnp, "ip"); break; case NET_QUAL_STACK: { std::array<char const *, 8> tags = {}; int count = 0; size_t len = 0; - TSHttpTxnClientProtocolStackGet(res.txnp, tags.size(), tags.data(), &count); + TSHttpTxnClientProtocolStackGet(res.state.txnp, tags.size(), tags.data(), &count); for (int i = 0; i < count; ++i) { len += 1 + strlen(tags[i]); } @@ -1188,6 +1277,44 @@ ConditionInbound::append_value(std::string &s, const Resources &res, NetworkSess s += tags[i]; } } break; +#if TS_HAS_CRIPTS + case NET_QUAL_CERT_PEM: + s += cert->certificate; + break; + case NET_QUAL_CERT_SIG: + s += cert->signature; + break; + case NET_QUAL_CERT_SUBJECT: + s += cert->subject; + break; + case NET_QUAL_CERT_ISSUER: + s += cert->issuer; + break; + case NET_QUAL_CERT_SERIAL: + s += cert->serialNumber; + break; + case NET_QUAL_CERT_NOT_BEFORE: + s += cert->notBefore; + break; + case NET_QUAL_CERT_NOT_AFTER: + s += cert->notAfter; + break; + case NET_QUAL_CERT_VERSION: + s += cert->version; + break; + case NET_QUAL_CERT_SAN_DNS: + s += cert->san.dns.Join(";"); + break; + case NET_QUAL_CERT_SAN_IP: + s += cert->san.ipadd.Join(";"); + break; + case NET_QUAL_CERT_SAN_EMAIL: + s += cert->san.email.Join(";"); + break; + case NET_QUAL_CERT_SAN_URI: + s += cert->san.uri.Join(";"); + break; +#endif } if (zret) { @@ -1231,7 +1358,7 @@ ConditionSessionTransactCount::initialize(Parser &p) bool ConditionSessionTransactCount::eval(const Resources &res) { - int const val = TSHttpTxnServerSsnTransactionCount(res.txnp); + int const val = TSHttpTxnServerSsnTransactionCount(res.state.txnp); Dbg(pi_dbg_ctl, "Evaluating SSN-TXN-COUNT()"); return static_cast<MatcherType *>(_matcher)->test(val, res); @@ -1241,7 +1368,7 @@ void ConditionSessionTransactCount::append_value(std::string &s, Resources const &res) { char value[32]; // enough for UINT64_MAX - int const count = TSHttpTxnServerSsnTransactionCount(res.txnp); + int const count = TSHttpTxnServerSsnTransactionCount(res.state.txnp); int const length = ink_fast_itoa(count, value, sizeof(value)); if (length > 0) { @@ -1287,7 +1414,7 @@ void ConditionTcpInfo::append_value(std::string &s, [[maybe_unused]] Resources const &res) { #if defined(TCP_INFO) && defined(HAVE_STRUCT_TCP_INFO) - if (TSHttpTxnIsInternal(res.txnp)) { + if (TSHttpTxnIsInternal(res.state.txnp)) { Dbg(pi_dbg_ctl, "No TCP-INFO available for internal transactions"); return; } @@ -1295,7 +1422,7 @@ ConditionTcpInfo::append_value(std::string &s, [[maybe_unused]] Resources const int fd; struct tcp_info info; socklen_t tcp_info_len = sizeof(info); - tsSsn = TSHttpTxnClientFdGet(res.txnp, &fd); + tsSsn = TSHttpTxnClientFdGet(res.state.txnp, &fd); if (tsSsn != TS_SUCCESS || fd <= 0) { Dbg(pi_dbg_ctl, "error getting the client socket fd from ssn"); } @@ -1347,7 +1474,7 @@ ConditionCache::eval(const Resources &res) void ConditionCache::append_value(std::string &s, const Resources &res) { - TSHttpTxn txn = res.txnp; + TSHttpTxn txn = res.state.txnp; int status; static const char *names[] = { @@ -1394,7 +1521,7 @@ ConditionNextHop::append_value(std::string &s, const Resources &res) { switch (_next_hop_qual) { case NEXT_HOP_HOST: { - char const *const name = TSHttpTxnNextHopNameGet(res.txnp); + char const *const name = TSHttpTxnNextHopNameGet(res.state.txnp); if (nullptr != name) { Dbg(pi_dbg_ctl, "Appending '%s' to evaluation value", name); s.append(name); @@ -1403,7 +1530,7 @@ ConditionNextHop::append_value(std::string &s, const Resources &res) } } break; case NEXT_HOP_PORT: { - int const port = TSHttpTxnNextHopPortGet(res.txnp); + int const port = TSHttpTxnNextHopPortGet(res.state.txnp); Dbg(pi_dbg_ctl, "Appending '%d' to evaluation value", port); s.append(std::to_string(port)); } break; @@ -1436,7 +1563,7 @@ ConditionHttpCntl::set_qualifier(const std::string &q) void ConditionHttpCntl::append_value(std::string &s, const Resources &res) { - s += TSHttpTxnCntlGet(res.txnp, _http_cntl_qual) ? "TRUE" : "FALSE"; + s += TSHttpTxnCntlGet(res.state.txnp, _http_cntl_qual) ? "TRUE" : "FALSE"; Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL(%s)", _qualifier.c_str()); } @@ -1444,7 +1571,7 @@ bool ConditionHttpCntl::eval(const Resources &res) { Dbg(pi_dbg_ctl, "Evaluating HTTP-CNTL()"); - return TSHttpTxnCntlGet(res.txnp, _http_cntl_qual); + return TSHttpTxnCntlGet(res.state.txnp, _http_cntl_qual); } // ConditionStateFlag @@ -1472,7 +1599,7 @@ ConditionStateFlag::append_value(std::string &s, const Resources &res) bool ConditionStateFlag::eval(const Resources &res) { - auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot)); + auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_slot)); Dbg(pi_dbg_ctl, "Evaluating STATE-FLAG()"); diff --git a/plugins/header_rewrite/conditions.h b/plugins/header_rewrite/conditions.h index 8d3edfec93..10d05fbaac 100644 --- a/plugins/header_rewrite/conditions.h +++ b/plugins/header_rewrite/conditions.h @@ -552,7 +552,10 @@ protected: private: NetworkSessionQualifiers _net_qual = NET_QUAL_STACK; - void append_value(std::string &s, const Resources &res, NetworkSessionQualifiers qual); +#if TS_HAS_CRIPTS + bool _mtls_cert = false; +#endif + void append_value(std::string &s, const Resources &res, NetworkSessionQualifiers qual); }; class ConditionStringLiteral : public Condition @@ -810,7 +813,7 @@ private: _get_data(const Resources &res) const { TSAssert(_byte_ix >= 0 && _byte_ix < NUM_STATE_INT8S); - auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot)); + auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_slot)); uint8_t data = (ptr & STATE_INT8_MASKS[_byte_ix]) >> (NUM_STATE_FLAGS + _byte_ix * 8); return data; @@ -853,7 +856,7 @@ private: uint16_t _get_data(const Resources &res) const { - auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot)); + auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_slot)); return ((ptr & STATE_INT16_MASK) >> 48); } diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc index b4f2da2505..91ac9a7f4c 100644 --- a/plugins/header_rewrite/header_rewrite.cc +++ b/plugins/header_rewrite/header_rewrite.cc @@ -300,7 +300,7 @@ RulesConfig::parse_config(const std::string &fname, TSHttpHookID default_hook, c } // Collect all resource IDs that we need - for (int i = TS_HTTP_READ_REQUEST_HDR_HOOK; i < TS_HTTP_LAST_HOOK; ++i) { + for (int i = TS_HTTP_READ_REQUEST_HDR_HOOK; i <= TS_HTTP_LAST_HOOK; ++i) { if (_rules[i]) { _resids[i] = _rules[i]->get_all_resource_ids(); } @@ -573,22 +573,24 @@ TSRemapDoRemap(void *ih, TSHttpTxn rh, TSRemapRequestInfo *rri) RuleSet *rule = conf->rule(TS_REMAP_PSEUDO_HOOK); Resources res(rh, rri); - res.gather(RSRC_CLIENT_REQUEST_HEADERS, TS_REMAP_PSEUDO_HOOK); - while (rule) { - const RuleSet::OperatorPair &ops = rule->eval(res); - const OperModifiers rt = rule->exec(ops, res); + if (rule) { + res.gather(conf->resid(TS_REMAP_PSEUDO_HOOK), TS_REMAP_PSEUDO_HOOK); - ink_assert((rt & OPER_NO_REENABLE) == 0); + do { + const RuleSet::OperatorPair &ops = rule->eval(res); + const OperModifiers rt = rule->exec(ops, res); - if (res.changed_url == true) { - rval = TSREMAP_DID_REMAP; - } + ink_assert((rt & OPER_NO_REENABLE) == 0); - if (rule->last() || (rt & OPER_LAST)) { - break; // Conditional break, force a break with [L] - } + if (res.changed_url == true) { + rval = TSREMAP_DID_REMAP; + } + + if (rule->last() || (rt & OPER_LAST)) { + break; // Conditional break, force a break with [L] + } - rule = rule->next; + } while ((rule = rule->next)); } Dbg(dbg_ctl, "Returning from TSRemapDoRemap with status: %d", rval); diff --git a/plugins/header_rewrite/operators.cc b/plugins/header_rewrite/operators.cc index 9666231491..126a928879 100644 --- a/plugins/header_rewrite/operators.cc +++ b/plugins/header_rewrite/operators.cc @@ -52,6 +52,7 @@ handleFetchEvents(TSCont cont, TSEvent event, void *edata) TSHttpParser parser = TSHttpParserCreate(); TSMBuffer hdr_buf = TSMBufferCreate(); TSMLoc hdr_loc = TSHttpHdrCreate(hdr_buf); + TSHttpHdrTypeSet(hdr_buf, hdr_loc, TS_HTTP_TYPE_RESPONSE); if (TSHttpHdrParseResp(parser, hdr_buf, hdr_loc, &data_start, data_end) == TS_PARSE_DONE) { TSHttpTxnErrorBodySet(http_txn, TSstrdup(data_start), (data_end - data_start), nullptr); @@ -120,7 +121,7 @@ OperatorSetConfig::initialize(Parser &p) _config = p.get_arg(); if (TS_SUCCESS == TSHttpTxnConfigFind(_config.c_str(), _config.size(), &_key, &_type)) { - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); } else { _key = TS_CONFIG_NULL; TSError("[%s] no such records config: %s", PLUGIN_NAME, _config.c_str()); @@ -133,21 +134,21 @@ OperatorSetConfig::exec(const Resources &res) const if (TS_CONFIG_NULL != _key) { switch (_type) { case TS_RECORDDATATYPE_INT: - if (TS_SUCCESS == TSHttpTxnConfigIntSet(res.txnp, _key, _value.get_int_value())) { + if (TS_SUCCESS == TSHttpTxnConfigIntSet(res.state.txnp, _key, _value.get_int_value())) { Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invoked on %s=%d", _config.c_str(), _value.get_int_value()); } else { Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invocation failed on %s=%d", _config.c_str(), _value.get_int_value()); } break; case TS_RECORDDATATYPE_FLOAT: - if (TS_SUCCESS == TSHttpTxnConfigFloatSet(res.txnp, _key, _value.get_float_value())) { + if (TS_SUCCESS == TSHttpTxnConfigFloatSet(res.state.txnp, _key, _value.get_float_value())) { Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invoked on %s=%f", _config.c_str(), _value.get_float_value()); } else { Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invocation failed on %s=%f", _config.c_str(), _value.get_float_value()); } break; case TS_RECORDDATATYPE_STRING: - if (TS_SUCCESS == TSHttpTxnConfigStringSet(res.txnp, _key, _value.get_value().c_str(), _value.size())) { + if (TS_SUCCESS == TSHttpTxnConfigStringSet(res.state.txnp, _key, _value.get_value().c_str(), _value.size())) { Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invoked on %s=%s", _config.c_str(), _value.get_value().c_str()); } else { Dbg(pi_dbg_ctl, "OperatorSetConfig::exec() invocation failed on %s=%s", _config.c_str(), _value.get_value().c_str()); @@ -167,7 +168,7 @@ OperatorSetStatus::initialize(Parser &p) { Operator::initialize(p); - _status.set_value(p.get_arg()); + _status.set_value(p.get_arg(), this); if (nullptr == (_reason = TSHttpHdrReasonLookup(static_cast<TSHttpStatus>(_status.get_int_value())))) { TSError("[%s] unknown status %d", PLUGIN_NAME, _status.get_int_value()); @@ -205,7 +206,7 @@ OperatorSetStatus::exec(const Resources &res) const } break; default: - TSHttpTxnStatusSet(res.txnp, static_cast<TSHttpStatus>(_status.get_int_value())); + TSHttpTxnStatusSet(res.state.txnp, static_cast<TSHttpStatus>(_status.get_int_value())); break; } @@ -220,7 +221,7 @@ OperatorSetStatusReason::initialize(Parser &p) { Operator::initialize(p); - _reason.set_value(p.get_arg()); + _reason.set_value(p.get_arg(), this); require_resources(RSRC_CLIENT_RESPONSE_HEADERS); require_resources(RSRC_SERVER_RESPONSE_HEADERS); } @@ -254,7 +255,7 @@ OperatorSetDestination::initialize(Parser &p) Operator::initialize(p); _url_qual = parse_url_qualifier(p.get_arg()); - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); require_resources(RSRC_CLIENT_REQUEST_HEADERS); require_resources(RSRC_SERVER_REQUEST_HEADERS); } @@ -264,10 +265,10 @@ OperatorSetDestination::exec(const Resources &res) const { if (res._rri || (res.bufp && res.hdr_loc)) { std::string value; + TSMBuffer bufp; + TSMLoc url_m_loc; // Determine which TSMBuffer and TSMLoc to use - TSMBuffer bufp; - TSMLoc url_m_loc; if (res._rri && !res.changed_url) { bufp = res._rri->requestBufp; url_m_loc = res._rri->requestUrl; @@ -480,8 +481,8 @@ OperatorSetRedirect::initialize(Parser &p) { Operator::initialize(p); - _status.set_value(p.get_arg()); - _location.set_value(p.get_value()); + _status.set_value(p.get_arg(), this); + _location.set_value(p.get_value(), this); auto status = _status.get_int_value(); if (status < 300 || status > 399 || status == TS_HTTP_STATUS_NOT_MODIFIED) { TSError("[%s] unsupported redirect status %d", PLUGIN_NAME, status); @@ -590,7 +591,7 @@ OperatorSetRedirect::exec(const Resources &res) const Dbg(pi_dbg_ctl, "Could not set Location field value to: %s", value.c_str()); } // Set the new status. - TSHttpTxnStatusSet(res.txnp, static_cast<TSHttpStatus>(_status.get_int_value())); + TSHttpTxnStatusSet(res.state.txnp, static_cast<TSHttpStatus>(_status.get_int_value())); const_cast<Resources &>(res).changed_url = true; res._rri->redirect = 1; } else { @@ -598,7 +599,7 @@ OperatorSetRedirect::exec(const Resources &res) const // Set the new status code and reason. TSHttpStatus status = static_cast<TSHttpStatus>(_status.get_int_value()); TSHttpHdrStatusSet(res.bufp, res.hdr_loc, status); - EditRedirectResponse(res.txnp, value, status, res.bufp, res.hdr_loc); + EditRedirectResponse(res.state.txnp, value, status, res.bufp, res.hdr_loc); } Dbg(pi_dbg_ctl, "OperatorSetRedirect::exec() invoked with destination=%s and status code=%d", value.c_str(), _status.get_int_value()); @@ -625,7 +626,7 @@ OperatorSetTimeoutOut::initialize(Parser &p) TSError("[%s] unsupported timeout qualifier: %s", PLUGIN_NAME, p.get_arg().c_str()); } - _timeout.set_value(p.get_value()); + _timeout.set_value(p.get_value(), this); } bool @@ -634,22 +635,22 @@ OperatorSetTimeoutOut::exec(const Resources &res) const switch (_type) { case TO_OUT_ACTIVE: Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(active, %d)", _timeout.get_int_value()); - TSHttpTxnActiveTimeoutSet(res.txnp, _timeout.get_int_value()); + TSHttpTxnActiveTimeoutSet(res.state.txnp, _timeout.get_int_value()); break; case TO_OUT_INACTIVE: Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(inactive, %d)", _timeout.get_int_value()); - TSHttpTxnNoActivityTimeoutSet(res.txnp, _timeout.get_int_value()); + TSHttpTxnNoActivityTimeoutSet(res.state.txnp, _timeout.get_int_value()); break; case TO_OUT_CONNECT: Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(connect, %d)", _timeout.get_int_value()); - TSHttpTxnConnectTimeoutSet(res.txnp, _timeout.get_int_value()); + TSHttpTxnConnectTimeoutSet(res.state.txnp, _timeout.get_int_value()); break; case TO_OUT_DNS: Dbg(pi_dbg_ctl, "OperatorSetTimeoutOut::exec(dns, %d)", _timeout.get_int_value()); - TSHttpTxnDNSTimeoutSet(res.txnp, _timeout.get_int_value()); + TSHttpTxnDNSTimeoutSet(res.state.txnp, _timeout.get_int_value()); break; default: TSError("[%s] unsupported timeout", PLUGIN_NAME); @@ -674,7 +675,7 @@ bool OperatorSkipRemap::exec(const Resources &res) const { Dbg(pi_dbg_ctl, "OperatorSkipRemap::exec() skipping remap: %s", _skip_remap ? "True" : "False"); - TSHttpTxnCntlSet(res.txnp, TS_HTTP_CNTL_SKIP_REMAPPING, _skip_remap); + TSHttpTxnCntlSet(res.state.txnp, TS_HTTP_CNTL_SKIP_REMAPPING, _skip_remap); return true; } @@ -704,7 +705,7 @@ OperatorAddHeader::initialize(Parser &p) { OperatorHeaders::initialize(p); - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); } bool @@ -741,7 +742,7 @@ OperatorSetHeader::initialize(Parser &p) { OperatorHeaders::initialize(p); - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); } bool @@ -799,7 +800,7 @@ OperatorSetBody::initialize(Parser &p) { Operator::initialize(p); // we want the arg since body only takes one value - _value.set_value(p.get_arg()); + _value.set_value(p.get_arg(), this); } void @@ -819,7 +820,7 @@ OperatorSetBody::exec(const Resources &res) const if (!value.empty()) { msg = TSstrdup(value.c_str()); } - TSHttpTxnErrorBodySet(res.txnp, msg, value.size(), nullptr); + TSHttpTxnErrorBodySet(res.state.txnp, msg, value.size(), nullptr); return true; } @@ -901,7 +902,7 @@ void OperatorAddCookie::initialize(Parser &p) { OperatorCookies::initialize(p); - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); } bool @@ -947,7 +948,7 @@ void OperatorSetCookie::initialize(Parser &p) { OperatorCookies::initialize(p); - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); } bool @@ -1085,7 +1086,7 @@ OperatorSetConnDSCP::initialize(Parser &p) { Operator::initialize(p); - _ds_value.set_value(p.get_arg()); + _ds_value.set_value(p.get_arg(), this); } void @@ -1099,8 +1100,8 @@ OperatorSetConnDSCP::initialize_hooks() bool OperatorSetConnDSCP::exec(const Resources &res) const { - if (res.txnp) { - TSHttpTxnClientPacketDscpSet(res.txnp, _ds_value.get_int_value()); + if (res.state.txnp) { + TSHttpTxnClientPacketDscpSet(res.state.txnp, _ds_value.get_int_value()); Dbg(pi_dbg_ctl, " Setting DSCP to %d", _ds_value.get_int_value()); } return true; @@ -1112,7 +1113,7 @@ OperatorSetConnMark::initialize(Parser &p) { Operator::initialize(p); - _ds_value.set_value(p.get_arg()); + _ds_value.set_value(p.get_arg(), this); } void @@ -1126,8 +1127,8 @@ OperatorSetConnMark::initialize_hooks() bool OperatorSetConnMark::exec(const Resources &res) const { - if (res.txnp) { - TSHttpTxnClientPacketMarkSet(res.txnp, _ds_value.get_int_value()); + if (res.state.txnp) { + TSHttpTxnClientPacketMarkSet(res.state.txnp, _ds_value.get_int_value()); Dbg(pi_dbg_ctl, " Setting MARK to %d", _ds_value.get_int_value()); } return true; @@ -1152,7 +1153,7 @@ OperatorSetDebug::initialize_hooks() bool OperatorSetDebug::exec(const Resources &res) const { - TSHttpTxnCntlSet(res.txnp, TS_HTTP_CNTL_TXN_DEBUG, true); + TSHttpTxnCntlSet(res.state.txnp, TS_HTTP_CNTL_TXN_DEBUG, true); return true; } @@ -1189,10 +1190,10 @@ bool OperatorSetHttpCntl::exec(const Resources &res) const { if (_flag) { - TSHttpTxnCntlSet(res.txnp, _cntl_qual, true); + TSHttpTxnCntlSet(res.state.txnp, _cntl_qual, true); Dbg(pi_dbg_ctl, " Turning ON %s for transaction", HttpCntls[static_cast<size_t>(_cntl_qual)]); } else { - TSHttpTxnCntlSet(res.txnp, _cntl_qual, false); + TSHttpTxnCntlSet(res.state.txnp, _cntl_qual, false); Dbg(pi_dbg_ctl, " Turning OFF %s for transaction", HttpCntls[static_cast<size_t>(_cntl_qual)]); } return true; @@ -1244,7 +1245,7 @@ bool OperatorSetPluginCntl::exec(const Resources &res) const { PrivateSlotData private_data; - private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_private_slot)); + private_data.raw = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_private_slot)); switch (_name) { case PluginCtrl::TIMEZONE: @@ -1256,7 +1257,7 @@ OperatorSetPluginCntl::exec(const Resources &res) const } Dbg(pi_dbg_ctl, " Setting plugin control %d to %d", static_cast<int>(_name), _value); - TSUserArgSet(res.txnp, _txn_private_slot, reinterpret_cast<void *>(private_data.raw)); + TSUserArgSet(res.state.txnp, _txn_private_slot, reinterpret_cast<void *>(private_data.raw)); return true; } @@ -1326,8 +1327,8 @@ OperatorRunPlugin::exec(const Resources &res) const { TSReleaseAssert(_plugin != nullptr); - if (res._rri && res.txnp) { - _plugin->doRemap(res.txnp, res._rri); + if (res._rri && res.state.txnp) { + _plugin->doRemap(res.state.txnp, res._rri); } return true; } @@ -1338,7 +1339,7 @@ OperatorSetBodyFrom::initialize(Parser &p) { Operator::initialize(p); // we want the arg since body only takes one value - _value.set_value(p.get_arg()); + _value.set_value(p.get_arg(), this); require_resources(RSRC_SERVER_RESPONSE_HEADERS); require_resources(RSRC_RESPONSE_STATUS); } @@ -1352,7 +1353,7 @@ OperatorSetBodyFrom::initialize_hooks() bool OperatorSetBodyFrom::exec(const Resources &res) const { - if (TSHttpTxnIsInternal(res.txnp)) { + if (TSHttpTxnIsInternal(res.state.txnp)) { // If this is triggered by an internal transaction, a infinte loop may occur // It should only be triggered by the original transaction sent by the client Dbg(pi_dbg_ctl, "OperatorSetBodyFrom triggered by an internal transaction"); @@ -1363,9 +1364,9 @@ OperatorSetBodyFrom::exec(const Resources &res) const int req_buf_size = 0; if (createRequestString(_value.get_value(), req_buf, &req_buf_size) == TS_SUCCESS) { TSCont fetchCont = TSContCreate(handleFetchEvents, TSMutexCreate()); - TSContDataSet(fetchCont, static_cast<void *>(res.txnp)); + TSContDataSet(fetchCont, static_cast<void *>(res.state.txnp)); - TSHttpTxnHookAdd(res.txnp, TS_HTTP_TXN_CLOSE_HOOK, fetchCont); + TSHttpTxnHookAdd(res.state.txnp, TS_HTTP_TXN_CLOSE_HOOK, fetchCont); TSFetchEvent event_ids; event_ids.success_event_id = TS_EVENT_FETCHSM_SUCCESS; @@ -1382,7 +1383,7 @@ OperatorSetBodyFrom::exec(const Resources &res) const // Forces original status code in event TSHttpTxnErrorBodySet changed // the code or another condition was set conflicting with this one. // Set here because res is the only structure that contains the original status code. - TSHttpTxnStatusSet(res.txnp, res.resp_status); + TSHttpTxnStatusSet(res.state.txnp, res.resp_status); } else { TSError(PLUGIN_NAME, "OperatorSetBodyFrom:exec:: Could not create request"); return true; @@ -1432,16 +1433,16 @@ OperatorSetStateFlag::initialize_hooks() bool OperatorSetStateFlag::exec(const Resources &res) const { - if (!res.txnp) { + if (!res.state.txnp) { TSError("[%s] OperatorSetStateFlag() failed. Transaction is null", PLUGIN_NAME); return false; } Dbg(pi_dbg_ctl, " Setting state flag %d to %d", _flag_ix, _flag); - auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot)); + auto data = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_slot)); - TSUserArgSet(res.txnp, _txn_slot, reinterpret_cast<void *>(_flag ? data | _mask : data & _mask)); + TSUserArgSet(res.state.txnp, _txn_slot, reinterpret_cast<void *>(_flag ? data | _mask : data & _mask)); return true; } @@ -1458,7 +1459,7 @@ OperatorSetStateInt8::initialize(Parser &p) return; } - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); if (!_value.has_conds()) { int v = _value.get_int_value(); @@ -1486,12 +1487,12 @@ OperatorSetStateInt8::initialize_hooks() bool OperatorSetStateInt8::exec(const Resources &res) const { - if (!res.txnp) { + if (!res.state.txnp) { TSError("[%s] OperatorSetStateInt8() failed. Transaction is null", PLUGIN_NAME); return false; } - auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot)); + auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_slot)); int val = 0; if (_value.has_conds()) { // If there are conditions, we need to evaluate them, which gives us a string @@ -1511,7 +1512,7 @@ OperatorSetStateInt8::exec(const Resources &res) const Dbg(pi_dbg_ctl, " Setting state int8 %d to %d", _byte_ix, val); ptr &= ~STATE_INT8_MASKS[_byte_ix]; // Clear any old value ptr |= (static_cast<uint64_t>(val) << (NUM_STATE_FLAGS + _byte_ix * 8)); - TSUserArgSet(res.txnp, _txn_slot, reinterpret_cast<void *>(ptr)); + TSUserArgSet(res.state.txnp, _txn_slot, reinterpret_cast<void *>(ptr)); return true; } @@ -1528,7 +1529,7 @@ OperatorSetStateInt16::initialize(Parser &p) return; } - _value.set_value(p.get_value()); + _value.set_value(p.get_value(), this); if (!_value.has_conds()) { int v = _value.get_int_value(); @@ -1556,12 +1557,12 @@ OperatorSetStateInt16::initialize_hooks() bool OperatorSetStateInt16::exec(const Resources &res) const { - if (!res.txnp) { + if (!res.state.txnp) { TSError("[%s] OperatorSetStateInt16() failed. Transaction is null", PLUGIN_NAME); return false; } - auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.txnp, _txn_slot)); + auto ptr = reinterpret_cast<uint64_t>(TSUserArgGet(res.state.txnp, _txn_slot)); int val = 0; if (_value.has_conds()) { // If there are conditions, we need to evaluate them, which gives us a string @@ -1581,7 +1582,7 @@ OperatorSetStateInt16::exec(const Resources &res) const Dbg(pi_dbg_ctl, " Setting state int16 to %d", val); ptr &= ~STATE_INT16_MASK; // Clear any old value ptr |= (static_cast<uint64_t>(val) << 48); - TSUserArgSet(res.txnp, _txn_slot, reinterpret_cast<void *>(ptr)); + TSUserArgSet(res.state.txnp, _txn_slot, reinterpret_cast<void *>(ptr)); return true; } diff --git a/plugins/header_rewrite/resources.cc b/plugins/header_rewrite/resources.cc index d54eb7d0ac..7f5a755fc8 100644 --- a/plugins/header_rewrite/resources.cc +++ b/plugins/header_rewrite/resources.cc @@ -24,6 +24,10 @@ #include "resources.h" #include "lulu.h" +#if TS_HAS_CRIPTS +#include "cripts/Connections.hpp" +#endif + // Collect all resources void Resources::gather(const ResourceIDs ids, TSHttpHookID hook) @@ -34,10 +38,12 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook) ovector_count = 0; ovector_ptr = nullptr; + Dbg(pi_dbg_ctl, "Gathering resources for hook %s with IDs %d", TSHttpHookNameLookup(hook), ids); + // If we need the client request headers, make sure it's also available in the client vars. if (ids & RSRC_CLIENT_REQUEST_HEADERS) { Dbg(pi_dbg_ctl, "\tAdding TXN client request header buffers"); - if (TSHttpTxnClientReqGet(txnp, &client_bufp, &client_hdr_loc) != TS_SUCCESS) { + if (TSHttpTxnClientReqGet(state.txnp, &client_bufp, &client_hdr_loc) != TS_SUCCESS) { Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request"); return; } @@ -48,7 +54,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook) // Read response headers from server if ((ids & RSRC_SERVER_RESPONSE_HEADERS) || (ids & RSRC_RESPONSE_STATUS)) { Dbg(pi_dbg_ctl, "\tAdding TXN server response header buffers"); - if (TSHttpTxnServerRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + if (TSHttpTxnServerRespGet(state.txnp, &bufp, &hdr_loc) != TS_SUCCESS) { Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for response"); return; } @@ -64,7 +70,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook) // Read request headers to server if (ids & RSRC_SERVER_REQUEST_HEADERS) { Dbg(pi_dbg_ctl, "\tAdding TXN server request header buffers"); - if (TSHttpTxnServerReqGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + if (TSHttpTxnServerReqGet(state.txnp, &bufp, &hdr_loc) != TS_SUCCESS) { Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request"); return; } @@ -84,7 +90,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook) // Send response headers to client if (ids & RSRC_CLIENT_RESPONSE_HEADERS) { Dbg(pi_dbg_ctl, "\tAdding TXN client response header buffers"); - if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + if (TSHttpTxnClientRespGet(state.txnp, &bufp, &hdr_loc) != TS_SUCCESS) { Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request"); return; } @@ -116,7 +122,7 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook) case TS_HTTP_TXN_CLOSE_HOOK: // Get TCP Info at transaction close Dbg(pi_dbg_ctl, "\tAdding TXN close buffers"); - if (TSHttpTxnClientRespGet(txnp, &bufp, &hdr_loc) != TS_SUCCESS) { + if (TSHttpTxnClientRespGet(state.txnp, &bufp, &hdr_loc) != TS_SUCCESS) { Dbg(pi_dbg_ctl, "could not gather bufp/hdr_loc for request"); return; } @@ -126,6 +132,32 @@ Resources::gather(const ResourceIDs ids, TSHttpHookID hook) break; } + // The following is all the new infrastructure borrowed / reused from + // the Cripts library. +#if TS_HAS_CRIPTS + if (ids & (RSRC_CLIENT_CONNECTION | RSRC_MTLS_CERTIFICATE | RSRC_SERVER_CERTIFICATE)) { + Dbg(pi_dbg_ctl, "\tAdding Cripts Client::Connection"); + client_conn = new cripts::Client::Connection(); + client_conn->set_state(&state); + } + + if (ids & RSRC_SERVER_CONNECTION) { + Dbg(pi_dbg_ctl, "\tAdding Cripts Server::Connection"); + server_conn = new cripts::Server::Connection(); + server_conn->set_state(&state); + } + + if (ids & RSRC_MTLS_CERTIFICATE) { + Dbg(pi_dbg_ctl, "\tAdding Cripts Certs::Client"); + mtls_cert = new cripts::Certs::Client(*client_conn); + } + + if (ids & RSRC_SERVER_CERTIFICATE) { + Dbg(pi_dbg_ctl, "\tAdding Cripts Certs::Server"); + server_cert = new cripts::Certs::Server(*client_conn); + } +#endif + _ready = true; } @@ -144,5 +176,12 @@ Resources::destroy() } } +#if TS_HAS_CRIPTS + delete client_conn; + delete server_conn; + delete mtls_cert; + delete server_cert; +#endif + _ready = false; } diff --git a/plugins/header_rewrite/resources.h b/plugins/header_rewrite/resources.h index 0aa0d82def..a56c808dee 100644 --- a/plugins/header_rewrite/resources.h +++ b/plugins/header_rewrite/resources.h @@ -28,30 +28,42 @@ #include "lulu.h" +#if TS_HAS_CRIPTS +#include "cripts/Certs.hpp" +#include "cripts/Transaction.hpp" +#endif + enum ResourceIDs { RSRC_NONE = 0, - RSRC_SERVER_RESPONSE_HEADERS = 1, - RSRC_SERVER_REQUEST_HEADERS = 2, - RSRC_CLIENT_REQUEST_HEADERS = 4, - RSRC_CLIENT_RESPONSE_HEADERS = 8, - RSRC_RESPONSE_STATUS = 16, + RSRC_SERVER_RESPONSE_HEADERS = 1 << 0, // 1 + RSRC_SERVER_REQUEST_HEADERS = 1 << 1, // 2 + RSRC_CLIENT_REQUEST_HEADERS = 1 << 2, // 4 + RSRC_CLIENT_RESPONSE_HEADERS = 1 << 3, // 8 + RSRC_RESPONSE_STATUS = 1 << 4, // 16 +#if TS_HAS_CRIPTS + RSRC_CLIENT_CONNECTION = 1 << 5, // 32 + RSRC_SERVER_CONNECTION = 1 << 6, // 64 + RSRC_SERVER_CERTIFICATE = 1 << 7, // 128 + RSRC_MTLS_CERTIFICATE = 1 << 8, // 256 +#endif }; /////////////////////////////////////////////////////////////////////////////// // Resources holds the minimum resources required to process a request. // +#if !TS_HAS_CRIPTS +struct TransactionState { + TSHttpTxn txnp = nullptr; + TSHttpSsn ssnp = nullptr; +}; +#endif + class Resources { public: - explicit Resources(TSHttpTxn txnptr, TSCont contptr) : txnp(txnptr), contp(contptr) - { - Dbg(dbg_ctl, "Calling CTOR for Resources (InkAPI)"); - } + explicit Resources(TSHttpTxn txnptr, TSCont contptr) : contp(contptr) { _initialize(txnptr, "InkAPI"); } - Resources(TSHttpTxn txnptr, TSRemapRequestInfo *rri) : txnp(txnptr), _rri(rri) - { - Dbg(dbg_ctl, "Calling CTOR for Resources (RemapAPI)"); - } + explicit Resources(TSHttpTxn txnptr, TSRemapRequestInfo *rri) : _rri(rri) { _initialize(txnptr, "RemapAPI"); } ~Resources() { destroy(); } @@ -66,20 +78,37 @@ public: return _ready; } - TSHttpTxn txnp; TSCont contp = nullptr; TSRemapRequestInfo *_rri = nullptr; TSMBuffer bufp = nullptr; TSMLoc hdr_loc = nullptr; TSMBuffer client_bufp = nullptr; TSMLoc client_hdr_loc = nullptr; - TSHttpStatus resp_status = TS_HTTP_STATUS_NONE; - const char *ovector_ptr = nullptr; - int ovector[OVECCOUNT]; - int ovector_count = 0; - bool changed_url = false; +#if TS_HAS_CRIPTS + cripts::Transaction state; // This now holds txpn / ssnp + cripts::Client::Connection *client_conn = nullptr; + cripts::Server::Connection *server_conn = nullptr; + cripts::Certs::Client *mtls_cert = nullptr; + cripts::Certs::Server *server_cert = nullptr; +#else + TransactionState state; // Without cripts, txnp / ssnp goes here +#endif + const char *ovector_ptr = nullptr; + TSHttpStatus resp_status = TS_HTTP_STATUS_NONE; + int ovector[OVECCOUNT]; + int ovector_count = 0; + bool changed_url = false; private: + void + _initialize(TSHttpTxn txnptr, const char *api_type) + { + state.txnp = txnptr; + state.ssnp = TSHttpTxnSsnGet(txnptr); // This is cheap, even if not used + + Dbg(dbg_ctl, "Calling CTOR for Resources (%s)", api_type); + } + void destroy(); bool _ready = false; diff --git a/plugins/header_rewrite/statement.h b/plugins/header_rewrite/statement.h index ce187b5cec..d711b9915c 100644 --- a/plugins/header_rewrite/statement.h +++ b/plugins/header_rewrite/statement.h @@ -112,6 +112,20 @@ enum NetworkSessionQualifiers { NET_QUAL_IPV6, ///< 'ipv6' or not. NET_QUAL_IP_FAMILY, ///< IP protocol family. NET_QUAL_STACK, ///< Full protocol stack. +#if TS_HAS_CRIPTS + NET_QUAL_CERT_PEM, ///< The PEM encoded certificate + NET_QUAL_CERT_SIG, ///< The signature of the certificate + NET_QUAL_CERT_SUBJECT, ///< The subject of the certificate + NET_QUAL_CERT_ISSUER, ///< The issuer of the certificate + NET_QUAL_CERT_SERIAL, ///< The serial number of the certificate + NET_QUAL_CERT_NOT_BEFORE, ///< The not before date of the certificate + NET_QUAL_CERT_NOT_AFTER, ///< The not after date of the certificate + NET_QUAL_CERT_VERSION, ///< The version of the certificate + NET_QUAL_CERT_SAN_DNS, ///< The DNS names in the SAN + NET_QUAL_CERT_SAN_IP, ///< The IP addresses in the SAN + NET_QUAL_CERT_SAN_EMAIL, ///< The email addresses in the SAN + NET_QUAL_CERT_SAN_URI, ///< The URIs in the SAN +#endif }; class Statement @@ -174,6 +188,12 @@ public: static int acquire_txn_slot(); static int acquire_txn_private_slot(); + void + require_resources(const ResourceIDs ids) + { + _rsrc = static_cast<ResourceIDs>(_rsrc | ids); + } + protected: virtual void initialize_hooks(); @@ -181,12 +201,6 @@ protected: NextHopQualifiers parse_next_hop_qualifier(const std::string &q) const; TSHttpCntlType parse_http_cntl_qualifier(const std::string &q) const; - void - require_resources(const ResourceIDs ids) - { - _rsrc = static_cast<ResourceIDs>(_rsrc | ids); - } - virtual bool need_txn_slot() const { diff --git a/plugins/header_rewrite/value.cc b/plugins/header_rewrite/value.cc index 69e32cbd06..28966cc292 100644 --- a/plugins/header_rewrite/value.cc +++ b/plugins/header_rewrite/value.cc @@ -39,7 +39,7 @@ Value::~Value() } void -Value::set_value(const std::string &val) +Value::set_value(const std::string &val, Statement *owner) { _value = val; @@ -58,6 +58,7 @@ Value::set_value(const std::string &val) if (parser.parse_line(cond_token)) { tcond_val->initialize(parser); + require_resources(tcond_val->get_resource_ids()); } else { // TODO: should we produce error here? Dbg(dbg_ctl, "Error parsing value '%s'", _value.c_str()); @@ -71,6 +72,11 @@ Value::set_value(const std::string &val) _cond_vals.push_back(tcond_val); } } + + // If we have an owner (e.g. an Operator) hoist up the resource requirements + if (owner) { + owner->require_resources(get_resource_ids()); + } } else { _int_value = strtol(_value.c_str(), nullptr, 10); _float_value = strtod(_value.c_str(), nullptr); diff --git a/plugins/header_rewrite/value.h b/plugins/header_rewrite/value.h index d27d3f8be3..f15d6b2537 100644 --- a/plugins/header_rewrite/value.h +++ b/plugins/header_rewrite/value.h @@ -36,7 +36,7 @@ // TODO: This is very incomplete, we need to support linked lists of these, // which evaluate each component and create a "joined" final string. // -class Value : Statement +class Value : public Statement { public: Value() { Dbg(dbg_ctl, "Calling CTOR for Value"); } @@ -47,7 +47,7 @@ public: Value(const Value &) = delete; void operator=(const Value &) = delete; - void set_value(const std::string &val); + void set_value(const std::string &val, Statement *owner = nullptr); void append_value(std::string &s, const Resources &res) const
