Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 17 additions & 9 deletions cmake/proxy-verifier.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@
#
#######################

# This will download and extract proxy-verifier to git common directory and setup variables to point to it.
# This will download and extract proxy-verifier to PV_DEST_DIR and setup variables to point to it.
#
# Required variables:
# PROXY_VERIFIER_VERSION
# PROXY_VERIFIER_HASH
#
# Defines variables:
#
# PV_DEST_DIR Directory the archive is downloaded to and extracted in
# PROXY_VERIFIER_PATH Full path to the extracted proxy verifier for the build architecture
# PROXY_VERIFIER_CLIENT Full path to client-verifier
# PROXY_VERIFIER_SERVER Full path to server-verifier
Expand All @@ -35,22 +36,29 @@ if(NOT PROXY_VERIFIER_HASH)
message(FATAL_ERROR "PROXY_VERIFIER_HASH Required")
endif()

# GIT_COMMON_DIR is set by the top-level CMakeLists.txt.
if(NOT GIT_COMMON_DIR)
message(FATAL_ERROR "GIT_COMMON_DIR not set. This should be set by the top-level CMakeLists.txt")
# Prefer the git common directory (set by the top-level CMakeLists.txt) so the download is shared by
# every worktree and build directory of the same clone. It isn't always available -- a source tree
# exported without .git, or a worktree whose common directory sits outside the paths visible to the
# build, such as when the worktree alone is mapped into a container. Fall back to the build
# directory, which always exists and is writable, rather than failing the configure.
if(GIT_COMMON_DIR)
set(PV_DEST_DIR "${GIT_COMMON_DIR}")
else()
set(PV_DEST_DIR "${CMAKE_BINARY_DIR}")
message(STATUS "GIT_COMMON_DIR not set, storing proxy-verifier in the build directory instead")
endif()

# Convert to absolute path (handles relative .git from regular non-worktree clones).
get_filename_component(GIT_COMMON_DIR "${GIT_COMMON_DIR}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")
get_filename_component(PV_DEST_DIR "${PV_DEST_DIR}" ABSOLUTE BASE_DIR "${CMAKE_SOURCE_DIR}")

# Download proxy-verifier to git common directory.
set(PV_ARCHIVE ${GIT_COMMON_DIR}/proxy-verifier/proxy-verifier.tar.gz)
# Download proxy-verifier to the destination directory.
set(PV_ARCHIVE ${PV_DEST_DIR}/proxy-verifier/proxy-verifier.tar.gz)
file(
DOWNLOAD https://ci.trafficserver.apache.org/bintray/proxy-verifier-${PROXY_VERIFIER_VERSION}.tar.gz ${PV_ARCHIVE}
EXPECTED_HASH ${PROXY_VERIFIER_HASH}
SHOW_PROGRESS
)
file(ARCHIVE_EXTRACT INPUT ${PV_ARCHIVE} DESTINATION ${GIT_COMMON_DIR})
file(ARCHIVE_EXTRACT INPUT ${PV_ARCHIVE} DESTINATION ${PV_DEST_DIR})

if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux")
if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64"
Expand Down Expand Up @@ -78,7 +86,7 @@ else()
message(FATAL_ERROR "Host ${CMAKE_HOST_SYSTEM_NAME} doesnt support running proxy verifier")
endif()

set(PROXY_VERIFIER_PATH ${GIT_COMMON_DIR}/proxy-verifier-${PROXY_VERIFIER_VERSION}/${PV_SUBDIR})
set(PROXY_VERIFIER_PATH ${PV_DEST_DIR}/proxy-verifier-${PROXY_VERIFIER_VERSION}/${PV_SUBDIR})
set(PROXY_VERIFIER_CLIENT ${PROXY_VERIFIER_PATH}/verifier-client)
set(PROXY_VERIFIER_SERVER ${PROXY_VERIFIER_PATH}/verifier-server)

Expand Down
4 changes: 4 additions & 0 deletions doc/admin-guide/files/records.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1532,6 +1532,10 @@ Parent Proxy Configuration

The amount of time allowed between connection retries to a parent cache that is unavailable.

Once this time has elapsed the parent is selected again as a retry candidate. It is
restored to the pool only if that retry actually succeeds; if the retry fails, the parent
remains unavailable and a further ``retry_time`` must elapse before it is tried again.

.. ts:cv:: CONFIG proxy.config.http.parent_proxy.max_trans_retries INT 2

