]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Add 'has' ACL
authorEduard Bagdasaryan <eduard.bagdasaryan@measurement-factory.com>
Thu, 25 May 2017 12:42:17 +0000 (00:42 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Thu, 25 May 2017 12:42:17 +0000 (00:42 +1200)
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.

src/AclRegs.cc
src/acl/HasComponent.cc [new file with mode: 0644]
src/acl/HasComponent.h [new file with mode: 0644]
src/acl/HasComponentData.cc [new file with mode: 0644]
src/acl/HasComponentData.h [new file with mode: 0644]
src/acl/Makefile.am
src/cf.data.pre

index dad76a2a288ebdfdda961ff05b5ddc89d24af37b..e0672c0254f5739369b19f1d0c733ccb13b7b605 100644 (file)
@@ -41,6 +41,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"
@@ -235,3 +237,6 @@ ACLStrategised<err_type> 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<ACLChecklist *> ACLHasComponent::RegistryEntry_(new ACLHasComponentData, ACLHasComponentStrategy::Instance(), "has");
+
diff --git a/src/acl/HasComponent.cc b/src/acl/HasComponent.cc
new file mode 100644 (file)
index 0000000..1b0d4dd
--- /dev/null
@@ -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<MatchType> * &data, ACLFilledChecklist *checklist, ACLFlags &flags)
+{
+    ACLHasComponentData *cdata = dynamic_cast<ACLHasComponentData*>(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 (file)
index 0000000..3aba6cd
--- /dev/null
@@ -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<ACLChecklist *>
+{
+public:
+    static ACLHasComponentStrategy *Instance();
+    ACLHasComponentStrategy(ACLHasComponentStrategy const &) = delete;
+    ACLHasComponentStrategy& operator=(ACLHasComponentStrategy const &) = delete;
+    virtual int match(ACLData<MatchType> * &, ACLFilledChecklist *, ACLFlags &);
+
+private:
+    static ACLHasComponentStrategy Instance_;
+    ACLHasComponentStrategy() { }
+};
+
+/// \ingroup ACLAPI
+class ACLHasComponent
+{
+private:
+    static ACL::Prototype RegistryProtoype;
+    static ACLStrategised<ACLChecklist *> RegistryEntry_;
+};
+
+#endif
+
diff --git a/src/acl/HasComponentData.cc b/src/acl/HasComponentData.cc
new file mode 100644 (file)
index 0000000..500c33c
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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<ACLChecklist *> *
+ACLHasComponentData::clone() const
+{
+    return new ACLHasComponentData(*this);
+}
+
diff --git a/src/acl/HasComponentData.h b/src/acl/HasComponentData.h
new file mode 100644 (file)
index 0000000..0b1bd05
--- /dev/null
@@ -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<ACLChecklist *>
+{
+    MEMPROXY_CLASS(ACLHasComponentData);
+
+public:
+    ACLHasComponentData();
+
+    /* ACLData<M> API */
+    virtual bool match(ACLChecklist *) override;
+    virtual SBufList dump() const override;
+    virtual void parse() override;
+    virtual bool empty() const override { return false; }
+    virtual ACLData<ACLChecklist *> *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<ComponentCheck> componentMethods;
+};
+
+#endif
+
index df3a9c5338688a3d73daa252e1b750227109bda7..6a5068aa6b001a6fe1decf8fdd5e9560a6b835de 100644 (file)
@@ -69,6 +69,10 @@ libacls_la_SOURCES = \
        DomainData.h \
        ExtUser.cc \
        ExtUser.h \
+       HasComponent.cc \
+       HasComponent.h \
+       HasComponentData.cc \
+       HasComponentData.h \
        HierCodeData.cc \
        HierCodeData.h \
        HierCode.cc \
index 046fa47dd6fbcb069474fc0592fba683b583ef28..6440247d9d100e646a99eaa3c0c6c97d4c694ccf 100644 (file)
@@ -1242,6 +1242,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]