RegisterMaker("user_cert", [](TypeName name)->ACL* { return new ACLStrategised<X509*>(new ACLCertificateData(Ssl::GetX509UserAttribute, "*"), new ACLCertificateStrategy, name); });
RegisterMaker("ca_cert", [](TypeName name)->ACL* { return new ACLStrategised<X509*>(new ACLCertificateData(Ssl::GetX509CAAttribute, "*"), new ACLCertificateStrategy, name); });
RegisterMaker("server_cert_fingerprint", [](TypeName name)->ACL* { return new ACLStrategised<X509*>(new ACLCertificateData(Ssl::GetX509Fingerprint, "-sha1", true), new ACLServerCertificateStrategy, name); });
- RegisterMaker("at_step", [](TypeName name)->ACL* { return new ACLStrategised<Ssl::BumpStep>(new ACLAtStepData, new ACLAtStepStrategy, name); });
+ RegisterMaker("at_step", [](TypeName name)->ACL* { return new ACLStrategised<XactionStep>(new ACLAtStepData, new ACLAtStepStrategy, name); });
RegisterMaker("ssl::server_name", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLServerNameData, new ACLServerNameStrategy, name); });
RegisterMaker("ssl::server_name_regex", [](TypeName name)->ACL* { return new ACLStrategised<char const *>(new ACLRegexData, new ACLServerNameStrategy, name); });
#endif
wordlist.cc \
XactionInitiator.h \
XactionInitiator.cc \
+ XactionStep.h \
$(WIN32_SOURCE) \
$(WINSVC_SOURCE)
/// the initiator of this transaction
XactionInitiator initiator;
+ /// whether we are currently creating a CONNECT header (to be sent to peer)
+ bool generatingConnect = false;
+
// TODO: add state from other Jobs in the transaction
};
--- /dev/null
+/*
+ * Copyright (C) 1996-2019 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_XACTIONSTEPS_H
+#define SQUID_XACTIONSTEPS_H
+
+enum class XactionStep {
+ enumBegin_ = 0, // for WholeEnum iteration
+ unknown = enumBegin_,
+ generatingConnect,
+#if USE_OPENSSL
+ tlsBump1,
+ tlsBump2,
+ tlsBump3,
+#endif
+ enumEnd_ // for WholeEnum iteration
+};
+
+#endif /* SQUID_XACTIONSTEPS_H */
+
#include "squid.h"
-#if USE_OPENSSL
-
#include "acl/AtStep.h"
#include "acl/AtStepData.h"
#include "acl/FilledChecklist.h"
#include "client_side.h"
#include "http/Stream.h"
+#if USE_OPENSSL
#include "ssl/ServerBump.h"
+#endif
int
-ACLAtStepStrategy::match (ACLData<Ssl::BumpStep> * &data, ACLFilledChecklist *checklist)
+ACLAtStepStrategy::match(ACLData<XactionStep> * &data, ACLFilledChecklist *checklist)
{
- Ssl::ServerBump *bump = NULL;
- if (checklist->conn() != NULL && (bump = checklist->conn()->serverBump()))
- return data->match(bump->step);
- else
- return data->match(Ssl::bumpStep1);
+#if USE_OPENSSL
+ // We use step1 for all these very different cases:
+ // - The transaction is not subject to ssl_bump rules (if any).
+ // - No ssl_bump action has matched yet.
+ // - The ssl_bump client-first action has already matched.
+ // - Another ssl_bump action has already matched, but
+ // ConnStateData::serverBump() has not been built yet.
+ auto currentSslBumpStep = XactionStep::tlsBump1;
+
+ if (const auto mgr = checklist->conn()) {
+ if (const auto serverBump = mgr->serverBump())
+ currentSslBumpStep = serverBump->step;
+ }
+
+ if (data->match(currentSslBumpStep))
+ return 1;
+#endif // USE_OPENSSL
+
+ if (data->match(XactionStep::generatingConnect)) {
+ if (!checklist->request)
+ return 0; // we have warned about the missing request earlier
+
+ if (!checklist->request->masterXaction) {
+ debugs(28, DBG_IMPORTANT, "BUG: at_step GeneratingCONNECT ACL is missing master transaction info. Assuming mismatch.");
+ return 0;
+ }
+
+ return checklist->request->masterXaction->generatingConnect ? 1 : 0;
+ }
+
return 0;
}
-#endif /* USE_OPENSSL */
-
#ifndef SQUID_ACLATSTEP_H
#define SQUID_ACLATSTEP_H
-#if USE_OPENSSL
-
#include "acl/Strategy.h"
-#include "ssl/support.h"
+#include "XactionStep.h"
/// \ingroup ACLAPI
-class ACLAtStepStrategy : public ACLStrategy<Ssl::BumpStep>
+class ACLAtStepStrategy: public ACLStrategy<XactionStep>
{
public:
virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *) override;
};
-#endif /* USE_OPENSSL */
-
#endif /* SQUID_ACLATSTEP_H */
*/
#include "squid.h"
-
-#if USE_OPENSSL
-
#include "acl/AtStepData.h"
#include "acl/Checklist.h"
+#include "base/EnumIterator.h"
#include "cache_cf.h"
#include "ConfigParser.h"
#include "Debug.h"
+#include "sbuf/Stream.h"
#include "wordlist.h"
+static inline const char *
+StepName(const XactionStep xstep)
+{
+ // keep in sync with XactionStep
+ static const char *StepNames[static_cast<int>(XactionStep::enumEnd_)] = {
+ "[unknown step]"
+ ,"GeneratingCONNECT"
+#if USE_OPENSSL
+ ,"SslBump1"
+ ,"SslBump2"
+ ,"SslBump3"
+#endif
+ };
+
+ assert(XactionStep::enumBegin_ <= xstep && xstep < XactionStep::enumEnd_);
+ return StepNames[static_cast<int>(xstep)];
+}
+
+static XactionStep
+StepValue(const char *name)
+{
+ assert(name);
+
+ for (const auto step: WholeEnum<XactionStep>()) {
+ if (strcasecmp(StepName(step), name) == 0)
+ return static_cast<XactionStep>(step);
+ }
+
+ throw TextException(ToSBuf("unknown at_step step name: ", name), Here());
+}
+
ACLAtStepData::ACLAtStepData()
{}
}
bool
-ACLAtStepData::match(Ssl::BumpStep toFind)
+ACLAtStepData::match(XactionStep toFind)
{
- for (std::list<Ssl::BumpStep>::const_iterator it = values.begin(); it != values.end(); ++it) {
- if (*it == toFind)
- return true;
- }
- return false;
+ const auto found = std::find(values.cbegin(), values.cend(), toFind);
+ return (found != values.cend());
}
SBufList
ACLAtStepData::dump() const
{
SBufList sl;
- for (std::list<Ssl::BumpStep>::const_iterator it = values.begin(); it != values.end(); ++it) {
- sl.push_back(SBuf(*it == Ssl::bumpStep1 ? "SslBump1" :
- *it == Ssl::bumpStep2 ? "SslBump2" :
- *it == Ssl::bumpStep3 ? "SslBump3" : "???"));
- }
+ for (const auto value : values)
+ sl.push_back(SBuf(StepName(value)));
return sl;
}
void
ACLAtStepData::parse()
{
- while (const char *t = ConfigParser::strtokFile()) {
- if (strcasecmp(t, "SslBump1") == 0) {
- values.push_back(Ssl::bumpStep1);
- } else if (strcasecmp(t, "SslBump2") == 0) {
- values.push_back(Ssl::bumpStep2);
- } else if (strcasecmp(t, "SslBump3") == 0) {
- values.push_back(Ssl::bumpStep3);
- } else {
- debugs(28, DBG_CRITICAL, "FATAL: invalid AtStep step: " << t);
- self_destruct();
- }
+ while (const auto name = ConfigParser::strtokFile()) {
+ const auto step = StepValue(name);
+ if (step == XactionStep::unknown)
+ throw TextException(ToSBuf("prohibited at_step step name: ", name), Here());
+ values.push_back(step);
}
}
return new ACLAtStepData(*this);
}
-#endif /* USE_OPENSSL */
-
#ifndef SQUID_ACLATSTEPDATA_H
#define SQUID_ACLATSTEPDATA_H
-#if USE_OPENSSL
-
#include "acl/Acl.h"
#include "acl/Data.h"
-#include "ssl/support.h"
-
+#include "XactionStep.h"
#include <list>
-class ACLAtStepData : public ACLData<Ssl::BumpStep>
+class ACLAtStepData : public ACLData<XactionStep>
{
MEMPROXY_CLASS(ACLAtStepData);
ACLAtStepData(ACLAtStepData const &);
ACLAtStepData &operator= (ACLAtStepData const &);
virtual ~ACLAtStepData();
- bool match(Ssl::BumpStep);
+ bool match(XactionStep);
virtual SBufList dump() const;
void parse();
bool empty() const;
virtual ACLAtStepData *clone() const;
- std::list<Ssl::BumpStep> values;
+ std::list<XactionStep> values;
};
-#endif /* USE_OPENSSL */
-
#endif /* SQUID_ACLSSL_ERRORDATA_H */
AnyOf.h \
Asn.cc \
Asn.h \
+ AtStep.cc \
+ AtStep.h \
+ AtStepData.cc \
+ AtStepData.h \
ConnectionsEncrypted.cc \
ConnectionsEncrypted.h \
ConnMark.cc \
EXTRA_libacls_la_SOURCES =
SSL_ACLS = \
- AtStep.cc \
- AtStep.h \
- AtStepData.cc \
- AtStepData.h \
CertificateData.cc \
CertificateData.h \
Certificate.cc \
# acl hasWhatMyLoggingDaemonNeeds has request
# acl hasWhatMyLoggingDaemonNeeds has response
+acl aclname at_step step
+ # match against the current request processing step [fast]
+ # Valid steps are:
+ # GeneratingCONNECT: Generating HTTP CONNECT request headers
+IF USE_OPENSSL
+ # The following ssl_bump processing steps are recognized:
+ # SslBump1: After getting TCP-level and HTTP CONNECT info.
+ # SslBump2: After getting SSL Client Hello info.
+ # SslBump3: After getting SSL Server Hello info.
+ENDIF
+
IF USE_OPENSSL
acl aclname ssl_error errorname
# match against SSL certificate validation error [fast]
# The SHA1 digest algorithm is the default and is currently
# the only algorithm supported (-sha1).
- acl aclname at_step step
- # match against the current step during ssl_bump evaluation [fast]
- # Never matches and should not be used outside the ssl_bump context.
- #
- # At each SslBump step, Squid evaluates ssl_bump directives to find
- # the next bumping action (e.g., peek or splice). Valid SslBump step
- # values and the corresponding ssl_bump evaluation moments are:
- # SslBump1: After getting TCP-level and HTTP CONNECT info.
- # SslBump2: After getting SSL Client Hello info.
- # SslBump3: After getting SSL Server Hello info.
-
acl aclname ssl::server_name [option] .foo.com ...
# matches server name obtained from various sources [fast]
#
Http::StreamPointer context = pipeline.front();
ClientHttpRequest *http = context ? context->http : nullptr;
- if (sslServerBump->step == Ssl::bumpStep1) {
- sslServerBump->step = Ssl::bumpStep2;
+ if (sslServerBump->at(XactionStep::tlsBump1)) {
+ sslServerBump->step = XactionStep::tlsBump2;
// Run a accessList check to check if want to splice or continue bumping
ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, sslServerBump->request.getRaw(), nullptr);
{
debugs(83, 5, connection);
- HttpHeader hdr_out(hoRequest);
Http::StateFlags flags;
flags.peering = true;
// flags.tunneling = false; // the CONNECT request itself is not tunneled
// flags.toOrigin = false; // the next HTTP hop is a non-originserver peer
+
MemBuf mb;
- mb.init();
- mb.appendf("CONNECT %s HTTP/1.1\r\n", url.c_str());
- HttpStateData::httpBuildRequestHeader(request.getRaw(),
- nullptr, // StoreEntry
- al,
- &hdr_out,
- flags);
- hdr_out.packInto(&mb);
- hdr_out.clean();
- mb.append("\r\n", 2);
+
+ try {
+ request->masterXaction->generatingConnect = true;
+
+ mb.init();
+ mb.appendf("CONNECT %s HTTP/1.1\r\n", url.c_str());
+ HttpHeader hdr_out(hoRequest);
+ HttpStateData::httpBuildRequestHeader(request.getRaw(),
+ nullptr, // StoreEntry
+ al,
+ &hdr_out,
+ flags);
+ hdr_out.packInto(&mb);
+ hdr_out.clean();
+ mb.append("\r\n", 2);
+
+ request->masterXaction->generatingConnect = false;
+ } catch (...) {
+ // TODO: Add scope_guard; do not wait until it is in the C++ standard.
+ request->masterXaction->generatingConnect = false;
+ throw;
+ }
debugs(11, 2, "Tunnel Server REQUEST: " << connection <<
":\n----------\n" << mb.buf << "\n----------");
// Mark Step3 of bumping
if (request->clientConnectionManager.valid()) {
if (Ssl::ServerBump *serverBump = request->clientConnectionManager->serverBump()) {
- serverBump->step = Ssl::bumpStep3;
+ serverBump->step = XactionStep::tlsBump3;
}
}
if (hostName)
SSL_set_ex_data(serverSession.get(), ssl_ex_index_server, (void*)hostName);
- Must(!csd->serverBump() || csd->serverBump()->step <= Ssl::bumpStep2);
+ Must(!csd->serverBump() || csd->serverBump()->at(XactionStep::tlsBump1, XactionStep::tlsBump2));
if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
auto clientSession = fd_table[clientConn->fd].ssl.get();
Must(clientSession);
CBDATA_NAMESPACED_CLASS_INIT(Ssl, ServerBump);
Ssl::ServerBump::ServerBump(ClientHttpRequest *http, StoreEntry *e, Ssl::BumpMode md):
- step(bumpStep1)
+ step(XactionStep::tlsBump1)
{
assert(http->request);
request = http->request;
#include "ip/Address.h"
#include "security/forward.h"
#include "Store.h"
+#include "XactionStep.h"
class ConnStateData;
class store_client;
namespace Ssl
{
+using BumpStep = XactionStep;
+
/**
* Maintains bump-server-first related information.
*/
/// whether there was a successful connection to (and peeking at) the origin server
bool connectedOk() const {return entry && entry->isEmpty();}
+ /// whether we are currently performing the given processing step
+ bool at(const BumpStep stp) const { return step == stp; }
+
+ /// whether we are currently performing one of the given processing steps
+ bool at(const BumpStep step1, const BumpStep step2) const { return at(step1) || at(step2); }
+
/// faked, minimal request; required by Client API
HttpRequest::Pointer request;
StoreEntry *entry; ///< for receiving Squid-generated error messages
*/
enum BumpMode {bumpNone = 0, bumpClientFirst, bumpServerFirst, bumpPeek, bumpStare, bumpBump, bumpSplice, bumpTerminate, /*bumpErr,*/ bumpEnd};
-enum BumpStep {bumpStep1, bumpStep2, bumpStep3};
-
/**
\ingroup ServerProtocolSSLAPI
* Short names for ssl-bump modes
return false;
#if USE_OPENSSL
// We are bumping and we had already send "OK CONNECTED"
- if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->step > Ssl::bumpStep1)
+ if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->at(XactionStep::tlsBump2, XactionStep::tlsBump3))
return false;
#endif
return !(request != NULL &&