Limits the number of simultaneous transactions that may retry a parent once the parents
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ dump_context(const char *ca_path, const char *ck_path)
// expiration date, serial number, common name, and subject alternative names
const ASN1_TIME *not_after = X509_get_notAfter(cert);
const ASN1_INTEGER *serial = X509_get_serialNumber(cert);
X509_NAME *subject_name = X509_get_subject_name(cert);
auto *subject_name = X509_get_subject_name(cert);

// Subject name
BIO *subject_bio = BIO_new(BIO_s_mem());
Expand Down
2 changes: 1 addition & 1 deletion example/plugins/c-api/verify_cert/verify_cert.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace
DbgCtl dbg_ctl{PLUGIN_NAME};

static void
debug_certificate(const char *msg, X509_NAME *name)
debug_certificate(const char *msg, const X509_NAME *name)
{
BIO *bio;

Expand Down
13 changes: 9 additions & 4 deletions include/cripts/Certs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,15 @@ class CertBase
}
}

void _load_name(X509_NAME *(*getter)(const X509 *)) const;
void _load_integer(ASN1_INTEGER *(*getter)(X509 *)) const;
void _load_long(long (*getter)(const X509 *)) const;
void _load_time(ASN1_TIME *(*getter)(const X509 *)) const;
using NameGetter = decltype(&X509_get_subject_name);
using IntegerGetter = decltype(&X509_get_serialNumber);
using LongGetter = decltype(&X509_get_version);
using TimeGetter = decltype(&X509_get_notBefore);

void _load_name(NameGetter getter) const;
void _load_integer(IntegerGetter getter) const;
void _load_long(LongGetter getter) const;
void _load_time(TimeGetter getter) const;

CertBase *_owner = nullptr;
mutable std::unique_ptr<BIO, decltype(&BIO_free)> _bio{nullptr, BIO_free};
Expand Down
21 changes: 15 additions & 6 deletions plugins/certifier/certifier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,11 @@ template <> struct default_delete<SSL_CTX> {
} // namespace std

/// Name aliases for unique pts to openSSL objects
using scoped_X509 = std::unique_ptr<X509>;
using scoped_X509_REQ = std::unique_ptr<X509_REQ>;
using scoped_EVP_PKEY = std::unique_ptr<EVP_PKEY>;
using scoped_SSL_CTX = std::unique_ptr<SSL_CTX>;
using scoped_X509 = std::unique_ptr<X509>;
using scoped_X509_REQ = std::unique_ptr<X509_REQ>;
using scoped_EVP_PKEY = std::unique_ptr<EVP_PKEY>;
using scoped_SSL_CTX = std::unique_ptr<SSL_CTX>;
using scoped_X509_NAME = std::unique_ptr<X509_NAME, decltype(&X509_NAME_free)>;

