]> git.ipfire.org Git - thirdparty/squid.git/blob - src/AccessLogEntry.cc
ccc9eda84d940fb3f9aad906bb32dce08a38ed9e
[thirdparty/squid.git] / src / AccessLogEntry.cc
1 /*
2 * Copyright (C) 1996-2022 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 #include "squid.h"
10 #include "AccessLogEntry.h"
11 #include "fqdncache.h"
12 #include "HttpReply.h"
13 #include "HttpRequest.h"
14 #include "MemBuf.h"
15 #include "proxyp/Header.h"
16 #include "SquidConfig.h"
17 #include "ssl/support.h"
18
19 void
20 AccessLogEntry::getLogClientIp(char *buf, size_t bufsz) const
21 {
22 Ip::Address log_ip;
23
24 #if FOLLOW_X_FORWARDED_FOR
25 if (Config.onoff.log_uses_indirect_client && request)
26 log_ip = request->indirect_client_addr;
27 else
28 #endif
29 if (tcpClient)
30 log_ip = tcpClient->remote;
31 else
32 log_ip = cache.caddr;
33
34 // internally generated requests (and some ICAP) lack client IP
35 if (log_ip.isNoAddr()) {
36 strncpy(buf, "-", bufsz);
37 return;
38 }
39
40 // Apply so-called 'privacy masking' to IPv4 clients
41 // - localhost IP is always shown in full
42 // - IPv4 clients masked with client_netmask
43 // - IPv6 clients use 'privacy addressing' instead.
44
45 log_ip.applyClientMask(Config.Addrs.client_netmask);
46
47 log_ip.toStr(buf, bufsz);
48 }
49
50 const char *
51 AccessLogEntry::getLogClientFqdn(char * const buf, const size_t bufSize) const
52 {
53 // TODO: Use indirect client and tcpClient like getLogClientIp() does.
54 const auto &client = cache.caddr;
55
56 // internally generated (and ICAP OPTIONS) requests lack client IP
57 if (client.isAnyAddr())
58 return "-";
59
60 // If we are here, Squid was configured to use %>A or equivalent.
61 // Improve our chances of getting FQDN by resolving client IPs ASAP.
62 Dns::ResolveClientAddressesAsap = true; // may already be true
63
64 // Too late for ours, but FQDN_LOOKUP_IF_MISS might help the next caller.
65 if (const auto fqdn = fqdncache_gethostbyaddr(client, FQDN_LOOKUP_IF_MISS))
66 return fqdn; // TODO: Return a safe SBuf from fqdncache_gethostbyaddr().
67
68 return client.toStr(buf, bufSize);
69 }
70
71 SBuf
72 AccessLogEntry::getLogMethod() const
73 {
74 static const SBuf dash("-");
75 SBuf method;
76 if (icp.opcode)
77 method.append(icp_opcode_str[icp.opcode]);
78 else if (htcp.opcode)
79 method.append(htcp.opcode);
80 else if (http.method)
81 method = http.method.image();
82 else
83 method = dash;
84 return method;
85 }
86
87 void
88 AccessLogEntry::syncNotes(HttpRequest *req)
89 {
90 // XXX: auth code only has access to HttpRequest being authenticated
91 // so we must handle the case where HttpRequest is set without ALE being set.
92 assert(req);
93 if (!notes)
94 notes = req->notes();
95 else
96 assert(notes == req->notes());
97 }
98
99 const char *
100 AccessLogEntry::getClientIdent() const
101 {
102 if (tcpClient)
103 return tcpClient->rfc931;
104
105 if (cache.rfc931 && *cache.rfc931)
106 return cache.rfc931;
107
108 return nullptr;
109 }
110
111 const char *
112 AccessLogEntry::getExtUser() const
113 {
114 if (request && request->extacl_user.size())
115 return request->extacl_user.termedBuf();
116
117 if (cache.extuser && *cache.extuser)
118 return cache.extuser;
119
120 return nullptr;
121 }
122
123 AccessLogEntry::AccessLogEntry() {}
124
125 AccessLogEntry::~AccessLogEntry()
126 {
127 safe_free(headers.request);
128
129 #if USE_ADAPTATION
130 safe_free(adapt.last_meta);
131 #endif
132
133 safe_free(headers.adapted_request);
134 HTTPMSGUNLOCK(adapted_request);
135
136 safe_free(lastAclName);
137
138 HTTPMSGUNLOCK(request);
139 #if ICAP_CLIENT
140 HTTPMSGUNLOCK(icap.reply);
141 HTTPMSGUNLOCK(icap.request);
142 #endif
143 }
144
145 ScopedId
146 AccessLogEntry::codeContextGist() const
147 {
148 if (request) {
149 if (const auto &mx = request->masterXaction)
150 return mx->id.detach();
151 }
152 // TODO: Carefully merge ALE and MasterXaction.
153 return ScopedId("ALE w/o master");
154 }
155
156 std::ostream &
157 AccessLogEntry::detailCodeContext(std::ostream &os) const
158 {
159 // TODO: Consider printing all instead of the first most important detail.
160
161 if (request) {
162 if (const auto &mx = request->masterXaction)
163 return os << Debug::Extra << "current master transaction: " << mx->id;
164 }
165
166 // provide helpful details since we cannot identify the transaction exactly
167
168 if (tcpClient)
169 return os << Debug::Extra << "current from-client connection: " << tcpClient;
170 else if (!cache.caddr.isNoAddr())
171 return os << Debug::Extra << "current client: " << cache.caddr;
172
173 const auto optionalMethod = [this,&os]() {
174 if (hasLogMethod())
175 os << getLogMethod() << ' ';
176 return "";
177 };
178 if (const auto uri = effectiveVirginUrl())
179 return os << Debug::Extra << "current client request: " << optionalMethod() << *uri;
180 else if (!url.isEmpty())
181 return os << Debug::Extra << "current request: " << optionalMethod() << url;
182 else if (hasLogMethod())
183 return os << Debug::Extra << "current request method: " << getLogMethod();
184
185 return os;
186 }
187
188 const SBuf *
189 AccessLogEntry::effectiveVirginUrl() const
190 {
191 const SBuf *effectiveUrl = request ? &request->effectiveRequestUri() : &virginUrlForMissingRequest_;
192 if (effectiveUrl && !effectiveUrl->isEmpty())
193 return effectiveUrl;
194 // We can not use ALE::url here because it may contain a request URI after
195 // adaptation/redirection. When the request is missing, a non-empty ALE::url
196 // means that we missed a setVirginUrlForMissingRequest() call somewhere.
197 return nullptr;
198 }
199
200 const Error *
201 AccessLogEntry::error() const
202 {
203 // the order ensures that the first-imported error is returned
204 if (error_) // updateError() was called before importing the request
205 return &error_;
206 if (request && request->error) // request was imported before updateError()
207 return &request->error;
208 return nullptr; // we imported no errors and no requests
209 }
210
211 void
212 AccessLogEntry::updateError(const Error &err)
213 {
214 // the order ensures that error() returns the first-imported error
215 if (request)
216 request->error.update(err);
217 else
218 error_.update(err);
219 }
220
221 void
222 AccessLogEntry::packReplyHeaders(MemBuf &mb) const
223 {
224 if (reply)
225 reply->packHeadersUsingFastPacker(mb);
226 }
227