]> git.ipfire.org Git - thirdparty/squid.git/blob - src/client_side.cc
Minimize direct comparisons with ACCESS_ALLOWED and ACCESS_DENIED.
[thirdparty/squid.git] / src / client_side.cc
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 /**
12 \defgroup ClientSide Client-Side Logics
13 *
14 \section cserrors Errors and client side
15 *
16 \par Problem the first:
17 * the store entry is no longer authoritative on the
18 * reply status. EBITTEST (E_ABORT) is no longer a valid test outside
19 * of client_side_reply.c.
20 * Problem the second: resources are wasted if we delay in cleaning up.
21 * Problem the third we can't depend on a connection close to clean up.
22 *
23 \par Nice thing the first:
24 * Any step in the stream can callback with data
25 * representing an error.
26 * Nice thing the second: once you stop requesting reads from upstream,
27 * upstream can be stopped too.
28 *
29 \par Solution #1:
30 * Error has a callback mechanism to hand over a membuf
31 * with the error content. The failing node pushes that back as the
32 * reply. Can this be generalised to reduce duplicate efforts?
33 * A: Possibly. For now, only one location uses this.
34 * How to deal with pre-stream errors?
35 * Tell client_side_reply that we *want* an error page before any
36 * stream calls occur. Then we simply read as normal.
37 *
38 *
39 \section pconn_logic Persistent connection logic:
40 *
41 \par
42 * requests (httpClientRequest structs) get added to the connection
43 * list, with the current one being chr
44 *
45 \par
46 * The request is *immediately* kicked off, and data flows through
47 * to clientSocketRecipient.
48 *
49 \par
50 * If the data that arrives at clientSocketRecipient is not for the current
51 * request, clientSocketRecipient simply returns, without requesting more
52 * data, or sending it.
53 *
54 \par
55 * ConnStateData::kick() will then detect the presence of data in
56 * the next ClientHttpRequest, and will send it, restablishing the
57 * data flow.
58 */
59
60 #include "squid.h"
61 #include "acl/FilledChecklist.h"
62 #include "anyp/PortCfg.h"
63 #include "base/Subscription.h"
64 #include "base/TextException.h"
65 #include "CachePeer.h"
66 #include "client_db.h"
67 #include "client_side.h"
68 #include "client_side_reply.h"
69 #include "client_side_request.h"
70 #include "ClientRequestContext.h"
71 #include "clientStream.h"
72 #include "comm.h"
73 #include "comm/Connection.h"
74 #include "comm/Loops.h"
75 #include "comm/Read.h"
76 #include "comm/TcpAcceptor.h"
77 #include "comm/Write.h"
78 #include "CommCalls.h"
79 #include "errorpage.h"
80 #include "fd.h"
81 #include "fde.h"
82 #include "fqdncache.h"
83 #include "FwdState.h"
84 #include "globals.h"
85 #include "helper.h"
86 #include "helper/Reply.h"
87 #include "http.h"
88 #include "http/one/RequestParser.h"
89 #include "http/one/TeChunkedParser.h"
90 #include "http/Stream.h"
91 #include "HttpHdrContRange.h"
92 #include "HttpHeaderTools.h"
93 #include "HttpReply.h"
94 #include "HttpRequest.h"
95 #include "ident/Config.h"
96 #include "ident/Ident.h"
97 #include "internal.h"
98 #include "ipc/FdNotes.h"
99 #include "ipc/StartListening.h"
100 #include "log/access_log.h"
101 #include "MemBuf.h"
102 #include "MemObject.h"
103 #include "mime_header.h"
104 #include "parser/Tokenizer.h"
105 #include "profiler/Profiler.h"
106 #include "rfc1738.h"
107 #include "security/NegotiationHistory.h"
108 #include "servers/forward.h"
109 #include "SquidConfig.h"
110 #include "SquidTime.h"
111 #include "StatCounters.h"
112 #include "StatHist.h"
113 #include "Store.h"
114 #include "TimeOrTag.h"
115 #include "tools.h"
116 #include "URL.h"
117
118 #if USE_AUTH
119 #include "auth/UserRequest.h"
120 #endif
121 #if USE_DELAY_POOLS
122 #include "ClientInfo.h"
123 #include "MessageDelayPools.h"
124 #endif
125 #if USE_OPENSSL
126 #include "ssl/bio.h"
127 #include "ssl/context_storage.h"
128 #include "ssl/gadgets.h"
129 #include "ssl/helper.h"
130 #include "ssl/ProxyCerts.h"
131 #include "ssl/ServerBump.h"
132 #include "ssl/support.h"
133 #endif
134
135 // for tvSubUsec() which should be in SquidTime.h
136 #include "util.h"
137
138 #include <climits>
139 #include <cmath>
140 #include <limits>
141
142 #if LINGERING_CLOSE
143 #define comm_close comm_lingering_close
144 #endif
145
146 /// dials clientListenerConnectionOpened call
147 class ListeningStartedDialer: public CallDialer, public Ipc::StartListeningCb
148 {
149 public:
150 typedef void (*Handler)(AnyP::PortCfgPointer &portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub);
151 ListeningStartedDialer(Handler aHandler, AnyP::PortCfgPointer &aPortCfg, const Ipc::FdNoteId note, const Subscription::Pointer &aSub):
152 handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
153
154 virtual void print(std::ostream &os) const {
155 startPrint(os) <<
156 ", " << FdNote(portTypeNote) << " port=" << (void*)&portCfg << ')';
157 }
158
159 virtual bool canDial(AsyncCall &) const { return true; }
160 virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
161
162 public:
163 Handler handler;
164
165 private:
166 AnyP::PortCfgPointer portCfg; ///< from HttpPortList
167 Ipc::FdNoteId portTypeNote; ///< Type of IPC socket being opened
168 Subscription::Pointer sub; ///< The handler to be subscribed for this connetion listener
169 };
170
171 static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
172
173 static IOACB httpAccept;
174 #if USE_OPENSSL
175 static IOACB httpsAccept;
176 #endif
177 static CTCB clientLifetimeTimeout;
178 #if USE_IDENT
179 static IDCB clientIdentDone;
180 #endif
181 static int clientIsContentLengthValid(HttpRequest * r);
182 static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
183
184 static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time);
185 static void clientUpdateStatCounters(const LogTags &logType);
186 static void clientUpdateHierCounters(HierarchyLogEntry *);
187 static bool clientPingHasFinished(ping_data const *aPing);
188 void prepareLogWithRequestDetails(HttpRequest *, AccessLogEntry::Pointer &);
189 static void ClientSocketContextPushDeferredIfNeeded(Http::StreamPointer deferredRequest, ConnStateData * conn);
190
191 char *skipLeadingSpace(char *aString);
192
193 #if USE_IDENT
194 static void
195 clientIdentDone(const char *ident, void *data)
196 {
197 ConnStateData *conn = (ConnStateData *)data;
198 xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
199 }
200 #endif
201
202 void
203 clientUpdateStatCounters(const LogTags &logType)
204 {
205 ++statCounter.client_http.requests;
206
207 if (logType.isTcpHit())
208 ++statCounter.client_http.hits;
209
210 if (logType.oldType == LOG_TCP_HIT)
211 ++statCounter.client_http.disk_hits;
212 else if (logType.oldType == LOG_TCP_MEM_HIT)
213 ++statCounter.client_http.mem_hits;
214 }
215
216 void
217 clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
218 {
219 statCounter.client_http.allSvcTime.count(svc_time);
220 /**
221 * The idea here is not to be complete, but to get service times
222 * for only well-defined types. For example, we don't include
223 * LOG_TCP_REFRESH_FAIL because its not really a cache hit
224 * (we *tried* to validate it, but failed).
225 */
226
227 switch (logType.oldType) {
228
229 case LOG_TCP_REFRESH_UNMODIFIED:
230 statCounter.client_http.nearHitSvcTime.count(svc_time);
231 break;
232
233 case LOG_TCP_INM_HIT:
234 case LOG_TCP_IMS_HIT:
235 statCounter.client_http.nearMissSvcTime.count(svc_time);
236 break;
237
238 case LOG_TCP_HIT:
239
240 case LOG_TCP_MEM_HIT:
241
242 case LOG_TCP_OFFLINE_HIT:
243 statCounter.client_http.hitSvcTime.count(svc_time);
244 break;
245
246 case LOG_TCP_MISS:
247
248 case LOG_TCP_CLIENT_REFRESH_MISS:
249 statCounter.client_http.missSvcTime.count(svc_time);
250 break;
251
252 default:
253 /* make compiler warnings go away */
254 break;
255 }
256 }
257
258 bool
259 clientPingHasFinished(ping_data const *aPing)
260 {
261 if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
262 return true;
263
264 return false;
265 }
266
267 void
268 clientUpdateHierCounters(HierarchyLogEntry * someEntry)
269 {
270 ping_data *i;
271
272 switch (someEntry->code) {
273 #if USE_CACHE_DIGESTS
274
275 case CD_PARENT_HIT:
276
277 case CD_SIBLING_HIT:
278 ++ statCounter.cd.times_used;
279 break;
280 #endif
281
282 case SIBLING_HIT:
283
284 case PARENT_HIT:
285
286 case FIRST_PARENT_MISS:
287
288 case CLOSEST_PARENT_MISS:
289 ++ statCounter.icp.times_used;
290 i = &someEntry->ping;
291
292 if (clientPingHasFinished(i))
293 statCounter.icp.querySvcTime.count(tvSubUsec(i->start, i->stop));
294
295 if (i->timeout)
296 ++ statCounter.icp.query_timeouts;
297
298 break;
299
300 case CLOSEST_PARENT:
301
302 case CLOSEST_DIRECT:
303 ++ statCounter.netdb.times_used;
304
305 break;
306
307 default:
308 break;
309 }
310 }
311
312 void
313 ClientHttpRequest::updateCounters()
314 {
315 clientUpdateStatCounters(logType);
316
317 if (request->errType != ERR_NONE)
318 ++ statCounter.client_http.errors;
319
320 clientUpdateStatHistCounters(logType,
321 tvSubMsec(al->cache.start_time, current_time));
322
323 clientUpdateHierCounters(&request->hier);
324 }
325
326 void
327 prepareLogWithRequestDetails(HttpRequest * request, AccessLogEntry::Pointer &aLogEntry)
328 {
329 assert(request);
330 assert(aLogEntry != NULL);
331
332 if (Config.onoff.log_mime_hdrs) {
333 MemBuf mb;
334 mb.init();
335 request->header.packInto(&mb);
336 //This is the request after adaptation or redirection
337 aLogEntry->headers.adapted_request = xstrdup(mb.buf);
338
339 // the virgin request is saved to aLogEntry->request
340 if (aLogEntry->request) {
341 mb.reset();
342 aLogEntry->request->header.packInto(&mb);
343 aLogEntry->headers.request = xstrdup(mb.buf);
344 }
345
346 #if USE_ADAPTATION
347 const Adaptation::History::Pointer ah = request->adaptLogHistory();
348 if (ah != NULL) {
349 mb.reset();
350 ah->lastMeta.packInto(&mb);
351 aLogEntry->adapt.last_meta = xstrdup(mb.buf);
352 }
353 #endif
354
355 mb.clean();
356 }
357
358 #if ICAP_CLIENT
359 const Adaptation::Icap::History::Pointer ih = request->icapHistory();
360 if (ih != NULL)
361 ih->processingTime(aLogEntry->icap.processingTime);
362 #endif
363
364 aLogEntry->http.method = request->method;
365 aLogEntry->http.version = request->http_ver;
366 aLogEntry->hier = request->hier;
367 aLogEntry->cache.extuser = request->extacl_user.termedBuf();
368
369 // Adapted request, if any, inherits and then collects all the stats, but
370 // the virgin request gets logged instead; copy the stats to log them.
371 // TODO: avoid losses by keeping these stats in a shared history object?
372 if (aLogEntry->request) {
373 aLogEntry->request->dnsWait = request->dnsWait;
374 aLogEntry->request->errType = request->errType;
375 aLogEntry->request->errDetail = request->errDetail;
376 }
377 }
378
379 void
380 ClientHttpRequest::logRequest()
381 {
382 if (!out.size && logType.oldType == LOG_TAG_NONE)
383 debugs(33, 5, "logging half-baked transaction: " << log_uri);
384
385 al->icp.opcode = ICP_INVALID;
386 al->url = log_uri;
387 debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
388
389 if (al->reply) {
390 al->http.code = al->reply->sline.status();
391 al->http.content_type = al->reply->content_type.termedBuf();
392 } else if (loggingEntry() && loggingEntry()->mem_obj) {
393 al->http.code = loggingEntry()->mem_obj->getReply()->sline.status();
394 al->http.content_type = loggingEntry()->mem_obj->getReply()->content_type.termedBuf();
395 }
396
397 debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
398
399 if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
400 al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
401
402 al->http.clientRequestSz.header = req_sz;
403 // the virgin request is saved to al->request
404 if (al->request && al->request->body_pipe)
405 al->http.clientRequestSz.payloadData = al->request->body_pipe->producedSize();
406 al->http.clientReplySz.header = out.headers_sz;
407 // XXX: calculate without payload encoding or headers !!
408 al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
409
410 al->cache.highOffset = out.offset;
411
412 al->cache.code = logType;
413
414 tvSub(al->cache.trTime, al->cache.start_time, current_time);
415
416 if (request)
417 prepareLogWithRequestDetails(request, al);
418
419 if (getConn() != NULL && getConn()->clientConnection != NULL && getConn()->clientConnection->rfc931[0])
420 al->cache.rfc931 = getConn()->clientConnection->rfc931;
421
422 #if USE_OPENSSL && 0
423
424 /* This is broken. Fails if the connection has been closed. Needs
425 * to snarf the ssl details some place earlier..
426 */
427 if (getConn() != NULL)
428 al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl);
429
430 #endif
431
432 /* Add notes (if we have a request to annotate) */
433 if (request) {
434 SBuf matched;
435 for (auto h: Config.notes) {
436 if (h->match(request, al->reply, NULL, matched)) {
437 request->notes()->add(h->key(), matched);
438 debugs(33, 3, h->key() << " " << matched);
439 }
440 }
441 // The al->notes and request->notes must point to the same object.
442 al->syncNotes(request);
443 }
444
445 ACLFilledChecklist checklist(NULL, request, NULL);
446 if (al->reply) {
447 checklist.reply = al->reply;
448 HTTPMSGLOCK(checklist.reply);
449 }
450
451 if (request) {
452 HTTPMSGUNLOCK(al->adapted_request);
453 al->adapted_request = request;
454 HTTPMSGLOCK(al->adapted_request);
455 }
456 accessLogLog(al, &checklist);
457
458 bool updatePerformanceCounters = true;
459 if (Config.accessList.stats_collection) {
460 ACLFilledChecklist statsCheck(Config.accessList.stats_collection, request, NULL);
461 if (al->reply) {
462 statsCheck.reply = al->reply;
463 HTTPMSGLOCK(statsCheck.reply);
464 }
465 updatePerformanceCounters = statsCheck.fastCheck().allowed();
466 }
467
468 if (updatePerformanceCounters) {
469 if (request)
470 updateCounters();
471
472 if (getConn() != NULL && getConn()->clientConnection != NULL)
473 clientdbUpdate(getConn()->clientConnection->remote, logType, AnyP::PROTO_HTTP, out.size);
474 }
475 }
476
477 void
478 ClientHttpRequest::freeResources()
479 {
480 safe_free(uri);
481 safe_free(log_uri);
482 safe_free(redirect.location);
483 range_iter.boundary.clean();
484 HTTPMSGUNLOCK(request);
485
486 if (client_stream.tail)
487 clientStreamAbort((clientStreamNode *)client_stream.tail->data, this);
488 }
489
490 void
491 httpRequestFree(void *data)
492 {
493 ClientHttpRequest *http = (ClientHttpRequest *)data;
494 assert(http != NULL);
495 delete http;
496 }
497
498 /* This is a handler normally called by comm_close() */
499 void ConnStateData::connStateClosed(const CommCloseCbParams &)
500 {
501 deleteThis("ConnStateData::connStateClosed");
502 }
503
504 #if USE_AUTH
505 void
506 ConnStateData::setAuth(const Auth::UserRequest::Pointer &aur, const char *by)
507 {
508 if (auth_ == NULL) {
509 if (aur != NULL) {
510 debugs(33, 2, "Adding connection-auth to " << clientConnection << " from " << by);
511 auth_ = aur;
512 }
513 return;
514 }
515
516 // clobered with self-pointer
517 // NP: something nasty is going on in Squid, but harmless.
518 if (aur == auth_) {
519 debugs(33, 2, "WARNING: Ignoring duplicate connection-auth for " << clientConnection << " from " << by);
520 return;
521 }
522
523 /*
524 * Connection-auth relies on a single set of credentials being preserved
525 * for all requests on a connection once they have been setup.
526 * There are several things which need to happen to preserve security
527 * when connection-auth credentials change unexpectedly or are unset.
528 *
529 * 1) auth helper released from any active state
530 *
531 * They can only be reserved by a handshake process which this
532 * connection can now never complete.
533 * This prevents helpers hanging when their connections close.
534 *
535 * 2) pinning is expected to be removed and server conn closed
536 *
537 * The upstream link is authenticated with the same credentials.
538 * Expecting the same level of consistency we should have received.
539 * This prevents upstream being faced with multiple or missing
540 * credentials after authentication.
541 * NP: un-pin is left to the cleanup in ConnStateData::swanSong()
542 * we just trigger that cleanup here via comm_reset_close() or
543 * ConnStateData::stopReceiving()
544 *
545 * 3) the connection needs to close.
546 *
547 * This prevents attackers injecting requests into a connection,
548 * or gateways wrongly multiplexing users into a single connection.
549 *
550 * When credentials are missing closure needs to follow an auth
551 * challenge for best recovery by the client.
552 *
553 * When credentials change there is nothing we can do but abort as
554 * fast as possible. Sending TCP RST instead of an HTTP response
555 * is the best-case action.
556 */
557
558 // clobbered with nul-pointer
559 if (aur == NULL) {
560 debugs(33, 2, "WARNING: Graceful closure on " << clientConnection << " due to connection-auth erase from " << by);
561 auth_->releaseAuthServer();
562 auth_ = NULL;
563 // XXX: need to test whether the connection re-auth challenge is sent. If not, how to trigger it from here.
564 // NP: the current situation seems to fix challenge loops in Safari without visible issues in others.
565 // we stop receiving more traffic but can leave the Job running to terminate after the error or challenge is delivered.
566 stopReceiving("connection-auth removed");
567 return;
568 }
569
570 // clobbered with alternative credentials
571 if (aur != auth_) {
572 debugs(33, 2, "ERROR: Closing " << clientConnection << " due to change of connection-auth from " << by);
573 auth_->releaseAuthServer();
574 auth_ = NULL;
575 // this is a fatal type of problem.
576 // Close the connection immediately with TCP RST to abort all traffic flow
577 comm_reset_close(clientConnection);
578 return;
579 }
580
581 /* NOT REACHABLE */
582 }
583 #endif
584
585 // cleans up before destructor is called
586 void
587 ConnStateData::swanSong()
588 {
589 debugs(33, 2, HERE << clientConnection);
590 checkLogging();
591
592 flags.readMore = false;
593 clientdbEstablished(clientConnection->remote, -1); /* decrement */
594 pipeline.terminateAll(0);
595
596 unpinConnection(true);
597
598 Server::swanSong(); // closes the client connection
599
600 #if USE_AUTH
601 // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
602 setAuth(NULL, "ConnStateData::SwanSong cleanup");
603 #endif
604
605 flags.swanSang = true;
606 }
607
608 bool
609 ConnStateData::isOpen() const
610 {
611 return cbdataReferenceValid(this) && // XXX: checking "this" in a method
612 Comm::IsConnOpen(clientConnection) &&
613 !fd_table[clientConnection->fd].closing();
614 }
615
616 ConnStateData::~ConnStateData()
617 {
618 debugs(33, 3, HERE << clientConnection);
619
620 if (isOpen())
621 debugs(33, DBG_IMPORTANT, "BUG: ConnStateData did not close " << clientConnection);
622
623 if (!flags.swanSang)
624 debugs(33, DBG_IMPORTANT, "BUG: ConnStateData was not destroyed properly; " << clientConnection);
625
626 if (bodyPipe != NULL)
627 stopProducingFor(bodyPipe, false);
628
629 delete bodyParser; // TODO: pool
630
631 #if USE_OPENSSL
632 delete sslServerBump;
633 #endif
634 }
635
636 /**
637 * clientSetKeepaliveFlag() sets request->flags.proxyKeepalive.
638 * This is the client-side persistent connection flag. We need
639 * to set this relatively early in the request processing
640 * to handle hacks for broken servers and clients.
641 */
642 void
643 clientSetKeepaliveFlag(ClientHttpRequest * http)
644 {
645 HttpRequest *request = http->request;
646
647 debugs(33, 3, "http_ver = " << request->http_ver);
648 debugs(33, 3, "method = " << request->method);
649
650 // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
651 request->flags.proxyKeepalive = request->persistent();
652 }
653
654 /// checks body length of non-chunked requests
655 static int
656 clientIsContentLengthValid(HttpRequest * r)
657 {
658 // No Content-Length means this request just has no body, but conflicting
659 // Content-Lengths mean a message framing error (RFC 7230 Section 3.3.3 #4).
660 if (r->header.conflictingContentLength())
661 return 0;
662
663 switch (r->method.id()) {
664
665 case Http::METHOD_GET:
666
667 case Http::METHOD_HEAD:
668 /* We do not want to see a request entity on GET/HEAD requests */
669 return (r->content_length <= 0 || Config.onoff.request_entities);
670
671 default:
672 /* For other types of requests we don't care */
673 return 1;
674 }
675
676 /* NOT REACHED */
677 }
678
679 int
680 clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength)
681 {
682 if (Config.maxRequestBodySize &&
683 bodyLength > Config.maxRequestBodySize)
684 return 1; /* too large */
685
686 return 0;
687 }
688
689 bool
690 ClientHttpRequest::multipartRangeRequest() const
691 {
692 return request->multipartRangeRequest();
693 }
694
695 void
696 clientPackTermBound(String boundary, MemBuf *mb)
697 {
698 mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
699 debugs(33, 6, "buf offset: " << mb->size);
700 }
701
702 void
703 clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
704 {
705 HttpHeader hdr(hoReply);
706 assert(rep);
707 assert(spec);
708
709 /* put boundary */
710 debugs(33, 5, "appending boundary: " << boundary);
711 /* rfc2046 requires to _prepend_ boundary with <crlf>! */
712 mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
713
714 /* stuff the header with required entries and pack it */
715
716 if (rep->header.has(Http::HdrType::CONTENT_TYPE))
717 hdr.putStr(Http::HdrType::CONTENT_TYPE, rep->header.getStr(Http::HdrType::CONTENT_TYPE));
718
719 httpHeaderAddContRange(&hdr, *spec, rep->content_length);
720
721 hdr.packInto(mb);
722 hdr.clean();
723
724 /* append <crlf> (we packed a header, not a reply) */
725 mb->append("\r\n", 2);
726 }
727
728 /** returns expected content length for multi-range replies
729 * note: assumes that httpHdrRangeCanonize has already been called
730 * warning: assumes that HTTP headers for individual ranges at the
731 * time of the actuall assembly will be exactly the same as
732 * the headers when clientMRangeCLen() is called */
733 int
734 ClientHttpRequest::mRangeCLen()
735 {
736 int64_t clen = 0;
737 MemBuf mb;
738
739 assert(memObject());
740
741 mb.init();
742 HttpHdrRange::iterator pos = request->range->begin();
743
744 while (pos != request->range->end()) {
745 /* account for headers for this range */
746 mb.reset();
747 clientPackRangeHdr(memObject()->getReply(),
748 *pos, range_iter.boundary, &mb);
749 clen += mb.size;
750
751 /* account for range content */
752 clen += (*pos)->length;
753
754 debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
755 ++pos;
756 }
757
758 /* account for the terminating boundary */
759 mb.reset();
760
761 clientPackTermBound(range_iter.boundary, &mb);
762
763 clen += mb.size;
764
765 mb.clean();
766
767 return clen;
768 }
769
770 /**
771 * generates a "unique" boundary string for multipart responses
772 * the caller is responsible for cleaning the string */
773 String
774 ClientHttpRequest::rangeBoundaryStr() const
775 {
776 const char *key;
777 String b(APP_FULLNAME);
778 b.append(":",1);
779 key = storeEntry()->getMD5Text();
780 b.append(key, strlen(key));
781 return b;
782 }
783
784 /**
785 * Write a chunk of data to a client socket. If the reply is present,
786 * send the reply headers down the wire too, and clean them up when
787 * finished.
788 * Pre-condition:
789 * The request is one backed by a connection, not an internal request.
790 * data context is not NULL
791 * There are no more entries in the stream chain.
792 */
793 void
794 clientSocketRecipient(clientStreamNode * node, ClientHttpRequest * http,
795 HttpReply * rep, StoreIOBuffer receivedData)
796 {
797 // dont tryt to deliver if client already ABORTED
798 if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
799 return;
800
801 /* Test preconditions */
802 assert(node != NULL);
803 PROF_start(clientSocketRecipient);
804 /* TODO: handle this rather than asserting
805 * - it should only ever happen if we cause an abort and
806 * the callback chain loops back to here, so we can simply return.
807 * However, that itself shouldn't happen, so it stays as an assert for now.
808 */
809 assert(cbdataReferenceValid(node));
810 assert(node->node.next == NULL);
811 Http::StreamPointer context = dynamic_cast<Http::Stream *>(node->data.getRaw());
812 assert(context != NULL);
813
814 /* TODO: check offset is what we asked for */
815
816 // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
817 if (context != http->getConn()->pipeline.front())
818 context->deferRecipientForLater(node, rep, receivedData);
819 else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending
820 context->deferRecipientForLater(node, rep, receivedData);
821 else
822 http->getConn()->handleReply(rep, receivedData);
823
824 PROF_stop(clientSocketRecipient);
825 }
826
827 /**
828 * Called when a downstream node is no longer interested in
829 * our data. As we are a terminal node, this means on aborts
830 * only
831 */
832 void
833 clientSocketDetach(clientStreamNode * node, ClientHttpRequest * http)
834 {
835 /* Test preconditions */
836 assert(node != NULL);
837 /* TODO: handle this rather than asserting
838 * - it should only ever happen if we cause an abort and
839 * the callback chain loops back to here, so we can simply return.
840 * However, that itself shouldn't happen, so it stays as an assert for now.
841 */
842 assert(cbdataReferenceValid(node));
843 /* Set null by ContextFree */
844 assert(node->node.next == NULL);
845 /* this is the assert discussed above */
846 assert(NULL == dynamic_cast<Http::Stream *>(node->data.getRaw()));
847 /* We are only called when the client socket shutsdown.
848 * Tell the prev pipeline member we're finished
849 */
850 clientStreamDetach(node, http);
851 }
852
853 void
854 ConnStateData::readNextRequest()
855 {
856 debugs(33, 5, HERE << clientConnection << " reading next req");
857
858 fd_note(clientConnection->fd, "Idle client: Waiting for next request");
859 /**
860 * Set the timeout BEFORE calling readSomeData().
861 */
862 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
863 AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
864 TimeoutDialer, this, ConnStateData::requestTimeout);
865 commSetConnTimeout(clientConnection, clientConnection->timeLeft(idleTimeout()), timeoutCall);
866
867 readSomeData();
868 /** Please don't do anything with the FD past here! */
869 }
870
871 static void
872 ClientSocketContextPushDeferredIfNeeded(Http::StreamPointer deferredRequest, ConnStateData * conn)
873 {
874 debugs(33, 2, HERE << conn->clientConnection << " Sending next");
875
876 /** If the client stream is waiting on a socket write to occur, then */
877
878 if (deferredRequest->flags.deferred) {
879 /** NO data is allowed to have been sent. */
880 assert(deferredRequest->http->out.size == 0);
881 /** defer now. */
882 clientSocketRecipient(deferredRequest->deferredparams.node,
883 deferredRequest->http,
884 deferredRequest->deferredparams.rep,
885 deferredRequest->deferredparams.queuedBuffer);
886 }
887
888 /** otherwise, the request is still active in a callbacksomewhere,
889 * and we are done
890 */
891 }
892
893 void
894 ConnStateData::kick()
895 {
896 if (!Comm::IsConnOpen(clientConnection)) {
897 debugs(33, 2, clientConnection << " Connection was closed");
898 return;
899 }
900
901 if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
902 debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
903 clientConnection->close();
904 return;
905 }
906
907 /** \par
908 * We are done with the response, and we are either still receiving request
909 * body (early response!) or have already stopped receiving anything.
910 *
911 * If we are still receiving, then clientParseRequest() below will fail.
912 * (XXX: but then we will call readNextRequest() which may succeed and
913 * execute a smuggled request as we are not done with the current request).
914 *
915 * If we stopped because we got everything, then try the next request.
916 *
917 * If we stopped receiving because of an error, then close now to avoid
918 * getting stuck and to prevent accidental request smuggling.
919 */
920
921 if (const char *reason = stoppedReceiving()) {
922 debugs(33, 3, "closing for earlier request error: " << reason);
923 clientConnection->close();
924 return;
925 }
926
927 /** \par
928 * Attempt to parse a request from the request buffer.
929 * If we've been fed a pipelined request it may already
930 * be in our read buffer.
931 *
932 \par
933 * This needs to fall through - if we're unlucky and parse the _last_ request
934 * from our read buffer we may never re-register for another client read.
935 */
936
937 if (clientParseRequests()) {
938 debugs(33, 3, clientConnection << ": parsed next request from buffer");
939 }
940
941 /** \par
942 * Either we need to kick-start another read or, if we have
943 * a half-closed connection, kill it after the last request.
944 * This saves waiting for half-closed connections to finished being
945 * half-closed _AND_ then, sometimes, spending "Timeout" time in
946 * the keepalive "Waiting for next request" state.
947 */
948 if (commIsHalfClosed(clientConnection->fd) && pipeline.empty()) {
949 debugs(33, 3, "half-closed client with no pending requests, closing");
950 clientConnection->close();
951 return;
952 }
953
954 /** \par
955 * At this point we either have a parsed request (which we've
956 * kicked off the processing for) or not. If we have a deferred
957 * request (parsed but deferred for pipeling processing reasons)
958 * then look at processing it. If not, simply kickstart
959 * another read.
960 */
961 Http::StreamPointer deferredRequest = pipeline.front();
962 if (deferredRequest != nullptr) {
963 debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
964 ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
965 } else if (flags.readMore) {
966 debugs(33, 3, clientConnection << ": calling readNextRequest()");
967 readNextRequest();
968 } else {
969 // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
970 debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
971 }
972 }
973
974 void
975 ConnStateData::stopSending(const char *error)
976 {
977 debugs(33, 4, HERE << "sending error (" << clientConnection << "): " << error <<
978 "; old receiving error: " <<
979 (stoppedReceiving() ? stoppedReceiving_ : "none"));
980
981 if (const char *oldError = stoppedSending()) {
982 debugs(33, 3, HERE << "already stopped sending: " << oldError);
983 return; // nothing has changed as far as this connection is concerned
984 }
985 stoppedSending_ = error;
986
987 if (!stoppedReceiving()) {
988 if (const int64_t expecting = mayNeedToReadMoreBody()) {
989 debugs(33, 5, HERE << "must still read " << expecting <<
990 " request body bytes with " << inBuf.length() << " unused");
991 return; // wait for the request receiver to finish reading
992 }
993 }
994
995 clientConnection->close();
996 }
997
998 void
999 ConnStateData::afterClientWrite(size_t size)
1000 {
1001 if (pipeline.empty())
1002 return;
1003
1004 auto ctx = pipeline.front();
1005 if (size) {
1006 statCounter.client_http.kbytes_out += size;
1007 if (ctx->http->logType.isTcpHit())
1008 statCounter.client_http.hit_kbytes_out += size;
1009 }
1010 ctx->writeComplete(size);
1011 }
1012
1013 Http::Stream *
1014 ConnStateData::abortRequestParsing(const char *const uri)
1015 {
1016 ClientHttpRequest *http = new ClientHttpRequest(this);
1017 http->req_sz = inBuf.length();
1018 http->uri = xstrdup(uri);
1019 setLogUri (http, uri);
1020 auto *context = new Http::Stream(clientConnection, http);
1021 StoreIOBuffer tempBuffer;
1022 tempBuffer.data = context->reqbuf;
1023 tempBuffer.length = HTTP_REQBUF_SZ;
1024 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
1025 clientReplyStatus, new clientReplyContext(http), clientSocketRecipient,
1026 clientSocketDetach, context, tempBuffer);
1027 return context;
1028 }
1029
1030 void
1031 ConnStateData::startShutdown()
1032 {
1033 // RegisteredRunner API callback - Squid has been shut down
1034
1035 // if connection is idle terminate it now,
1036 // otherwise wait for grace period to end
1037 if (pipeline.empty())
1038 endingShutdown();
1039 }
1040
1041 void
1042 ConnStateData::endingShutdown()
1043 {
1044 // RegisteredRunner API callback - Squid shutdown grace period is over
1045
1046 // force the client connection to close immediately
1047 // swanSong() in the close handler will cleanup.
1048 if (Comm::IsConnOpen(clientConnection))
1049 clientConnection->close();
1050 }
1051
1052 char *
1053 skipLeadingSpace(char *aString)
1054 {
1055 char *result = aString;
1056
1057 while (xisspace(*aString))
1058 ++aString;
1059
1060 return result;
1061 }
1062
1063 /**
1064 * 'end' defaults to NULL for backwards compatibility
1065 * remove default value if we ever get rid of NULL-terminated
1066 * request buffers.
1067 */
1068 const char *
1069 findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
1070 {
1071 if (NULL == end) {
1072 end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1073 assert(end);
1074 }
1075
1076 for (; end > uriAndHTTPVersion; --end) {
1077 if (*end == '\n' || *end == '\r')
1078 continue;
1079
1080 if (xisspace(*end)) {
1081 if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1082 return end + 1;
1083 else
1084 break;
1085 }
1086 }
1087
1088 return NULL;
1089 }
1090
1091 void
1092 setLogUri(ClientHttpRequest * http, char const *uri, bool cleanUrl)
1093 {
1094 safe_free(http->log_uri);
1095
1096 if (!cleanUrl)
1097 // The uri is already clean just dump it.
1098 http->log_uri = xstrndup(uri, MAX_URL);
1099 else {
1100 int flags = 0;
1101 switch (Config.uri_whitespace) {
1102 case URI_WHITESPACE_ALLOW:
1103 flags |= RFC1738_ESCAPE_NOSPACE;
1104
1105 case URI_WHITESPACE_ENCODE:
1106 flags |= RFC1738_ESCAPE_UNESCAPED;
1107 http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
1108 break;
1109
1110 case URI_WHITESPACE_CHOP: {
1111 flags |= RFC1738_ESCAPE_NOSPACE;
1112 flags |= RFC1738_ESCAPE_UNESCAPED;
1113 http->log_uri = xstrndup(rfc1738_do_escape(uri, flags), MAX_URL);
1114 int pos = strcspn(http->log_uri, w_space);
1115 http->log_uri[pos] = '\0';
1116 }
1117 break;
1118
1119 case URI_WHITESPACE_DENY:
1120 case URI_WHITESPACE_STRIP:
1121 default: {
1122 const char *t;
1123 char *tmp_uri = static_cast<char*>(xmalloc(strlen(uri) + 1));
1124 char *q = tmp_uri;
1125 t = uri;
1126 while (*t) {
1127 if (!xisspace(*t)) {
1128 *q = *t;
1129 ++q;
1130 }
1131 ++t;
1132 }
1133 *q = '\0';
1134 http->log_uri = xstrndup(rfc1738_escape_unescaped(tmp_uri), MAX_URL);
1135 xfree(tmp_uri);
1136 }
1137 break;
1138 }
1139 }
1140 }
1141
1142 static void
1143 prepareAcceleratedURL(ConnStateData * conn, ClientHttpRequest *http, const Http1::RequestParserPointer &hp)
1144 {
1145 int vhost = conn->port->vhost;
1146 int vport = conn->port->vport;
1147 static char ipbuf[MAX_IPSTRLEN];
1148
1149 http->flags.accel = true;
1150
1151 /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1152
1153 static const SBuf cache_object("cache_object://");
1154 if (hp->requestUri().startsWith(cache_object))
1155 return; /* already in good shape */
1156
1157 // XXX: re-use proper URL parser for this
1158 SBuf url = hp->requestUri(); // use full provided URI if we abort
1159 do { // use a loop so we can break out of it
1160 ::Parser::Tokenizer tok(url);
1161 if (tok.skip('/')) // origin-form URL already.
1162 break;
1163
1164 if (conn->port->vhost)
1165 return; /* already in good shape */
1166
1167 // skip the URI scheme
1168 static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
1169 static const SBuf uriSchemeEnd("://");
1170 if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
1171 break;
1172
1173 // skip the authority segment
1174 // RFC 3986 complex nested ABNF for "authority" boils down to this:
1175 static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
1176 CharacterSet::HEXDIG + CharacterSet::ALPHA + CharacterSet::DIGIT;
1177 if (!tok.skipAll(authority))
1178 break;
1179
1180 static const SBuf slashUri("/");
1181 const SBuf t = tok.remaining();
1182 if (t.isEmpty())
1183 url = slashUri;
1184 else if (t[0]=='/') // looks like path
1185 url = t;
1186 else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
1187 url = slashUri;
1188 url.append(t);
1189 } // else do nothing. invalid path
1190
1191 } while(false);
1192
1193 #if SHOULD_REJECT_UNKNOWN_URLS
1194 // reject URI which are not well-formed even after the processing above
1195 if (url.isEmpty() || url[0] != '/') {
1196 hp->parseStatusCode = Http::scBadRequest;
1197 return conn->abortRequestParsing("error:invalid-request");
1198 }
1199 #endif
1200
1201 if (vport < 0)
1202 vport = http->getConn()->clientConnection->local.port();
1203
1204 const bool switchedToHttps = conn->switchedToHttps();
1205 const bool tryHostHeader = vhost || switchedToHttps;
1206 char *host = NULL;
1207 if (tryHostHeader && (host = hp->getHeaderField("Host"))) {
1208 debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
1209 char thost[256];
1210 if (vport > 0) {
1211 thost[0] = '\0';
1212 char *t = NULL;
1213 if (host[strlen(host)] != ']' && (t = strrchr(host,':')) != NULL) {
1214 strncpy(thost, host, (t-host));
1215 snprintf(thost+(t-host), sizeof(thost)-(t-host), ":%d", vport);
1216 host = thost;
1217 } else if (!t) {
1218 snprintf(thost, sizeof(thost), "%s:%d",host, vport);
1219 host = thost;
1220 }
1221 } // else nothing to alter port-wise.
1222 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen + strlen(host);
1223 http->uri = (char *)xcalloc(url_sz, 1);
1224 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1225 snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(url));
1226 debugs(33, 5, "ACCEL VHOST REWRITE: " << http->uri);
1227 } else if (conn->port->defaultsite /* && !vhost */) {
1228 debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
1229 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
1230 strlen(conn->port->defaultsite);
1231 http->uri = (char *)xcalloc(url_sz, 1);
1232 char vportStr[32];
1233 vportStr[0] = '\0';
1234 if (vport > 0) {
1235 snprintf(vportStr, sizeof(vportStr),":%d",vport);
1236 }
1237 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1238 snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
1239 SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
1240 debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << http->uri);
1241 } else if (vport > 0 /* && (!vhost || no Host:) */) {
1242 debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
1243 /* Put the local socket IP address as the hostname, with whatever vport we found */
1244 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
1245 http->uri = (char *)xcalloc(url_sz, 1);
1246 http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
1247 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1248 snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1249 SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
1250 debugs(33, 5, "ACCEL VPORT REWRITE: " << http->uri);
1251 }
1252 }
1253
1254 static void
1255 prepareTransparentURL(ConnStateData * conn, ClientHttpRequest *http, const Http1::RequestParserPointer &hp)
1256 {
1257 // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
1258 if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1259 return; /* already in good shape */
1260
1261 /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1262
1263 if (const char *host = hp->getHeaderField("Host")) {
1264 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen +
1265 strlen(host);
1266 http->uri = (char *)xcalloc(url_sz, 1);
1267 const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1268 snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
1269 SQUIDSBUFPRINT(scheme), host, SQUIDSBUFPRINT(hp->requestUri()));
1270 debugs(33, 5, "TRANSPARENT HOST REWRITE: " << http->uri);
1271 } else {
1272 /* Put the local socket IP address as the hostname. */
1273 const int url_sz = hp->requestUri().length() + 32 + Config.appendDomainLen;
1274 http->uri = (char *)xcalloc(url_sz, 1);
1275 static char ipbuf[MAX_IPSTRLEN];
1276 http->getConn()->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
1277 const SBuf &scheme = AnyP::UriScheme(http->getConn()->transferProtocol.protocol).image();
1278 snprintf(http->uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1279 SQUIDSBUFPRINT(scheme),
1280 ipbuf, http->getConn()->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
1281 debugs(33, 5, "TRANSPARENT REWRITE: " << http->uri);
1282 }
1283 }
1284
1285 /** Parse an HTTP request
1286 *
1287 * \note Sets result->flags.parsed_ok to 0 if failed to parse the request,
1288 * to 1 if the request was correctly parsed.
1289 * \param[in] csd a ConnStateData. The caller must make sure it is not null
1290 * \param[in] hp an Http1::RequestParser
1291 * \param[out] mehtod_p will be set as a side-effect of the parsing.
1292 * Pointed-to value will be set to Http::METHOD_NONE in case of
1293 * parsing failure
1294 * \param[out] http_ver will be set as a side-effect of the parsing
1295 * \return NULL on incomplete requests,
1296 * a Http::Stream on success or failure.
1297 */
1298 Http::Stream *
1299 parseHttpRequest(ConnStateData *csd, const Http1::RequestParserPointer &hp)
1300 {
1301 /* Attempt to parse the first line; this will define where the method, url, version and header begin */
1302 {
1303 const bool parsedOk = hp->parse(csd->inBuf);
1304
1305 // sync the buffers after parsing.
1306 csd->inBuf = hp->remaining();
1307
1308 if (hp->needsMoreData()) {
1309 debugs(33, 5, "Incomplete request, waiting for end of request line");
1310 return NULL;
1311 }
1312
1313 if (csd->mayTunnelUnsupportedProto()) {
1314 csd->preservedClientData = hp->parsed();
1315 csd->preservedClientData.append(csd->inBuf);
1316 }
1317
1318 if (!parsedOk) {
1319 const bool tooBig =
1320 hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge ||
1321 hp->parseStatusCode == Http::scUriTooLong;
1322 auto result = csd->abortRequestParsing(
1323 tooBig ? "error:request-too-large" : "error:invalid-request");
1324 // assume that remaining leftovers belong to this bad request
1325 if (!csd->inBuf.isEmpty())
1326 csd->consumeInput(csd->inBuf.length());
1327 return result;
1328 }
1329 }
1330
1331 /* We know the whole request is in parser now */
1332 debugs(11, 2, "HTTP Client " << csd->clientConnection);
1333 debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
1334 hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
1335 hp->mimeHeader() <<
1336 "\n----------");
1337
1338 /* deny CONNECT via accelerated ports */
1339 if (hp->method() == Http::METHOD_CONNECT && csd->port != NULL && csd->port->flags.accelSurrogate) {
1340 debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->transferProtocol << " Accelerator port " << csd->port->s.port());
1341 debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1342 hp->parseStatusCode = Http::scMethodNotAllowed;
1343 return csd->abortRequestParsing("error:method-not-allowed");
1344 }
1345
1346 /* RFC 7540 section 11.6 registers the method PRI as HTTP/2 specific
1347 * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
1348 * If seen it signals a broken client or proxy has corrupted the traffic.
1349 */
1350 if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
1351 debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << csd->transferProtocol << " port " << csd->port->s.port());
1352 debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1353 hp->parseStatusCode = Http::scMethodNotAllowed;
1354 return csd->abortRequestParsing("error:method-not-allowed");
1355 }
1356
1357 if (hp->method() == Http::METHOD_NONE) {
1358 debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1359 hp->parseStatusCode = Http::scMethodNotAllowed;
1360 return csd->abortRequestParsing("error:unsupported-request-method");
1361 }
1362
1363 // Process headers after request line
1364 debugs(33, 3, "complete request received. " <<
1365 "prefix_sz = " << hp->messageHeaderSize() <<
1366 ", request-line-size=" << hp->firstLineSize() <<
1367 ", mime-header-size=" << hp->headerBlockSize() <<
1368 ", mime header block:\n" << hp->mimeHeader() << "\n----------");
1369
1370 /* Ok, all headers are received */
1371 ClientHttpRequest *http = new ClientHttpRequest(csd);
1372
1373 http->req_sz = hp->messageHeaderSize();
1374 Http::Stream *result = new Http::Stream(csd->clientConnection, http);
1375
1376 StoreIOBuffer tempBuffer;
1377 tempBuffer.data = result->reqbuf;
1378 tempBuffer.length = HTTP_REQBUF_SZ;
1379
1380 ClientStreamData newServer = new clientReplyContext(http);
1381 ClientStreamData newClient = result;
1382 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
1383 clientReplyStatus, newServer, clientSocketRecipient,
1384 clientSocketDetach, newClient, tempBuffer);
1385
1386 /* set url */
1387 debugs(33,5, "Prepare absolute URL from " <<
1388 (csd->transparent()?"intercept":(csd->port->flags.accelSurrogate ? "accel":"")));
1389 /* Rewrite the URL in transparent or accelerator mode */
1390 /* NP: there are several cases to traverse here:
1391 * - standard mode (forward proxy)
1392 * - transparent mode (TPROXY)
1393 * - transparent mode with failures
1394 * - intercept mode (NAT)
1395 * - intercept mode with failures
1396 * - accelerator mode (reverse proxy)
1397 * - internal relative-URL
1398 * - mixed combos of the above with internal URL
1399 * - remote interception with PROXY protocol
1400 * - remote reverse-proxy with PROXY protocol
1401 */
1402 if (csd->transparent()) {
1403 /* intercept or transparent mode, properly working with no failures */
1404 prepareTransparentURL(csd, http, hp);
1405
1406 } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
1407 /* internal URL mode */
1408 /* prepend our name & port */
1409 http->uri = xstrdup(internalLocalUri(NULL, hp->requestUri()));
1410 // We just re-wrote the URL. Must replace the Host: header.
1411 // But have not parsed there yet!! flag for local-only handling.
1412 http->flags.internal = true;
1413
1414 } else if (csd->port->flags.accelSurrogate || csd->switchedToHttps()) {
1415 /* accelerator mode */
1416 prepareAcceleratedURL(csd, http, hp);
1417 }
1418
1419 if (!http->uri) {
1420 /* No special rewrites have been applied above, use the
1421 * requested url. may be rewritten later, so make extra room */
1422 int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
1423 http->uri = (char *)xcalloc(url_sz, 1);
1424 SBufToCstring(http->uri, hp->requestUri());
1425 }
1426
1427 result->flags.parsed_ok = 1;
1428 return result;
1429 }
1430
1431 bool
1432 ConnStateData::connFinishedWithConn(int size)
1433 {
1434 if (size == 0) {
1435 if (pipeline.empty() && inBuf.isEmpty()) {
1436 /* no current or pending requests */
1437 debugs(33, 4, HERE << clientConnection << " closed");
1438 return true;
1439 } else if (!Config.onoff.half_closed_clients) {
1440 /* admin doesn't want to support half-closed client sockets */
1441 debugs(33, 3, HERE << clientConnection << " aborted (half_closed_clients disabled)");
1442 pipeline.terminateAll(0);
1443 return true;
1444 }
1445 }
1446
1447 return false;
1448 }
1449
1450 void
1451 ConnStateData::consumeInput(const size_t byteCount)
1452 {
1453 assert(byteCount > 0 && byteCount <= inBuf.length());
1454 inBuf.consume(byteCount);
1455 debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
1456 }
1457
1458 void
1459 ConnStateData::clientAfterReadingRequests()
1460 {
1461 // Were we expecting to read more request body from half-closed connection?
1462 if (mayNeedToReadMoreBody() && commIsHalfClosed(clientConnection->fd)) {
1463 debugs(33, 3, HERE << "truncated body: closing half-closed " << clientConnection);
1464 clientConnection->close();
1465 return;
1466 }
1467
1468 if (flags.readMore)
1469 readSomeData();
1470 }
1471
1472 void
1473 ConnStateData::quitAfterError(HttpRequest *request)
1474 {
1475 // From HTTP p.o.v., we do not have to close after every error detected
1476 // at the client-side, but many such errors do require closure and the
1477 // client-side code is bad at handling errors so we play it safe.
1478 if (request)
1479 request->flags.proxyKeepalive = false;
1480 flags.readMore = false;
1481 debugs(33,4, HERE << "Will close after error: " << clientConnection);
1482 }
1483
1484 #if USE_OPENSSL
1485 bool ConnStateData::serveDelayedError(Http::Stream *context)
1486 {
1487 ClientHttpRequest *http = context->http;
1488
1489 if (!sslServerBump)
1490 return false;
1491
1492 assert(sslServerBump->entry);
1493 // Did we create an error entry while processing CONNECT?
1494 if (!sslServerBump->entry->isEmpty()) {
1495 quitAfterError(http->request);
1496
1497 // Get the saved error entry and send it to the client by replacing the
1498 // ClientHttpRequest store entry with it.
1499 clientStreamNode *node = context->getClientReplyContext();
1500 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1501 assert(repContext);
1502 debugs(33, 5, "Responding with delated error for " << http->uri);
1503 repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
1504
1505 // save the original request for logging purposes
1506 if (!context->http->al->request) {
1507 context->http->al->request = http->request;
1508 HTTPMSGLOCK(context->http->al->request);
1509 }
1510
1511 // Get error details from the fake certificate-peeking request.
1512 http->request->detailError(sslServerBump->request->errType, sslServerBump->request->errDetail);
1513 context->pullData();
1514 return true;
1515 }
1516
1517 // In bump-server-first mode, we have not necessarily seen the intended
1518 // server name at certificate-peeking time. Check for domain mismatch now,
1519 // when we can extract the intended name from the bumped HTTP request.
1520 if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
1521 HttpRequest *request = http->request;
1522 if (!Ssl::checkX509ServerValidity(srvCert.get(), request->url.host())) {
1523 debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
1524 "does not match domainname " << request->url.host());
1525
1526 bool allowDomainMismatch = false;
1527 if (Config.ssl_client.cert_error) {
1528 ACLFilledChecklist check(Config.ssl_client.cert_error, request, dash_str);
1529 check.sslErrors = new Security::CertErrors(Security::CertError(SQUID_X509_V_ERR_DOMAIN_MISMATCH, srvCert));
1530 allowDomainMismatch = check.fastCheck().allowed();
1531 delete check.sslErrors;
1532 check.sslErrors = NULL;
1533 }
1534
1535 if (!allowDomainMismatch) {
1536 quitAfterError(request);
1537
1538 clientStreamNode *node = context->getClientReplyContext();
1539 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1540 assert (repContext);
1541
1542 // Fill the server IP and hostname for error page generation.
1543 HttpRequest::Pointer const & peekerRequest = sslServerBump->request;
1544 request->hier.note(peekerRequest->hier.tcpServer, request->url.host());
1545
1546 // Create an error object and fill it
1547 ErrorState *err = new ErrorState(ERR_SECURE_CONNECT_FAIL, Http::scServiceUnavailable, request);
1548 err->src_addr = clientConnection->remote;
1549 Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail(
1550 SQUID_X509_V_ERR_DOMAIN_MISMATCH,
1551 srvCert.get(), nullptr);
1552 err->detail = errDetail;
1553 // Save the original request for logging purposes.
1554 if (!context->http->al->request) {
1555 context->http->al->request = request;
1556 HTTPMSGLOCK(context->http->al->request);
1557 }
1558 repContext->setReplyToError(request->method, err);
1559 assert(context->http->out.offset == 0);
1560 context->pullData();
1561 return true;
1562 }
1563 }
1564 }
1565
1566 return false;
1567 }
1568 #endif // USE_OPENSSL
1569
1570 /**
1571 * Check on_unsupported_protocol checklist and return true if tunnel mode selected
1572 * or false otherwise
1573 */
1574 bool
1575 clientTunnelOnError(ConnStateData *conn, Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod& method, err_type requestError)
1576 {
1577 if (conn->mayTunnelUnsupportedProto()) {
1578 ACLFilledChecklist checklist(Config.accessList.on_unsupported_protocol, request.getRaw(), nullptr);
1579 checklist.requestErrorType = requestError;
1580 checklist.src_addr = conn->clientConnection->remote;
1581 checklist.my_addr = conn->clientConnection->local;
1582 checklist.conn(conn);
1583 allow_t answer = checklist.fastCheck();
1584 if (answer.allowed() && answer.kind == 1) {
1585 debugs(33, 3, "Request will be tunneled to server");
1586 if (context) {
1587 assert(conn->pipeline.front() == context); // XXX: still assumes HTTP/1 semantics
1588 context->finished(); // Will remove from conn->pipeline queue
1589 }
1590 Comm::SetSelect(conn->clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0);
1591 return conn->initiateTunneledRequest(request, Http::METHOD_NONE, "unknown-protocol", conn->preservedClientData);
1592 } else {
1593 debugs(33, 3, "Continue with returning the error: " << requestError);
1594 }
1595 }
1596
1597 return false;
1598 }
1599
1600 void
1601 clientProcessRequestFinished(ConnStateData *conn, const HttpRequest::Pointer &request)
1602 {
1603 /*
1604 * DPW 2007-05-18
1605 * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
1606 * to here because calling comm_reset_close() causes http to
1607 * be freed before accessing.
1608 */
1609 if (request != NULL && request->flags.resetTcp && Comm::IsConnOpen(conn->clientConnection)) {
1610 debugs(33, 3, HERE << "Sending TCP RST on " << conn->clientConnection);
1611 conn->flags.readMore = false;
1612 comm_reset_close(conn->clientConnection);
1613 }
1614 }
1615
1616 void
1617 clientProcessRequest(ConnStateData *conn, const Http1::RequestParserPointer &hp, Http::Stream *context)
1618 {
1619 ClientHttpRequest *http = context->http;
1620 bool chunked = false;
1621 bool mustReplyToOptions = false;
1622 bool unsupportedTe = false;
1623 bool expectBody = false;
1624
1625 // We already have the request parsed and checked, so we
1626 // only need to go through the final body/conn setup to doCallouts().
1627 assert(http->request);
1628 HttpRequest::Pointer request = http->request;
1629
1630 // temporary hack to avoid splitting this huge function with sensitive code
1631 const bool isFtp = !hp;
1632
1633 // Some blobs below are still HTTP-specific, but we would have to rewrite
1634 // this entire function to remove them from the FTP code path. Connection
1635 // setup and body_pipe preparation blobs are needed for FTP.
1636
1637 request->manager(conn, http->al);
1638
1639 request->flags.accelerated = http->flags.accel;
1640 request->flags.sslBumped=conn->switchedToHttps();
1641 // TODO: decouple http->flags.accel from request->flags.sslBumped
1642 request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
1643 !conn->port->allow_direct : 0;
1644 request->sources |= isFtp ? Http::Message::srcFtp :
1645 ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
1646 #if USE_AUTH
1647 if (request->flags.sslBumped) {
1648 if (conn->getAuth() != NULL)
1649 request->auth_user_request = conn->getAuth();
1650 }
1651 #endif
1652
1653 if (internalCheck(request->url.path())) {
1654 if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
1655 debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
1656 http->flags.internal = true;
1657 } else if (Config.onoff.global_internal_static && internalStaticCheck(request->url.path())) {
1658 debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
1659 request->url.setScheme(AnyP::PROTO_HTTP, "http");
1660 request->url.host(internalHostname());
1661 request->url.port(getMyPort());
1662 http->flags.internal = true;
1663 } else
1664 debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
1665 }
1666
1667 request->flags.internal = http->flags.internal;
1668 setLogUri (http, urlCanonicalClean(request.getRaw()));
1669
1670 if (!isFtp) {
1671 // XXX: for non-HTTP messages instantiate a different Http::Message child type
1672 // for now Squid only supports HTTP requests
1673 const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1674 assert(request->http_ver.protocol == http_ver.protocol);
1675 request->http_ver.major = http_ver.major;
1676 request->http_ver.minor = http_ver.minor;
1677 }
1678
1679 if (request->header.chunked()) {
1680 chunked = true;
1681 } else if (request->header.has(Http::HdrType::TRANSFER_ENCODING)) {
1682 const String te = request->header.getList(Http::HdrType::TRANSFER_ENCODING);
1683 // HTTP/1.1 requires chunking to be the last encoding if there is one
1684 unsupportedTe = te.size() && te != "identity";
1685 } // else implied identity coding
1686
1687 mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
1688 (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
1689 if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions || unsupportedTe) {
1690 clientStreamNode *node = context->getClientReplyContext();
1691 conn->quitAfterError(request.getRaw());
1692 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1693 assert (repContext);
1694 repContext->setReplyToError(ERR_UNSUP_REQ, Http::scNotImplemented, request->method, NULL,
1695 conn->clientConnection->remote, request.getRaw(), NULL, NULL);
1696 assert(context->http->out.offset == 0);
1697 context->pullData();
1698 clientProcessRequestFinished(conn, request);
1699 return;
1700 }
1701
1702 if (!chunked && !clientIsContentLengthValid(request.getRaw())) {
1703 clientStreamNode *node = context->getClientReplyContext();
1704 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1705 assert (repContext);
1706 conn->quitAfterError(request.getRaw());
1707 repContext->setReplyToError(ERR_INVALID_REQ,
1708 Http::scLengthRequired, request->method, NULL,
1709 conn->clientConnection->remote, request.getRaw(), NULL, NULL);
1710 assert(context->http->out.offset == 0);
1711 context->pullData();
1712 clientProcessRequestFinished(conn, request);
1713 return;
1714 }
1715
1716 clientSetKeepaliveFlag(http);
1717 // Let tunneling code be fully responsible for CONNECT requests
1718 if (http->request->method == Http::METHOD_CONNECT) {
1719 context->mayUseConnection(true);
1720 conn->flags.readMore = false;
1721 }
1722
1723 #if USE_OPENSSL
1724 if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
1725 clientProcessRequestFinished(conn, request);
1726 return;
1727 }
1728 #endif
1729
1730 /* Do we expect a request-body? */
1731 expectBody = chunked || request->content_length > 0;
1732 if (!context->mayUseConnection() && expectBody) {
1733 request->body_pipe = conn->expectRequestBody(
1734 chunked ? -1 : request->content_length);
1735
1736 /* Is it too large? */
1737 if (!chunked && // if chunked, we will check as we accumulate
1738 clientIsRequestBodyTooLargeForPolicy(request->content_length)) {
1739 clientStreamNode *node = context->getClientReplyContext();
1740 clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1741 assert (repContext);
1742 conn->quitAfterError(request.getRaw());
1743 repContext->setReplyToError(ERR_TOO_BIG,
1744 Http::scPayloadTooLarge, Http::METHOD_NONE, NULL,
1745 conn->clientConnection->remote, http->request, NULL, NULL);
1746 assert(context->http->out.offset == 0);
1747 context->pullData();
1748 clientProcessRequestFinished(conn, request);
1749 return;
1750 }
1751
1752 if (!isFtp) {
1753 // We may stop producing, comm_close, and/or call setReplyToError()
1754 // below, so quit on errors to avoid http->doCallouts()
1755 if (!conn->handleRequestBodyData()) {
1756 clientProcessRequestFinished(conn, request);
1757 return;
1758 }
1759
1760 if (!request->body_pipe->productionEnded()) {
1761 debugs(33, 5, "need more request body");
1762 context->mayUseConnection(true);
1763 assert(conn->flags.readMore);
1764 }
1765 }
1766 }
1767
1768 http->calloutContext = new ClientRequestContext(http);
1769
1770 http->doCallouts();
1771
1772 clientProcessRequestFinished(conn, request);
1773 }
1774
1775 int
1776 ConnStateData::pipelinePrefetchMax() const
1777 {
1778 // TODO: Support pipelined requests through pinned connections.
1779 if (pinning.pinned)
1780 return 0;
1781 return Config.pipeline_max_prefetch;
1782 }
1783
1784 /**
1785 * Limit the number of concurrent requests.
1786 * \return true when there are available position(s) in the pipeline queue for another request.
1787 * \return false when the pipeline queue is full or disabled.
1788 */
1789 bool
1790 ConnStateData::concurrentRequestQueueFilled() const
1791 {
1792 const int existingRequestCount = pipeline.count();
1793
1794 // default to the configured pipeline size.
1795 // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
1796 #if USE_OPENSSL
1797 const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
1798 #else
1799 const int internalRequest = 0;
1800 #endif
1801 const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
1802
1803 // when queue filled already we cant add more.
1804 if (existingRequestCount >= concurrentRequestLimit) {
1805 debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1806 debugs(33, 5, clientConnection << " deferring new request until one is done");
1807 return true;
1808 }
1809
1810 return false;
1811 }
1812
1813 /**
1814 * Perform proxy_protocol_access ACL tests on the client which
1815 * connected to PROXY protocol port to see if we trust the
1816 * sender enough to accept their PROXY header claim.
1817 */
1818 bool
1819 ConnStateData::proxyProtocolValidateClient()
1820 {
1821 if (!Config.accessList.proxyProtocol)
1822 return proxyProtocolError("PROXY client not permitted by default ACL");
1823
1824 ACLFilledChecklist ch(Config.accessList.proxyProtocol, NULL, clientConnection->rfc931);
1825 ch.src_addr = clientConnection->remote;
1826 ch.my_addr = clientConnection->local;
1827 ch.conn(this);
1828
1829 if (!ch.fastCheck().allowed())
1830 return proxyProtocolError("PROXY client not permitted by ACLs");
1831
1832 return true;
1833 }
1834
1835 /**
1836 * Perform cleanup on PROXY protocol errors.
1837 * If header parsing hits a fatal error terminate the connection,
1838 * otherwise wait for more data.
1839 */
1840 bool
1841 ConnStateData::proxyProtocolError(const char *msg)
1842 {
1843 if (msg) {
1844 // This is important to know, but maybe not so much that flooding the log is okay.
1845 #if QUIET_PROXY_PROTOCOL
1846 // display the first of every 32 occurances at level 1, the others at level 2.
1847 static uint8_t hide = 0;
1848 debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1849 #else
1850 debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1851 #endif
1852 mustStop(msg);
1853 }
1854 return false;
1855 }
1856
1857 /// magic octet prefix for PROXY protocol version 1
1858 static const SBuf Proxy1p0magic("PROXY ", 6);
1859
1860 /// magic octet prefix for PROXY protocol version 2
1861 static const SBuf Proxy2p0magic("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
1862
1863 /**
1864 * Test the connection read buffer for PROXY protocol header.
1865 * Version 1 and 2 header currently supported.
1866 */
1867 bool
1868 ConnStateData::parseProxyProtocolHeader()
1869 {
1870 // http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
1871
1872 // detect and parse PROXY/2.0 protocol header
1873 if (inBuf.startsWith(Proxy2p0magic))
1874 return parseProxy2p0();
1875
1876 // detect and parse PROXY/1.0 protocol header
1877 if (inBuf.startsWith(Proxy1p0magic))
1878 return parseProxy1p0();
1879
1880 // detect and terminate other protocols
1881 if (inBuf.length() >= Proxy2p0magic.length()) {
1882 // PROXY/1.0 magic is shorter, so we know that
1883 // the input does not start with any PROXY magic
1884 return proxyProtocolError("PROXY protocol error: invalid header");
1885 }
1886
1887 // TODO: detect short non-magic prefixes earlier to avoid
1888 // waiting for more data which may never come
1889
1890 // not enough bytes to parse yet.
1891 return false;
1892 }
1893
1894 /// parse the PROXY/1.0 protocol header from the connection read buffer
1895 bool
1896 ConnStateData::parseProxy1p0()
1897 {
1898 ::Parser::Tokenizer tok(inBuf);
1899 tok.skip(Proxy1p0magic);
1900
1901 // skip to first LF (assumes it is part of CRLF)
1902 static const CharacterSet lineContent = CharacterSet::LF.complement("non-LF");
1903 SBuf line;
1904 if (tok.prefix(line, lineContent, 107-Proxy1p0magic.length())) {
1905 if (tok.skip('\n')) {
1906 // found valid header
1907 inBuf = tok.remaining();
1908 needProxyProtocolHeader_ = false;
1909 // reset the tokenizer to work on found line only.
1910 tok.reset(line);
1911 } else
1912 return false; // no LF yet
1913
1914 } else // protocol error only if there are more than 107 bytes prefix header
1915 return proxyProtocolError(inBuf.length() > 107? "PROXY/1.0 error: missing CRLF" : NULL);
1916
1917 static const SBuf unknown("UNKNOWN"), tcpName("TCP");
1918 if (tok.skip(tcpName)) {
1919
1920 // skip TCP/IP version number
1921 static const CharacterSet tcpVersions("TCP-version","46");
1922 if (!tok.skipOne(tcpVersions))
1923 return proxyProtocolError("PROXY/1.0 error: missing TCP version");
1924
1925 // skip SP after protocol version
1926 if (!tok.skip(' '))
1927 return proxyProtocolError("PROXY/1.0 error: missing SP");
1928
1929 SBuf ipa, ipb;
1930 int64_t porta, portb;
1931 static const CharacterSet ipChars = CharacterSet("IP Address",".:") + CharacterSet::HEXDIG;
1932
1933 // parse: src-IP SP dst-IP SP src-port SP dst-port CR
1934 // leave the LF until later.
1935 const bool correct = tok.prefix(ipa, ipChars) && tok.skip(' ') &&
1936 tok.prefix(ipb, ipChars) && tok.skip(' ') &&
1937 tok.int64(porta) && tok.skip(' ') &&
1938 tok.int64(portb) &&
1939 tok.skip('\r');
1940 if (!correct)
1941 return proxyProtocolError("PROXY/1.0 error: invalid syntax");
1942
1943 // parse IP and port strings
1944 Ip::Address originalClient, originalDest;
1945
1946 if (!originalClient.GetHostByName(ipa.c_str()))
1947 return proxyProtocolError("PROXY/1.0 error: invalid src-IP address");
1948
1949 if (!originalDest.GetHostByName(ipb.c_str()))
1950 return proxyProtocolError("PROXY/1.0 error: invalid dst-IP address");
1951
1952 if (porta > 0 && porta <= 0xFFFF) // max uint16_t
1953 originalClient.port(static_cast<uint16_t>(porta));
1954 else
1955 return proxyProtocolError("PROXY/1.0 error: invalid src port");
1956
1957 if (portb > 0 && portb <= 0xFFFF) // max uint16_t
1958 originalDest.port(static_cast<uint16_t>(portb));
1959 else
1960 return proxyProtocolError("PROXY/1.0 error: invalid dst port");
1961
1962 // we have original client and destination details now
1963 // replace the client connection values
1964 debugs(33, 5, "PROXY/1.0 protocol on connection " << clientConnection);
1965 clientConnection->local = originalDest;
1966 clientConnection->remote = originalClient;
1967 if ((clientConnection->flags & COMM_TRANSPARENT))
1968 clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1969 debugs(33, 5, "PROXY/1.0 upgrade: " << clientConnection);
1970 return true;
1971
1972 } else if (tok.skip(unknown)) {
1973 // found valid but unusable header
1974 return true;
1975
1976 } else
1977 return proxyProtocolError("PROXY/1.0 error: invalid protocol family");
1978
1979 return false;
1980 }
1981
1982 /// parse the PROXY/2.0 protocol header from the connection read buffer
1983 bool
1984 ConnStateData::parseProxy2p0()
1985 {
1986 static const SBuf::size_type prefixLen = Proxy2p0magic.length();
1987 if (inBuf.length() < prefixLen + 4)
1988 return false; // need more bytes
1989
1990 if ((inBuf[prefixLen] & 0xF0) != 0x20) // version == 2 is mandatory
1991 return proxyProtocolError("PROXY/2.0 error: invalid version");
1992
1993 const char command = (inBuf[prefixLen] & 0x0F);
1994 if ((command & 0xFE) != 0x00) // values other than 0x0-0x1 are invalid
1995 return proxyProtocolError("PROXY/2.0 error: invalid command");
1996
1997 const char family = (inBuf[prefixLen+1] & 0xF0) >>4;
1998 if (family > 0x3) // values other than 0x0-0x3 are invalid
1999 return proxyProtocolError("PROXY/2.0 error: invalid family");
2000
2001 const char proto = (inBuf[prefixLen+1] & 0x0F);
2002 if (proto > 0x2) // values other than 0x0-0x2 are invalid
2003 return proxyProtocolError("PROXY/2.0 error: invalid protocol type");
2004
2005 const char *clen = inBuf.rawContent() + prefixLen + 2;
2006 uint16_t len;
2007 memcpy(&len, clen, sizeof(len));
2008 len = ntohs(len);
2009
2010 if (inBuf.length() < prefixLen + 4 + len)
2011 return false; // need more bytes
2012
2013 inBuf.consume(prefixLen + 4); // 4 being the extra bytes
2014 const SBuf extra = inBuf.consume(len);
2015 needProxyProtocolHeader_ = false; // found successfully
2016
2017 // LOCAL connections do nothing with the extras
2018 if (command == 0x00/* LOCAL*/)
2019 return true;
2020
2021 union pax {
2022 struct { /* for TCP/UDP over IPv4, len = 12 */
2023 struct in_addr src_addr;
2024 struct in_addr dst_addr;
2025 uint16_t src_port;
2026 uint16_t dst_port;
2027 } ipv4_addr;
2028 struct { /* for TCP/UDP over IPv6, len = 36 */
2029 struct in6_addr src_addr;
2030 struct in6_addr dst_addr;
2031 uint16_t src_port;
2032 uint16_t dst_port;
2033 } ipv6_addr;
2034 #if NOT_SUPPORTED
2035 struct { /* for AF_UNIX sockets, len = 216 */
2036 uint8_t src_addr[108];
2037 uint8_t dst_addr[108];
2038 } unix_addr;
2039 #endif
2040 };
2041
2042 pax ipu;
2043 memcpy(&ipu, extra.rawContent(), sizeof(pax));
2044
2045 // replace the client connection values
2046 debugs(33, 5, "PROXY/2.0 protocol on connection " << clientConnection);
2047 switch (family) {
2048 case 0x1: // IPv4
2049 clientConnection->local = ipu.ipv4_addr.dst_addr;
2050 clientConnection->local.port(ntohs(ipu.ipv4_addr.dst_port));
2051 clientConnection->remote = ipu.ipv4_addr.src_addr;
2052 clientConnection->remote.port(ntohs(ipu.ipv4_addr.src_port));
2053 if ((clientConnection->flags & COMM_TRANSPARENT))
2054 clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
2055 break;
2056 case 0x2: // IPv6
2057 clientConnection->local = ipu.ipv6_addr.dst_addr;
2058 clientConnection->local.port(ntohs(ipu.ipv6_addr.dst_port));
2059 clientConnection->remote = ipu.ipv6_addr.src_addr;
2060 clientConnection->remote.port(ntohs(ipu.ipv6_addr.src_port));
2061 if ((clientConnection->flags & COMM_TRANSPARENT))
2062 clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
2063 break;
2064 default: // do nothing
2065 break;
2066 }
2067 debugs(33, 5, "PROXY/2.0 upgrade: " << clientConnection);
2068 return true;
2069 }
2070
2071 void
2072 ConnStateData::receivedFirstByte()
2073 {
2074 if (receivedFirstByte_)
2075 return;
2076
2077 receivedFirstByte_ = true;
2078 // Set timeout to Config.Timeout.request
2079 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
2080 AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
2081 TimeoutDialer, this, ConnStateData::requestTimeout);
2082 commSetConnTimeout(clientConnection, Config.Timeout.request, timeoutCall);
2083 }
2084
2085 /**
2086 * Attempt to parse one or more requests from the input buffer.
2087 * Returns true after completing parsing of at least one request [header]. That
2088 * includes cases where parsing ended with an error (e.g., a huge request).
2089 */
2090 bool
2091 ConnStateData::clientParseRequests()
2092 {
2093 bool parsed_req = false;
2094
2095 debugs(33, 5, HERE << clientConnection << ": attempting to parse");
2096
2097 // Loop while we have read bytes that are not needed for producing the body
2098 // On errors, bodyPipe may become nil, but readMore will be cleared
2099 while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
2100
2101 /* Limit the number of concurrent requests */
2102 if (concurrentRequestQueueFilled())
2103 break;
2104
2105 // try to parse the PROXY protocol header magic bytes
2106 if (needProxyProtocolHeader_) {
2107 if (!parseProxyProtocolHeader())
2108 break;
2109
2110 // we have been waiting for PROXY to provide client-IP
2111 // for some lookups, ie rDNS and IDENT.
2112 whenClientIpKnown();
2113 }
2114
2115 if (Http::StreamPointer context = parseOneRequest()) {
2116 debugs(33, 5, clientConnection << ": done parsing a request");
2117
2118 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
2119 CommTimeoutCbPtrFun(clientLifetimeTimeout, context->http));
2120 commSetConnTimeout(clientConnection, Config.Timeout.lifetime, timeoutCall);
2121
2122 context->registerWithConn();
2123
2124 processParsedRequest(context);
2125
2126 parsed_req = true; // XXX: do we really need to parse everything right NOW ?
2127
2128 if (context->mayUseConnection()) {
2129 debugs(33, 3, HERE << "Not parsing new requests, as this request may need the connection");
2130 break;
2131 }
2132 } else {
2133 debugs(33, 5, clientConnection << ": not enough request data: " <<
2134 inBuf.length() << " < " << Config.maxRequestHeaderSize);
2135 Must(inBuf.length() < Config.maxRequestHeaderSize);
2136 break;
2137 }
2138 }
2139
2140 /* XXX where to 'finish' the parsing pass? */
2141 return parsed_req;
2142 }
2143
2144 void
2145 ConnStateData::afterClientRead()
2146 {
2147 #if USE_OPENSSL
2148 if (parsingTlsHandshake) {
2149 parseTlsHandshake();
2150 return;
2151 }
2152 #endif
2153
2154 /* Process next request */
2155 if (pipeline.empty())
2156 fd_note(clientConnection->fd, "Reading next request");
2157
2158 if (!clientParseRequests()) {
2159 if (!isOpen())
2160 return;
2161 /*
2162 * If the client here is half closed and we failed
2163 * to parse a request, close the connection.
2164 * The above check with connFinishedWithConn() only
2165 * succeeds _if_ the buffer is empty which it won't
2166 * be if we have an incomplete request.
2167 * XXX: This duplicates ConnStateData::kick
2168 */
2169 if (pipeline.empty() && commIsHalfClosed(clientConnection->fd)) {
2170 debugs(33, 5, clientConnection << ": half-closed connection, no completed request parsed, connection closing.");
2171 clientConnection->close();
2172 return;
2173 }
2174 }
2175
2176 if (!isOpen())
2177 return;
2178
2179 clientAfterReadingRequests();
2180 }
2181
2182 /**
2183 * called when new request data has been read from the socket
2184 *
2185 * \retval false called comm_close or setReplyToError (the caller should bail)
2186 * \retval true we did not call comm_close or setReplyToError
2187 */
2188 bool
2189 ConnStateData::handleReadData()
2190 {
2191 // if we are reading a body, stuff data into the body pipe
2192 if (bodyPipe != NULL)
2193 return handleRequestBodyData();
2194 return true;
2195 }
2196
2197 /**
2198 * called when new request body data has been buffered in inBuf
2199 * may close the connection if we were closing and piped everything out
2200 *
2201 * \retval false called comm_close or setReplyToError (the caller should bail)
2202 * \retval true we did not call comm_close or setReplyToError
2203 */
2204 bool
2205 ConnStateData::handleRequestBodyData()
2206 {
2207 assert(bodyPipe != NULL);
2208
2209 if (bodyParser) { // chunked encoding
2210 if (const err_type error = handleChunkedRequestBody()) {
2211 abortChunkedRequestBody(error);
2212 return false;
2213 }
2214 } else { // identity encoding
2215 debugs(33,5, HERE << "handling plain request body for " << clientConnection);
2216 const size_t putSize = bodyPipe->putMoreData(inBuf.c_str(), inBuf.length());
2217 if (putSize > 0)
2218 consumeInput(putSize);
2219
2220 if (!bodyPipe->mayNeedMoreData()) {
2221 // BodyPipe will clear us automagically when we produced everything
2222 bodyPipe = NULL;
2223 }
2224 }
2225
2226 if (!bodyPipe) {
2227 debugs(33,5, HERE << "produced entire request body for " << clientConnection);
2228
2229 if (const char *reason = stoppedSending()) {
2230 /* we've finished reading like good clients,
2231 * now do the close that initiateClose initiated.
2232 */
2233 debugs(33, 3, HERE << "closing for earlier sending error: " << reason);
2234 clientConnection->close();
2235 return false;
2236 }
2237 }
2238
2239 return true;
2240 }
2241
2242 /// parses available chunked encoded body bytes, checks size, returns errors
2243 err_type
2244 ConnStateData::handleChunkedRequestBody()
2245 {
2246 debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
2247
2248 try { // the parser will throw on errors
2249
2250 if (inBuf.isEmpty()) // nothing to do
2251 return ERR_NONE;
2252
2253 BodyPipeCheckout bpc(*bodyPipe);
2254 bodyParser->setPayloadBuffer(&bpc.buf);
2255 const bool parsed = bodyParser->parse(inBuf);
2256 inBuf = bodyParser->remaining(); // sync buffers
2257 bpc.checkIn();
2258
2259 // dechunk then check: the size limit applies to _dechunked_ content
2260 if (clientIsRequestBodyTooLargeForPolicy(bodyPipe->producedSize()))
2261 return ERR_TOO_BIG;
2262
2263 if (parsed) {
2264 finishDechunkingRequest(true);
2265 Must(!bodyPipe);
2266 return ERR_NONE; // nil bodyPipe implies body end for the caller
2267 }
2268
2269 // if chunk parser needs data, then the body pipe must need it too
2270 Must(!bodyParser->needsMoreData() || bodyPipe->mayNeedMoreData());
2271
2272 // if parser needs more space and we can consume nothing, we will stall
2273 Must(!bodyParser->needsMoreSpace() || bodyPipe->buf().hasContent());
2274 } catch (...) { // TODO: be more specific
2275 debugs(33, 3, HERE << "malformed chunks" << bodyPipe->status());
2276 return ERR_INVALID_REQ;
2277 }
2278
2279 debugs(33, 7, HERE << "need more chunked data" << *bodyPipe->status());
2280 return ERR_NONE;
2281 }
2282
2283 /// quit on errors related to chunked request body handling
2284 void
2285 ConnStateData::abortChunkedRequestBody(const err_type error)
2286 {
2287 finishDechunkingRequest(false);
2288
2289 // XXX: The code below works if we fail during initial request parsing,
2290 // but if we fail when the server connection is used already, the server may send
2291 // us its response too, causing various assertions. How to prevent that?
2292 #if WE_KNOW_HOW_TO_SEND_ERRORS
2293 Http::StreamPointer context = pipeline.front();
2294 if (context != NULL && !context->http->out.offset) { // output nothing yet
2295 clientStreamNode *node = context->getClientReplyContext();
2296 clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2297 assert(repContext);
2298 const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
2299 Http::scPayloadTooLarge : HTTP_BAD_REQUEST;
2300 repContext->setReplyToError(error, scode,
2301 repContext->http->request->method,
2302 repContext->http->uri,
2303 CachePeer,
2304 repContext->http->request,
2305 inBuf, NULL);
2306 context->pullData();
2307 } else {
2308 // close or otherwise we may get stuck as nobody will notice the error?
2309 comm_reset_close(clientConnection);
2310 }
2311 #else
2312 debugs(33, 3, HERE << "aborting chunked request without error " << error);
2313 comm_reset_close(clientConnection);
2314 #endif
2315 flags.readMore = false;
2316 }
2317
2318 void
2319 ConnStateData::noteBodyConsumerAborted(BodyPipe::Pointer )
2320 {
2321 // request reader may get stuck waiting for space if nobody consumes body
2322 if (bodyPipe != NULL)
2323 bodyPipe->enableAutoConsumption();
2324
2325 // kids extend
2326 }
2327
2328 /** general lifetime handler for HTTP requests */
2329 void
2330 ConnStateData::requestTimeout(const CommTimeoutCbParams &io)
2331 {
2332 if (!Comm::IsConnOpen(io.conn))
2333 return;
2334
2335 if (mayTunnelUnsupportedProto() && !receivedFirstByte_) {
2336 Http::StreamPointer context = pipeline.front();
2337 Must(context && context->http);
2338 HttpRequest::Pointer request = context->http->request;
2339 if (clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_REQUEST_START_TIMEOUT))
2340 return;
2341 }
2342 /*
2343 * Just close the connection to not confuse browsers
2344 * using persistent connections. Some browsers open
2345 * a connection and then do not use it until much
2346 * later (presumeably because the request triggering
2347 * the open has already been completed on another
2348 * connection)
2349 */
2350 debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
2351 io.conn->close();
2352 }
2353
2354 static void
2355 clientLifetimeTimeout(const CommTimeoutCbParams &io)
2356 {
2357 ClientHttpRequest *http = static_cast<ClientHttpRequest *>(io.data);
2358 debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout");
2359 debugs(33, DBG_IMPORTANT, "\t" << http->uri);
2360 http->logType.err.timedout = true;
2361 if (Comm::IsConnOpen(io.conn))
2362 io.conn->close();
2363 }
2364
2365 ConnStateData::ConnStateData(const MasterXaction::Pointer &xact) :
2366 AsyncJob("ConnStateData"), // kids overwrite
2367 Server(xact),
2368 bodyParser(nullptr),
2369 #if USE_OPENSSL
2370 sslBumpMode(Ssl::bumpEnd),
2371 #endif
2372 needProxyProtocolHeader_(false),
2373 #if USE_OPENSSL
2374 switchedToHttps_(false),
2375 parsingTlsHandshake(false),
2376 sslServerBump(NULL),
2377 signAlgorithm(Ssl::algSignTrusted),
2378 #endif
2379 stoppedSending_(NULL),
2380 stoppedReceiving_(NULL)
2381 {
2382 flags.readMore = true; // kids may overwrite
2383 flags.swanSang = false;
2384
2385 pinning.host = NULL;
2386 pinning.port = -1;
2387 pinning.pinned = false;
2388 pinning.auth = false;
2389 pinning.zeroReply = false;
2390 pinning.peer = NULL;
2391
2392 // store the details required for creating more MasterXaction objects as new requests come in
2393 log_addr = xact->tcpClient->remote;
2394 log_addr.applyMask(Config.Addrs.client_netmask);
2395
2396 // register to receive notice of Squid signal events
2397 // which may affect long persisting client connections
2398 registerRunner();
2399 }
2400
2401 void
2402 ConnStateData::start()
2403 {
2404 BodyProducer::start();
2405 HttpControlMsgSink::start();
2406
2407 if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2408 (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2409 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2410 int i = IP_PMTUDISC_DONT;
2411 if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2412 int xerrno = errno;
2413 debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2414 }
2415 #else
2416 static bool reported = false;
2417
2418 if (!reported) {
2419 debugs(33, DBG_IMPORTANT, "NOTICE: Path MTU discovery disabling is not supported on your platform.");
2420 reported = true;
2421 }
2422 #endif
2423 }
2424
2425 typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
2426 AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2427 comm_add_close_handler(clientConnection->fd, call);
2428
2429 needProxyProtocolHeader_ = port->flags.proxySurrogate;
2430 if (needProxyProtocolHeader_) {
2431 if (!proxyProtocolValidateClient()) // will close the connection on failure
2432 return;
2433 } else
2434 whenClientIpKnown();
2435
2436 }
2437
2438 void
2439 ConnStateData::whenClientIpKnown()
2440 {
2441 if (Config.onoff.log_fqdn)
2442 fqdncache_gethostbyaddr(clientConnection->remote, FQDN_LOOKUP_IF_MISS);
2443
2444 #if USE_IDENT
2445 if (Ident::TheConfig.identLookup) {
2446 ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
2447 identChecklist.src_addr = clientConnection->remote;
2448 identChecklist.my_addr = clientConnection->local;
2449 if (identChecklist.fastCheck().allowed())
2450 Ident::Start(clientConnection, clientIdentDone, this);
2451 }
2452 #endif
2453
2454 clientdbEstablished(clientConnection->remote, 1);
2455
2456 #if USE_DELAY_POOLS
2457 fd_table[clientConnection->fd].clientInfo = NULL;
2458
2459 if (Config.onoff.client_db) {
2460 /* it was said several times that client write limiter does not work if client_db is disabled */
2461
2462 auto &pools = ClientDelayPools::Instance()->pools;
2463 ACLFilledChecklist ch(NULL, NULL, NULL);
2464
2465 // TODO: we check early to limit error response bandwith but we
2466 // should recheck when we can honor delay_pool_uses_indirect
2467 // TODO: we should also pass the port details for myportname here.
2468 ch.src_addr = clientConnection->remote;
2469 ch.my_addr = clientConnection->local;
2470
2471 for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2472
2473 /* pools require explicit 'allow' to assign a client into them */
2474 if (pools[pool]->access) {
2475 ch.changeAcl(pools[pool]->access);
2476 allow_t answer = ch.fastCheck();
2477 if (answer.allowed()) {
2478
2479 /* request client information from db after we did all checks
2480 this will save hash lookup if client failed checks */
2481 ClientInfo * cli = clientdbGetInfo(clientConnection->remote);
2482 assert(cli);
2483
2484 /* put client info in FDE */
2485 fd_table[clientConnection->fd].clientInfo = cli;
2486
2487 /* setup write limiter for this request */
2488 const double burst = floor(0.5 +
2489 (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2490 cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2491 break;
2492 } else {
2493 debugs(83, 4, HERE << "Delay pool " << pool << " skipped because ACL " << answer);
2494 }
2495 }
2496 }
2497 }
2498 #endif
2499
2500 // kids must extend to actually start doing something (e.g., reading)
2501 }
2502
2503 /** Handle a new connection on an HTTP socket. */
2504 void
2505 httpAccept(const CommAcceptCbParams &params)
2506 {
2507 MasterXaction::Pointer xact = params.xaction;
2508 AnyP::PortCfgPointer s = xact->squidPort;
2509
2510 // NP: it is possible the port was reconfigured when the call or accept() was queued.
2511
2512 if (params.flag != Comm::OK) {
2513 // Its possible the call was still queued when the client disconnected
2514 debugs(33, 2, s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2515 return;
2516 }
2517
2518 debugs(33, 4, params.conn << ": accepted");
2519 fd_note(params.conn->fd, "client http connect");
2520
2521 if (s->tcp_keepalive.enabled)
2522 commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2523
2524 ++incoming_sockets_accepted;
2525
2526 // Socket is ready, setup the connection manager to start using it
2527 auto *srv = Http::NewServer(xact);
2528 AsyncJob::Start(srv); // usually async-calls readSomeData()
2529 }
2530
2531 #if USE_OPENSSL
2532 /// Create TLS connection structure and update fd_table
2533 static bool
2534 httpsCreate(const Comm::ConnectionPointer &conn, const Security::ContextPointer &ctx)
2535 {
2536 if (Security::CreateServerSession(ctx, conn, "client https start")) {
2537 debugs(33, 5, "will negotiate TLS on " << conn);
2538 return true;
2539 }
2540
2541 conn->close();
2542 return false;
2543 }
2544
2545 /**
2546 *
2547 * \retval 1 on success
2548 * \retval 0 when needs more data
2549 * \retval -1 on error
2550 */
2551 static int
2552 Squid_SSL_accept(ConnStateData *conn, PF *callback)
2553 {
2554 int fd = conn->clientConnection->fd;
2555 auto ssl = fd_table[fd].ssl.get();
2556 int ret;
2557
2558 errno = 0;
2559 if ((ret = SSL_accept(ssl)) <= 0) {
2560 const int xerrno = errno;
2561 const int ssl_error = SSL_get_error(ssl, ret);
2562
2563 switch (ssl_error) {
2564
2565 case SSL_ERROR_WANT_READ:
2566 Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback != NULL ? conn : NULL), 0);
2567 return 0;
2568
2569 case SSL_ERROR_WANT_WRITE:
2570 Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback != NULL ? conn : NULL), 0);
2571 return 0;
2572
2573 case SSL_ERROR_SYSCALL:
2574 if (ret == 0) {
2575 debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error);
2576 } else {
2577 debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " <<
2578 (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno)));
2579 }
2580 return -1;
2581
2582 case SSL_ERROR_ZERO_RETURN:
2583 debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << fd << ": Closed by client");
2584 return -1;
2585
2586 default:
2587 debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " <<
2588 fd << ": " << Security::ErrorString(ERR_get_error()) <<
2589 " (" << ssl_error << "/" << ret << ")");
2590 return -1;
2591 }
2592
2593 /* NOTREACHED */
2594 }
2595 return 1;
2596 }
2597
2598 /** negotiate an SSL connection */
2599 static void
2600 clientNegotiateSSL(int fd, void *data)
2601 {
2602 ConnStateData *conn = (ConnStateData *)data;
2603 int ret;
2604 if ((ret = Squid_SSL_accept(conn, clientNegotiateSSL)) <= 0) {
2605 if (ret < 0) // An error
2606 conn->clientConnection->close();
2607 return;
2608 }
2609
2610 Security::SessionPointer session(fd_table[fd].ssl);
2611 if (Security::SessionIsResumed(session)) {
2612 debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2613 " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2614 ":" << (int)fd_table[fd].remote_port << ")");
2615 } else {
2616 if (Debug::Enabled(83, 4)) {
2617 /* Write out the SSL session details.. actually the call below, but
2618 * OpenSSL headers do strange typecasts confusing GCC.. */
2619 /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
2620 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2621 PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2622 PEM_STRING_SSL_SESSION, debug_log,
2623 reinterpret_cast<char *>(SSL_get_session(session.get())),
2624 nullptr, nullptr, 0, nullptr, nullptr);
2625
2626 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2627
2628 /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2629 * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2630 * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2631 * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2632 * Because there are two possible usable cast, if you get an error here, try the other
2633 * commented line. */
2634
2635 PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2636 debug_log,
2637 reinterpret_cast<char *>(SSL_get_session(session.get())),
2638 nullptr, nullptr, 0, nullptr, nullptr);
2639 /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2640 debug_log,
2641 reinterpret_cast<char *>(SSL_get_session(session.get())),
2642 nullptr, nullptr, 0, nullptr, nullptr);
2643 */
2644 #else
2645 debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2646
2647 #endif
2648 /* Note: This does not automatically fflush the log file.. */
2649 }
2650
2651 debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2652 " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2653 fd_table[fd].remote_port << ")");
2654 }
2655
2656 // Connection established. Retrieve TLS connection parameters for logging.
2657 conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session);
2658
2659 X509 *client_cert = SSL_get_peer_certificate(session.get());
2660
2661 if (client_cert) {
2662 debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2663 X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0));
2664
2665 debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2666 X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
2667
2668 X509_free(client_cert);
2669 } else {
2670 debugs(83, 5, "FD " << fd << " has no certificate.");
2671 }
2672
2673 conn->readSomeData();
2674 }
2675
2676 /**
2677 * If Security::ContextPointer is given, starts reading the TLS handshake.
2678 * Otherwise, calls switchToHttps to generate a dynamic Security::ContextPointer.
2679 */
2680 static void
2681 httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
2682 {
2683 assert(connState);
2684 const Comm::ConnectionPointer &details = connState->clientConnection;
2685
2686 if (!ctx || !httpsCreate(details, ctx))
2687 return;
2688
2689 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
2690 AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
2691 connState, ConnStateData::requestTimeout);
2692 commSetConnTimeout(details, Config.Timeout.request, timeoutCall);
2693
2694 Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2695 }
2696
2697 /**
2698 * A callback function to use with the ACLFilledChecklist callback.
2699 */
2700 static void
2701 httpsSslBumpAccessCheckDone(allow_t answer, void *data)
2702 {
2703 ConnStateData *connState = (ConnStateData *) data;
2704
2705 // if the connection is closed or closing, just return.
2706 if (!connState->isOpen())
2707 return;
2708
2709 if (answer.allowed()) {
2710 debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2711 connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2712 } else {
2713 debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2714 connState->sslBumpMode = Ssl::bumpSplice;
2715 }
2716
2717 if (connState->sslBumpMode == Ssl::bumpTerminate) {
2718 connState->clientConnection->close();
2719 return;
2720 }
2721
2722 if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2723 connState->clientConnection->close();
2724 }
2725
2726 /** handle a new HTTPS connection */
2727 static void
2728 httpsAccept(const CommAcceptCbParams &params)
2729 {
2730 MasterXaction::Pointer xact = params.xaction;
2731 const AnyP::PortCfgPointer s = xact->squidPort;
2732
2733 // NP: it is possible the port was reconfigured when the call or accept() was queued.
2734
2735 if (params.flag != Comm::OK) {
2736 // Its possible the call was still queued when the client disconnected
2737 debugs(33, 2, "httpsAccept: " << s->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2738 return;
2739 }
2740
2741 debugs(33, 4, HERE << params.conn << " accepted, starting SSL negotiation.");
2742 fd_note(params.conn->fd, "client https connect");
2743
2744 if (s->tcp_keepalive.enabled) {
2745 commSetTcpKeepalive(params.conn->fd, s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
2746 }
2747 ++incoming_sockets_accepted;
2748
2749 // Socket is ready, setup the connection manager to start using it
2750 auto *srv = Https::NewServer(xact);
2751 AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2752 }
2753
2754 void
2755 ConnStateData::postHttpsAccept()
2756 {
2757 if (port->flags.tunnelSslBumping) {
2758 debugs(33, 5, "accept transparent connection: " << clientConnection);
2759
2760 if (!Config.accessList.ssl_bump) {
2761 httpsSslBumpAccessCheckDone(ACCESS_DENIED, this);
2762 return;
2763 }
2764
2765 MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
2766 mx->tcpClient = clientConnection;
2767 // Create a fake HTTP request for ssl_bump ACL check,
2768 // using tproxy/intercept provided destination IP and port.
2769 HttpRequest *request = new HttpRequest(mx);
2770 static char ip[MAX_IPSTRLEN];
2771 assert(clientConnection->flags & (COMM_TRANSPARENT | COMM_INTERCEPTION));
2772 request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2773 request->url.port(clientConnection->local.port());
2774 request->myportname = port->name;
2775
2776 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, request, NULL);
2777 acl_checklist->src_addr = clientConnection->remote;
2778 acl_checklist->my_addr = port->s;
2779 // Build a local AccessLogEntry to allow requiresAle() acls work
2780 acl_checklist->al = new AccessLogEntry;
2781 acl_checklist->al->cache.start_time = current_time;
2782 acl_checklist->al->tcpClient = clientConnection;
2783 acl_checklist->al->cache.port = port;
2784 acl_checklist->al->cache.caddr = log_addr;
2785 HTTPMSGUNLOCK(acl_checklist->al->request);
2786 acl_checklist->al->request = request;
2787 HTTPMSGLOCK(acl_checklist->al->request);
2788 acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
2789 return;
2790 } else {
2791 httpsEstablish(this, port->secure.staticContext);
2792 }
2793 }
2794
2795 void
2796 ConnStateData::sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply)
2797 {
2798 ConnStateData * state_data = (ConnStateData *)(data);
2799 state_data->sslCrtdHandleReply(reply);
2800 }
2801
2802 void
2803 ConnStateData::sslCrtdHandleReply(const Helper::Reply &reply)
2804 {
2805 if (!isOpen()) {
2806 debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2807 return;
2808 }
2809
2810 if (reply.result == Helper::BrokenHelper) {
2811 debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2812 } else if (!reply.other().hasContent()) {
2813 debugs(1, DBG_IMPORTANT, HERE << "\"ssl_crtd\" helper returned <NULL> reply.");
2814 } else {
2815 Ssl::CrtdMessage reply_message(Ssl::CrtdMessage::REPLY);
2816 if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2817 debugs(33, 5, HERE << "Reply from ssl_crtd for " << sslConnectHostOrIp << " is incorrect");
2818 } else {
2819 if (reply.result != Helper::Okay) {
2820 debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2821 } else {
2822 debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " was successfully recieved from ssl_crtd");
2823 if (sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare)) {
2824 doPeekAndSpliceStep();
2825 auto ssl = fd_table[clientConnection->fd].ssl.get();
2826 bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2827 if (!ret)
2828 debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2829
2830 Security::ContextPointer ctx(Security::GetFrom(fd_table[clientConnection->fd].ssl));
2831 Ssl::configureUnconfiguredSslContext(ctx, signAlgorithm, *port);
2832 } else {
2833 Security::ContextPointer ctx(Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port));
2834 getSslContextDone(ctx, true);
2835 }
2836 return;
2837 }
2838 }
2839 }
2840 Security::ContextPointer nil;
2841 getSslContextDone(nil);
2842 }
2843
2844 void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &certProperties)
2845 {
2846 certProperties.commonName = sslCommonName_.isEmpty() ? sslConnectHostOrIp.termedBuf() : sslCommonName_.c_str();
2847
2848 const bool triedToConnect = sslServerBump && sslServerBump->entry;
2849 const bool connectedOK = triedToConnect && sslServerBump->entry->isEmpty();
2850 if (connectedOK) {
2851 if (X509 *mimicCert = sslServerBump->serverCert.get())
2852 certProperties.mimicCert.resetAndLock(mimicCert);
2853
2854 ACLFilledChecklist checklist(NULL, sslServerBump->request.getRaw(),
2855 clientConnection != NULL ? clientConnection->rfc931 : dash_str);
2856 checklist.sslErrors = cbdataReference(sslServerBump->sslErrors());
2857
2858 for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
2859 // If the algorithm already set, then ignore it.
2860 if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2861 (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2862 (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2863 continue;
2864
2865 if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2866 const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2867 const char *param = ca->param;
2868
2869 // For parameterless CN adaptation, use hostname from the
2870 // CONNECT request.
2871 if (ca->alg == Ssl::algSetCommonName) {
2872 if (!param)
2873 param = sslConnectHostOrIp.termedBuf();
2874 certProperties.commonName = param;
2875 certProperties.setCommonName = true;
2876 } else if (ca->alg == Ssl::algSetValidAfter)
2877 certProperties.setValidAfter = true;
2878 else if (ca->alg == Ssl::algSetValidBefore)
2879 certProperties.setValidBefore = true;
2880
2881 debugs(33, 5, HERE << "Matches certificate adaptation aglorithm: " <<
2882 alg << " param: " << (param ? param : "-"));
2883 }
2884 }
2885
2886 certProperties.signAlgorithm = Ssl::algSignEnd;
2887 for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
2888 if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2889 certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2890 break;
2891 }
2892 }
2893 } else {// did not try to connect (e.g. client-first) or failed to connect
2894 // In case of an error while connecting to the secure server, use a
2895 // trusted certificate, with no mimicked fields and no adaptation
2896 // algorithms. There is nothing we can mimic, so we want to minimize the
2897 // number of warnings the user will have to see to get to the error page.
2898 // We will close the connection, so that the trust is not extended to
2899 // non-Squid content.
2900 certProperties.signAlgorithm = Ssl::algSignTrusted;
2901 }
2902
2903 assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2904
2905 if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2906 assert(port->untrustedSigningCert.get());
2907 certProperties.signWithX509.resetAndLock(port->untrustedSigningCert.get());
2908 certProperties.signWithPkey.resetAndLock(port->untrustedSignPkey.get());
2909 } else {
2910 assert(port->signingCert.get());
2911 certProperties.signWithX509.resetAndLock(port->signingCert.get());
2912
2913 if (port->signPkey.get())
2914 certProperties.signWithPkey.resetAndLock(port->signPkey.get());
2915 }
2916 signAlgorithm = certProperties.signAlgorithm;
2917
2918 certProperties.signHash = Ssl::DefaultSignHash;
2919 }
2920
2921 void
2922 ConnStateData::getSslContextStart()
2923 {
2924 // If we are called, then CONNECT has succeeded. Finalize it.
2925 if (auto xact = pipeline.front()) {
2926 if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2927 xact->finished();
2928 // cannot proceed with encryption if requests wait for plain responses
2929 Must(pipeline.empty());
2930 }
2931 /* careful: finished() above frees request, host, etc. */
2932
2933 if (port->generateHostCertificates) {
2934 Ssl::CertificateProperties certProperties;
2935 buildSslCertGenerationParams(certProperties);
2936 sslBumpCertKey = certProperties.dbKey().c_str();
2937 assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
2938
2939 // Disable caching for bumpPeekAndSplice mode
2940 if (!(sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare))) {
2941 debugs(33, 5, "Finding SSL certificate for " << sslBumpCertKey << " in cache");
2942 Ssl::LocalContextStorage * ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
2943 Security::ContextPointer *cachedCtx = ssl_ctx_cache ? ssl_ctx_cache->get(sslBumpCertKey.termedBuf()) : nullptr;
2944 if (cachedCtx) {
2945 debugs(33, 5, "SSL certificate for " << sslBumpCertKey << " found in cache");
2946 if (Ssl::verifySslCertificate(*cachedCtx, certProperties)) {
2947 debugs(33, 5, "Cached SSL certificate for " << sslBumpCertKey << " is valid");
2948 getSslContextDone(*cachedCtx);
2949 return;
2950 } else {
2951 debugs(33, 5, "Cached SSL certificate for " << sslBumpCertKey << " is out of date. Delete this certificate from cache");
2952 if (ssl_ctx_cache)
2953 ssl_ctx_cache->del(sslBumpCertKey.termedBuf());
2954 }
2955 } else {
2956 debugs(33, 5, "SSL certificate for " << sslBumpCertKey << " haven't found in cache");
2957 }
2958 }
2959
2960 #if USE_SSL_CRTD
2961 try {
2962 debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
2963 Ssl::CrtdMessage request_message(Ssl::CrtdMessage::REQUEST);
2964 request_message.setCode(Ssl::CrtdMessage::code_new_certificate);
2965 request_message.composeRequest(certProperties);
2966 debugs(33, 5, HERE << "SSL crtd request: " << request_message.compose().c_str());
2967 Ssl::Helper::GetInstance()->sslSubmit(request_message, sslCrtdHandleReplyWrapper, this);
2968 return;
2969 } catch (const std::exception &e) {
2970 debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2971 "request for " << certProperties.commonName <<
2972 " certificate: " << e.what() << "; will now block to " <<
2973 "generate that certificate.");
2974 // fall through to do blocking in-process generation.
2975 }
2976 #endif // USE_SSL_CRTD
2977
2978 debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName);
2979 if (sslServerBump && (sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare)) {
2980 doPeekAndSpliceStep();
2981 auto ssl = fd_table[clientConnection->fd].ssl.get();
2982 if (!Ssl::configureSSL(ssl, certProperties, *port))
2983 debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2984
2985 Security::ContextPointer ctx(Security::GetFrom(fd_table[clientConnection->fd].ssl));
2986 Ssl::configureUnconfiguredSslContext(ctx, certProperties.signAlgorithm, *port);
2987 } else {
2988 Security::ContextPointer dynCtx(Ssl::generateSslContext(certProperties, *port));
2989 getSslContextDone(dynCtx, true);
2990 }
2991 return;
2992 }
2993
2994 Security::ContextPointer nil;
2995 getSslContextDone(nil);
2996 }
2997
2998 void
2999 ConnStateData::getSslContextDone(Security::ContextPointer &ctx, bool isNew)
3000 {
3001 // Try to add generated ssl context to storage.
3002 if (port->generateHostCertificates && isNew) {
3003
3004 if (ctx && (signAlgorithm == Ssl::algSignTrusted)) {
3005 Ssl::chainCertificatesToSSLContext(ctx, *port);
3006 } else if (signAlgorithm == Ssl::algSignTrusted) {
3007 debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain because SSL context chain is invalid!");
3008 }
3009 //else it is self-signed or untrusted do not attrach any certificate
3010
3011 Ssl::LocalContextStorage *ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
3012 assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
3013 if (ctx) {
3014 if (!ssl_ctx_cache || !ssl_ctx_cache->add(sslBumpCertKey.termedBuf(), new Security::ContextPointer(ctx))) {
3015 // If it is not in storage delete after using. Else storage deleted it.
3016 fd_table[clientConnection->fd].dynamicTlsContext = ctx;
3017 }
3018 } else {
3019 debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslConnectHostOrIp);
3020 }
3021 }
3022
3023 // If generated ssl context = NULL, try to use static ssl context.
3024 if (!ctx) {
3025 if (!port->secure.staticContext) {
3026 debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
3027 clientConnection->close();
3028 return;
3029 } else {
3030 debugs(33, 5, "Using static TLS context.");
3031 ctx = port->secure.staticContext;
3032 }
3033 }
3034
3035 if (!httpsCreate(clientConnection, ctx))
3036 return;
3037
3038 // bumped intercepted conns should already have Config.Timeout.request set
3039 // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
3040 // to make sure the connection does not get stuck on non-SSL clients.
3041 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
3042 AsyncCall::Pointer timeoutCall = JobCallback(33, 5, TimeoutDialer,
3043 this, ConnStateData::requestTimeout);
3044 commSetConnTimeout(clientConnection, Config.Timeout.request, timeoutCall);
3045
3046 switchedToHttps_ = true;
3047
3048 auto ssl = fd_table[clientConnection->fd].ssl.get();
3049 BIO *b = SSL_get_rbio(ssl);
3050 Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3051 bio->setReadBufData(inBuf);
3052 inBuf.clear();
3053 clientNegotiateSSL(clientConnection->fd, this);
3054 }
3055
3056 void
3057 ConnStateData::switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode)
3058 {
3059 assert(!switchedToHttps_);
3060
3061 sslConnectHostOrIp = request->url.host();
3062 resetSslCommonName(request->url.host());
3063
3064 // We are going to read new request
3065 flags.readMore = true;
3066 debugs(33, 5, HERE << "converting " << clientConnection << " to SSL");
3067
3068 // keep version major.minor details the same.
3069 // but we are now performing the HTTPS handshake traffic
3070 transferProtocol.protocol = AnyP::PROTO_HTTPS;
3071
3072 // If sslServerBump is set, then we have decided to deny CONNECT
3073 // and now want to switch to SSL to send the error to the client
3074 // without even peeking at the origin server certificate.
3075 if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
3076 request->flags.sslPeek = true;
3077 sslServerBump = new Ssl::ServerBump(request);
3078 } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
3079 request->flags.sslPeek = true;
3080 sslServerBump = new Ssl::ServerBump(request, NULL, bumpServerMode);
3081 }
3082
3083 // commSetConnTimeout() was called for this request before we switched.
3084 // Fix timeout to request_start_timeout
3085 typedef CommCbMemFunT<ConnStateData, CommTimeoutCbParams> TimeoutDialer;
3086 AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
3087 TimeoutDialer, this, ConnStateData::requestTimeout);
3088 commSetConnTimeout(clientConnection, Config.Timeout.request_start_timeout, timeoutCall);
3089 // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
3090 // a bumbed "connect" request on non transparent port.
3091 receivedFirstByte_ = false;
3092 // Get more data to peek at Tls
3093 parsingTlsHandshake = true;
3094 readSomeData();
3095 }
3096
3097 void
3098 ConnStateData::parseTlsHandshake()
3099 {
3100 Must(parsingTlsHandshake);
3101
3102 assert(!inBuf.isEmpty());
3103 receivedFirstByte();
3104 fd_note(clientConnection->fd, "Parsing TLS handshake");
3105
3106 bool unsupportedProtocol = false;
3107 try {
3108 if (!tlsParser.parseHello(inBuf)) {
3109 // need more data to finish parsing
3110 readSomeData();
3111 return;
3112 }
3113 }
3114 catch (const std::exception &ex) {
3115 debugs(83, 2, "error on FD " << clientConnection->fd << ": " << ex.what());
3116 unsupportedProtocol = true;
3117 }
3118
3119 parsingTlsHandshake = false;
3120
3121 // client data may be needed for splicing and for
3122 // tunneling unsupportedProtocol after an error
3123 preservedClientData = inBuf;
3124
3125 // Even if the parser failed, each TLS detail should either be set
3126 // correctly or still be "unknown"; copying unknown detail is a no-op.
3127 Security::TlsDetails::Pointer const &details = tlsParser.details;
3128 clientConnection->tlsNegotiations()->retrieveParsedInfo(details);
3129 if (details && !details->serverName.isEmpty()) {
3130 resetSslCommonName(details->serverName.c_str());
3131 tlsClientSni_ = details->serverName;
3132 }
3133
3134 // We should disable read/write handlers
3135 Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0);
3136 Comm::SetSelect(clientConnection->fd, COMM_SELECT_WRITE, NULL, NULL, 0);
3137
3138 if (unsupportedProtocol) {
3139 Http::StreamPointer context = pipeline.front();
3140 Must(context && context->http);
3141 HttpRequest::Pointer request = context->http->request;
3142 debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
3143 sslBumpMode = Ssl::bumpSplice;
3144 context->http->al->ssl.bumpMode = Ssl::bumpSplice;
3145 if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_PROTOCOL_UNKNOWN))
3146 clientConnection->close();
3147 return;
3148 }
3149
3150 if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
3151 getSslContextStart();
3152 return;
3153 } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
3154 // will call httpsPeeked() with certificate and connection, eventually
3155 FwdState::fwdStart(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw());
3156 } else {
3157 Must(sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare);
3158 startPeekAndSplice();
3159 }
3160 }
3161
3162 void httpsSslBumpStep2AccessCheckDone(allow_t answer, void *data)
3163 {
3164 ConnStateData *connState = (ConnStateData *) data;
3165
3166 // if the connection is closed or closing, just return.
3167 if (!connState->isOpen())
3168 return;
3169
3170 debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
3171 assert(connState->serverBump());
3172 Ssl::BumpMode bumpAction;
3173 if (answer.allowed()) {
3174 bumpAction = (Ssl::BumpMode)answer.kind;
3175 } else
3176 bumpAction = Ssl::bumpSplice;
3177
3178 connState->serverBump()->act.step2 = bumpAction;
3179 connState->sslBumpMode = bumpAction;
3180 Http::StreamPointer context = connState->pipeline.front();
3181 if (ClientHttpRequest *http = (context ? context->http : nullptr))
3182 http->al->ssl.bumpMode = bumpAction;
3183
3184 if (bumpAction == Ssl::bumpTerminate) {
3185 connState->clientConnection->close();
3186 } else if (bumpAction != Ssl::bumpSplice) {
3187 connState->startPeekAndSplice();
3188 } else if (!connState->splice())
3189 connState->clientConnection->close();
3190 }
3191
3192 bool
3193 ConnStateData::splice()
3194 {
3195 // normally we can splice here, because we just got client hello message
3196
3197 if (fd_table[clientConnection->fd].ssl.get()) {
3198 // Restore default read methods
3199 fd_table[clientConnection->fd].read_method = &default_read_method;
3200 fd_table[clientConnection->fd].write_method = &default_write_method;
3201 }
3202
3203 // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
3204 // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
3205 transferProtocol = Http::ProtocolVersion();
3206 assert(!pipeline.empty());
3207 Http::StreamPointer context = pipeline.front();
3208 Must(context);
3209 Must(context->http);
3210 ClientHttpRequest *http = context->http;
3211 HttpRequest::Pointer request = http->request;
3212 context->finished();
3213 if (transparent()) {
3214 // For transparent connections, make a new fake CONNECT request, now
3215 // with SNI as target. doCallout() checks, adaptations may need that.
3216 return fakeAConnectRequest("splice", preservedClientData);
3217 } else {
3218 // For non transparent connections make a new tunneled CONNECT, which
3219 // also sets the HttpRequest::flags::forceTunnel flag to avoid
3220 // respond with "Connection Established" to the client.
3221 // This fake CONNECT request required to allow use of SNI in
3222 // doCallout() checks and adaptations.
3223 return initiateTunneledRequest(request, Http::METHOD_CONNECT, "splice", preservedClientData);
3224 }
3225 }
3226
3227 void
3228 ConnStateData::startPeekAndSplice()
3229 {
3230 // This is the Step2 of the SSL bumping
3231 assert(sslServerBump);
3232 Http::StreamPointer context = pipeline.front();
3233 ClientHttpRequest *http = context ? context->http : nullptr;
3234
3235 if (sslServerBump->step == Ssl::bumpStep1) {
3236 sslServerBump->step = Ssl::bumpStep2;
3237 // Run a accessList check to check if want to splice or continue bumping
3238
3239 ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, sslServerBump->request.getRaw(), nullptr);
3240 acl_checklist->al = http ? http->al : nullptr;
3241 //acl_checklist->src_addr = params.conn->remote;
3242 //acl_checklist->my_addr = s->s;
3243 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpNone));
3244 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpClientFirst));
3245 acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpServerFirst));
3246 acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this);
3247 return;
3248 }
3249
3250 // will call httpsPeeked() with certificate and connection, eventually
3251 Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->signingCert, port->signPkey, *port));
3252 fd_table[clientConnection->fd].dynamicTlsContext = unConfiguredCTX;
3253
3254 if (!httpsCreate(clientConnection, unConfiguredCTX))
3255 return;
3256
3257 switchedToHttps_ = true;
3258
3259 auto ssl = fd_table[clientConnection->fd].ssl.get();
3260 BIO *b = SSL_get_rbio(ssl);
3261 Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3262 bio->setReadBufData(inBuf);
3263 bio->hold(true);
3264
3265 // Here squid should have all of the client hello message so the
3266 // Squid_SSL_accept should return 0;
3267 // This block exist only to force openSSL parse client hello and detect
3268 // ERR_SECURE_ACCEPT_FAIL error, which should be checked and splice if required.
3269 int ret = 0;
3270 if ((ret = Squid_SSL_accept(this, NULL)) < 0) {
3271 debugs(83, 2, "SSL_accept failed.");
3272 HttpRequest::Pointer request(http ? http->request : nullptr);
3273 if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_SECURE_ACCEPT_FAIL))
3274 clientConnection->close();
3275 return;
3276 }
3277
3278 // We need to reset inBuf here, to be used by incoming requests in the case
3279 // of SSL bump
3280 inBuf.clear();
3281
3282 debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3283 FwdState::Start(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw(), http ? http->al : NULL);
3284 }
3285
3286 void
3287 ConnStateData::doPeekAndSpliceStep()
3288 {
3289 auto ssl = fd_table[clientConnection->fd].ssl.get();
3290 BIO *b = SSL_get_rbio(ssl);
3291 assert(b);
3292 Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3293
3294 debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Currrent state:" << SSL_state_string_long(ssl));
3295 bio->hold(false);
3296
3297 Comm::SetSelect(clientConnection->fd, COMM_SELECT_WRITE, clientNegotiateSSL, this, 0);
3298 switchedToHttps_ = true;
3299 }
3300
3301 void
3302 ConnStateData::httpsPeeked(Comm::ConnectionPointer serverConnection)
3303 {
3304 Must(sslServerBump != NULL);
3305
3306 if (Comm::IsConnOpen(serverConnection)) {
3307 pinConnection(serverConnection, NULL, NULL, false);
3308
3309 debugs(33, 5, HERE << "bumped HTTPS server: " << sslConnectHostOrIp);
3310 } else {
3311 debugs(33, 5, HERE << "Error while bumping: " << sslConnectHostOrIp);
3312
3313 // copy error detail from bump-server-first request to CONNECT request
3314 if (!pipeline.empty() && pipeline.front()->http != nullptr && pipeline.front()->http->request)
3315 pipeline.front()->http->request->detailError(sslServerBump->request->errType, sslServerBump->request->errDetail);
3316 }
3317
3318 getSslContextStart();
3319 }
3320
3321 #endif /* USE_OPENSSL */
3322
3323 bool
3324 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload)
3325 {
3326 // fake a CONNECT request to force connState to tunnel
3327 SBuf connectHost;
3328 unsigned short connectPort = 0;
3329
3330 if (pinning.serverConnection != nullptr) {
3331 static char ip[MAX_IPSTRLEN];
3332 pinning.serverConnection->remote.toHostStr(ip, sizeof(ip));
3333 connectHost.assign(ip);
3334 connectPort = pinning.serverConnection->remote.port();
3335 } else if (cause && cause->method == Http::METHOD_CONNECT) {
3336 // We are inside a (not fully established) CONNECT request
3337 connectHost = cause->url.host();
3338 connectPort = cause->url.port();
3339 } else {
3340 debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3341 return false;
3342 }
3343
3344 debugs(33, 2, "Request tunneling for " << reason);
3345 ClientHttpRequest *http = buildFakeRequest(method, connectHost, connectPort, payload);
3346 HttpRequest::Pointer request = http->request;
3347 request->flags.forceTunnel = true;
3348 http->calloutContext = new ClientRequestContext(http);
3349 http->doCallouts();
3350 clientProcessRequestFinished(this, request);
3351 return true;
3352 }
3353
3354 bool
3355 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3356 {
3357 debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3358
3359 SBuf connectHost;
3360 assert(transparent());
3361 const unsigned short connectPort = clientConnection->local.port();
3362
3363 #if USE_OPENSSL
3364 if (!tlsClientSni_.isEmpty())
3365 connectHost.assign(tlsClientSni_);
3366 else
3367 #endif
3368 {
3369 static char ip[MAX_IPSTRLEN];
3370 clientConnection->local.toHostStr(ip, sizeof(ip));
3371 connectHost.assign(ip);
3372 }
3373
3374 ClientHttpRequest *http = buildFakeRequest(Http::METHOD_CONNECT, connectHost, connectPort, payload);
3375
3376 http->calloutContext = new ClientRequestContext(http);
3377 HttpRequest::Pointer request = http->request;
3378 http->doCallouts();
3379 clientProcessRequestFinished(this, request);
3380 return true;
3381 }
3382
3383 ClientHttpRequest *
3384 ConnStateData::buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload)
3385 {
3386 ClientHttpRequest *http = new ClientHttpRequest(this);
3387 Http::Stream *stream = new Http::Stream(clientConnection, http);
3388
3389 StoreIOBuffer tempBuffer;
3390 tempBuffer.data = stream->reqbuf;
3391 tempBuffer.length = HTTP_REQBUF_SZ;
3392
3393 ClientStreamData newServer = new clientReplyContext(http);
3394 ClientStreamData newClient = stream;
3395 clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach,
3396 clientReplyStatus, newServer, clientSocketRecipient,
3397 clientSocketDetach, newClient, tempBuffer);
3398
3399 http->uri = SBufToCstring(useHost);
3400 stream->flags.parsed_ok = 1; // Do we need it?
3401 stream->mayUseConnection(true);
3402
3403 AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout",
3404 CommTimeoutCbPtrFun(clientLifetimeTimeout, stream->http));
3405 commSetConnTimeout(clientConnection, Config.Timeout.lifetime, timeoutCall);
3406
3407 stream->registerWithConn();
3408
3409 MasterXaction::Pointer mx = new MasterXaction(XactionInitiator::initClient);
3410 mx->tcpClient = clientConnection;
3411 // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3412 // clientProcessRequest
3413 HttpRequest::Pointer request = new HttpRequest(mx);
3414 AnyP::ProtocolType proto = (method == Http::METHOD_NONE) ? AnyP::PROTO_AUTHORITY_FORM : AnyP::PROTO_HTTP;
3415 request->url.setScheme(proto, nullptr);
3416 request->method = method;
3417 request->url.host(useHost.c_str());
3418 request->url.port(usePort);
3419 http->request = request.getRaw();
3420 HTTPMSGLOCK(http->request);
3421
3422 request->manager(this, http->al);
3423
3424 if (proto == AnyP::PROTO_HTTP)
3425 request->header.putStr(Http::HOST, useHost.c_str());
3426
3427 request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3428 #if USE_AUTH
3429 if (getAuth())
3430 request->auth_user_request = getAuth();
3431 #endif
3432
3433 inBuf = payload;
3434 flags.readMore = false;
3435
3436 setLogUri(http, urlCanonicalClean(request.getRaw()));
3437 return http;
3438 }
3439
3440 /// check FD after clientHttp[s]ConnectionOpened, adjust HttpSockets as needed
3441 static bool
3442 OpenedHttpSocket(const Comm::ConnectionPointer &c, const Ipc::FdNoteId portType)
3443 {
3444 if (!Comm::IsConnOpen(c)) {
3445 Must(NHttpSockets > 0); // we tried to open some
3446 --NHttpSockets; // there will be fewer sockets than planned
3447 Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3448
3449 if (!NHttpSockets) // we could not open any listen sockets at all
3450 fatalf("Unable to open %s",FdNote(portType));
3451
3452 return false;
3453 }
3454 return true;
3455 }
3456
3457 /// find any unused HttpSockets[] slot and store fd there or return false
3458 static bool
3459 AddOpenedHttpSocket(const Comm::ConnectionPointer &conn)
3460 {
3461 bool found = false;
3462 for (int i = 0; i < NHttpSockets && !found; ++i) {
3463 if ((found = HttpSockets[i] < 0))
3464 HttpSockets[i] = conn->fd;
3465 }
3466 return found;
3467 }
3468
3469 static void
3470 clientHttpConnectionsOpen(void)
3471 {
3472 for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3473 const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3474
3475 if (MAXTCPLISTENPORTS == NHttpSockets) {
3476 debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines.");
3477 debugs(1, DBG_IMPORTANT, " The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3478 continue;
3479 }
3480
3481 #if USE_OPENSSL
3482 if (s->flags.tunnelSslBumping) {
3483 if (!Config.accessList.ssl_bump) {
3484 debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3485 s->flags.tunnelSslBumping = false;
3486 }
3487 if (!s->secure.staticContext && !s->generateHostCertificates) {
3488 debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3489 s->flags.tunnelSslBumping = false;
3490 if (s->transport.protocol == AnyP::PROTO_HTTP)
3491 s->secure.encryptTransport = false;
3492 }
3493 if (s->flags.tunnelSslBumping) {
3494 // Create ssl_ctx cache for this port.
3495 auto sz = s->dynamicCertMemCacheSize == std::numeric_limits<size_t>::max() ? 4194304 : s->dynamicCertMemCacheSize;
3496 Ssl::TheGlobalContextStorage.addLocalStorage(s->s, sz);
3497 }
3498 }
3499
3500 if (s->secure.encryptTransport && !s->secure.staticContext) {
3501 debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3502 continue;
3503 }
3504 #endif
3505
3506 // Fill out a Comm::Connection which IPC will open as a listener for us
3507 // then pass back when active so we can start a TcpAcceptor subscription.
3508 s->listenConn = new Comm::Connection;
3509 s->listenConn->local = s->s;
3510
3511 s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3512 (s->flags.natIntercept ? COMM_INTERCEPTION : 0);
3513
3514 typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3515 if (s->transport.protocol == AnyP::PROTO_HTTP) {
3516 // setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
3517 RefCount<AcceptCall> subCall = commCbCall(5, 5, "httpAccept", CommAcceptCbPtrFun(httpAccept, CommAcceptCbParams(NULL)));
3518 Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
3519
3520 AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
3521 ListeningStartedDialer(&clientListenerConnectionOpened, s, Ipc::fdnHttpSocket, sub));
3522 Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
3523
3524 #if USE_OPENSSL
3525 } else if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3526 // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
3527 RefCount<AcceptCall> subCall = commCbCall(5, 5, "httpsAccept", CommAcceptCbPtrFun(httpsAccept, CommAcceptCbParams(NULL)));
3528 Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
3529
3530 AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
3531 ListeningStartedDialer(&clientListenerConnectionOpened,
3532 s, Ipc::fdnHttpsSocket, sub));
3533 Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
3534 #endif
3535 }
3536
3537 HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened
3538 ++NHttpSockets;
3539 }
3540 }
3541
3542 void
3543 clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT<CommAcceptCbPtrFun> > &subCall, const Ipc::FdNoteId fdNote)
3544 {
3545 // Fill out a Comm::Connection which IPC will open as a listener for us
3546 port->listenConn = new Comm::Connection;
3547 port->listenConn->local = port->s;
3548 port->listenConn->flags =
3549 COMM_NONBLOCKING |
3550 (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3551 (port->flags.natIntercept ? COMM_INTERCEPTION : 0);
3552
3553 // route new connections to subCall
3554 typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3555 Subscription::Pointer sub = new CallSubscription<AcceptCall>(subCall);
3556 AsyncCall::Pointer listenCall =
3557 asyncCall(33, 2, "clientListenerConnectionOpened",
3558 ListeningStartedDialer(&clientListenerConnectionOpened,
3559 port, fdNote, sub));
3560 Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, listenCall);
3561
3562 assert(NHttpSockets < MAXTCPLISTENPORTS);
3563 HttpSockets[NHttpSockets] = -1;
3564 ++NHttpSockets;
3565 }
3566
3567 /// process clientHttpConnectionsOpen result
3568 static void
3569 clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
3570 {
3571 Must(s != NULL);
3572
3573 if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3574 return;
3575
3576 Must(Comm::IsConnOpen(s->listenConn));
3577
3578 // TCP: setup a job to handle accept() with subscribed handler
3579 AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3580
3581 debugs(1, DBG_IMPORTANT, "Accepting " <<
3582 (s->flags.natIntercept ? "NAT intercepted " : "") <<
3583 (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3584 (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3585 (s->flags.accelSurrogate ? "reverse-proxy " : "")
3586 << FdNote(portTypeNote) << " connections at "
3587 << s->listenConn);
3588
3589 Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3590 }
3591
3592 void
3593 clientOpenListenSockets(void)
3594 {
3595 clientHttpConnectionsOpen();
3596 Ftp::StartListening();
3597
3598 if (NHttpSockets < 1)
3599 fatal("No HTTP, HTTPS, or FTP ports configured");
3600 }
3601
3602 void
3603 clientConnectionsClose()
3604 {
3605 for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3606 if (s->listenConn != NULL) {
3607 debugs(1, DBG_IMPORTANT, "Closing HTTP(S) port " << s->listenConn->local);
3608 s->listenConn->close();
3609 s->listenConn = NULL;
3610 }
3611 }
3612
3613 Ftp::StopListening();
3614
3615 // TODO see if we can drop HttpSockets array entirely */
3616 for (int i = 0; i < NHttpSockets; ++i) {
3617 HttpSockets[i] = -1;
3618 }
3619
3620 NHttpSockets = 0;
3621 }
3622
3623 int
3624 varyEvaluateMatch(StoreEntry * entry, HttpRequest * request)
3625 {
3626 SBuf vary(request->vary_headers);
3627 int has_vary = entry->getReply()->header.has(Http::HdrType::VARY);
3628 #if X_ACCELERATOR_VARY
3629
3630 has_vary |=
3631 entry->getReply()->header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
3632 #endif
3633
3634 if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3635 if (!vary.isEmpty()) {
3636 /* Oops... something odd is going on here.. */
3637 debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3638 entry->mem_obj->urlXXX() << "' '" << vary << "'");
3639 request->vary_headers.clear();
3640 return VARY_CANCEL;
3641 }
3642
3643 if (!has_vary) {
3644 /* This is not a varying object */
3645 return VARY_NONE;
3646 }
3647
3648 /* virtual "vary" object found. Calculate the vary key and
3649 * continue the search
3650 */
3651 vary = httpMakeVaryMark(request, entry->getReply());
3652
3653 if (!vary.isEmpty()) {
3654 request->vary_headers = vary;
3655 return VARY_OTHER;
3656 } else {
3657 /* Ouch.. we cannot handle this kind of variance */
3658 /* XXX This cannot really happen, but just to be complete */
3659 return VARY_CANCEL;
3660 }
3661 } else {
3662 if (vary.isEmpty()) {
3663 vary = httpMakeVaryMark(request, entry->getReply());
3664
3665 if (!vary.isEmpty())
3666 request->vary_headers = vary;
3667 }
3668
3669 if (vary.isEmpty()) {
3670 /* Ouch.. we cannot handle this kind of variance */
3671 /* XXX This cannot really happen, but just to be complete */
3672 return VARY_CANCEL;
3673 } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3674 return VARY_MATCH;
3675 } else {
3676 /* Oops.. we have already been here and still haven't
3677 * found the requested variant. Bail out
3678 */
3679 debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3680 entry->mem_obj->urlXXX() << "' '" << vary << "'");
3681 return VARY_CANCEL;
3682 }
3683 }
3684 }
3685
3686 ACLFilledChecklist *
3687 clientAclChecklistCreate(const acl_access * acl, ClientHttpRequest * http)
3688 {
3689 ConnStateData * conn = http->getConn();
3690 ACLFilledChecklist *ch = new ACLFilledChecklist(acl, http->request,
3691 cbdataReferenceValid(conn) && conn != NULL && conn->clientConnection != NULL ? conn->clientConnection->rfc931 : dash_str);
3692 ch->al = http->al;
3693 /*
3694 * hack for ident ACL. It needs to get full addresses, and a place to store
3695 * the ident result on persistent connections...
3696 */
3697 /* connection oriented auth also needs these two lines for it's operation. */
3698 return ch;
3699 }
3700
3701 bool
3702 ConnStateData::transparent() const
3703 {
3704 return clientConnection != NULL && (clientConnection->flags & (COMM_TRANSPARENT|COMM_INTERCEPTION));
3705 }
3706
3707 BodyPipe::Pointer
3708 ConnStateData::expectRequestBody(int64_t size)
3709 {
3710 bodyPipe = new BodyPipe(this);
3711 if (size >= 0)
3712 bodyPipe->setBodySize(size);
3713 else
3714 startDechunkingRequest();
3715 return bodyPipe;
3716 }
3717
3718 int64_t
3719 ConnStateData::mayNeedToReadMoreBody() const
3720 {
3721 if (!bodyPipe)
3722 return 0; // request without a body or read/produced all body bytes
3723
3724 if (!bodyPipe->bodySizeKnown())
3725 return -1; // probably need to read more, but we cannot be sure
3726
3727 const int64_t needToProduce = bodyPipe->unproducedSize();
3728 const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3729
3730 if (needToProduce <= haveAvailable)
3731 return 0; // we have read what we need (but are waiting for pipe space)
3732
3733 return needToProduce - haveAvailable;
3734 }
3735
3736 void
3737 ConnStateData::stopReceiving(const char *error)
3738 {
3739 debugs(33, 4, HERE << "receiving error (" << clientConnection << "): " << error <<
3740 "; old sending error: " <<
3741 (stoppedSending() ? stoppedSending_ : "none"));
3742
3743 if (const char *oldError = stoppedReceiving()) {
3744 debugs(33, 3, HERE << "already stopped receiving: " << oldError);
3745 return; // nothing has changed as far as this connection is concerned
3746 }
3747
3748 stoppedReceiving_ = error;
3749
3750 if (const char *sendError = stoppedSending()) {
3751 debugs(33, 3, HERE << "closing because also stopped sending: " << sendError);
3752 clientConnection->close();
3753 }
3754 }
3755
3756 void
3757 ConnStateData::expectNoForwarding()
3758 {
3759 if (bodyPipe != NULL) {
3760 debugs(33, 4, HERE << "no consumer for virgin body " << bodyPipe->status());
3761 bodyPipe->expectNoConsumption();
3762 }
3763 }
3764
3765 /// initialize dechunking state
3766 void
3767 ConnStateData::startDechunkingRequest()
3768 {
3769 Must(bodyPipe != NULL);
3770 debugs(33, 5, HERE << "start dechunking" << bodyPipe->status());
3771 assert(!bodyParser);
3772 bodyParser = new Http1::TeChunkedParser;
3773 }
3774
3775 /// put parsed content into input buffer and clean up
3776 void
3777 ConnStateData::finishDechunkingRequest(bool withSuccess)
3778 {
3779 debugs(33, 5, HERE << "finish dechunking: " << withSuccess);
3780
3781 if (bodyPipe != NULL) {
3782 debugs(33, 7, HERE << "dechunked tail: " << bodyPipe->status());
3783 BodyPipe::Pointer myPipe = bodyPipe;
3784 stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3785 Must(!bodyPipe); // we rely on it being nil after we are done with body
3786 if (withSuccess) {
3787 Must(myPipe->bodySizeKnown());
3788 Http::StreamPointer context = pipeline.front();
3789 if (context != NULL && context->http && context->http->request)
3790 context->http->request->setContentLength(myPipe->bodySize());
3791 }
3792 }
3793
3794 delete bodyParser;
3795 bodyParser = NULL;
3796 }
3797
3798 // XXX: this is an HTTP/1-only operation
3799 void
3800 ConnStateData::sendControlMsg(HttpControlMsg msg)
3801 {
3802 if (!isOpen()) {
3803 debugs(33, 3, HERE << "ignoring 1xx due to earlier closure");
3804 return;
3805 }
3806
3807 // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3808 if (!pipeline.empty()) {
3809 HttpReply::Pointer rep(msg.reply);
3810 Must(rep);
3811 // remember the callback
3812 cbControlMsgSent = msg.cbSuccess;
3813
3814 typedef CommCbMemFunT<HttpControlMsgSink, CommIoCbParams> Dialer;
3815 AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, HttpControlMsgSink::wroteControlMsg);
3816
3817 if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3818 // but still inform the caller (so it may resume its operation)
3819 doneWithControlMsg();
3820 }
3821 return;
3822 }
3823
3824 debugs(33, 3, HERE << " closing due to missing context for 1xx");
3825 clientConnection->close();
3826 }
3827
3828 void
3829 ConnStateData::doneWithControlMsg()
3830 {
3831 HttpControlMsgSink::doneWithControlMsg();
3832
3833 if (Http::StreamPointer deferredRequest = pipeline.front()) {
3834 debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3835 ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3836 }
3837 }
3838
3839 /// Our close handler called by Comm when the pinned connection is closed
3840 void
3841 ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io)
3842 {
3843 // FwdState might repin a failed connection sooner than this close
3844 // callback is called for the failed connection.
3845 assert(pinning.serverConnection == io.conn);
3846 pinning.closeHandler = NULL; // Comm unregisters handlers before calling
3847 const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3848 pinning.serverConnection->noteClosure();
3849 unpinConnection(false);
3850
3851 if (sawZeroReply && clientConnection != NULL) {
3852 debugs(33, 3, "Closing client connection on pinned zero reply.");
3853 clientConnection->close();
3854 }
3855
3856 }
3857
3858 void
3859 ConnStateData::pinConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth, bool monitor)
3860 {
3861 if (!Comm::IsConnOpen(pinning.serverConnection) ||
3862 pinning.serverConnection->fd != pinServer->fd)
3863 pinNewConnection(pinServer, request, aPeer, auth);
3864
3865 if (monitor)
3866 startPinnedConnectionMonitoring();
3867 }
3868
3869 void
3870 ConnStateData::pinNewConnection(const Comm::ConnectionPointer &pinServer, HttpRequest *request, CachePeer *aPeer, bool auth)
3871 {
3872 unpinConnection(true); // closes pinned connection, if any, and resets fields
3873
3874 pinning.serverConnection = pinServer;
3875
3876 debugs(33, 3, HERE << pinning.serverConnection);
3877
3878 Must(pinning.serverConnection != NULL);
3879
3880 // when pinning an SSL bumped connection, the request may be NULL
3881 const char *pinnedHost = "[unknown]";
3882 if (request) {
3883 pinning.host = xstrdup(request->url.host());
3884 pinning.port = request->url.port();
3885 pinnedHost = pinning.host;
3886 } else {
3887 pinning.port = pinServer->remote.port();
3888 }
3889 pinning.pinned = true;
3890 if (aPeer)
3891 pinning.peer = cbdataReference(aPeer);
3892 pinning.auth = auth;
3893 char stmp[MAX_IPSTRLEN];
3894 char desc[FD_DESC_SZ];
3895 snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3896 (auth || !aPeer) ? pinnedHost : aPeer->name,
3897 clientConnection->remote.toUrl(stmp,MAX_IPSTRLEN),
3898 clientConnection->fd);
3899 fd_note(pinning.serverConnection->fd, desc);
3900
3901 typedef CommCbMemFunT<ConnStateData, CommCloseCbParams> Dialer;
3902 pinning.closeHandler = JobCallback(33, 5,
3903 Dialer, this, ConnStateData::clientPinnedConnectionClosed);
3904 // remember the pinned connection so that cb does not unpin a fresher one
3905 typedef CommCloseCbParams Params;
3906 Params &params = GetCommParams<Params>(pinning.closeHandler);
3907 params.conn = pinning.serverConnection;
3908 comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3909 }
3910
3911 /// [re]start monitoring pinned connection for peer closures so that we can
3912 /// propagate them to an _idle_ client pinned to that peer
3913 void
3914 ConnStateData::startPinnedConnectionMonitoring()
3915 {
3916 if (pinning.readHandler != NULL)
3917 return; // already monitoring
3918
3919 typedef CommCbMemFunT<ConnStateData, CommIoCbParams> Dialer;
3920 pinning.readHandler = JobCallback(33, 3,
3921 Dialer, this, ConnStateData::clientPinnedConnectionRead);
3922 Comm::Read(pinning.serverConnection, pinning.readHandler);
3923 }
3924
3925 void
3926 ConnStateData::stopPinnedConnectionMonitoring()
3927 {
3928 if (pinning.readHandler != NULL) {
3929 Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
3930 pinning.readHandler = NULL;
3931 }
3932 }
3933
3934 #if USE_OPENSSL
3935 bool
3936 ConnStateData::handleIdleClientPinnedTlsRead()
3937 {
3938 // A ready-for-reading connection means that the TLS server either closed
3939 // the connection, sent us some unexpected HTTP data, or started TLS
3940 // renegotiations. We should close the connection except for the last case.
3941
3942 Must(pinning.serverConnection != nullptr);
3943 auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
3944 if (!ssl)
3945 return false;
3946
3947 char buf[1];
3948 const int readResult = SSL_read(ssl, buf, sizeof(buf));
3949
3950 if (readResult > 0 || SSL_pending(ssl) > 0) {
3951 debugs(83, 2, pinning.serverConnection << " TLS application data read");
3952 return false;
3953 }
3954
3955 switch(const int error = SSL_get_error(ssl, readResult)) {
3956 case SSL_ERROR_WANT_WRITE:
3957 debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
3958 // fall through to restart monitoring, for now
3959 case SSL_ERROR_NONE:
3960 case SSL_ERROR_WANT_READ:
3961 startPinnedConnectionMonitoring();
3962 return true;
3963
3964 default:
3965 debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
3966 return false;
3967 }
3968
3969 // not reached
3970 return true;
3971 }
3972 #endif
3973
3974 /// Our read handler called by Comm when the server either closes an idle pinned connection or
3975 /// perhaps unexpectedly sends something on that idle (from Squid p.o.v.) connection.
3976 void
3977 ConnStateData::clientPinnedConnectionRead(const CommIoCbParams &io)
3978 {
3979 pinning.readHandler = NULL; // Comm unregisters handlers before calling
3980
3981 if (io.flag == Comm::ERR_CLOSING)
3982 return; // close handler will clean up
3983
3984 Must(pinning.serverConnection == io.conn);
3985
3986 #if USE_OPENSSL
3987 if (handleIdleClientPinnedTlsRead())
3988 return;
3989 #endif
3990
3991 const bool clientIsIdle = pipeline.empty();
3992
3993 debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
3994 io.size << (clientIsIdle ? " with idle client" : ""));
3995
3996 pinning.serverConnection->close();
3997
3998 // If we are still sending data to the client, do not close now. When we are done sending,
3999 // ConnStateData::kick() checks pinning.serverConnection and will close.
4000 // However, if we are idle, then we must close to inform the idle client and minimize races.
4001 if (clientIsIdle && clientConnection != NULL)
4002 clientConnection->close();
4003 }
4004
4005 const Comm::ConnectionPointer
4006 ConnStateData::validatePinnedConnection(HttpRequest *request, const CachePeer *aPeer)
4007 {
4008 debugs(33, 7, HERE << pinning.serverConnection);
4009
4010 bool valid = true;
4011 if (!Comm::IsConnOpen(pinning.serverConnection))
4012 valid = false;
4013 else if (pinning.auth && pinning.host && request && strcasecmp(pinning.host, request->url.host()) != 0)
4014 valid = false;
4015 else if (request && pinning.port != request->url.port())
4016 valid = false;
4017 else if (pinning.peer && !cbdataReferenceValid(pinning.peer))
4018 valid = false;
4019 else if (aPeer != pinning.peer)
4020 valid = false;
4021
4022 if (!valid) {
4023 /* The pinning info is not safe, remove any pinning info */
4024 unpinConnection(true);
4025 }
4026
4027 return pinning.serverConnection;
4028 }
4029
4030 Comm::ConnectionPointer
4031 ConnStateData::borrowPinnedConnection(HttpRequest *request, const CachePeer *aPeer)
4032 {
4033 debugs(33, 7, pinning.serverConnection);
4034 if (validatePinnedConnection(request, aPeer) != NULL)
4035 stopPinnedConnectionMonitoring();
4036
4037 return pinning.serverConnection; // closed if validation failed
4038 }
4039
4040 void
4041 ConnStateData::unpinConnection(const bool andClose)
4042 {
4043 debugs(33, 3, HERE << pinning.serverConnection);
4044
4045 if (pinning.peer)
4046 cbdataReferenceDone(pinning.peer);
4047
4048 if (Comm::IsConnOpen(pinning.serverConnection)) {
4049 if (pinning.closeHandler != NULL) {
4050 comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
4051 pinning.closeHandler = NULL;
4052 }
4053
4054 stopPinnedConnectionMonitoring();
4055
4056 // close the server side socket if requested
4057 if (andClose)
4058 pinning.serverConnection->close();
4059 pinning.serverConnection = NULL;
4060 }
4061
4062 safe_free(pinning.host);
4063
4064 pinning.zeroReply = false;
4065
4066 /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
4067 * connection has gone away */
4068 }
4069
4070 void
4071 ConnStateData::checkLogging()
4072 {
4073 // if we are parsing request body, its request is responsible for logging
4074 if (bodyPipe)
4075 return;
4076
4077 // a request currently using this connection is responsible for logging
4078 if (!pipeline.empty() && pipeline.back()->mayUseConnection())
4079 return;
4080
4081 /* Either we are waiting for the very first transaction, or
4082 * we are done with the Nth transaction and are waiting for N+1st.
4083 * XXX: We assume that if anything was added to inBuf, then it could
4084 * only be consumed by actions already covered by the above checks.
4085 */
4086
4087 // do not log connections that closed after a transaction (it is normal)
4088 // TODO: access_log needs ACLs to match received-no-bytes connections
4089 if (pipeline.nrequests && inBuf.isEmpty())
4090 return;
4091
4092 /* Create a temporary ClientHttpRequest object. Its destructor will log. */
4093 ClientHttpRequest http(this);
4094 http.req_sz = inBuf.length();
4095 char const *uri = "error:transaction-end-before-headers";
4096 http.uri = xstrdup(uri);
4097 setLogUri(&http, uri);
4098 }
4099
4100 bool
4101 ConnStateData::mayTunnelUnsupportedProto()
4102 {
4103 return Config.accessList.on_unsupported_protocol
4104 #if USE_OPENSSL
4105 &&
4106 ((port->flags.isIntercepted() && port->flags.tunnelSslBumping)
4107 || (serverBump() && pinning.serverConnection))
4108 #endif
4109 ;
4110 }
4111
4112 NotePairs::Pointer
4113 ConnStateData::notes()
4114 {
4115 if (!theNotes)
4116 theNotes = new NotePairs;
4117 return theNotes;
4118 }
4119