]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.h
transaction_initiator ACL for detecting various unusual transactions
[thirdparty/squid.git] / src / client_side.h
1 /*
2 * Copyright (C) 1996-2017 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 33 Client-side Routines */
10
11 #ifndef SQUID_CLIENTSIDE_H
12 #define SQUID_CLIENTSIDE_H
13
14 #include "base/RunnersRegistry.h"
15 #include "clientStreamForward.h"
16 #include "comm.h"
17 #include "forward.h"
18 #include "helper/forward.h"
19 #include "http/forward.h"
20 #include "HttpControlMsg.h"
21 #include "ipc/FdNotes.h"
22 #include "sbuf/SBuf.h"
23 #include "servers/Server.h"
24 #if USE_AUTH
25 #include "auth/UserRequest.h"
26 #endif
27 #if USE_OPENSSL
28 #include "security/Handshake.h"
29 #include "ssl/support.h"
30 #endif
31 #if USE_DELAY_POOLS
32 #include "MessageBucket.h"
33 #endif
34
35 class ClientHttpRequest;
36 class HttpHdrRangeSpec;
37
38 #if USE_OPENSSL
39 namespace Ssl
40 {
41 class ServerBump;
42 }
43 #endif
44
45 /**
46 * Legacy Server code managing a connection to a client.
47 *
48 * NP: presents AsyncJob API but does not operate autonomously as a Job.
49 * So Must() is not safe to use.
50 *
51 * Multiple requests (up to pipeline_prefetch) can be pipelined.
52 * This object is responsible for managing which one is currently being
53 * fulfilled and what happens to the queue if the current one causes the client
54 * connection to be closed early.
55 *
56 * Act as a manager for the client connection and passes data in buffer to a
57 * Parser relevant to the state (message headers vs body) that is being
58 * processed.
59 *
60 * Performs HTTP message processing to kick off the actual HTTP request
61 * handling objects (Http::Stream, ClientHttpRequest, HttpRequest).
62 *
63 * Performs SSL-Bump processing for switching between HTTP and HTTPS protocols.
64 *
65 * To terminate a ConnStateData close() the client Comm::Connection it is
66 * managing, or for graceful half-close use the stopReceiving() or
67 * stopSending() methods.
68 */
69 class ConnStateData : public Server, public HttpControlMsgSink, private IndependentRunner
70 {
71
72 public:
73 explicit ConnStateData(const MasterXactionPointer &xact);
74 virtual ~ConnStateData();
75
76 /* ::Server API */
77 virtual void receivedFirstByte();
78 virtual bool handleReadData();
79 virtual void afterClientRead();
80 virtual void afterClientWrite(size_t);
81
82 /* HttpControlMsgSink API */
83 virtual void sendControlMsg(HttpControlMsg);
84 virtual void doneWithControlMsg();
85
86 /// Traffic parsing
87 bool clientParseRequests();
88 void readNextRequest();
89
90 /// try to make progress on a transaction or read more I/O
91 void kick();
92
93 bool isOpen() const;
94
95 Http1::TeChunkedParser *bodyParser; ///< parses HTTP/1.1 chunked request body
96
97 /** number of body bytes we need to comm_read for the "current" request
98 *
99 * \retval 0 We do not need to read any [more] body bytes
100 * \retval negative May need more but do not know how many; could be zero!
101 * \retval positive Need to read exactly that many more body bytes
102 */
103 int64_t mayNeedToReadMoreBody() const;
104
105 #if USE_AUTH
106 /**
107 * Fetch the user details for connection based authentication
108 * NOTE: this is ONLY connection based because NTLM and Negotiate is against HTTP spec.
109 */
110 const Auth::UserRequest::Pointer &getAuth() const { return auth_; }
111
112 /**
113 * Set the user details for connection-based authentication to use from now until connection closure.
114 *
115 * Any change to existing credentials shows that something invalid has happened. Such as:
116 * - NTLM/Negotiate auth was violated by the per-request headers missing a revalidation token
117 * - NTLM/Negotiate auth was violated by the per-request headers being for another user
118 * - SSL-Bump CONNECT tunnel with persistent credentials has ended
119 */
120 void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause);
121 #endif
122
123 Ip::Address log_addr;
124
125 struct {
126 bool readMore; ///< needs comm_read (for this request or new requests)
127 bool swanSang; // XXX: temporary flag to check proper cleanup
128 } flags;
129 struct {
130 Comm::ConnectionPointer serverConnection; /* pinned server side connection */
131 char *host; /* host name of pinned connection */
132 int port; /* port of pinned connection */
133 bool pinned; /* this connection was pinned */
134 bool auth; /* pinned for www authentication */
135 bool reading; ///< we are monitoring for peer connection closure
136 bool zeroReply; ///< server closed w/o response (ERR_ZERO_SIZE_OBJECT)
137 CachePeer *peer; /* CachePeer the connection goes via */
138 AsyncCall::Pointer readHandler; ///< detects serverConnection closure
139 AsyncCall::Pointer closeHandler; /*The close handler for pinned server side connection*/
140 } pinning;
141
142 bool transparent() const;
143
144 /// true if we stopped receiving the request
145 const char *stoppedReceiving() const { return stoppedReceiving_; }
146 /// true if we stopped sending the response
147 const char *stoppedSending() const { return stoppedSending_; }
148 /// note request receiving error and close as soon as we write the response
149 void stopReceiving(const char *error);
150 /// note response sending error and close as soon as we read the request
151 void stopSending(const char *error);
152
153 void expectNoForwarding(); ///< cleans up virgin request [body] forwarding state
154
155 /* BodyPipe API */
156 BodyPipe::Pointer expectRequestBody(int64_t size);
157 virtual void noteMoreBodySpaceAvailable(BodyPipe::Pointer) = 0;
158 virtual void noteBodyConsumerAborted(BodyPipe::Pointer) = 0;
159
160 bool handleRequestBodyData();
161
162 /// Forward future client requests using the given server connection.
163 /// Optionally, monitor pinned server connection for remote-end closures.
164 void pinConnection(const Comm::ConnectionPointer &pinServerConn, HttpRequest *request, CachePeer *peer, bool auth, bool monitor = true);
165 /// Undo pinConnection() and, optionally, close the pinned connection.
166 void unpinConnection(const bool andClose);
167 /// Returns validated pinnned server connection (and stops its monitoring).
168 Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *request, const CachePeer *aPeer);
169 /**
170 * Checks if there is pinning info if it is valid. It can close the server side connection
171 * if pinned info is not valid.
172 \param request if it is not NULL also checks if the pinning info refers to the request client side HttpRequest
173 \param CachePeer if it is not NULL also check if the CachePeer is the pinning CachePeer
174 \return The details of the server side connection (may be closed if failures were present).
175 */
176 const Comm::ConnectionPointer validatePinnedConnection(HttpRequest *request, const CachePeer *peer);
177 /**
178 * returts the pinned CachePeer if exists, NULL otherwise
179 */
180 CachePeer *pinnedPeer() const {return pinning.peer;}
181 bool pinnedAuth() const {return pinning.auth;}
182
183 /// called just before a FwdState-dispatched job starts using connection
184 virtual void notePeerConnection(Comm::ConnectionPointer) {}
185
186 // pining related comm callbacks
187 virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
188
189 // comm callbacks
190 void clientReadFtpData(const CommIoCbParams &io);
191 void connStateClosed(const CommCloseCbParams &io);
192 void requestTimeout(const CommTimeoutCbParams &params);
193
194 // AsyncJob API
195 virtual void start();
196 virtual bool doneAll() const { return BodyProducer::doneAll() && false;}
197 virtual void swanSong();
198
199 /// Changes state so that we close the connection and quit after serving
200 /// the client-side-detected error response instead of getting stuck.
201 void quitAfterError(HttpRequest *request); // meant to be private
202
203 /// The caller assumes responsibility for connection closure detection.
204 void stopPinnedConnectionMonitoring();
205
206 #if USE_OPENSSL
207 /// the second part of old httpsAccept, waiting for future HttpsServer home
208 void postHttpsAccept();
209
210 /// Initializes and starts a peek-and-splice negotiation with the SSL client
211 void startPeekAndSplice();
212
213 /// Called when a peek-and-splice step finished. For example after
214 /// server SSL certificates received and fake server SSL certificates
215 /// generated
216 void doPeekAndSpliceStep();
217 /// called by FwdState when it is done bumping the server
218 void httpsPeeked(Comm::ConnectionPointer serverConnection);
219
220 /// Splice a bumped client connection on peek-and-splice mode
221 bool splice();
222
223 /// Start to create dynamic Security::ContextPointer for host or uses static port SSL context.
224 void getSslContextStart();
225 /**
226 * Done create dynamic ssl certificate.
227 *
228 * \param[in] isNew if generated certificate is new, so we need to add this certificate to storage.
229 */
230 void getSslContextDone(Security::ContextPointer &, bool isNew = false);
231 /// Callback function. It is called when squid receive message from ssl_crtd.
232 static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply);
233 /// Proccess response from ssl_crtd.
234 void sslCrtdHandleReply(const Helper::Reply &reply);
235
236 void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
237 void parseTlsHandshake();
238 bool switchedToHttps() const { return switchedToHttps_; }
239 Ssl::ServerBump *serverBump() {return sslServerBump;}
240 inline void setServerBump(Ssl::ServerBump *srvBump) {
241 if (!sslServerBump)
242 sslServerBump = srvBump;
243 else
244 assert(sslServerBump == srvBump);
245 }
246 const SBuf &sslCommonName() const {return sslCommonName_;}
247 void resetSslCommonName(const char *name) {sslCommonName_ = name;}
248 const SBuf &tlsClientSni() const { return tlsClientSni_; }
249 /// Fill the certAdaptParams with the required data for certificate adaptation
250 /// and create the key for storing/retrieve the certificate to/from the cache
251 void buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties);
252 /// Called when the client sends the first request on a bumped connection.
253 /// Returns false if no [delayed] error should be written to the client.
254 /// Otherwise, writes the error to the client and returns true. Also checks
255 /// for SQUID_X509_V_ERR_DOMAIN_MISMATCH on bumped requests.
256 bool serveDelayedError(Http::Stream *);
257
258 Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
259
260 /// Tls parser to use for client HELLO messages parsing on bumped
261 /// connections.
262 Security::HandshakeParser tlsParser;
263 #else
264 bool switchedToHttps() const { return false; }
265 #endif
266
267 /// handle a control message received by context from a peer and call back
268 virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
269
270 /// ClientStream calls this to supply response header (once) and data
271 /// for the current Http::Stream.
272 virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) = 0;
273
274 /// remove no longer needed leading bytes from the input buffer
275 void consumeInput(const size_t byteCount);
276
277 /* TODO: Make the methods below (at least) non-public when possible. */
278
279 /// stop parsing the request and create context for relaying error info
280 Http::Stream *abortRequestParsing(const char *const errUri);
281
282 /// generate a fake CONNECT request with the given payload
283 /// at the beginning of the client I/O buffer
284 bool fakeAConnectRequest(const char *reason, const SBuf &payload);
285
286 /// generates and sends to tunnel.cc a fake request with a given payload
287 bool initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload);
288
289 /// whether tunneling of unsupported protocol is allowed for this connection
290 bool mayTunnelUnsupportedProto();
291
292 /// build a fake http request
293 ClientHttpRequest *buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload);
294
295 /// client data which may need to forward as-is to server after an
296 /// on_unsupported_protocol tunnel decision.
297 SBuf preservedClientData;
298
299 /* Registered Runner API */
300 virtual void startShutdown();
301 virtual void endingShutdown();
302
303 /// \returns existing non-empty connection annotations,
304 /// creates and returns empty annotations otherwise
305 NotePairs::Pointer notes();
306 bool hasNotes() const { return bool(theNotes) && !theNotes->empty(); }
307
308 protected:
309 void startDechunkingRequest();
310 void finishDechunkingRequest(bool withSuccess);
311 void abortChunkedRequestBody(const err_type error);
312 err_type handleChunkedRequestBody();
313
314 void startPinnedConnectionMonitoring();
315 void clientPinnedConnectionRead(const CommIoCbParams &io);
316 #if USE_OPENSSL
317 /// Handles a ready-for-reading TLS squid-to-server connection that
318 /// we thought was idle.
319 /// \return false if and only if the connection should be closed.
320 bool handleIdleClientPinnedTlsRead();
321 #endif
322
323 /// parse input buffer prefix into a single transfer protocol request
324 /// return NULL to request more header bytes (after checking any limits)
325 /// use abortRequestParsing() to handle parsing errors w/o creating request
326 virtual Http::Stream *parseOneRequest() = 0;
327
328 /// start processing a freshly parsed request
329 virtual void processParsedRequest(Http::StreamPointer &) = 0;
330
331 /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
332 virtual int pipelinePrefetchMax() const;
333
334 /// timeout to use when waiting for the next request
335 virtual time_t idleTimeout() const = 0;
336
337 /// Perform client data lookups that depend on client src-IP.
338 /// The PROXY protocol may require some data input first.
339 void whenClientIpKnown();
340
341 BodyPipe::Pointer bodyPipe; ///< set when we are reading request body
342
343 private:
344 /* ::Server API */
345 virtual bool connFinishedWithConn(int size);
346 virtual void checkLogging();
347
348 void clientAfterReadingRequests();
349 bool concurrentRequestQueueFilled() const;
350
351 void pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth);
352
353 /* PROXY protocol functionality */
354 bool proxyProtocolValidateClient();
355 bool parseProxyProtocolHeader();
356 bool parseProxy1p0();
357 bool parseProxy2p0();
358 bool proxyProtocolError(const char *reason);
359
360 /// whether PROXY protocol header is still expected
361 bool needProxyProtocolHeader_;
362
363 #if USE_AUTH
364 /// some user details that can be used to perform authentication on this connection
365 Auth::UserRequest::Pointer auth_;
366 #endif
367
368 /// the parser state for current HTTP/1.x input buffer processing
369 Http1::RequestParserPointer parser_;
370
371 #if USE_OPENSSL
372 bool switchedToHttps_;
373 bool parsingTlsHandshake; ///< whether we are getting/parsing TLS Hello bytes
374
375 /// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
376 String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
377 SBuf sslCommonName_; ///< CN name for SSL certificate generation
378
379 /// TLS client delivered SNI value. Empty string if none has been received.
380 SBuf tlsClientSni_;
381 String sslBumpCertKey; ///< Key to use to store/retrieve generated certificate
382
383 /// HTTPS server cert. fetching state for bump-ssl-server-first
384 Ssl::ServerBump *sslServerBump;
385 Ssl::CertSignAlgorithm signAlgorithm; ///< The signing algorithm to use
386 #endif
387
388 /// the reason why we no longer write the response or nil
389 const char *stoppedSending_;
390 /// the reason why we no longer read the request or nil
391 const char *stoppedReceiving_;
392 /// Connection annotations, clt_conn_tag and other tags are stored here.
393 /// If set, are propagated to the current and all future master transactions
394 /// on the connection.
395 NotePairs::Pointer theNotes;
396 };
397
398 void setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl = false);
399
400 const char *findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end = NULL);
401
402 int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req);
403
404 /// accept requests to a given port and inform subCall about them
405 void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId noteId);
406
407 void clientOpenListenSockets(void);
408 void clientConnectionsClose(void);
409 void httpRequestFree(void *);
410
411 /// decide whether to expect multiple requests on the corresponding connection
412 void clientSetKeepaliveFlag(ClientHttpRequest *http);
413
414 /// append a "part" HTTP header (as in a multi-part/range reply) to the buffer
415 void clientPackRangeHdr(const HttpReplyPointer &, const HttpHdrRangeSpec *, String boundary, MemBuf *);
416
417 /// put terminating boundary for multiparts to the buffer
418 void clientPackTermBound(String boundary, MemBuf *);
419
420 /* misplaced declaratrions of Stream callbacks provided/used by client side */
421 SQUIDCEXTERN CSR clientGetMoreData;
422 SQUIDCEXTERN CSS clientReplyStatus;
423 SQUIDCEXTERN CSD clientReplyDetach;
424 CSCB clientSocketRecipient;
425 CSD clientSocketDetach;
426
427 /* TODO: Move to HttpServer. Warning: Move requires large code nonchanges! */
428 Http::Stream *parseHttpRequest(ConnStateData *, const Http1::RequestParserPointer &);
429 void clientProcessRequest(ConnStateData *, const Http1::RequestParserPointer &, Http::Stream *);
430 void clientPostHttpsAccept(ConnStateData *);
431
432 #endif /* SQUID_CLIENTSIDE_H */
433