]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Add 'has' ACL
authorEduard Bagdasaryan <eduard.bagdasaryan@measurement-factory.com>
Tue, 16 May 2017 14:27:49 +0000 (02:27 +1200)
committerAmos Jeffries <squid3@treenet.co.nz>
Tue, 16 May 2017 14:27:49 +0000 (02:27 +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 9783721f8ce8d4fe2c53e04074d4a71ae2e1b5f3..bbf2995c2b6cb17143c00160192bf6aad3b09ce4 100644 (file)
@@ -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<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..7942b18
--- /dev/null
@@ -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<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 51b6c4eab9e1c7bf27b0ba4acb5aee5190e10dc0..133ba56cba65fd1a864f840d6daf1868053342a5 100644 (file)
@@ -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 \
index 3ae25a90ecfb48802894030336b55c1e480c7d27..40b5fe75eaa9563d60661001a3437552fa87e02b 100644 (file)
@@ -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]