#include "acl/Asn.h"
#include "acl/Browser.h"
#include "acl/Checklist.h"
+#include "acl/ConnectionsEncrypted.h"
#include "acl/Data.h"
#include "acl/DestinationAsn.h"
#include "acl/DestinationDomain.h"
ACL::Prototype ACLSquidError::RegistryProtoype(&ACLSquidError::RegistryEntry_, "squid_error");
ACLStrategised<err_type> ACLSquidError::RegistryEntry_(new ACLSquidErrorData, ACLSquidErrorStrategy::Instance(), "squid_error");
+ACL::Prototype Acl::ConnectionsEncrypted::RegistryProtoype(&Acl::ConnectionsEncrypted::RegistryEntry_, "connections_encrypted");
+Acl::ConnectionsEncrypted Acl::ConnectionsEncrypted::RegistryEntry_("connections_encrypted");
cache_control(NULL),
hdr_sz(0),
content_length(0),
- pstate(psReadyToParseStartLine)
+ pstate(psReadyToParseStartLine),
+ sources(0)
{}
HttpMsg::~HttpMsg()
public:
typedef RefCount<HttpMsg> Pointer;
+ /// Who may have created or modified this message?
+ enum Sources {
+ srcUnknown = 0,
+
+ /* flags in 0xFFFF zone are for "secure" or "encrypted" sources */
+ srcHttps = 1 << 0, ///< https_port or bumped http_port tunnel; HTTPS server
+ srcFtps = 1 << 1, ///< ftps_port or SFTP server; currently unused
+ srcIcaps = 1 << 2, ///< Secure ICAP service
+ srcEcaps = 1 << 3, ///< eCAP service that is considered secure; currently unused
+
+ /* these flags "taint" the message: it may have been observed or mangled outside Squid */
+ srcHttp = 1 << (16 + 0), ///< http_port or HTTP server
+ srcFtp = 1 << (16 + 1), ///< ftp_port or FTP server
+ srcIcap = 1 << (16 + 2), ///< traditional ICAP service without encryption
+ srcEcap = 1 << (16 + 3), ///< eCAP service that uses insecure libraries/daemons
+ srcGopher = 1 << (16 + 14), ///< Gopher server
+ srcWhois = 1 << (16 + 15), ///< Whois server
+ srcUnsafe = 0xFFFF0000, ///< Unsafe sources mask
+ srcSafe = 0x0000FFFF ///< Safe sources mask
+ };
HttpMsg(http_hdr_owner_type owner);
virtual ~HttpMsg();
BodyPipe::Pointer body_pipe; // optional pipeline to receive message body
+ uint32_t sources; ///< The message sources
+
// returns true and sets hdr_sz on success
// returns false and sets *error to zero when needs more data
// returns false and sets *error to a positive Http::StatusCode on error
if (!aRep)
return false;
keep_alive = aRep->keep_alive;
+ sources = aRep->sources;
return true;
}
clientConnectionManager = aReq->clientConnectionManager;
notes = aReq->notes;
+
+ sources = aReq->sources;
return true;
}
CertificateData.h \
Certificate.cc \
Certificate.h \
+ ConnectionsEncrypted.cc \
+ ConnectionsEncrypted.h \
ServerCertificate.cc \
ServerCertificate.h \
ServerName.cc \
typedef Services::iterator SCI;
for (SCI i = AllServices().begin(); i != AllServices().end(); ++i) {
const ServiceConfig &cfg = (*i)->cfg();
- storeAppendPrintf(entry, "%s " SQUIDSTRINGPH "_%s %s %d " SQUIDSTRINGPH "\n",
+ bool isEcap = cfg.protocol.caseCmp("ecap") == 0;
+ bool isIcap = !isEcap;
+ const char *optConnectionEncryption = "";
+ // Print connections_encrypted option if no default value is used
+ if (cfg.secure.encryptTransport && !cfg.connectionEncryption)
+ optConnectionEncryption = " connection-encryption=off";
+ else if (isEcap && !cfg.connectionEncryption)
+ optConnectionEncryption = " connection-encryption=off";
+ else if (isIcap && !cfg.secure.encryptTransport && cfg.connectionEncryption)
+ optConnectionEncryption = " connection-encryption=on";
+
+ storeAppendPrintf(entry, "%s " SQUIDSTRINGPH " %s_%s %d " SQUIDSTRINGPH "%s\n",
name,
SQUIDSTRINGPRINT(cfg.key),
cfg.methodStr(), cfg.vectPointStr(), cfg.bypass,
- SQUIDSTRINGPRINT(cfg.uri));
+ SQUIDSTRINGPRINT(cfg.uri),
+
+ optConnectionEncryption);
}
}
else if (strcmp(name, "on-overload") == 0) {
grokked = grokOnOverload(onOverload, value);
onOverloadSet = true;
+ } else if (strcmp(name, "connection-encryption") == 0) {
+ bool encrypt;
+ grokked = grokBool(encrypt, name, value);
+ connectionEncryption.configure(encrypt);
} else if (strncmp(name, "ssl", 3) == 0 || strncmp(name, "tls-", 4) == 0) {
#if !USE_OPENSSL
debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: adaptation option '" << name << "' requires --with-openssl. ICAP service option ignored.");
#include "base/RefCount.h"
#include "security/PeerOptions.h"
#include "SquidString.h"
+#include "YesNoNone.h"
namespace Adaptation
{
// security settings for adaptation service
Security::PeerOptions secure;
+ YesNoNone connectionEncryption; ///< whether this service uses only secure connections
protected:
Method parseMethod(const char *buf) const;
Adaptation::Ecap::ServiceRep::finalize()
{
Adaptation::Service::finalize();
+ if (!cfg().connectionEncryption.configured())
+ writeableCfg().connectionEncryption.configure(true);
theService = FindAdapterService(cfg().uri);
if (theService) {
try {
Must(proxyingAb == opUndecided);
HttpMsg *msg = answer().header;
+ updateSources(msg);
if (!theAnswerRep->body()) { // final, bodyless answer
proxyingAb = opNever;
updateHistory(msg);
return buf.content();
}
+void
+Adaptation::Ecap::XactionRep::updateSources(HttpMsg *adapted)
+{
+ adapted->sources |= service().cfg().connectionEncryption ? HttpMsg::srcEcaps : HttpMsg::srcEcap;
+}
void updateHistory(HttpMsg *adapted);
void terminateMaster();
void scheduleStop(const char *reason);
+ void updateSources(HttpMsg *adapted);
const libecap::Area clientIpValue() const;
const libecap::Area usernameValue() const;
if (state.sending == State::sendingVirgin)
echoMore();
+ else {
+ // If we are not using the virgin HTTP object update the
+ // HttpMsg::sources flag.
+ // The state.sending may set to State::sendingVirgin in the case
+ // of 206 responses too, where we do not want to update HttpMsg::sources
+ // flag. However even for 206 responses the state.sending is
+ // not set yet to sendingVirgin. This is done in later step
+ // after the parseBody method called.
+ updateSources();
+ }
}
void Adaptation::Icap::ModXact::parseIcapHead()
request->clearError();
}
+void Adaptation::Icap::ModXact::updateSources()
+{
+ Must(adapted.header);
+ adapted.header->sources |= (service().cfg().connectionEncryption ? HttpMsg::srcIcaps : HttpMsg::srcIcap);
+}
+
/* Adaptation::Icap::ModXactLauncher */
Adaptation::Icap::ModXactLauncher::ModXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause, AccessLogEntry::Pointer &alp, Adaptation::ServicePointer aService):
void prepEchoing();
void prepPartialBodyEchoing(uint64_t pos);
void echoMore();
+ void updateSources(); ///< Update the HttpMsg sources
virtual bool doneAll() const;
virtual void swanSong();
if (cfg().secure.encryptTransport) {
debugs(3, DBG_IMPORTANT, "Initializing service " << cfg().resource << " SSL context");
sslContext = writeableCfg().secure.createClientContext(true);
- }
+ if (!cfg().connectionEncryption.configured())
+ writeableCfg().connectionEncryption.configure(true);
+ } else if (!cfg().connectionEncryption.configured())
+ writeableCfg().connectionEncryption.configure(false);
+
theSessionFailures.configure(TheConfig.oldest_service_failure > 0 ?
TheConfig.oldest_service_failure : -1);
acl aclname ssl::server_name_regex [-i] \.foo\.com ...
# regex matches server name obtained from various sources [fast]
+
+ acl aclname connections_encrypted
+ # matches transactions with all HTTP messages received over TLS
+ # transport connections. [fast]
+ #
+ # The master transaction deals with HTTP messages received from
+ # various sources. All sources used by the master transaction in the
+ # past are considered by the ACL. The following rules define whether
+ # a given message source taints the entire master transaction,
+ # resulting in ACL mismatches:
+ #
+ # * The HTTP client transport connection is not TLS.
+ # * An adaptation service connection-encryption flag is off.
+ # * The peer or origin server transport connection is not TLS.
+ #
+ # Caching currently does not affect these rules. This cache ignorance
+ # implies that only the current HTTP client transport and REQMOD
+ # services status determine whether this ACL matches a from-cache
+ # transaction. The source of the cached response does not have any
+ # effect on future transaction that use the cached response without
+ # revalidation. This may change.
+ #
+ # DNS, ICP, and HTCP exchanges during the master transaction do not
+ # affect these rules.
ENDIF
acl aclname any-of acl1 acl2 ...
# match any one of the acls [fast or slow]
Use the given number as the Max-Connections limit, regardless
of the Max-Connections value given by the service, if any.
+ connection-encryption=on|off
+ Determines the ICAP service effect on the connections_encrypted
+ ACL.
+
+ The default is "on" for Secure ICAP services (i.e., those
+ with the icaps:// service URIs scheme) and "off" for plain ICAP
+ services.
+
+ Does not affect ICAP connections (e.g., does not turn Secure
+ ICAP on or off).
+
==== ICAPS / TLS OPTIONS ====
These options are used for Secure ICAP (icaps://....) services only.
Routing is not allowed by default.
+ connection-encryption=on|off
+ Determines the eCAP service effect on the connections_encrypted
+ ACL.
+
+ Defaults to "on", which does not taint the master transaction
+ w.r.t. that ACL.
+
+ Does not affect eCAP API calls.
+
Older ecap_service format without optional named parameters is
deprecated but supported for backward compatibility.
// TODO: decouple http->flags.accel from request->flags.sslBumped
request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
!conn->port->allow_direct : 0;
+ request->sources |= isFtp ? HttpMsg::srcFtp :
+ ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? HttpMsg::srcHttps : HttpMsg::srcHttp);
#if USE_AUTH
if (request->flags.sslBumped) {
if (conn->getAuth() != NULL)
if (mime_enc)
reply->header.putStr(Http::HdrType::CONTENT_ENCODING, mime_enc);
+ reply->sources |= HttpMsg::srcFtp;
setVirginReply(reply);
adaptOrFinalizeReply();
}
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
HttpReply *const reply = createHttpReply(Http::scNoContent);
+ reply->sources |= HttpMsg::srcFtp;
setVirginReply(reply);
adaptOrFinalizeReply();
" (" << data.conn->local << ")");
HttpReply *const reply = createHttpReply(Http::scOkay, -1);
+ reply->sources |= HttpMsg::srcFtp;
+
EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
setVirginReply(reply);
adaptOrFinalizeReply();
char *buf; /* pts to a 4k page */
Comm::ConnectionPointer serverConn;
FwdState::Pointer fwd;
+ HttpReply::Pointer reply_;
char replybuf[BUFSIZ];
};
reply->header.putStr(Http::HdrType::CONTENT_ENCODING, mime_enc);
entry->replaceHttpReply(reply);
+ gopherState->reply_ = reply;
}
/**
++IOStats.Gopher.read_hist[bin];
HttpRequest *req = gopherState->fwd->request;
- if (req->hier.bodyBytesRead < 0)
+ if (req->hier.bodyBytesRead < 0) {
req->hier.bodyBytesRead = 0;
+ // first bytes read, update Reply flags:
+ gopherState->reply_->sources |= HttpMsg::srcGopher;
+ }
req->hier.bodyBytesRead += len;
}
// done with Parser, now process using the HttpReply
hp = NULL;
+ newrep->sources |= request->url.getScheme() == AnyP::PROTO_HTTPS ? HttpMsg::srcHttps : HttpMsg::srcHttp;
+
newrep->removeStaleWarnings();
if (newrep->sline.protocol == AnyP::PROTO_HTTP && newrep->sline.status() >= 100 && newrep->sline.status() < 200) {
HttpReply *reply = new HttpReply;
sentry->buffer();
reply->setHeaders(Http::scOkay, "Gatewaying", "text/plain", -1, -1, -2);
+ reply->sources |= HttpMsg::srcWhois;
sentry->replaceHttpReply(reply);
}