From: Eduard Bagdasaryan Date: Tue, 16 May 2017 14:27:49 +0000 (+1200) Subject: Add 'has' ACL X-Git-Tag: M-staged-PR71~177 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5ec4cffe0838306a6e667bfc3bc7881d61570588;p=thirdparty%2Fsquid.git Add 'has' ACL This ACL detects presence of request, response or ALE transaction components. Since many ACLs require some of these components, lack of them in a transaction may spoil the check and confuse admin with warnings like "... ACL is used in context without an HTTP request". Using 'has' ACL should help dealing with these problems caused by component-less transactions. Also: addressed TODO in item #3 of v4 revision 14752. --- diff --git a/src/AclRegs.cc b/src/AclRegs.cc index 9783721f8c..bbf2995c2b 100644 --- a/src/AclRegs.cc +++ b/src/AclRegs.cc @@ -44,6 +44,8 @@ #endif #include "acl/FilledChecklist.h" #include "acl/Gadgets.h" +#include "acl/HasComponent.h" +#include "acl/HasComponentData.h" #include "acl/HierCode.h" #include "acl/HierCodeData.h" #include "acl/HttpHeaderData.h" @@ -244,3 +246,6 @@ ACLStrategised ACLSquidError::RegistryEntry_(new ACLSquidErrorData, AC ACL::Prototype Acl::ConnectionsEncrypted::RegistryProtoype(&Acl::ConnectionsEncrypted::RegistryEntry_, "connections_encrypted"); Acl::ConnectionsEncrypted Acl::ConnectionsEncrypted::RegistryEntry_("connections_encrypted"); +ACL::Prototype ACLHasComponent::RegistryProtoype(&ACLHasComponent::RegistryEntry_, "has"); +ACLStrategised ACLHasComponent::RegistryEntry_(new ACLHasComponentData, ACLHasComponentStrategy::Instance(), "has"); + diff --git a/src/acl/HasComponent.cc b/src/acl/HasComponent.cc new file mode 100644 index 0000000000..1b0d4dd1b4 --- /dev/null +++ b/src/acl/HasComponent.cc @@ -0,0 +1,28 @@ +/* + * Copyright (C) 1996-2017 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. + */ + +#include "squid.h" +#include "acl/HasComponent.h" +#include "acl/HasComponentData.h" + +int +ACLHasComponentStrategy::match(ACLData * &data, ACLFilledChecklist *checklist, ACLFlags &flags) +{ + ACLHasComponentData *cdata = dynamic_cast(data); + assert(cdata); + return cdata->match(checklist); +} + +ACLHasComponentStrategy * +ACLHasComponentStrategy::Instance() +{ + return &Instance_; +} + +ACLHasComponentStrategy ACLHasComponentStrategy::Instance_; + diff --git a/src/acl/HasComponent.h b/src/acl/HasComponent.h new file mode 100644 index 0000000000..3aba6cdda8 --- /dev/null +++ b/src/acl/HasComponent.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 1996-2017 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_ACLHASCOMPONENT_H +#define SQUID_ACLHASCOMPONENT_H + +#include "acl/Strategised.h" +#include "acl/Strategy.h" + +/// \ingroup ACLAPI +class ACLHasComponentStrategy : public ACLStrategy +{ +public: + static ACLHasComponentStrategy *Instance(); + ACLHasComponentStrategy(ACLHasComponentStrategy const &) = delete; + ACLHasComponentStrategy& operator=(ACLHasComponentStrategy const &) = delete; + virtual int match(ACLData * &, ACLFilledChecklist *, ACLFlags &); + +private: + static ACLHasComponentStrategy Instance_; + ACLHasComponentStrategy() { } +}; + +/// \ingroup ACLAPI +class ACLHasComponent +{ +private: + static ACL::Prototype RegistryProtoype; + static ACLStrategised RegistryEntry_; +}; + +#endif + diff --git a/src/acl/HasComponentData.cc b/src/acl/HasComponentData.cc new file mode 100644 index 0000000000..7942b18f7e --- /dev/null +++ b/src/acl/HasComponentData.cc @@ -0,0 +1,83 @@ +/* + * Copyright (C) 1996-2017 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. + */ + +#include "squid.h" +#include "acl/HasComponentData.h" +#include "cache_cf.h" +#include "ConfigParser.h" +#include "sbuf/Algorithms.h" + + +const SBuf ACLHasComponentData::RequestStr("request"); +const SBuf ACLHasComponentData::ResponseStr("response"); +const SBuf ACLHasComponentData::AleStr("ALE"); + +ACLHasComponentData::ACLHasComponentData() + : componentMethods(coEnd, nullptr) +{ } + +void +ACLHasComponentData::parse() +{ + const char *tok = ConfigParser::NextToken(); + if (!tok) { + debugs(28, DBG_CRITICAL, "FATAL: \"has\" acl argument missing"); + self_destruct(); + return; + } + if (ConfigParser::PeekAtToken()) { + debugs(28, DBG_CRITICAL, "FATAL: multiple components not supported for \"has\" acl"); + self_destruct(); + return; + } + parseComponent(tok); +} + +bool +ACLHasComponentData::match(ACLChecklist *checklist) +{ + for (const auto method: componentMethods) + if (method && (checklist->*method)()) + return true; + return false; +} + +SBufList +ACLHasComponentData::dump() const +{ + SBufList sl; + if (componentMethods.at(coRequest)) + sl.push_back(RequestStr); + if (componentMethods.at(coResponse)) + sl.push_back(ResponseStr); + if (componentMethods.at(coAle)) + sl.push_back(AleStr); + return sl; +} + +void +ACLHasComponentData::parseComponent(const char *token) +{ + if (RequestStr.cmp(token) == 0) + componentMethods[coRequest] = &ACLChecklist::hasRequest; + else if (ResponseStr.cmp(token) == 0) + componentMethods[coResponse] = &ACLChecklist::hasReply; + else if (AleStr.cmp(token) == 0) + componentMethods[coAle] = &ACLChecklist::hasAle; + else { + debugs(28, DBG_CRITICAL, "FATAL: unsupported component '" << token << "' for 'has' acl"); + self_destruct(); + } +} + +ACLData * +ACLHasComponentData::clone() const +{ + return new ACLHasComponentData(*this); +} + diff --git a/src/acl/HasComponentData.h b/src/acl/HasComponentData.h new file mode 100644 index 0000000000..0b1bd05b28 --- /dev/null +++ b/src/acl/HasComponentData.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 1996-2017 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_ACLHASCOMPONENTDATA_H +#define SQUID_ACLHASCOMPONENTDATA_H + +#include "acl/Checklist.h" +#include "acl/Data.h" + +/// \ingroup ACLAPI +class ACLHasComponentData : public ACLData +{ + MEMPROXY_CLASS(ACLHasComponentData); + +public: + ACLHasComponentData(); + + /* ACLData API */ + virtual bool match(ACLChecklist *) override; + virtual SBufList dump() const override; + virtual void parse() override; + virtual bool empty() const override { return false; } + virtual ACLData *clone() const override; + +private: + enum ComponentKind { coRequest = 0, coResponse, coAle, coEnd }; + void parseComponent(const char *token); + + static const SBuf RequestStr; + static const SBuf ResponseStr; + static const SBuf AleStr; + + typedef bool (ACLChecklist::*ComponentCheck)() const; + /// component check callbacks, ordered by component kind ID + std::vector componentMethods; +}; + +#endif + diff --git a/src/acl/Makefile.am b/src/acl/Makefile.am index 51b6c4eab9..133ba56cba 100644 --- a/src/acl/Makefile.am +++ b/src/acl/Makefile.am @@ -75,6 +75,10 @@ libacls_la_SOURCES = \ DomainData.h \ ExtUser.cc \ ExtUser.h \ + HasComponent.cc \ + HasComponent.h \ + HasComponentData.cc \ + HasComponentData.h \ HierCodeData.cc \ HierCodeData.h \ HierCode.cc \ diff --git a/src/cf.data.pre b/src/cf.data.pre index 3ae25a90ec..40b5fe75ea 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1299,6 +1299,33 @@ DOC_START # adaptation_meta because it starts matching immediately after # the service has been selected for adaptation. + acl aclname has component + # matches a transaction "component" [fast] + # + # Supported transaction components are: + # request: transaction has a request header (at least) + # response: transaction has a response header (at least) + # ALE: transaction has an internally-generated Access Log Entry + # structure; bugs notwithstanding, all transaction have it + # + # For example, the following configuration helps when dealing with HTTP + # clients that close connections without sending a request header: + # + # acl hasRequest has request + # acl logMe note important_transaction + # # avoid "logMe ACL is used in context without an HTTP request" warnings + # access_log ... logformat=detailed hasRequest logMe + # # log request-less transactions, instead of ignoring them + # access_log ... logformat=brief !hasRequest + # + # Multiple components are not supported for one "acl" rule, but + # can be specified (and are ORed) using multiple same-name rules: + # + # # OK, this strange logging daemon needs request or response, + # # but can work without either a request or a response: + # acl hasWhatMyLoggingDaemonNeeds has request + # acl hasWhatMyLoggingDaemonNeeds has response + IF USE_OPENSSL acl aclname ssl_error errorname # match against SSL certificate validation error [fast]