/* * Copyright (C) 1996-2023 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" #if USE_ADAPTATION #include "acl/AdaptationService.h" #include "acl/AdaptationServiceData.h" #endif #include "acl/AllOf.h" #include "acl/AnnotateClient.h" #include "acl/AnnotateTransaction.h" #include "acl/AnnotationData.h" #include "acl/AnyOf.h" #if USE_SQUID_EUI #include "acl/Arp.h" #include "acl/Eui64.h" #endif #if USE_OPENSSL #include "acl/AtStep.h" #include "acl/AtStepData.h" #endif #include "acl/Asn.h" #include "acl/Checklist.h" #include "acl/ConnectionsEncrypted.h" #include "acl/Data.h" #include "acl/DestinationAsn.h" #include "acl/DestinationDomain.h" #include "acl/DestinationIp.h" #include "acl/DomainData.h" #if USE_LIBNETFILTERCONNTRACK #include "acl/ConnMark.h" #endif #if USE_AUTH #include "acl/ExtUser.h" #endif #include "acl/FilledChecklist.h" #include "acl/forward.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" #include "acl/HttpRepHeader.h" #include "acl/HttpReqHeader.h" #include "acl/HttpStatus.h" #include "acl/IntRange.h" #include "acl/Ip.h" #include "acl/LocalIp.h" #include "acl/LocalPort.h" #include "acl/MaxConnection.h" #include "acl/Method.h" #include "acl/MethodData.h" #include "acl/MyPortName.h" #include "acl/Node.h" #include "acl/Note.h" #include "acl/NoteData.h" #include "acl/PeerName.h" #include "acl/Protocol.h" #include "acl/ProtocolData.h" #include "acl/Random.h" #include "acl/RegexData.h" #include "acl/ReplyHeaderStrategy.h" #include "acl/ReplyMimeType.h" #include "acl/RequestHeaderStrategy.h" #include "acl/RequestMimeType.h" #include "acl/SourceAsn.h" #include "acl/SourceDomain.h" #include "acl/SourceIp.h" #include "acl/SquidError.h" #include "acl/SquidErrorData.h" #if USE_OPENSSL #include "acl/Certificate.h" #include "acl/CertificateData.h" #include "acl/ServerName.h" #include "acl/SslError.h" #include "acl/SslErrorData.h" #endif #include "acl/StringData.h" #if USE_OPENSSL #include "acl/ServerCertificate.h" #endif #include "acl/Tag.h" #include "acl/Time.h" #include "acl/TimeData.h" #include "acl/TransactionInitiator.h" #include "acl/Url.h" #include "acl/UrlLogin.h" #include "acl/UrlPath.h" #include "acl/UrlPort.h" #include "acl/UserData.h" #if USE_AUTH #include "auth/AclMaxUserIp.h" #include "auth/AclProxyAuth.h" #endif #include "base/RegexPattern.h" #include "ExternalACL.h" #if SQUID_SNMP #include "snmp_core.h" #endif #include "sbuf/Stream.h" namespace Acl { /// Constructs a ParameterizedNode-derived ACL (specified as a Parent class). /// This template exists to avoid placing a variant of this ACL construction /// code in each ParameterizedNode-derived ACL class just to pass through /// TypeName and Parameters onto ParameterizedNode (and to add MEMPROXY_CLASS). template class FinalizedParameterizedNode: public Parent { MEMPROXY_CLASS(FinalizedParameterizedNode); public: using Parameters = typename Parent::Parameters; using Parent::data; /// Replaces generic memory allocator label X set by our MEMPROXY_CLASS(X) /// with an admin-friendly label based on the given acltype-like name. /// Normally, our class constructor sets the right allocator label using the /// actlype name, but that algorithm results in unstable and misleading /// labels when the same instantiation of this template class is used for /// _multiple_ acltype names. Calling this method corrects that behavior. /// \prec this method must be called at most once /// \prec if called, this method must be called before the class constructor static void PreferAllocatorLabelPrefix(const char * const suffix) { assert(!PreferredAllocatorLabelSuffix); // must be called at most once assert(!FinalPoolLabel); // must be called before the class constructor assert(suffix); PreferredAllocatorLabelSuffix = suffix; } FinalizedParameterizedNode(TypeName typeName, Parameters * const params): typeName_(typeName) { Assure(!data); // base classes never set this data member data.reset(params); Assure(data); // ... but we always do FinalizePoolLabel(typeName); } ~FinalizedParameterizedNode() override = default; /* ACL API */ const char *typeString() const override { return typeName_; } private: /// A constructor helper function that replaces generic memory allocator /// label X set by our MEMPROXY_CLASS(X) with an admin-friendly label based /// on the acltype name from squid.conf. Meant to be called from the /// constructor so that no mgr:mem report lists this C++ template class /// statistics using label X. Repeated calls are allowed but have no effect. /// \sa PreferAllocatorLabelPrefix() static void FinalizePoolLabel(const TypeName typeName) { if (FinalPoolLabel) return; // the label has been finalized already assert(typeName); const auto label = ToSBuf("acltype=", PreferredAllocatorLabelSuffix ? PreferredAllocatorLabelSuffix : typeName); FinalPoolLabel = SBufToCstring(label); Pool().relabel(FinalPoolLabel); } /// if set, overrules FinalizePoolLabel() argument inline static const char *PreferredAllocatorLabelSuffix = nullptr; /// custom allocator label set by FinalizePoolLabel() inline static const char *FinalPoolLabel = nullptr; // TODO: Consider storing the spelling used by the admin instead. /// the "acltype" name in its canonical spelling TypeName typeName_; }; } // namespace Acl // Not in src/acl/ because some of the ACLs it registers are not in src/acl/. void Acl::Init() { /* the registration order does not matter */ // The explicit return type (Acl::Node*) for lambdas is needed because the type // of the return expression inside lambda is not Node* but AclFoo* while // Maker is defined to return Node*. RegisterMaker("all-of", [](TypeName)->Node* { return new AllOf; }); // XXX: Add name parameter to ctor RegisterMaker("any-of", [](TypeName)->Node* { return new AnyOf; }); // XXX: Add name parameter to ctor RegisterMaker("random", [](TypeName name)->Node* { return new ACLRandom(name); }); RegisterMaker("time", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLTimeData); }); RegisterMaker("src_as", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLASN); }); RegisterMaker("dst_as", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLASN); }); RegisterMaker("browser", [](TypeName name)->Node* { return new FinalizedParameterizedNode >(name, new ACLRegexData); }); RegisterMaker("dstdomain", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLDomainData); }); RegisterMaker("dstdom_regex", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLRegexData); }); FinalizedParameterizedNode::PreferAllocatorLabelPrefix("dstdomain+"); RegisterMaker("dst", [](TypeName)->Node* { return new ACLDestinationIP; }); // XXX: Add name parameter to ctor RegisterMaker("hier_code", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLHierCodeData); }); RegisterMaker("rep_header", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLHTTPHeaderData); }); RegisterMaker("req_header", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLHTTPHeaderData); }); RegisterMaker("http_status", [](TypeName name)->Node* { return new ACLHTTPStatus(name); }); RegisterMaker("maxconn", [](TypeName name)->Node* { return new ACLMaxConnection(name); }); RegisterMaker("method", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLMethodData); }); RegisterMaker("localip", [](TypeName)->Node* { return new ACLLocalIP; }); // XXX: Add name parameter to ctor RegisterMaker("localport", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLIntRange); }); RegisterMaker("myportname", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLStringData); }); RegisterMaker("peername", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLStringData); }); RegisterMaker("peername_regex", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLRegexData); }); FinalizedParameterizedNode::PreferAllocatorLabelPrefix("peername+"); RegisterMaker("proto", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLProtocolData); }); RegisterMaker("referer_regex", [](TypeName name)->Node* { return new FinalizedParameterizedNode >(name, new ACLRegexData); }); RegisterMaker("rep_mime_type", [](TypeName name)->Node* { return new FinalizedParameterizedNode >(name, new ACLRegexData); }); RegisterMaker("req_mime_type", [](TypeName name)->Node* { return new FinalizedParameterizedNode >(name, new ACLRegexData); }); RegisterMaker("srcdomain", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLDomainData); }); RegisterMaker("srcdom_regex", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLRegexData); }); FinalizedParameterizedNode::PreferAllocatorLabelPrefix("srcdomain+"); RegisterMaker("src", [](TypeName)->Node* { return new ACLSourceIP; }); // XXX: Add name parameter to ctor RegisterMaker("url_regex", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLRegexData); }); RegisterMaker("urllogin", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLRegexData); }); RegisterMaker("urlpath_regex", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLRegexData); }); RegisterMaker("port", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLIntRange); }); RegisterMaker("external", [](TypeName name)->Node* { return new ACLExternal(name); }); RegisterMaker("squid_error", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLSquidErrorData); }); RegisterMaker("connections_encrypted", [](TypeName name)->Node* { return new ConnectionsEncrypted(name); }); RegisterMaker("tag", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLStringData); }); RegisterMaker("note", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLNoteData); }); RegisterMaker("annotate_client", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLAnnotationData); }); RegisterMaker("annotate_transaction", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLAnnotationData); }); RegisterMaker("has", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLHasComponentData); }); RegisterMaker("transaction_initiator", [](TypeName name)->Node* {return new TransactionInitiator(name);}); #if USE_LIBNETFILTERCONNTRACK RegisterMaker("clientside_mark", [](TypeName)->Node* { return new ConnMark; }); // XXX: Add name parameter to ctor RegisterMaker("client_connection_mark", [](TypeName)->Node* { return new ConnMark; }); // XXX: Add name parameter to ctor #endif #if USE_OPENSSL RegisterMaker("ssl_error", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLSslErrorData); }); RegisterMaker("user_cert", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLCertificateData(Ssl::GetX509UserAttribute, "*")); }); RegisterMaker("ca_cert", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLCertificateData(Ssl::GetX509CAAttribute, "*")); }); FinalizedParameterizedNode::PreferAllocatorLabelPrefix("user_cert+"); RegisterMaker("server_cert_fingerprint", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLCertificateData(Ssl::GetX509Fingerprint, nullptr, true)); }); RegisterMaker("at_step", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLAtStepData); }); RegisterMaker("ssl::server_name", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLServerNameData); }); RegisterMaker("ssl::server_name_regex", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLRegexData); }); FinalizedParameterizedNode::PreferAllocatorLabelPrefix("ssl::server_name+"); #endif #if USE_SQUID_EUI RegisterMaker("arp", [](TypeName name)->Node* { return new ACLARP(name); }); RegisterMaker("eui64", [](TypeName name)->Node* { return new ACLEui64(name); }); #endif #if USE_AUTH RegisterMaker("ext_user", [](TypeName name)->Node* { return new ACLExtUser(new ACLUserData, name); }); RegisterMaker("ext_user_regex", [](TypeName name)->Node* { return new ACLExtUser(new ACLRegexData, name); }); RegisterMaker("proxy_auth", [](TypeName name)->Node* { return new ACLProxyAuth(new ACLUserData, name); }); RegisterMaker("proxy_auth_regex", [](TypeName name)->Node* { return new ACLProxyAuth(new ACLRegexData, name); }); RegisterMaker("max_user_ip", [](TypeName name)->Node* { return new ACLMaxUserIP(name); }); #endif #if USE_ADAPTATION RegisterMaker("adaptation_service", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLAdaptationServiceData); }); #endif #if SQUID_SNMP RegisterMaker("snmp_community", [](TypeName name)->Node* { return new FinalizedParameterizedNode(name, new ACLStringData); }); #endif }