Squid Web Cache master
Loading...
Searching...
No Matches
ServerName.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 28 Access Control */
10
11#include "squid.h"
12#include "acl/FilledChecklist.h"
13#include "acl/ServerName.h"
14#include "anyp/Host.h"
15#include "client_side.h"
16#include "http/Stream.h"
17#include "HttpRequest.h"
18#include "sbuf/Stream.h"
19#include "ssl/bio.h"
20#include "ssl/ServerBump.h"
21#include "ssl/support.h"
22
23// Compare function for tree search algorithms
24static int
25aclHostDomainCompare( char *const &a, char * const &b)
26{
27 const char *h = static_cast<const char *>(a);
28 const char *d = static_cast<const char *>(b);
29 debugs(28, 7, "Match:" << h << " <> " << d);
31}
32
33bool
34ACLServerNameData::match(const char *host)
35{
36 if (host == nullptr)
37 return 0;
38
39 debugs(28, 3, "checking '" << host << "'");
40
41 char *h = const_cast<char *>(host);
42 char const * const * result = domains.find(h, aclHostDomainCompare);
43
44 debugs(28, 3, "'" << host << "' " << (result ? "found" : "NOT found"));
45
46 return (result != nullptr);
47
48}
49
50namespace Acl {
51
54{
55public:
57
58protected:
59 /* GeneralNameMatcher API */
60 bool matchDomainName(const Dns::DomainName &) const override;
61 bool matchIp(const Ip::Address &) const override;
62
63private:
64 // TODO: Make ServerNameCheck::Parameters::match() and this reference constant.
66};
67
68} // namespace Acl
69
70bool
72{
73 return parameters.match(SBuf(domain).c_str()); // TODO: Upgrade string-matching ACLs to SBuf
74}
75
76bool
78{
79 // We are given an Ip::Address, but our ACL parameters use case-insensitive
80 // string equality (::matchDomainName) or regex string matches. There are
81 // many ways to convert an IPv6 address to a string, but only one format can
82 // correctly match certain configured parameters. Our ssl::server_name docs
83 // request the following ACL parameter formatting (that this to-string
84 // conversion code produces): IPv6 addresses use "::" notation (where
85 // applicable) and are not bracketed.
86 //
87 // Similar problems affect dstdomain ACLs. TODO: Instead of relying on users
88 // reading docs and following their inet_ntop(3) implementation to match
89 // IPv6 addresses handled by matchDomainName(), enhance matchDomainName()
90 // code and ACL parameter storage to support Ip::Address objects.
91 char hostStr[MAX_IPSTRLEN];
92 (void)ip.toStr(hostStr, sizeof(hostStr)); // no brackets
93 return parameters.match(hostStr);
94}
95
96int
98{
99 const auto checklist = Filled(ch);
100
101 assert(checklist != nullptr && checklist->request != nullptr);
102
103 std::optional<AnyP::Host> serverNameFromConn;
104 if (ConnStateData *conn = checklist->conn()) {
105 std::optional<AnyP::Host> clientRequestedServerName;
106 const auto &clientSni = conn->tlsClientSni();
107 if (clientSni.isEmpty()) {
108 clientRequestedServerName = checklist->request->url.parsedHost();
109 } else {
110 // RFC 6066: "The hostname is represented as a byte string using
111 // ASCII encoding"; "Literal IPv4 and IPv6 addresses are not
112 // permitted". TODO: Store TlsDetails::serverName and similar
113 // domains using a new domain-only type instead of SBuf.
114 clientRequestedServerName = AnyP::Host::ParseSimpleDomainName(clientSni);
115 }
116
117 if (useConsensus) {
118 X509 *peer_cert = conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr;
119 // use the client requested name if it matches the server
120 // certificate or if the certificate is not available
121 if (!peer_cert || !clientRequestedServerName ||
122 Ssl::HasSubjectName(*peer_cert, *clientRequestedServerName))
123 serverNameFromConn = clientRequestedServerName;
124 } else if (useClientRequested)
125 serverNameFromConn = clientRequestedServerName;
126 else { // either no options or useServerProvided
127 if (X509 *peer_cert = (conn->serverBump() ? conn->serverBump()->serverCert.get() : nullptr))
128 return Ssl::HasMatchingSubjectName(*peer_cert, ServerNameMatcher(*data));
129 if (!useServerProvided)
130 serverNameFromConn = clientRequestedServerName;
131 }
132 }
133
134 std::optional<SBuf> printedServerName;
135 if (serverNameFromConn)
136 printedServerName = ToSBuf(*serverNameFromConn); // no brackets
137 const auto serverName = printedServerName ? printedServerName->c_str() : "none";
138 return data->match(serverName);
139}
140
141const Acl::Options &
143{
144 static const Acl::BooleanOption ClientRequested("--client-requested");
145 static const Acl::BooleanOption ServerProvided("--server-provided");
146 static const Acl::BooleanOption Consensus("--consensus");
147 static const Acl::Options MyOptions = { &ClientRequested, &ServerProvided, &Consensus };
148 ClientRequested.linkWith(&useClientRequested);
149 ServerProvided.linkWith(&useServerProvided);
150 Consensus.linkWith(&useConsensus);
151 return MyOptions;
152}
153
154bool
156{
157 int optionCount = 0;
158
159 if (useClientRequested)
160 optionCount++;
161 if (useServerProvided)
162 optionCount++;
163 if (useConsensus)
164 optionCount++;
165
166 if (optionCount > 1) {
167 debugs(28, DBG_CRITICAL, "ERROR: Multiple options given for the server_name ACL");
168 return false;
169 }
170 return true;
171}
172
static int aclHostDomainCompare(char *const &a, char *const &b)
Definition DomainData.cc:53
ACLFilledChecklist * Filled(ACLChecklist *checklist)
convenience and safety wrapper for dynamic_cast<ACLFilledChecklist*>
static int aclHostDomainCompare(char *const &a, char *const &b)
Definition ServerName.cc:25
int matchDomainName(const char *h, const char *d, MatchDomainNameFlags flags)
Definition Uri.cc:903
@ mdnHonorWildcards
Definition Uri.h:240
#define assert(EX)
Definition assert.h:17
Configured ACL parameter(s) (e.g., domain names in dstdomain ACL).
Definition Data.h:18
virtual bool match(M)=0
Splay< char * > domains
Definition DomainData.h:28
bool match(const char *) override
Definition ServerName.cc:34
const Acl::Options & options() override
bool valid() const override
int match(ACLChecklist *) override
Matches the actual data in checklist against this Acl::Node.
Definition ServerName.cc:97
GeneralNameMatcher for matching configured ACL parameters.
Definition ServerName.cc:54
ServerNameMatcher(ServerNameCheck::Parameters &p)
Definition ServerName.cc:56
bool matchIp(const Ip::Address &) const override
Definition ServerName.cc:77
ServerNameCheck::Parameters & parameters
configured ACL parameters
Definition ServerName.cc:65
bool matchDomainName(const Dns::DomainName &) const override
Definition ServerName.cc:71
a type-specific Option (e.g., a boolean –toggle or -m=SBuf)
Definition Options.h:130
void linkWith(Recipient *recipient) const
who to tell when this option is enabled
Definition Options.h:137
static std::optional< Host > ParseSimpleDomainName(const SBuf &)
Definition Host.cc:49
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition Address.cc:804
Definition SBuf.h:94
Value const * find(FindValue const &, int(*compare)(FindValue const &a, Value const &b)) const
an algorithm for checking/testing/comparing X.509 certificate names
Definition support.h:299
#define debugs(SECTION, LEVEL, CONTENT)
Definition Stream.h:192
#define DBG_CRITICAL
Definition Stream.h:37
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition forward.h:25
Definition Acl.cc:33
std::vector< const Option * > Options
Definition Options.h:217
bool HasMatchingSubjectName(X509 &, const GeneralNameMatcher &)
Definition support.cc:307
bool HasSubjectName(X509 &, const AnyP::Host &)
whether at least one common or alternate subject name matches the given one
Definition support.cc:338
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition Stream.h:63