class SslLRUList
{
Expand Down Expand Up @@ -401,12 +402,20 @@ mkcrt(const std::string &commonName, int serial)
X509_gmtime_adj(X509_get_notAfter(cert.get()), static_cast<long>(3650) * 24 * 3600);

// Get handle to subject name
X509_NAME *n = X509_get_subject_name(cert.get());
scoped_X509_NAME n{X509_NAME_dup(X509_get_subject_name(cert.get())), X509_NAME_free};
if (n == nullptr) {
TSError("[%s] %s: failed to duplicate certificate subject", PLUGIN_NAME, __func__);
return nullptr;
}
// Set common name field
if (X509_NAME_add_entry_by_txt(n, "CN", MBSTRING_ASC, (unsigned char *)commonName.c_str(), -1, -1, 0) != 1) {
if (X509_NAME_add_entry_by_txt(n.get(), "CN", MBSTRING_ASC, (unsigned char *)commonName.c_str(), -1, -1, 0) != 1) {
TSError("[%s] %s: failed to add certificate subject CN", PLUGIN_NAME, __func__);
return nullptr;
}
if (X509_set_subject_name(cert.get(), n.get()) != 1) {
TSError("[%s] %s: failed to set certificate subject", PLUGIN_NAME, __func__);
return nullptr;
}

// Set Traffic Server public key
if (X509_set_pubkey(cert.get(), ca_pkey_scoped.get()) == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ dump_context(const char *ca_path, const char *ck_path)
// expiration date, serial number, common name, and subject alternative names
const ASN1_TIME *not_after = X509_get_notAfter(cert);
const ASN1_INTEGER *serial = X509_get_serialNumber(cert);
X509_NAME *subject_name = X509_get_subject_name(cert);
const X509_NAME *subject_name = X509_get_subject_name(cert);

// Subject name
BIO *subject_bio = BIO_new(BIO_s_mem());
Expand Down
8 changes: 4 additions & 4 deletions plugins/experimental/sslheaders/expand.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ x509_expand_certificate(X509 *x509, BIO *bio)
static void
x509_expand_subject(X509 *x509, BIO *bio)
{
X509_NAME *name = X509_get_subject_name(x509);
const X509_NAME *name = X509_get_subject_name(x509);
X509_NAME_print_ex(bio, name, 0 /* indent */, XN_FLAG_ONELINE);
}

static void
x509_expand_issuer(X509 *x509, BIO *bio)
{
X509_NAME *name = X509_get_issuer_name(x509);
const X509_NAME *name = X509_get_issuer_name(x509);
X509_NAME_print_ex(bio, name, 0 /* indent */, XN_FLAG_ONELINE);
}

Expand All @@ -72,8 +72,8 @@ x509_expand_signature(X509 *x509, BIO *bio)
{
const ASN1_BIT_STRING *sig;
X509_get0_signature(&sig, nullptr, x509);
const char *ptr = reinterpret_cast<const char *>(sig->data);
const char *end = ptr + sig->length;
const char *ptr = reinterpret_cast<const char *>(ASN1_STRING_get0_data(sig));
const char *end = ptr + ASN1_STRING_length(sig);

// The canonical OpenSSL way to format the signature seems to be
// X509_signature_dump(). However that separates each byte with a ':', which is
Expand Down
4 changes: 3 additions & 1 deletion plugins/experimental/txn_box/plugin/src/ts_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1111,8 +1111,10 @@ ssl_nid(swoc::TextView const &name)

namespace
{
using X509_NAME_ptr = decltype(X509_get_subject_name(nullptr));

TextView
ssl_value_for(X509_NAME *name, int nid)
ssl_value_for(X509_NAME_ptr name, int nid)
{
if (int loc = X509_NAME_get_index_by_NID(name, nid, -1); loc >= 0) {
if (auto entry = X509_NAME_get_entry(name, loc); entry != nullptr) {
Expand Down
31 changes: 12 additions & 19 deletions plugins/header_rewrite/header_rewrite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,12 @@ validate_rule_completion(RuleSet *rule, const std::string &fname, int lineno)
bool
RulesConfig::parse_config(const std::string &fname, TSHttpHookID default_hook, char *from_url, char *to_url)
{
std::unique_ptr<RuleSet> rule(nullptr);
std::string filename;
int lineno = 0;
ConditionGroup *group = nullptr;
std::stack<ConditionGroup *> group_stack;
std::stack<OperatorIf *> if_stack;
std::unique_ptr<RuleSet> rule(nullptr);
std::string filename;
int lineno = 0;
ConditionGroup *group = nullptr;
std::stack<ConditionGroup *> group_stack;
std::stack<std::unique_ptr<OperatorIf>> if_stack;

constexpr int MAX_IF_NESTING_DEPTH = 10;

Expand Down Expand Up @@ -366,32 +366,29 @@ RulesConfig::parse_config(const std::string &fname, TSHttpHookID default_hook, c
throw std::runtime_error("maximum if nesting depth exceeded");
}

auto *op_if = new OperatorIf();

if_stack.push(op_if);
group = op_if->get_group(); // Set group to the new OperatorIf's group
if_stack.push(std::make_unique<OperatorIf>());
group = if_stack.top()->get_group(); // Set group to the new OperatorIf's group
Dbg(dbg_ctl, "Started nested OperatorIf, depth: %zu", if_stack.size());

} else if (p.is_endif()) {
if (if_stack.empty()) {
throw std::runtime_error("endif without matching if");
}

OperatorIf *op_if = if_stack.top();
auto op_if = std::move(if_stack.top());

if_stack.pop();
if (!if_stack.empty()) {
auto *parent_sec = if_stack.top()->cur_section();

if (parent_sec->ops.oper) {
parent_sec->ops.oper->append(op_if);
parent_sec->ops.oper->append(op_if.release());
} else {
parent_sec->ops.oper.reset(op_if);
parent_sec->ops.oper = std::move(op_if);
}
group = if_stack.top()->get_group();
} else {
if (!rule->add_operator(op_if)) {
delete op_if;
if (!rule->add_operator(std::move(op_if))) {
throw std::runtime_error("Failed to add nested OperatorIf to RuleSet");
}
group = rule->get_group();
Expand Down Expand Up @@ -434,10 +431,6 @@ RulesConfig::parse_config(const std::string &fname, TSHttpHookID default_hook, c
// Check for unmatched if statements
if (!if_stack.empty()) {
TSError("[%s] %zu unmatched 'if' statement(s) without 'endif' in file: %s", PLUGIN_NAME, if_stack.size(), fname.c_str());
while (!if_stack.empty()) {
delete if_stack.top();
if_stack.pop();
}
return false;
}

Expand Down
36 changes: 16 additions & 20 deletions plugins/header_rewrite/operators.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <cstring>
#include <algorithm>
#include <iomanip>
#include <stdexcept>

#include "records/RecCore.h"
#include "ts/ts.h"
Expand Down Expand Up @@ -1272,8 +1273,7 @@ OperatorRunPlugin::initialize(Parser &p)
auto plugin_args = p.get_value();

if (plugin_name.empty()) {
TSError("[%s] missing plugin name", PLUGIN_NAME);
return;
throw std::runtime_error("run-plugin missing plugin name");
}

std::vector<std::string> tokens;
Expand All @@ -1284,15 +1284,10 @@ OperatorRunPlugin::initialize(Parser &p)
tokens.push_back(token);
}

// Create argc and argv
int argc = tokens.size() + 2;
char **argv = new char *[argc];

argv[0] = p.from_url();
argv[1] = p.to_url();
std::vector<char *> argv{p.from_url(), p.to_url()};

for (size_t i = 0; i < tokens.size(); ++i) {
argv[i + 2] = const_cast<char *>(tokens[i].c_str());
for (auto const &argument : tokens) {
argv.push_back(const_cast<char *>(argument.c_str()));
}

std::string error;
Expand All @@ -1304,14 +1299,12 @@ OperatorRunPlugin::initialize(Parser &p)
elevate_access = RecGetRecordInt("proxy.config.plugin.load_elevated").value_or(0);
ElevateAccess access(elevate_access ? ElevateAccess::FILE_PRIVILEGE : 0);

_plugin = plugin_factory.getRemapPlugin(swoc::file::path(plugin_name), argc, const_cast<char **>(argv), error,
_plugin = plugin_factory.getRemapPlugin(swoc::file::path(plugin_name), static_cast<int>(argv.size()), argv.data(), error,
isPluginDynamicReloadEnabled());
} // done elevating access

delete[] argv;

if (!_plugin) {
TSError("[%s] Unable to load plugin '%s': %s", PLUGIN_NAME, plugin_name.c_str(), error.c_str());
throw std::runtime_error("run-plugin unable to load plugin '" + std::string{plugin_name} + "': " + error);
}
}

Expand All @@ -1326,7 +1319,11 @@ OperatorRunPlugin::initialize_hooks()
bool
OperatorRunPlugin::exec(const Resources &res) const
{
TSReleaseAssert(_plugin != nullptr);
// Rejected at config load (see initialize); guard anyway so a stray bad rule can't abort the server.
if (!_plugin) {
Dbg(pi_dbg_ctl, "OperatorRunPlugin::exec skipped, plugin was not loaded");
return true;
}

if (res._rri && res.state.txnp) {
_plugin->doRemap(res.state.txnp, res._rri);
Expand Down Expand Up @@ -1654,7 +1651,7 @@ OperatorIf::new_section(Parser::CondClause clause)
bool
OperatorIf::add_operator(Parser &p, const char *filename, int lineno)
{
Operator *op = operator_factory(p.get_op());
std::unique_ptr<Operator> op{operator_factory(p.get_op())};

if (!op) {
TSError("[%s] Unknown operator: %s, file: %s, line: %d", PLUGIN_NAME, p.get_op().c_str(), filename, lineno);
Expand All @@ -1667,18 +1664,17 @@ OperatorIf::add_operator(Parser &p, const char *filename, int lineno)
try {
op->initialize(p);
} catch (std::exception const &ex) {
delete op;
TSError("[%s] Failed to initialize operator: %s, file: %s, line: %d, error: %s", PLUGIN_NAME, p.get_op().c_str(), filename,
lineno, ex.what());
return false;
}

// Add to current section
if (_cur_section->ops.oper) {
_cur_section->ops.oper->append(op);
_cur_section->ops.oper->append(op.release());
} else {
_cur_section->ops.oper.reset(op);
_cur_section->ops.oper_mods = op->get_oper_modifiers();
_cur_section->ops.oper = std::move(op);
_cur_section->ops.oper_mods = _cur_section->ops.oper->get_oper_modifiers();
}

return true;
Expand Down
Loading