client_side.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 33 Client-side Routines */
10 
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 "debug/Messages.h"
81 #include "errorpage.h"
82 #include "fd.h"
83 #include "fde.h"
84 #include "fqdncache.h"
85 #include "FwdState.h"
86 #include "globals.h"
87 #include "helper.h"
88 #include "helper/Reply.h"
89 #include "http.h"
90 #include "http/one/RequestParser.h"
92 #include "http/Stream.h"
93 #include "HttpHdrContRange.h"
94 #include "HttpHeaderTools.h"
95 #include "HttpReply.h"
96 #include "HttpRequest.h"
97 #include "ident/Config.h"
98 #include "ident/Ident.h"
99 #include "internal.h"
100 #include "ipc/FdNotes.h"
101 #include "ipc/StartListening.h"
102 #include "log/access_log.h"
103 #include "MemBuf.h"
104 #include "MemObject.h"
105 #include "mime_header.h"
106 #include "parser/Tokenizer.h"
107 #include "proxyp/Header.h"
108 #include "proxyp/Parser.h"
109 #include "sbuf/Stream.h"
111 #include "security/Io.h"
112 #include "security/KeyLog.h"
114 #include "servers/forward.h"
115 #include "SquidConfig.h"
116 #include "StatCounters.h"
117 #include "StatHist.h"
118 #include "Store.h"
119 #include "TimeOrTag.h"
120 #include "tools.h"
121 
122 #if USE_AUTH
123 #include "auth/UserRequest.h"
124 #endif
125 #if USE_DELAY_POOLS
126 #include "ClientInfo.h"
127 #include "MessageDelayPools.h"
128 #endif
129 #if USE_OPENSSL
130 #include "ssl/bio.h"
131 #include "ssl/context_storage.h"
132 #include "ssl/gadgets.h"
133 #include "ssl/helper.h"
134 #include "ssl/ProxyCerts.h"
135 #include "ssl/ServerBump.h"
136 #include "ssl/support.h"
137 #endif
138 
139 #include <climits>
140 #include <cmath>
141 #include <limits>
142 
143 #if HAVE_SYSTEMD_SD_DAEMON_H
144 #include <systemd/sd-daemon.h>
145 #endif
146 
149 {
150 public:
153  handler(aHandler), portCfg(aPortCfg), portTypeNote(note), sub(aSub) {}
154 
155  virtual void print(std::ostream &os) const {
156  startPrint(os) <<
157  ", " << FdNote(portTypeNote) << " port=" << (void*)&portCfg << ')';
158  }
159 
160  virtual bool canDial(AsyncCall &) const { return true; }
161  virtual void dial(AsyncCall &) { (handler)(portCfg, portTypeNote, sub); }
162 
163 public:
165 
166 private:
170 };
171 
172 static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub);
173 
175 #if USE_IDENT
177 #endif
178 static int clientIsRequestBodyTooLargeForPolicy(int64_t bodyLength);
179 
180 static void clientUpdateStatHistCounters(const LogTags &logType, int svc_time);
181 static void clientUpdateStatCounters(const LogTags &logType);
183 static bool clientPingHasFinished(ping_data const *aPing);
186 
187 char *skipLeadingSpace(char *aString);
188 
189 #if USE_IDENT
190 static void
191 clientIdentDone(const char *ident, void *data)
192 {
193  ConnStateData *conn = (ConnStateData *)data;
194  xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
195 }
196 #endif
197 
198 void
200 {
202 
203  if (logType.isTcpHit())
205 
206  if (logType.oldType == LOG_TCP_HIT)
208  else if (logType.oldType == LOG_TCP_MEM_HIT)
210 }
211 
212 void
213 clientUpdateStatHistCounters(const LogTags &logType, int svc_time)
214 {
223  switch (logType.oldType) {
224 
227  break;
228 
229  case LOG_TCP_INM_HIT:
230  case LOG_TCP_IMS_HIT:
232  break;
233 
234  case LOG_TCP_HIT:
235 
236  case LOG_TCP_MEM_HIT:
237 
238  case LOG_TCP_OFFLINE_HIT:
240  break;
241 
242  case LOG_TCP_MISS:
243 
246  break;
247 
248  default:
249  /* make compiler warnings go away */
250  break;
251  }
252 }
253 
254 bool
256 {
257  if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
258  return true;
259 
260  return false;
261 }
262 
263 void
265 {
266  ping_data *i;
267 
268  switch (someEntry->code) {
269 #if USE_CACHE_DIGESTS
270 
271  case CD_PARENT_HIT:
272 
273  case CD_SIBLING_HIT:
275  break;
276 #endif
277 
278  case SIBLING_HIT:
279 
280  case PARENT_HIT:
281 
282  case FIRST_PARENT_MISS:
283 
284  case CLOSEST_PARENT_MISS:
286  i = &someEntry->ping;
287 
288  if (clientPingHasFinished(i))
290 
291  if (i->timeout)
293 
294  break;
295 
296  case CLOSEST_PARENT:
297 
298  case CLOSEST_DIRECT:
300 
301  break;
302 
303  default:
304  break;
305  }
306 }
307 
308 void
310 {
312 
313  if (request->error)
315 
317  tvSubMsec(al->cache.start_time, current_time));
318 
320 }
321 
322 void
324 {
325  assert(request);
326  assert(aLogEntry != NULL);
327 
328  if (Config.onoff.log_mime_hdrs) {
329  MemBuf mb;
330  mb.init();
331  request->header.packInto(&mb);
332  //This is the request after adaptation or redirection
333  aLogEntry->headers.adapted_request = xstrdup(mb.buf);
334 
335  // the virgin request is saved to aLogEntry->request
336  if (aLogEntry->request) {
337  mb.reset();
338  aLogEntry->request->header.packInto(&mb);
339  aLogEntry->headers.request = xstrdup(mb.buf);
340  }
341 
342 #if USE_ADAPTATION
343  const Adaptation::History::Pointer ah = request->adaptLogHistory();
344  if (ah != NULL) {
345  mb.reset();
346  ah->lastMeta.packInto(&mb);
347  aLogEntry->adapt.last_meta = xstrdup(mb.buf);
348  }
349 #endif
350 
351  mb.clean();
352  }
353 
354 #if ICAP_CLIENT
355  const Adaptation::Icap::History::Pointer ih = request->icapHistory();
356  if (ih != NULL)
357  ih->processingTime(aLogEntry->icap.processingTime);
358 #endif
359 
360  aLogEntry->http.method = request->method;
361  aLogEntry->http.version = request->http_ver;
362  aLogEntry->hier = request->hier;
363  aLogEntry->cache.extuser = request->extacl_user.termedBuf();
364 
365  // Adapted request, if any, inherits and then collects all the stats, but
366  // the virgin request gets logged instead; copy the stats to log them.
367  // TODO: avoid losses by keeping these stats in a shared history object?
368  if (aLogEntry->request) {
369  aLogEntry->request->dnsWait = request->dnsWait;
370  aLogEntry->request->error = request->error;
371  }
372 }
373 
374 void
376 {
377  if (!out.size && loggingTags().oldType == LOG_TAG_NONE)
378  debugs(33, 5, "logging half-baked transaction: " << log_uri);
379 
380  al->icp.opcode = ICP_INVALID;
381  al->url = log_uri;
382  debugs(33, 9, "clientLogRequest: al.url='" << al->url << "'");
383 
384  const auto findReply = [this]() -> const HttpReply * {
385  if (al->reply)
386  return al->reply.getRaw();
387  if (const auto le = loggingEntry())
388  return le->hasFreshestReply();
389  return nullptr;
390  };
391  if (const auto reply = findReply()) {
392  al->http.code = reply->sline.status();
393  al->http.content_type = reply->content_type.termedBuf();
394  }
395 
396  debugs(33, 9, "clientLogRequest: http.code='" << al->http.code << "'");
397 
398  if (loggingEntry() && loggingEntry()->mem_obj && loggingEntry()->objectLen() >= 0)
399  al->cache.objectSize = loggingEntry()->contentLen(); // payload duplicate ?? with or without TE ?
400 
401  al->http.clientRequestSz.header = req_sz;
402  // the virgin request is saved to al->request
403  if (al->request && al->request->body_pipe)
404  al->http.clientRequestSz.payloadData = al->request->body_pipe->producedSize();
405  al->http.clientReplySz.header = out.headers_sz;
406  // XXX: calculate without payload encoding or headers !!
407  al->http.clientReplySz.payloadData = out.size - out.headers_sz; // pretend its all un-encoded data for now.
408 
409  al->cache.highOffset = out.offset;
410 
411  tvSub(al->cache.trTime, al->cache.start_time, current_time);
412 
413  if (request)
415 
416 #if USE_OPENSSL && 0
417 
418  /* This is broken. Fails if the connection has been closed. Needs
419  * to snarf the ssl details some place earlier..
420  */
421  if (getConn() != NULL)
422  al->cache.ssluser = sslGetUserEmail(fd_table[getConn()->fd].ssl);
423 
424 #endif
425 
426  /* Add notes (if we have a request to annotate) */
427  if (request) {
428  SBuf matched;
429  for (auto h: Config.notes) {
430  if (h->match(request, al->reply.getRaw(), al, matched)) {
431  request->notes()->add(h->key(), matched);
432  debugs(33, 3, h->key() << " " << matched);
433  }
434  }
435  // The al->notes and request->notes must point to the same object.
436  al->syncNotes(request);
437  }
438 
439  ACLFilledChecklist checklist(NULL, request, NULL);
440  if (al->reply) {
441  checklist.reply = al->reply.getRaw();
442  HTTPMSGLOCK(checklist.reply);
443  }
444 
445  if (request) {
446  HTTPMSGUNLOCK(al->adapted_request);
447  al->adapted_request = request;
448  HTTPMSGLOCK(al->adapted_request);
449  }
450  // no need checklist.syncAle(): already synced
451  checklist.al = al;
452  accessLogLog(al, &checklist);
453 
454  bool updatePerformanceCounters = true;
457  statsCheck.al = al;
458  if (al->reply) {
459  statsCheck.reply = al->reply.getRaw();
460  HTTPMSGLOCK(statsCheck.reply);
461  }
462  updatePerformanceCounters = statsCheck.fastCheck().allowed();
463  }
464 
465  if (updatePerformanceCounters) {
466  if (request)
467  updateCounters();
468 
469  if (getConn() != NULL && getConn()->clientConnection != NULL)
470  clientdbUpdate(getConn()->clientConnection->remote, loggingTags(), AnyP::PROTO_HTTP, out.size);
471  }
472 }
473 
474 void
476 {
477  safe_free(uri);
480  clearRequest();
481 
482  if (client_stream.tail)
484 }
485 
486 void
487 httpRequestFree(void *data)
488 {
489  ClientHttpRequest *http = (ClientHttpRequest *)data;
490  assert(http != NULL);
491  delete http;
492 }
493 
494 /* This is a handler normally called by comm_close() */
496 {
497  if (clientConnection) {
499  // keep closed clientConnection for logging, clientdb cleanup, etc.
500  }
501  deleteThis("ConnStateData::connStateClosed");
502 }
503 
504 #if USE_AUTH
505 void
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);
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);
574  auth_ = NULL;
575  // this is a fatal type of problem.
576  // Close the connection immediately with TCP RST to abort all traffic flow
578  return;
579  }
580 
581  /* NOT REACHABLE */
582 }
583 #endif
584 
585 void
586 ConnStateData::resetReadTimeout(const time_t timeout)
587 {
589  AsyncCall::Pointer callback = JobCallback(33, 5, TimeoutDialer, this, ConnStateData::requestTimeout);
590  commSetConnTimeout(clientConnection, timeout, callback);
591 }
592 
593 void
595 {
597  AsyncCall::Pointer callback = JobCallback(5, 4, TimeoutDialer, this, ConnStateData::lifetimeTimeout);
599 }
600 
601 // cleans up before destructor is called
602 void
604 {
605  debugs(33, 2, clientConnection);
606 
607  flags.readMore = false;
608  clientdbEstablished(clientConnection->remote, -1); /* decrement */
609 
611  checkLogging();
612 
613  // XXX: Closing pinned conn is too harsh: The Client may want to continue!
614  unpinConnection(true);
615 
617 
618 #if USE_AUTH
619  // NP: do this bit after closing the connections to avoid side effects from unwanted TCP RST
620  setAuth(NULL, "ConnStateData::SwanSong cleanup");
621 #endif
622 
623  flags.swanSang = true;
624 }
625 
626 void
627 ConnStateData::callException(const std::exception &ex)
628 {
629  Server::callException(ex); // logs ex and stops the job
630 
631  ErrorDetail::Pointer errorDetail;
632  if (const auto tex = dynamic_cast<const TextException*>(&ex))
633  errorDetail = new ExceptionErrorDetail(tex->id());
634  else
635  errorDetail = new ExceptionErrorDetail(Here().id());
636  updateError(ERR_GATEWAY_FAILURE, errorDetail);
637 }
638 
639 void
641 {
642  if (const auto context = pipeline.front()) {
643  const auto http = context->http;
644  assert(http);
645  http->updateError(error);
646  } else {
648  }
649 }
650 
651 bool
653 {
654  return cbdataReferenceValid(this) && // XXX: checking "this" in a method
656  !fd_table[clientConnection->fd].closing();
657 }
658 
660 {
661  debugs(33, 3, clientConnection);
662 
663  if (isOpen())
664  debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData did not close " << clientConnection);
665 
666  if (!flags.swanSang)
667  debugs(33, DBG_IMPORTANT, "ERROR: Squid BUG: ConnStateData was not destroyed properly; " << clientConnection);
668 
669  if (bodyPipe != NULL)
670  stopProducingFor(bodyPipe, false);
671 
672  delete bodyParser; // TODO: pool
673 
674 #if USE_OPENSSL
675  delete sslServerBump;
676 #endif
677 }
678 
685 void
687 {
688  HttpRequest *request = http->request;
689 
690  debugs(33, 3, "http_ver = " << request->http_ver);
691  debugs(33, 3, "method = " << request->method);
692 
693  // TODO: move to HttpRequest::hdrCacheInit, just like HttpReply.
694  request->flags.proxyKeepalive = request->persistent();
695 }
696 
697 int
699 {
701  bodyLength > Config.maxRequestBodySize)
702  return 1; /* too large */
703 
704  return 0;
705 }
706 
707 bool
709 {
710  return request->multipartRangeRequest();
711 }
712 
713 void
715 {
716  mb->appendf("\r\n--" SQUIDSTRINGPH "--\r\n", SQUIDSTRINGPRINT(boundary));
717  debugs(33, 6, "buf offset: " << mb->size);
718 }
719 
720 void
721 clientPackRangeHdr(const HttpReplyPointer &rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb)
722 {
723  HttpHeader hdr(hoReply);
724  assert(rep);
725  assert(spec);
726 
727  /* put boundary */
728  debugs(33, 5, "appending boundary: " << boundary);
729  /* rfc2046 requires to _prepend_ boundary with <crlf>! */
730  mb->appendf("\r\n--" SQUIDSTRINGPH "\r\n", SQUIDSTRINGPRINT(boundary));
731 
732  /* stuff the header with required entries and pack it */
733 
734  if (rep->header.has(Http::HdrType::CONTENT_TYPE))
736 
737  httpHeaderAddContRange(&hdr, *spec, rep->content_length);
738 
739  hdr.packInto(mb);
740  hdr.clean();
741 
742  /* append <crlf> (we packed a header, not a reply) */
743  mb->append("\r\n", 2);
744 }
745 
751 int64_t
753 {
754  int64_t clen = 0;
755  MemBuf mb;
756 
757  assert(memObject());
758 
759  mb.init();
761 
762  while (pos != request->range->end()) {
763  /* account for headers for this range */
764  mb.reset();
765  clientPackRangeHdr(&storeEntry()->mem().freshestReply(),
766  *pos, range_iter.boundary, &mb);
767  clen += mb.size;
768 
769  /* account for range content */
770  clen += (*pos)->length;
771 
772  debugs(33, 6, "clientMRangeCLen: (clen += " << mb.size << " + " << (*pos)->length << ") == " << clen);
773  ++pos;
774  }
775 
776  /* account for the terminating boundary */
777  mb.reset();
778 
780 
781  clen += mb.size;
782 
783  mb.clean();
784 
785  return clen;
786 }
787 
791 String
793 {
794  const char *key;
795  String b(APP_FULLNAME);
796  b.append(":",1);
797  key = storeEntry()->getMD5Text();
798  b.append(key, strlen(key));
799  return b;
800 }
801 
811 void
813  HttpReply * rep, StoreIOBuffer receivedData)
814 {
815  // do not try to deliver if client already ABORTED
816  if (!http->getConn() || !cbdataReferenceValid(http->getConn()) || !Comm::IsConnOpen(http->getConn()->clientConnection))
817  return;
818 
819  /* Test preconditions */
820  assert(node != NULL);
821  /* TODO: handle this rather than asserting
822  * - it should only ever happen if we cause an abort and
823  * the callback chain loops back to here, so we can simply return.
824  * However, that itself shouldn't happen, so it stays as an assert for now.
825  */
827  assert(node->node.next == NULL);
828  Http::StreamPointer context = dynamic_cast<Http::Stream *>(node->data.getRaw());
829  assert(context != NULL);
830 
831  /* TODO: check offset is what we asked for */
832 
833  // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
834  if (context != http->getConn()->pipeline.front())
835  context->deferRecipientForLater(node, rep, receivedData);
836  else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending
837  context->deferRecipientForLater(node, rep, receivedData);
838  else
839  http->getConn()->handleReply(rep, receivedData);
840 }
841 
847 void
849 {
850  /* Test preconditions */
851  assert(node != NULL);
852  /* TODO: handle this rather than asserting
853  * - it should only ever happen if we cause an abort and
854  * the callback chain loops back to here, so we can simply return.
855  * However, that itself shouldn't happen, so it stays as an assert for now.
856  */
858  /* Set null by ContextFree */
859  assert(node->node.next == NULL);
860  /* this is the assert discussed above */
861  assert(NULL == dynamic_cast<Http::Stream *>(node->data.getRaw()));
862  /* We are only called when the client socket shutsdown.
863  * Tell the prev pipeline member we're finished
864  */
865  clientStreamDetach(node, http);
866 }
867 
868 void
870 {
871  debugs(33, 5, clientConnection << " reading next req");
872 
873  fd_note(clientConnection->fd, "Idle client: Waiting for next request");
878 
879  readSomeData();
881 }
882 
883 static void
885 {
886  debugs(33, 2, conn->clientConnection << " Sending next");
887 
890  if (deferredRequest->flags.deferred) {
892  assert(deferredRequest->http->out.size == 0);
894  clientSocketRecipient(deferredRequest->deferredparams.node,
895  deferredRequest->http,
896  deferredRequest->deferredparams.rep,
897  deferredRequest->deferredparams.queuedBuffer);
898  }
899 
903 }
904 
905 void
907 {
909  debugs(33, 2, clientConnection << " Connection was closed");
910  return;
911  }
912 
913  if (pinning.pinned && !Comm::IsConnOpen(pinning.serverConnection)) {
914  debugs(33, 2, clientConnection << " Connection was pinned but server side gone. Terminating client connection");
916  return;
917  }
918 
933  if (const char *reason = stoppedReceiving()) {
934  debugs(33, 3, "closing for earlier request error: " << reason);
936  return;
937  }
938 
949  if (clientParseRequests()) {
950  debugs(33, 3, clientConnection << ": parsed next request from buffer");
951  }
952 
961  debugs(33, 3, "half-closed client with no pending requests, closing");
963  return;
964  }
965 
973  Http::StreamPointer deferredRequest = pipeline.front();
974  if (deferredRequest != nullptr) {
975  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded");
976  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
977  } else if (flags.readMore) {
978  debugs(33, 3, clientConnection << ": calling readNextRequest()");
979  readNextRequest();
980  } else {
981  // XXX: Can this happen? CONNECT tunnels have deferredRequest set.
982  debugs(33, DBG_IMPORTANT, MYNAME << "abandoning " << clientConnection);
983  }
984 }
985 
986 void
988 {
989  debugs(33, 4, "sending error (" << clientConnection << "): " << error <<
990  "; old receiving error: " <<
991  (stoppedReceiving() ? stoppedReceiving_ : "none"));
992 
993  if (const char *oldError = stoppedSending()) {
994  debugs(33, 3, "already stopped sending: " << oldError);
995  return; // nothing has changed as far as this connection is concerned
996  }
998 
999  if (!stoppedReceiving()) {
1000  if (const int64_t expecting = mayNeedToReadMoreBody()) {
1001  debugs(33, 5, "must still read " << expecting <<
1002  " request body bytes with " << inBuf.length() << " unused");
1003  return; // wait for the request receiver to finish reading
1004  }
1005  }
1006 
1008 }
1009 
1010 void
1012 {
1013  if (pipeline.empty())
1014  return;
1015 
1016  auto ctx = pipeline.front();
1017  if (size) {
1019  if (ctx->http->loggingTags().isTcpHit())
1021  }
1022  ctx->writeComplete(size);
1023 }
1024 
1025 Http::Stream *
1027 {
1028  ClientHttpRequest *http = new ClientHttpRequest(this);
1029  http->req_sz = inBuf.length();
1030  http->setErrorUri(uri);
1031  auto *context = new Http::Stream(clientConnection, http);
1032  StoreIOBuffer tempBuffer;
1033  tempBuffer.data = context->reqbuf;
1034  tempBuffer.length = HTTP_REQBUF_SZ;
1037  clientSocketDetach, context, tempBuffer);
1038  return context;
1039 }
1040 
1041 void
1043 {
1044  // RegisteredRunner API callback - Squid has been shut down
1045 
1046  // if connection is idle terminate it now,
1047  // otherwise wait for grace period to end
1048  if (pipeline.empty())
1049  endingShutdown();
1050 }
1051 
1052 void
1054 {
1055  // RegisteredRunner API callback - Squid shutdown grace period is over
1056 
1057  // force the client connection to close immediately
1058  // swanSong() in the close handler will cleanup.
1061 }
1062 
1063 char *
1064 skipLeadingSpace(char *aString)
1065 {
1066  char *result = aString;
1067 
1068  while (xisspace(*aString))
1069  ++aString;
1070 
1071  return result;
1072 }
1073 
1079 const char *
1080 findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
1081 {
1082  if (NULL == end) {
1083  end = uriAndHTTPVersion + strcspn(uriAndHTTPVersion, "\r\n");
1084  assert(end);
1085  }
1086 
1087  for (; end > uriAndHTTPVersion; --end) {
1088  if (*end == '\n' || *end == '\r')
1089  continue;
1090 
1091  if (xisspace(*end)) {
1092  if (strncasecmp(end + 1, "HTTP/", 5) == 0)
1093  return end + 1;
1094  else
1095  break;
1096  }
1097  }
1098 
1099  return NULL;
1100 }
1101 
1102 static char *
1104 {
1105  int vhost = conn->port->vhost;
1106  int vport = conn->port->vport;
1107  static char ipbuf[MAX_IPSTRLEN];
1108 
1109  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1110 
1111  static const SBuf cache_object("cache_object://");
1112  if (hp->requestUri().startsWith(cache_object))
1113  return nullptr; /* already in good shape */
1114 
1115  // XXX: re-use proper URL parser for this
1116  SBuf url = hp->requestUri(); // use full provided URI if we abort
1117  do { // use a loop so we can break out of it
1118  ::Parser::Tokenizer tok(url);
1119  if (tok.skip('/')) // origin-form URL already.
1120  break;
1121 
1122  if (conn->port->vhost)
1123  return nullptr; /* already in good shape */
1124 
1125  // skip the URI scheme
1126  static const CharacterSet uriScheme = CharacterSet("URI-scheme","+-.") + CharacterSet::ALPHA + CharacterSet::DIGIT;
1127  static const SBuf uriSchemeEnd("://");
1128  if (!tok.skipAll(uriScheme) || !tok.skip(uriSchemeEnd))
1129  break;
1130 
1131  // skip the authority segment
1132  // RFC 3986 complex nested ABNF for "authority" boils down to this:
1133  static const CharacterSet authority = CharacterSet("authority","-._~%:@[]!$&'()*+,;=") +
1135  if (!tok.skipAll(authority))
1136  break;
1137 
1138  static const SBuf slashUri("/");
1139  const SBuf t = tok.remaining();
1140  if (t.isEmpty())
1141  url = slashUri;
1142  else if (t[0]=='/') // looks like path
1143  url = t;
1144  else if (t[0]=='?' || t[0]=='#') { // looks like query or fragment. fix '/'
1145  url = slashUri;
1146  url.append(t);
1147  } // else do nothing. invalid path
1148 
1149  } while(false);
1150 
1151 #if SHOULD_REJECT_UNKNOWN_URLS
1152  // reject URI which are not well-formed even after the processing above
1153  if (url.isEmpty() || url[0] != '/') {
1154  hp->parseStatusCode = Http::scBadRequest;
1155  return conn->abortRequestParsing("error:invalid-request");
1156  }
1157 #endif
1158 
1159  if (vport < 0)
1160  vport = conn->clientConnection->local.port();
1161 
1162  char *receivedHost = nullptr;
1163  if (vhost && (receivedHost = hp->getHostHeaderField())) {
1164  SBuf host(receivedHost);
1165  debugs(33, 5, "ACCEL VHOST REWRITE: vhost=" << host << " + vport=" << vport);
1166  if (vport > 0) {
1167  // remove existing :port (if any), cope with IPv6+ without port
1168  const auto lastColonPos = host.rfind(':');
1169  if (lastColonPos != SBuf::npos && *host.rbegin() != ']') {
1170  host.chop(0, lastColonPos); // truncate until the last colon
1171  }
1172  host.appendf(":%d", vport);
1173  } // else nothing to alter port-wise.
1174  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1175  const auto url_sz = scheme.length() + host.length() + url.length() + 32;
1176  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1177  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH SQUIDSBUFPH, SQUIDSBUFPRINT(scheme), SQUIDSBUFPRINT(host), SQUIDSBUFPRINT(url));
1178  debugs(33, 5, "ACCEL VHOST REWRITE: " << uri);
1179  return uri;
1180  } else if (conn->port->defaultsite /* && !vhost */) {
1181  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: defaultsite=" << conn->port->defaultsite << " + vport=" << vport);
1182  char vportStr[32];
1183  vportStr[0] = '\0';
1184  if (vport > 0) {
1185  snprintf(vportStr, sizeof(vportStr),":%d",vport);
1186  }
1187  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1188  const int url_sz = scheme.length() + strlen(conn->port->defaultsite) + sizeof(vportStr) + url.length() + 32;
1189  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1190  snprintf(uri, url_sz, SQUIDSBUFPH "://%s%s" SQUIDSBUFPH,
1191  SQUIDSBUFPRINT(scheme), conn->port->defaultsite, vportStr, SQUIDSBUFPRINT(url));
1192  debugs(33, 5, "ACCEL DEFAULTSITE REWRITE: " << uri);
1193  return uri;
1194  } else if (vport > 0 /* && (!vhost || no Host:) */) {
1195  debugs(33, 5, "ACCEL VPORT REWRITE: *_port IP + vport=" << vport);
1196  /* Put the local socket IP address as the hostname, with whatever vport we found */
1197  conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
1198  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1199  const int url_sz = scheme.length() + sizeof(ipbuf) + url.length() + 32;
1200  char *uri = static_cast<char *>(xcalloc(url_sz, 1));
1201  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1202  SQUIDSBUFPRINT(scheme), ipbuf, vport, SQUIDSBUFPRINT(url));
1203  debugs(33, 5, "ACCEL VPORT REWRITE: " << uri);
1204  return uri;
1205  }
1206 
1207  return nullptr;
1208 }
1209 
1210 static char *
1212 {
1213  char *uri = nullptr;
1214  /* BUG: Squid cannot deal with '*' URLs (RFC2616 5.1.2) */
1215  if (const char *host = hp->getHostHeaderField()) {
1216  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1217  const int url_sz = scheme.length() + strlen(host) + hp->requestUri().length() + 32;
1218  uri = static_cast<char *>(xcalloc(url_sz, 1));
1219  snprintf(uri, url_sz, SQUIDSBUFPH "://%s" SQUIDSBUFPH,
1220  SQUIDSBUFPRINT(scheme),
1221  host,
1222  SQUIDSBUFPRINT(hp->requestUri()));
1223  }
1224  return uri;
1225 }
1226 
1227 char *
1229 {
1230  Must(switchedToHttps());
1231 
1232  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1233  return nullptr; /* already in good shape */
1234 
1235  char *uri = buildUrlFromHost(this, hp);
1236 #if USE_OPENSSL
1237  if (!uri) {
1240  SBuf useHost;
1241  if (!tlsClientSni().isEmpty())
1242  useHost = tlsClientSni();
1243  else
1244  useHost = tlsConnectHostOrIp;
1245 
1246  const SBuf &scheme = AnyP::UriScheme(transferProtocol.protocol).image();
1247  const int url_sz = scheme.length() + useHost.length() + hp->requestUri().length() + 32;
1248  uri = static_cast<char *>(xcalloc(url_sz, 1));
1249  snprintf(uri, url_sz, SQUIDSBUFPH "://" SQUIDSBUFPH ":%d" SQUIDSBUFPH,
1250  SQUIDSBUFPRINT(scheme),
1251  SQUIDSBUFPRINT(useHost),
1253  SQUIDSBUFPRINT(hp->requestUri()));
1254  }
1255 #endif
1256  if (uri)
1257  debugs(33, 5, "TLS switching host rewrite: " << uri);
1258  return uri;
1259 }
1260 
1261 static char *
1263 {
1264  // TODO Must() on URI !empty when the parser supports throw. For now avoid assert().
1265  if (!hp->requestUri().isEmpty() && hp->requestUri()[0] != '/')
1266  return nullptr; /* already in good shape */
1267 
1268  char *uri = buildUrlFromHost(conn, hp);
1269  if (!uri) {
1270  /* Put the local socket IP address as the hostname. */
1271  static char ipbuf[MAX_IPSTRLEN];
1272  conn->clientConnection->local.toHostStr(ipbuf,MAX_IPSTRLEN);
1273  const SBuf &scheme = AnyP::UriScheme(conn->transferProtocol.protocol).image();
1274  const int url_sz = sizeof(ipbuf) + hp->requestUri().length() + 32;
1275  uri = static_cast<char *>(xcalloc(url_sz, 1));
1276  snprintf(uri, url_sz, SQUIDSBUFPH "://%s:%d" SQUIDSBUFPH,
1277  SQUIDSBUFPRINT(scheme),
1278  ipbuf, conn->clientConnection->local.port(), SQUIDSBUFPRINT(hp->requestUri()));
1279  }
1280 
1281  if (uri)
1282  debugs(33, 5, "TRANSPARENT REWRITE: " << uri);
1283  return uri;
1284 }
1285 
1286 Http::Stream *
1288 {
1289  /* Attempt to parse the first line; this will define where the method, url, version and header begin */
1290  {
1291  Must(hp);
1292 
1295 
1296  const bool parsedOk = hp->parse(inBuf);
1297 
1298  // sync the buffers after parsing.
1299  inBuf = hp->remaining();
1300 
1301  if (hp->needsMoreData()) {
1302  debugs(33, 5, "Incomplete request, waiting for end of request line");
1303  return NULL;
1304  }
1305 
1306  if (!parsedOk) {
1307  const bool tooBig =
1308  hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge ||
1309  hp->parseStatusCode == Http::scUriTooLong;
1310  auto result = abortRequestParsing(
1311  tooBig ? "error:request-too-large" : "error:invalid-request");
1312  // assume that remaining leftovers belong to this bad request
1313  if (!inBuf.isEmpty())
1315  return result;
1316  }
1317  }
1318 
1319  /* We know the whole request is in parser now */
1320  debugs(11, 2, "HTTP Client " << clientConnection);
1321  debugs(11, 2, "HTTP Client REQUEST:\n---------\n" <<
1322  hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol() << "\n" <<
1323  hp->mimeHeader() <<
1324  "\n----------");
1325 
1326  /* deny CONNECT via accelerated ports */
1327  if (hp->method() == Http::METHOD_CONNECT && port != NULL && port->flags.accelSurrogate) {
1328  debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << transferProtocol << " Accelerator port " << port->s.port());
1329  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1330  hp->parseStatusCode = Http::scMethodNotAllowed;
1331  return abortRequestParsing("error:method-not-allowed");
1332  }
1333 
1334  /* RFC 7540 section 11.6 registers the method PRI as HTTP/2 specific
1335  * Deny "PRI" method if used in HTTP/1.x or 0.9 versions.
1336  * If seen it signals a broken client or proxy has corrupted the traffic.
1337  */
1338  if (hp->method() == Http::METHOD_PRI && hp->messageProtocol() < Http::ProtocolVersion(2,0)) {
1339  debugs(33, DBG_IMPORTANT, "WARNING: PRI method received on " << transferProtocol << " port " << port->s.port());
1340  debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1341  hp->parseStatusCode = Http::scMethodNotAllowed;
1342  return abortRequestParsing("error:method-not-allowed");
1343  }
1344 
1345  if (hp->method() == Http::METHOD_NONE) {
1346  debugs(33, DBG_IMPORTANT, "WARNING: Unsupported method: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol());
1347  hp->parseStatusCode = Http::scMethodNotAllowed;
1348  return abortRequestParsing("error:unsupported-request-method");
1349  }
1350 
1351  // Process headers after request line
1352  debugs(33, 3, "complete request received. " <<
1353  "prefix_sz = " << hp->messageHeaderSize() <<
1354  ", request-line-size=" << hp->firstLineSize() <<
1355  ", mime-header-size=" << hp->headerBlockSize() <<
1356  ", mime header block:\n" << hp->mimeHeader() << "\n----------");
1357 
1358  /* Ok, all headers are received */
1359  ClientHttpRequest *http = new ClientHttpRequest(this);
1360 
1361  http->req_sz = hp->messageHeaderSize();
1362  Http::Stream *result = new Http::Stream(clientConnection, http);
1363 
1364  StoreIOBuffer tempBuffer;
1365  tempBuffer.data = result->reqbuf;
1366  tempBuffer.length = HTTP_REQBUF_SZ;
1367 
1368  ClientStreamData newServer = new clientReplyContext(http);
1369  ClientStreamData newClient = result;
1372  clientSocketDetach, newClient, tempBuffer);
1373 
1374  /* set url */
1375  debugs(33,5, "Prepare absolute URL from " <<
1376  (transparent()?"intercept":(port->flags.accelSurrogate ? "accel":"")));
1377  /* Rewrite the URL in transparent or accelerator mode */
1378  /* NP: there are several cases to traverse here:
1379  * - standard mode (forward proxy)
1380  * - transparent mode (TPROXY)
1381  * - transparent mode with failures
1382  * - intercept mode (NAT)
1383  * - intercept mode with failures
1384  * - accelerator mode (reverse proxy)
1385  * - internal relative-URL
1386  * - mixed combos of the above with internal URL
1387  * - remote interception with PROXY protocol
1388  * - remote reverse-proxy with PROXY protocol
1389  */
1390  if (switchedToHttps()) {
1391  http->uri = prepareTlsSwitchingURL(hp);
1392  } else if (transparent()) {
1393  /* intercept or transparent mode, properly working with no failures */
1394  http->uri = prepareTransparentURL(this, hp);
1395 
1396  } else if (internalCheck(hp->requestUri())) { // NP: only matches relative-URI
1397  /* internal URL mode */
1398  /* prepend our name & port */
1399  http->uri = xstrdup(internalLocalUri(NULL, hp->requestUri()));
1400  // We just re-wrote the URL. Must replace the Host: header.
1401  // But have not parsed there yet!! flag for local-only handling.
1402  http->flags.internal = true;
1403 
1404  } else if (port->flags.accelSurrogate) {
1405  /* accelerator mode */
1406  http->uri = prepareAcceleratedURL(this, hp);
1407  http->flags.accel = true;
1408  }
1409 
1410  if (!http->uri) {
1411  /* No special rewrites have been applied above, use the
1412  * requested url. may be rewritten later, so make extra room */
1413  int url_sz = hp->requestUri().length() + Config.appendDomainLen + 5;
1414  http->uri = (char *)xcalloc(url_sz, 1);
1415  SBufToCstring(http->uri, hp->requestUri());
1416  }
1417 
1418  result->flags.parsed_ok = 1;
1419  return result;
1420 }
1421 
1422 bool
1424 {
1425  if (pipeline.empty() && inBuf.isEmpty()) {
1426  debugs(33, 4, "yes, without active requests and unparsed input");
1427  return true;
1428  }
1429 
1431  debugs(33, 3, "yes, without half_closed_clients");
1432  return true;
1433  }
1434 
1435  // Squid currently tries to parse (possibly again) a partially received
1436  // request after an EOF with half_closed_clients. To give that last parse in
1437  // afterClientRead() a chance, we ignore partially parsed requests here.
1438  debugs(33, 3, "no, honoring half_closed_clients");
1439  return false;
1440 }
1441 
1442 void
1443 ConnStateData::consumeInput(const size_t byteCount)
1444 {
1445  assert(byteCount > 0 && byteCount <= inBuf.length());
1446  inBuf.consume(byteCount);
1447  debugs(33, 5, "inBuf has " << inBuf.length() << " unused bytes");
1448 }
1449 
1450 void
1452 {
1453  // Were we expecting to read more request body from half-closed connection?
1455  debugs(33, 3, "truncated body: closing half-closed " << clientConnection);
1457  return;
1458  }
1459 
1460  if (flags.readMore)
1461  readSomeData();
1462 }
1463 
1464 void
1466 {
1467  // From HTTP p.o.v., we do not have to close after every error detected
1468  // at the client-side, but many such errors do require closure and the
1469  // client-side code is bad at handling errors so we play it safe.
1470  if (request)
1471  request->flags.proxyKeepalive = false;
1472  flags.readMore = false;
1473  debugs(33,4, "Will close after error: " << clientConnection);
1474 }
1475 
1476 #if USE_OPENSSL
1478 {
1479  ClientHttpRequest *http = context->http;
1480 
1481  if (!sslServerBump)
1482  return false;
1483 
1485  // Did we create an error entry while processing CONNECT?
1486  if (!sslServerBump->entry->isEmpty()) {
1487  quitAfterError(http->request);
1488 
1489  // Get the saved error entry and send it to the client by replacing the
1490  // ClientHttpRequest store entry with it.
1492  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1493  assert(repContext);
1494  debugs(33, 5, "Responding with delated error for " << http->uri);
1495  repContext->setReplyToStoreEntry(sslServerBump->entry, "delayed SslBump error");
1496 
1497  // Get error details from the fake certificate-peeking request.
1499  context->pullData();
1500  return true;
1501  }
1502 
1503  // In bump-server-first mode, we have not necessarily seen the intended
1504  // server name at certificate-peeking time. Check for domain mismatch now,
1505  // when we can extract the intended name from the bumped HTTP request.
1506  if (const Security::CertPointer &srvCert = sslServerBump->serverCert) {
1507  HttpRequest *request = http->request;
1508  if (!Ssl::checkX509ServerValidity(srvCert.get(), request->url.host())) {
1509  debugs(33, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " <<
1510  "does not match domainname " << request->url.host());
1511 
1512  bool allowDomainMismatch = false;
1516  clientAclChecklistFill(check, http);
1517  allowDomainMismatch = check.fastCheck().allowed();
1518  delete check.sslErrors;
1519  check.sslErrors = NULL;
1520  }
1521 
1522  if (!allowDomainMismatch) {
1524 
1526  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1527  assert (repContext);
1528 
1529  request->hier = sslServerBump->request->hier;
1530 
1531  // Create an error object and fill it
1533  err->src_addr = clientConnection->remote;
1536  srvCert, nullptr);
1538  repContext->setReplyToError(request->method, err);
1539  assert(context->http->out.offset == 0);
1540  context->pullData();
1541  return true;
1542  }
1543  }
1544  }
1545 
1546  return false;
1547 }
1548 #endif // USE_OPENSSL
1549 
1551 bool
1553 {
1555  debugs(33, 5, "disabled; send error: " << requestError);
1556  return false;
1557  }
1558 
1559  if (!preservingClientData_) {
1560  debugs(33, 3, "may have forgotten client data; send error: " << requestError);
1561  return false;
1562  }
1563 
1565  checklist.requestErrorType = requestError;
1566  fillChecklist(checklist);
1567  auto answer = checklist.fastCheck();
1568  if (answer.allowed() && answer.kind == 1) {
1569  debugs(33, 3, "Request will be tunneled to server");
1570  const auto context = pipeline.front();
1571  const auto http = context ? context->http : nullptr;
1572  const auto request = http ? http->request : nullptr;
1573  if (context)
1574  context->finished(); // Will remove from pipeline queue
1576  return initiateTunneledRequest(request, "unknown-protocol", preservedClientData);
1577  }
1578  debugs(33, 3, "denied; send error: " << requestError);
1579  return false;
1580 }
1581 
1582 void
1584 {
1585  /*
1586  * DPW 2007-05-18
1587  * Moved the TCP_RESET feature from clientReplyContext::sendMoreData
1588  * to here because calling comm_reset_close() causes http to
1589  * be freed before accessing.
1590  */
1591  if (request != NULL && request->flags.resetTcp && Comm::IsConnOpen(conn->clientConnection)) {
1592  debugs(33, 3, "Sending TCP RST on " << conn->clientConnection);
1593  conn->flags.readMore = false;
1594  comm_reset_close(conn->clientConnection);
1595  }
1596 }
1597 
1598 void
1600 {
1601  ClientHttpRequest *http = context->http;
1602  bool mustReplyToOptions = false;
1603  bool expectBody = false;
1604 
1605  // We already have the request parsed and checked, so we
1606  // only need to go through the final body/conn setup to doCallouts().
1607  assert(http->request);
1609 
1610  // temporary hack to avoid splitting this huge function with sensitive code
1611  const bool isFtp = !hp;
1612 
1613  // Some blobs below are still HTTP-specific, but we would have to rewrite
1614  // this entire function to remove them from the FTP code path. Connection
1615  // setup and body_pipe preparation blobs are needed for FTP.
1616 
1617  request->manager(conn, http->al);
1618 
1619  request->flags.accelerated = http->flags.accel;
1620  request->flags.sslBumped=conn->switchedToHttps();
1621  // TODO: decouple http->flags.accel from request->flags.sslBumped
1622  request->flags.noDirect = (request->flags.accelerated && !request->flags.sslBumped) ?
1623  !conn->port->allow_direct : 0;
1624  request->sources |= isFtp ? Http::Message::srcFtp :
1625  ((request->flags.sslBumped || conn->port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
1626 #if USE_AUTH
1627  if (request->flags.sslBumped) {
1628  if (conn->getAuth() != NULL)
1629  request->auth_user_request = conn->getAuth();
1630  }
1631 #endif
1632 
1633  if (internalCheck(request->url.path())) {
1634  if (internalHostnameIs(request->url.host()) && request->url.port() == getMyPort()) {
1635  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true));
1636  http->flags.internal = true;
1638  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (global_internal_static on)");
1639  request->url.setScheme(AnyP::PROTO_HTTP, "http");
1640  request->url.host(internalHostname());
1641  request->url.port(getMyPort());
1642  http->flags.internal = true;
1643  http->setLogUriToRequestUri();
1644  } else
1645  debugs(33, 2, "internal URL found: " << request->url.getScheme() << "://" << request->url.authority(true) << " (not this proxy)");
1646  }
1647 
1648  request->flags.internal = http->flags.internal;
1649 
1650  if (!isFtp) {
1651  // XXX: for non-HTTP messages instantiate a different Http::Message child type
1652  // for now Squid only supports HTTP requests
1653  const AnyP::ProtocolVersion &http_ver = hp->messageProtocol();
1654  assert(request->http_ver.protocol == http_ver.protocol);
1655  request->http_ver.major = http_ver.major;
1656  request->http_ver.minor = http_ver.minor;
1657  }
1658 
1659  mustReplyToOptions = (request->method == Http::METHOD_OPTIONS) &&
1660  (request->header.getInt64(Http::HdrType::MAX_FORWARDS) == 0);
1661  if (!urlCheckRequest(request.getRaw()) || mustReplyToOptions) {
1663  conn->quitAfterError(request.getRaw());
1664  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1665  assert (repContext);
1667  conn, request.getRaw(), nullptr, nullptr);
1668  assert(context->http->out.offset == 0);
1669  context->pullData();
1671  return;
1672  }
1673 
1674  const auto frameStatus = request->checkEntityFraming();
1675  if (frameStatus != Http::scNone) {
1677  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1678  assert (repContext);
1679  conn->quitAfterError(request.getRaw());
1680  repContext->setReplyToError(ERR_INVALID_REQ, frameStatus, nullptr, conn, request.getRaw(), nullptr, nullptr);
1681  assert(context->http->out.offset == 0);
1682  context->pullData();
1684  return;
1685  }
1686 
1687  clientSetKeepaliveFlag(http);
1688  // Let tunneling code be fully responsible for CONNECT requests
1689  if (http->request->method == Http::METHOD_CONNECT) {
1690  context->mayUseConnection(true);
1691  conn->flags.readMore = false;
1692  }
1693 
1694 #if USE_OPENSSL
1695  if (conn->switchedToHttps() && conn->serveDelayedError(context)) {
1697  return;
1698  }
1699 #endif
1700 
1701  /* Do we expect a request-body? */
1702  const auto chunked = request->header.chunked();
1703  expectBody = chunked || request->content_length > 0;
1704  if (!context->mayUseConnection() && expectBody) {
1705  request->body_pipe = conn->expectRequestBody(
1706  chunked ? -1 : request->content_length);
1707 
1708  /* Is it too large? */
1709  if (!chunked && // if chunked, we will check as we accumulate
1712  clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
1713  assert (repContext);
1714  conn->quitAfterError(request.getRaw());
1715  repContext->setReplyToError(ERR_TOO_BIG,
1716  Http::scContentTooLarge, nullptr,
1717  conn, http->request, nullptr, nullptr);
1718  assert(context->http->out.offset == 0);
1719  context->pullData();
1721  return;
1722  }
1723 
1724  if (!isFtp) {
1725  // We may stop producing, comm_close, and/or call setReplyToError()
1726  // below, so quit on errors to avoid http->doCallouts()
1727  if (!conn->handleRequestBodyData()) {
1729  return;
1730  }
1731 
1732  if (!request->body_pipe->productionEnded()) {
1733  debugs(33, 5, "need more request body");
1734  context->mayUseConnection(true);
1735  assert(conn->flags.readMore);
1736  }
1737  }
1738  }
1739 
1740  http->calloutContext = new ClientRequestContext(http);
1741 
1742  http->doCallouts();
1743 
1745 }
1746 
1747 void
1749 {
1750  debugs(33, 3, context << " to " << pipeline.count() << '/' << pipeline.nrequests);
1751  if (bareError) {
1752  debugs(33, 5, "assigning " << bareError);
1753  assert(context);
1754  assert(context->http);
1755  context->http->updateError(bareError);
1756  bareError.clear();
1757  }
1758  pipeline.add(context);
1759 }
1760 
1761 int
1763 {
1764  // TODO: Support pipelined requests through pinned connections.
1765  if (pinning.pinned)
1766  return 0;
1768 }
1769 
1775 bool
1777 {
1778  const int existingRequestCount = pipeline.count();
1779 
1780  // default to the configured pipeline size.
1781  // add 1 because the head of pipeline is counted in concurrent requests and not prefetch queue
1782 #if USE_OPENSSL
1783  const int internalRequest = (transparent() && sslBumpMode == Ssl::bumpSplice) ? 1 : 0;
1784 #else
1785  const int internalRequest = 0;
1786 #endif
1787  const int concurrentRequestLimit = pipelinePrefetchMax() + 1 + internalRequest;
1788 
1789  // when queue filled already we can't add more.
1790  if (existingRequestCount >= concurrentRequestLimit) {
1791  debugs(33, 3, clientConnection << " max concurrent requests reached (" << concurrentRequestLimit << ")");
1792  debugs(33, 5, clientConnection << " deferring new request until one is done");
1793  return true;
1794  }
1795 
1796  return false;
1797 }
1798 
1804 bool
1806 {
1808  return proxyProtocolError("PROXY client not permitted by default ACL");
1809 
1811  fillChecklist(ch);
1812  if (!ch.fastCheck().allowed())
1813  return proxyProtocolError("PROXY client not permitted by ACLs");
1814 
1815  return true;
1816 }
1817 
1823 bool
1825 {
1826  if (msg) {
1827  // This is important to know, but maybe not so much that flooding the log is okay.
1828 #if QUIET_PROXY_PROTOCOL
1829  // display the first of every 32 occurrences at level 1, the others at level 2.
1830  static uint8_t hide = 0;
1831  debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
1832 #else
1833  debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
1834 #endif
1835  mustStop(msg);
1836  }
1837  return false;
1838 }
1839 
1844 bool
1846 {
1847  try {
1848  const auto parsed = ProxyProtocol::Parse(inBuf);
1849  proxyProtocolHeader_ = parsed.header;
1851  inBuf.consume(parsed.size);
1852  needProxyProtocolHeader_ = false;
1853  if (proxyProtocolHeader_->hasForwardedAddresses()) {
1854  clientConnection->local = proxyProtocolHeader_->destinationAddress;
1855  clientConnection->remote = proxyProtocolHeader_->sourceAddress;
1857  clientConnection->flags ^= COMM_TRANSPARENT; // prevent TPROXY spoofing of this new IP.
1858  debugs(33, 5, "PROXY/" << proxyProtocolHeader_->version() << " upgrade: " << clientConnection);
1859  }
1860  } catch (const Parser::BinaryTokenizer::InsufficientInput &) {
1861  debugs(33, 3, "PROXY protocol: waiting for more than " << inBuf.length() << " bytes");
1862  return false;
1863  } catch (const std::exception &e) {
1864  return proxyProtocolError(e.what());
1865  }
1866  return true;
1867 }
1868 
1869 void
1871 {
1872  if (receivedFirstByte_)
1873  return;
1874 
1875  receivedFirstByte_ = true;
1877 }
1878 
1884 bool
1886 {
1887  bool parsed_req = false;
1888 
1889  debugs(33, 5, clientConnection << ": attempting to parse");
1890 
1891  // Loop while we have read bytes that are not needed for producing the body
1892  // On errors, bodyPipe may become nil, but readMore will be cleared
1893  while (!inBuf.isEmpty() && !bodyPipe && flags.readMore) {
1894 
1895  // Prohibit concurrent requests when using a pinned to-server connection
1896  // because our Client classes do not support request pipelining.
1897  if (pinning.pinned && !pinning.readHandler) {
1898  debugs(33, 3, clientConnection << " waits for busy " << pinning.serverConnection);
1899  break;
1900  }
1901 
1902  /* Limit the number of concurrent requests */
1904  break;
1905 
1906  // try to parse the PROXY protocol header magic bytes
1908  if (!parseProxyProtocolHeader())
1909  break;
1910 
1911  // we have been waiting for PROXY to provide client-IP
1912  // for some lookups, ie rDNS and IDENT.
1914 
1915  // Done with PROXY protocol which has cleared preservingClientData_.
1916  // If the next protocol supports on_unsupported_protocol, then its
1917  // parseOneRequest() must reset preservingClientData_.
1919  }
1920 
1921  if (Http::StreamPointer context = parseOneRequest()) {
1922  debugs(33, 5, clientConnection << ": done parsing a request");
1923  extendLifetime();
1924  context->registerWithConn();
1925 
1926 #if USE_OPENSSL
1927  if (switchedToHttps())
1929 #endif
1930 
1931  processParsedRequest(context);
1932 
1933  parsed_req = true; // XXX: do we really need to parse everything right NOW ?
1934 
1935  if (context->mayUseConnection()) {
1936  debugs(33, 3, "Not parsing new requests, as this request may need the connection");
1937  break;
1938  }
1939  } else {
1940  debugs(33, 5, clientConnection << ": not enough request data: " <<
1941  inBuf.length() << " < " << Config.maxRequestHeaderSize);
1943  break;
1944  }
1945  }
1946 
1947  /* XXX where to 'finish' the parsing pass? */
1948  return parsed_req;
1949 }
1950 
1951 void
1953 {
1954 #if USE_OPENSSL
1955  if (parsingTlsHandshake) {
1957  return;
1958  }
1959 #endif
1960 
1961  /* Process next request */
1962  if (pipeline.empty())
1963  fd_note(clientConnection->fd, "Reading next request");
1964 
1965  if (!clientParseRequests()) {
1966  if (!isOpen())
1967  return;
1968  // We may get here if the client half-closed after sending a partial
1969  // request. See doClientRead() and shouldCloseOnEof().
1970  // XXX: This partially duplicates ConnStateData::kick().
1972  debugs(33, 5, clientConnection << ": half-closed connection, no completed request parsed, connection closing.");
1974  return;
1975  }
1976  }
1977 
1978  if (!isOpen())
1979  return;
1980 
1982 }
1983 
1990 bool
1992 {
1993  // if we are reading a body, stuff data into the body pipe
1994  if (bodyPipe != NULL)
1995  return handleRequestBodyData();
1996  return true;
1997 }
1998 
2006 bool
2008 {
2009  assert(bodyPipe != NULL);
2010 
2011  if (bodyParser) { // chunked encoding
2012  if (const err_type error = handleChunkedRequestBody()) {
2014  return false;
2015  }
2016  } else { // identity encoding
2017  debugs(33,5, "handling plain request body for " << clientConnection);
2018  const size_t putSize = bodyPipe->putMoreData(inBuf.c_str(), inBuf.length());
2019  if (putSize > 0)
2020  consumeInput(putSize);
2021 
2022  if (!bodyPipe->mayNeedMoreData()) {
2023  // BodyPipe will clear us automagically when we produced everything
2024  bodyPipe = NULL;
2025  }
2026  }
2027 
2028  if (!bodyPipe) {
2029  debugs(33,5, "produced entire request body for " << clientConnection);
2030 
2031  if (const char *reason = stoppedSending()) {
2032  /* we've finished reading like good clients,
2033  * now do the close that initiateClose initiated.
2034  */
2035  debugs(33, 3, "closing for earlier sending error: " << reason);
2037  return false;
2038  }
2039  }
2040 
2041  return true;
2042 }
2043 
2045 err_type
2047 {
2048  debugs(33, 7, "chunked from " << clientConnection << ": " << inBuf.length());
2049 
2050  try { // the parser will throw on errors
2051 
2052  if (inBuf.isEmpty()) // nothing to do
2053  return ERR_NONE;
2054 
2055  BodyPipeCheckout bpc(*bodyPipe);
2057  const bool parsed = bodyParser->parse(inBuf);
2058  inBuf = bodyParser->remaining(); // sync buffers
2059  bpc.checkIn();
2060 
2061  // dechunk then check: the size limit applies to _dechunked_ content
2063  return ERR_TOO_BIG;
2064 
2065  if (parsed) {
2067  Must(!bodyPipe);
2068  return ERR_NONE; // nil bodyPipe implies body end for the caller
2069  }
2070 
2071  // if chunk parser needs data, then the body pipe must need it too
2073 
2074  // if parser needs more space and we can consume nothing, we will stall
2076  } catch (...) { // TODO: be more specific
2077  debugs(33, 3, "malformed chunks" << bodyPipe->status());
2078  return ERR_INVALID_REQ;
2079  }
2080 
2081  debugs(33, 7, "need more chunked data" << *bodyPipe->status());
2082  return ERR_NONE;
2083 }
2084 
2086 void
2088 {
2089  finishDechunkingRequest(false);
2090 
2091  // XXX: The code below works if we fail during initial request parsing,
2092  // but if we fail when the server connection is used already, the server may send
2093  // us its response too, causing various assertions. How to prevent that?
2094 #if WE_KNOW_HOW_TO_SEND_ERRORS
2095  Http::StreamPointer context = pipeline.front();
2096  if (context != NULL && !context->http->out.offset) { // output nothing yet
2097  clientStreamNode *node = context->getClientReplyContext();
2098  clientReplyContext *repContext = dynamic_cast<clientReplyContext*>(node->data.getRaw());
2099  assert(repContext);
2100  const Http::StatusCode scode = (error == ERR_TOO_BIG) ?
2101  Http::scContentTooLarge : HTTP_BAD_REQUEST;
2102  repContext->setReplyToError(error, scode,
2103  repContext->http->uri,
2104  CachePeer,
2105  repContext->http->request,
2106  inBuf, NULL);
2107  context->pullData();
2108  } else {
2109  // close or otherwise we may get stuck as nobody will notice the error?
2111  }
2112 #else
2113  debugs(33, 3, "aborting chunked request without error " << error);
2115 #endif
2116  flags.readMore = false;
2117 }
2118 
2119 void
2121 {
2122  // request reader may get stuck waiting for space if nobody consumes body
2123  if (bodyPipe != NULL)
2125 
2126  // kids extend
2127 }
2128 
2130 void
2132 {
2133  if (!Comm::IsConnOpen(io.conn))
2134  return;
2135 
2137  updateError(error);
2138  if (tunnelOnError(error))
2139  return;
2140 
2141  /*
2142  * Just close the connection to not confuse browsers
2143  * using persistent connections. Some browsers open
2144  * a connection and then do not use it until much
2145  * later (presumeably because the request triggering
2146  * the open has already been completed on another
2147  * connection)
2148  */
2149  debugs(33, 3, "requestTimeout: FD " << io.fd << ": lifetime is expired.");
2150  io.conn->close();
2151 }
2152 
2153 void
2155 {
2156  debugs(33, DBG_IMPORTANT, "WARNING: Closing client connection due to lifetime timeout" <<
2157  Debug::Extra << "connection: " << io.conn);
2158 
2159  LogTagsErrors lte;
2160  lte.timedout = true;
2162 }
2163 
2165  AsyncJob("ConnStateData"), // kids overwrite
2166  Server(xact)
2167 #if USE_OPENSSL
2168  , tlsParser(Security::HandshakeParser::fromClient)
2169 #endif
2170 {
2171  // store the details required for creating more MasterXaction objects as new requests come in
2172  log_addr = xact->tcpClient->remote;
2174 
2175  // register to receive notice of Squid signal events
2176  // which may affect long persisting client connections
2177  registerRunner();
2178 }
2179 
2180 void
2182 {
2185 
2186  if (port->disable_pmtu_discovery != DISABLE_PMTU_OFF &&
2187  (transparent() || port->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)) {
2188 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
2189  int i = IP_PMTUDISC_DONT;
2190  if (setsockopt(clientConnection->fd, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0) {
2191  int xerrno = errno;
2192  debugs(33, 2, "WARNING: Path MTU discovery disabling failed on " << clientConnection << " : " << xstrerr(xerrno));
2193  }
2194 #else
2195  static bool reported = false;
2196 
2197  if (!reported) {
2198  debugs(33, DBG_IMPORTANT, "WARNING: Path MTU discovery disabling is not supported on your platform.");
2199  reported = true;
2200  }
2201 #endif
2202  }
2203 
2205  AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, ConnStateData::connStateClosed);
2207 
2208  needProxyProtocolHeader_ = port->flags.proxySurrogate;
2210  if (!proxyProtocolValidateClient()) // will close the connection on failure
2211  return;
2212  } else
2214 
2215  // requires needProxyProtocolHeader_ which is initialized above
2217 }
2218 
2219 void
2221 {
2222  debugs(33, 7, clientConnection->remote);
2225 
2226 #if USE_IDENT
2227  if (Ident::TheConfig.identLookup) {
2228  ACLFilledChecklist identChecklist(Ident::TheConfig.identLookup, NULL, NULL);
2229  fillChecklist(identChecklist);
2230  if (identChecklist.fastCheck().allowed())
2232  }
2233 #endif
2234 
2236 
2237 #if USE_DELAY_POOLS
2238  fd_table[clientConnection->fd].clientInfo = NULL;
2239 
2240  if (!Config.onoff.client_db)
2241  return; // client delay pools require client_db
2242 
2243  const auto &pools = ClientDelayPools::Instance()->pools;
2244  if (pools.size()) {
2246  fillChecklist(ch);
2247  // TODO: we check early to limit error response bandwidth but we
2248  // should recheck when we can honor delay_pool_uses_indirect
2249  for (unsigned int pool = 0; pool < pools.size(); ++pool) {
2250 
2251  /* pools require explicit 'allow' to assign a client into them */
2252  if (pools[pool]->access) {
2253  ch.changeAcl(pools[pool]->access);
2254  auto answer = ch.fastCheck();
2255  if (answer.allowed()) {
2256 
2257  /* request client information from db after we did all checks
2258  this will save hash lookup if client failed checks */
2260  assert(cli);
2261 
2262  /* put client info in FDE */
2263  fd_table[clientConnection->fd].clientInfo = cli;
2264 
2265  /* setup write limiter for this request */
2266  const double burst = floor(0.5 +
2267  (pools[pool]->highwatermark * Config.ClientDelay.initial)/100.0);
2268  cli->setWriteLimiter(pools[pool]->rate, burst, pools[pool]->highwatermark);
2269  break;
2270  } else {
2271  debugs(83, 4, "Delay pool " << pool << " skipped because ACL " << answer);
2272  }
2273  }
2274  }
2275  }
2276 #endif
2277 
2278  // kids must extend to actually start doing something (e.g., reading)
2279 }
2280 
2283 {
2284  const auto handshakeResult = Security::Accept(*clientConnection);
2285 
2286 #if USE_OPENSSL
2287  // log ASAP, even if the handshake has not completed (or failed)
2288  const auto fd = clientConnection->fd;
2289  assert(fd >= 0);
2290  keyLogger.checkpoint(*fd_table[fd].ssl, *this);
2291 #else
2292  // TODO: Support fd_table[fd].ssl dereference in other builds.
2293 #endif
2294 
2295  return handshakeResult;
2296 }
2297 
2299 void
2301 {
2302  Assure(params.port);
2303 
2304  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2305 
2306  if (params.flag != Comm::OK) {
2307  // Its possible the call was still queued when the client disconnected
2308  debugs(33, 2, params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2309  return;
2310  }
2311 
2312  debugs(33, 4, params.conn << ": accepted");
2313  fd_note(params.conn->fd, "client http connect");
2314  const auto xact = MasterXaction::MakePortful(params.port);
2315  xact->tcpClient = params.conn;
2316 
2317  // Socket is ready, setup the connection manager to start using it
2318  auto *srv = Http::NewServer(xact);
2319  // XXX: do not abandon the MasterXaction object
2320  AsyncJob::Start(srv); // usually async-calls readSomeData()
2321 }
2322 
2324 static bool
2326 {
2327  const auto conn = connState->clientConnection;
2328  if (Security::CreateServerSession(ctx, conn, connState->port->secure, "client https start")) {
2329  debugs(33, 5, "will negotiate TLS on " << conn);
2330  return true;
2331  }
2332 
2333  debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn);
2334  conn->close();
2335  return false;
2336 }
2337 
2339 static void
2340 clientNegotiateSSL(int fd, void *data)
2341 {
2342  ConnStateData *conn = (ConnStateData *)data;
2343 
2344  const auto handshakeResult = conn->acceptTls();
2345  switch (handshakeResult.category) {
2347  break;
2348 
2350  Comm::SetSelect(conn->clientConnection->fd, COMM_SELECT_READ, clientNegotiateSSL, conn, 0);
2351  return;
2352 
2354  Comm::SetSelect(conn->clientConnection->fd, COMM_SELECT_WRITE, clientNegotiateSSL, conn, 0);
2355  return;
2356 
2358  debugs(83, (handshakeResult.important ? Important(62) : 2), "ERROR: " << handshakeResult.errorDescription <<
2359  " while accepting a TLS connection on " << conn->clientConnection << ": " << handshakeResult.errorDetail);
2360  // TODO: No ConnStateData::tunnelOnError() on this forward-proxy code
2361  // path because we cannot know the intended connection target?
2362  conn->updateError(ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
2363  conn->clientConnection->close();
2364  return;
2365  }
2366 
2367  Security::SessionPointer session(fd_table[fd].ssl);
2368 
2369 #if USE_OPENSSL
2370  if (Security::SessionIsResumed(session)) {
2371  debugs(83, 2, "Session " << SSL_get_session(session.get()) <<
2372  " reused on FD " << fd << " (" << fd_table[fd].ipaddr <<
2373  ":" << (int)fd_table[fd].remote_port << ")");
2374  } else {
2375  if (Debug::Enabled(83, 4)) {
2376  /* Write out the SSL session details.. actually the call below, but
2377  * OpenSSL headers do strange typecasts confusing GCC.. */
2378  /* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
2379 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00908000L
2380  PEM_ASN1_write(reinterpret_cast<i2d_of_void *>(i2d_SSL_SESSION),
2381  PEM_STRING_SSL_SESSION, debug_log,
2382  reinterpret_cast<char *>(SSL_get_session(session.get())),
2383  nullptr, nullptr, 0, nullptr, nullptr);
2384 
2385 #elif (ALLOW_ALWAYS_SSL_SESSION_DETAIL == 1)
2386 
2387  /* When using gcc 3.3.x and OpenSSL 0.9.7x sometimes a compile error can occur here.
2388  * This is caused by an unpredicatble gcc behaviour on a cast of the first argument
2389  * of PEM_ASN1_write(). For this reason this code section is disabled. To enable it,
2390  * define ALLOW_ALWAYS_SSL_SESSION_DETAIL=1.
2391  * Because there are two possible usable cast, if you get an error here, try the other
2392  * commented line. */
2393 
2394  PEM_ASN1_write((int(*)())i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2395  debug_log,
2396  reinterpret_cast<char *>(SSL_get_session(session.get())),
2397  nullptr, nullptr, 0, nullptr, nullptr);
2398  /* PEM_ASN1_write((int(*)(...))i2d_SSL_SESSION, PEM_STRING_SSL_SESSION,
2399  debug_log,
2400  reinterpret_cast<char *>(SSL_get_session(session.get())),
2401  nullptr, nullptr, 0, nullptr, nullptr);
2402  */
2403 #else
2404  debugs(83, 4, "With " OPENSSL_VERSION_TEXT ", session details are available only defining ALLOW_ALWAYS_SSL_SESSION_DETAIL=1 in the source.");
2405 
2406 #endif
2407  /* Note: This does not automatically fflush the log file.. */
2408  }
2409 
2410  debugs(83, 2, "New session " << SSL_get_session(session.get()) <<
2411  " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" <<
2412  fd_table[fd].remote_port << ")");
2413  }
2414 #else
2415  debugs(83, 2, "TLS session reuse not yet implemented.");
2416 #endif
2417 
2418  // Connection established. Retrieve TLS connection parameters for logging.
2419  conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session);
2420 
2421 #if USE_OPENSSL
2422  X509 *client_cert = SSL_get_peer_certificate(session.get());
2423 
2424  if (client_cert) {
2425  debugs(83, 3, "FD " << fd << " client certificate: subject: " <<
2426  X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0));
2427 
2428  debugs(83, 3, "FD " << fd << " client certificate: issuer: " <<
2429  X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0));
2430 
2431  X509_free(client_cert);
2432  } else {
2433  debugs(83, 5, "FD " << fd << " has no client certificate.");
2434  }
2435 #else
2436  debugs(83, 2, "Client certificate requesting not yet implemented.");
2437 #endif
2438 
2439  // If we are called, then bumped CONNECT has succeeded. Finalize it.
2440  if (auto xact = conn->pipeline.front()) {
2441  if (xact->http && xact->http->request && xact->http->request->method == Http::METHOD_CONNECT)
2442  xact->finished();
2443  // cannot proceed with encryption if requests wait for plain responses
2444  Must(conn->pipeline.empty());
2445  }
2446  /* careful: finished() above frees request, host, etc. */
2447 
2448  conn->readSomeData();
2449 }
2450 
2455 static void
2457 {
2458  assert(connState);
2459  const Comm::ConnectionPointer &details = connState->clientConnection;
2460 
2461  if (!ctx || !httpsCreate(connState, ctx))
2462  return;
2463 
2464  connState->resetReadTimeout(Config.Timeout.request);
2465 
2466  Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0);
2467 }
2468 
2469 #if USE_OPENSSL
2470 
2473 static void
2475 {
2476  ConnStateData *connState = (ConnStateData *) data;
2477 
2478  // if the connection is closed or closing, just return.
2479  if (!connState->isOpen())
2480  return;
2481 
2482  if (answer.allowed()) {
2483  debugs(33, 2, "sslBump action " << Ssl::bumpMode(answer.kind) << "needed for " << connState->clientConnection);
2484  connState->sslBumpMode = static_cast<Ssl::BumpMode>(answer.kind);
2485  } else {
2486  debugs(33, 3, "sslBump not needed for " << connState->clientConnection);
2487  connState->sslBumpMode = Ssl::bumpSplice;
2488  }
2489 
2490  if (connState->sslBumpMode == Ssl::bumpTerminate) {
2491  connState->clientConnection->close();
2492  return;
2493  }
2494 
2495  if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf))
2496  connState->clientConnection->close();
2497 }
2498 #endif
2499 
2501 static void
2503 {
2504  Assure(params.port);
2505 
2506  // NP: it is possible the port was reconfigured when the call or accept() was queued.
2507 
2508  if (params.flag != Comm::OK) {
2509  // Its possible the call was still queued when the client disconnected
2510  debugs(33, 2, "httpsAccept: " << params.port->listenConn << ": accept failure: " << xstrerr(params.xerrno));
2511  return;
2512  }
2513 
2514  const auto xact = MasterXaction::MakePortful(params.port);
2515  xact->tcpClient = params.conn;
2516 
2517  debugs(33, 4, params.conn << " accepted, starting SSL negotiation.");
2518  fd_note(params.conn->fd, "client https connect");
2519 
2520  // Socket is ready, setup the connection manager to start using it
2521  auto *srv = Https::NewServer(xact);
2522  // XXX: do not abandon the MasterXaction object
2523  AsyncJob::Start(srv); // usually async-calls postHttpsAccept()
2524 }
2525 
2526 void
2528 {
2529  if (port->flags.tunnelSslBumping) {
2530 #if USE_OPENSSL
2531  debugs(33, 5, "accept transparent connection: " << clientConnection);
2532 
2533  if (!Config.accessList.ssl_bump) {
2535  return;
2536  }
2537 
2538  const auto mx = MasterXaction::MakePortful(port);
2539  mx->tcpClient = clientConnection;
2540  // Create a fake HTTP request and ALE for the ssl_bump ACL check,
2541  // using tproxy/intercept provided destination IP and port.
2542  // XXX: Merge with subsequent fakeAConnectRequest(), buildFakeRequest().
2543  // XXX: Do this earlier (e.g., in Http[s]::One::Server constructor).
2544  HttpRequest *request = new HttpRequest(mx);
2545  static char ip[MAX_IPSTRLEN];
2547  request->url.host(clientConnection->local.toStr(ip, sizeof(ip)));
2549  request->myportname = port->name;
2550  const AccessLogEntry::Pointer connectAle = new AccessLogEntry;
2551  CodeContext::Reset(connectAle);
2552  // TODO: Use these request/ALE when waiting for new bumped transactions.
2553 
2555  fillChecklist(*acl_checklist);
2556  // Build a local AccessLogEntry to allow requiresAle() acls work
2557  acl_checklist->al = connectAle;
2558  acl_checklist->al->cache.start_time = current_time;
2559  acl_checklist->al->tcpClient = clientConnection;
2560  acl_checklist->al->cache.port = port;
2561  acl_checklist->al->cache.caddr = log_addr;
2562  acl_checklist->al->proxyProtocolHeader = proxyProtocolHeader_;
2563  acl_checklist->al->updateError(bareError);
2564  HTTPMSGUNLOCK(acl_checklist->al->request);
2565  acl_checklist->al->request = request;
2566  HTTPMSGLOCK(acl_checklist->al->request);
2567  Http::StreamPointer context = pipeline.front();
2568  ClientHttpRequest *http = context ? context->http : nullptr;
2569  const char *log_uri = http ? http->log_uri : nullptr;
2570  acl_checklist->syncAle(request, log_uri);
2571  acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this);
2572 #else
2573  fatal("FATAL: SSL-Bump requires --with-openssl");
2574 #endif
2575  return;
2576  } else {
2577  httpsEstablish(this, port->secure.staticContext);
2578  }
2579 }
2580 
2581 #if USE_OPENSSL
2582 void
2584 {
2585  ConnStateData * state_data = (ConnStateData *)(data);
2586  state_data->sslCrtdHandleReply(reply);
2587 }
2588 
2589 void
2591 {
2592  if (!isOpen()) {
2593  debugs(33, 3, "Connection gone while waiting for ssl_crtd helper reply; helper reply:" << reply);
2594  return;
2595  }
2596 
2597  if (reply.result == Helper::BrokenHelper) {
2598  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply);
2599  } else if (!reply.other().hasContent()) {
2600  debugs(1, DBG_IMPORTANT, "\"ssl_crtd\" helper returned <NULL> reply.");
2601  } else {
2603  if (reply_message.parse(reply.other().content(), reply.other().contentSize()) != Ssl::CrtdMessage::OK) {
2604  debugs(33, 5, "Reply from ssl_crtd for " << tlsConnectHostOrIp << " is incorrect");
2605  } else {
2606  if (reply.result != Helper::Okay) {
2607  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody());
2608  } else {
2609  debugs(33, 5, "Certificate for " << tlsConnectHostOrIp << " was successfully received from ssl_crtd");
2612  auto ssl = fd_table[clientConnection->fd].ssl.get();
2613  bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port);
2614  if (!ret)
2615  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2616 
2619  } else {
2621  if (ctx && !sslBumpCertKey.isEmpty())
2623  getSslContextDone(ctx);
2624  }
2625  return;
2626  }
2627  }
2628  }
2631 }
2632 
2634 {
2636 
2637  const bool connectedOk = sslServerBump && sslServerBump->connectedOk();
2638  if (connectedOk) {
2639  if (X509 *mimicCert = sslServerBump->serverCert.get())
2640  certProperties.mimicCert.resetAndLock(mimicCert);
2641 
2642  ACLFilledChecklist checklist(nullptr, sslServerBump->request.getRaw());
2643  fillChecklist(checklist);
2644 
2645  for (sslproxy_cert_adapt *ca = Config.ssl_client.cert_adapt; ca != NULL; ca = ca->next) {
2646  // If the algorithm already set, then ignore it.
2647  if ((ca->alg == Ssl::algSetCommonName && certProperties.setCommonName) ||
2648  (ca->alg == Ssl::algSetValidAfter && certProperties.setValidAfter) ||
2649  (ca->alg == Ssl::algSetValidBefore && certProperties.setValidBefore) )
2650  continue;
2651 
2652  if (ca->aclList && checklist.fastCheck(ca->aclList).allowed()) {
2653  const char *alg = Ssl::CertAdaptAlgorithmStr[ca->alg];
2654  const char *param = ca->param;
2655 
2656  // For parameterless CN adaptation, use hostname from the
2657  // CONNECT request.
2658  if (ca->alg == Ssl::algSetCommonName) {
2659  if (!param)
2660  param = tlsConnectHostOrIp.c_str();
2661  certProperties.commonName = param;
2662  certProperties.setCommonName = true;
2663  } else if (ca->alg == Ssl::algSetValidAfter)
2664  certProperties.setValidAfter = true;
2665  else if (ca->alg == Ssl::algSetValidBefore)
2666  certProperties.setValidBefore = true;
2667 
2668  debugs(33, 5, "Matches certificate adaptation aglorithm: " <<
2669  alg << " param: " << (param ? param : "-"));
2670  }
2671  }
2672 
2673  certProperties.signAlgorithm = Ssl::algSignEnd;
2674  for (sslproxy_cert_sign *sg = Config.ssl_client.cert_sign; sg != NULL; sg = sg->next) {
2675  if (sg->aclList && checklist.fastCheck(sg->aclList).allowed()) {
2676  certProperties.signAlgorithm = (Ssl::CertSignAlgorithm)sg->alg;
2677  break;
2678  }
2679  }
2680  } else {// did not try to connect (e.g. client-first) or failed to connect
2681  // In case of an error while connecting to the secure server, use a
2682  // trusted certificate, with no mimicked fields and no adaptation
2683  // algorithms. There is nothing we can mimic, so we want to minimize the
2684  // number of warnings the user will have to see to get to the error page.
2685  // We will close the connection, so that the trust is not extended to
2686  // non-Squid content.
2687  certProperties.signAlgorithm = Ssl::algSignTrusted;
2688  }
2689 
2690  assert(certProperties.signAlgorithm != Ssl::algSignEnd);
2691 
2692  if (certProperties.signAlgorithm == Ssl::algSignUntrusted) {
2693  assert(port->secure.untrustedSigningCa.cert);
2694  certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get());
2695  certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get());
2696  } else {
2697  assert(port->secure.signingCa.cert.get());
2698  certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get());
2699 
2700  if (port->secure.signingCa.pkey)
2701  certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get());
2702  }
2703  signAlgorithm = certProperties.signAlgorithm;
2704 
2705  certProperties.signHash = Ssl::DefaultSignHash;
2706 }
2707 
2710 {
2711  debugs(33, 5, "Finding SSL certificate for " << cacheKey << " in cache");
2713  if (const auto ctx = ssl_ctx_cache ? ssl_ctx_cache->get(cacheKey) : nullptr) {
2714  if (Ssl::verifySslCertificate(*ctx, certProperties)) {
2715  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is valid");
2716  return *ctx;
2717  } else {
2718  debugs(33, 5, "Cached SSL certificate for " << certProperties.commonName << " is out of date. Delete this certificate from cache");
2719  if (ssl_ctx_cache)
2720  ssl_ctx_cache->del(cacheKey);
2721  }
2722  }
2723  return Security::ContextPointer(nullptr);
2724 }
2725 
2726 void
2728 {
2730  if (!ssl_ctx_cache || !ssl_ctx_cache->add(cacheKey, ctx)) {
2731  // If it is not in storage delete after using. Else storage deleted it.
2732  fd_table[clientConnection->fd].html?amicTlsContext = ctx;
2733  }
2734 }
2735 
2736 void
2738 {
2739  if (port->secure.generateHostCertificates) {
2740  Ssl::CertificateProperties certProperties;
2741  buildSslCertGenerationParams(certProperties);
2742 
2743  // Disable caching for bumpPeekAndSplice mode
2746  Ssl::InRamCertificateDbKey(certProperties, sslBumpCertKey);
2748 
2750  if (ctx) {
2751  getSslContextDone(ctx);
2752  return;
2753  }
2754  }
2755 
2756 #if USE_SSL_CRTD
2757  try {
2758  debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName << " using ssl_crtd.");
2761  request_message.composeRequest(certProperties);
2762  debugs(33, 5, "SSL crtd request: " << request_message.compose().c_str());
2763  Ssl::Helper::Submit(request_message, sslCrtdHandleReplyWrapper, this);
2764  return;
2765  } catch (const std::exception &e) {
2766  debugs(33, DBG_IMPORTANT, "ERROR: Failed to compose ssl_crtd " <<
2767  "request for " << certProperties.commonName <<
2768  " certificate: " << e.what() << "; will now block to " <<
2769  "generate that certificate.");
2770  // fall through to do blocking in-process generation.
2771  }
2772 #endif // USE_SSL_CRTD
2773 
2774  debugs(33, 5, "Generating SSL certificate for " << certProperties.commonName);
2777  auto ssl = fd_table[clientConnection->fd].ssl.get();
2778  if (!Ssl::configureSSL(ssl, certProperties, *port))
2779  debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode");
2780 
2783  } else {
2785  if (dynCtx && !sslBumpCertKey.isEmpty())
2787  getSslContextDone(dynCtx);
2788  }
2789  return;
2790  }
2791 
2794 }
2795 
2796 void
2798 {
2799  if (port->secure.generateHostCertificates && !ctx) {
2800  debugs(33, 2, "Failed to generate TLS context for " << tlsConnectHostOrIp);
2801  }
2802 
2803  // If generated ssl context = NULL, try to use static ssl context.
2804  if (!ctx) {
2805  if (!port->secure.staticContext) {
2806  debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
2808  return;
2809  } else {
2810  debugs(33, 5, "Using static TLS context.");
2811  ctx = port->secure.staticContext;
2812  }
2813  }
2814 
2815  if (!httpsCreate(this, ctx))
2816  return;
2817 
2818  // bumped intercepted conns should already have Config.Timeout.request set
2819  // but forwarded connections may only have Config.Timeout.lifetime. [Re]set
2820  // to make sure the connection does not get stuck on non-SSL clients.
2822 
2823  switchedToHttps_ = true;
2824 
2825  auto ssl = fd_table[clientConnection->fd].ssl.get();
2826  BIO *b = SSL_get_rbio(ssl);
2827  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
2828  bio->setReadBufData(inBuf);
2829  inBuf.clear();
2831 }
2832 
2833 void
2835 {
2837  Must(http->request);
2838  auto &request = http->request;
2839 
2840  // Depending on receivedFirstByte_, we are at the start of either an
2841  // established CONNECT tunnel with the client or an intercepted TCP (and
2842  // presumably TLS) connection from the client. Expect TLS Client Hello.
2843  const auto insideConnectTunnel = receivedFirstByte_;
2844  debugs(33, 5, (insideConnectTunnel ? "post-CONNECT " : "raw TLS ") << clientConnection);
2845 
2846  tlsConnectHostOrIp = request->url.hostOrIp();
2847  tlsConnectPort = request->url.port();
2848  resetSslCommonName(request->url.host());
2849 
2850  // We are going to read new request
2851  flags.readMore = true;
2852 
2853  // keep version major.minor details the same.
2854  // but we are now performing the HTTPS handshake traffic
2856 
2857  // If sslServerBump is set, then we have decided to deny CONNECT
2858  // and now want to switch to SSL to send the error to the client
2859  // without even peeking at the origin server certificate.
2860  if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
2861  request->flags.sslPeek = true;
2862  sslServerBump = new Ssl::ServerBump(http);
2863  } else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
2864  request->flags.sslPeek = true;
2865  sslServerBump = new Ssl::ServerBump(http, nullptr, bumpServerMode);
2866  }
2867 
2868  // commSetConnTimeout() was called for this request before we switched.
2869  // Fix timeout to request_start_timeout
2871  // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
2872  // a bumbed "connect" request on non transparent port.
2873  receivedFirstByte_ = false;
2874  // Get more data to peek at Tls
2875  parsingTlsHandshake = true;
2876 
2877  // If the protocol has changed, then reset preservingClientData_.
2878  // Otherwise, its value initially set in start() is still valid/fresh.
2879  // shouldPreserveClientData() uses parsingTlsHandshake which is reset above.
2880  if (insideConnectTunnel)
2882 
2883  readSomeData();
2884 }
2885 
2886 void
2888 {
2890 
2891  assert(!inBuf.isEmpty());
2893  fd_note(clientConnection->fd, "Parsing TLS handshake");
2894 
2895  // stops being nil if we fail to parse the handshake
2896  ErrorDetail::Pointer parseErrorDetails;
2897 
2898  try {
2899  if (!tlsParser.parseHello(inBuf)) {
2900  // need more data to finish parsing
2901  readSomeData();
2902  return;
2903  }
2904  }
2905  catch (const TextException &ex) {
2906  debugs(83, 2, "exception: " << ex);
2907  parseErrorDetails = new ExceptionErrorDetail(ex.id());
2908  }
2909  catch (...) {
2910  debugs(83, 2, "exception: " << CurrentException);
2911  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_PARSE");
2912  parseErrorDetails = d;
2913  }
2914 
2915  parsingTlsHandshake = false;
2916 
2917  // client data may be needed for splicing and for
2918  // tunneling unsupportedProtocol after an error
2920 
2921  // Even if the parser failed, each TLS detail should either be set
2922  // correctly or still be "unknown"; copying unknown detail is a no-op.
2925  if (details && !details->serverName.isEmpty()) {
2926  resetSslCommonName(details->serverName.c_str());
2927  tlsClientSni_ = details->serverName;
2928  }
2929 
2930  // We should disable read/write handlers
2932 
2933  if (parseErrorDetails) {
2934  Http::StreamPointer context = pipeline.front();
2935  Must(context && context->http);
2936  HttpRequest::Pointer request = context->http->request;
2937  debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump.");
2938  updateError(ERR_PROTOCOL_UNKNOWN, parseErrorDetails);
2941  return;
2942  }
2943 
2944  if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first.
2946  return;
2947  } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
2948  debugs(83, 5, "server-first skips step2; start forwarding the request");
2949  sslServerBump->step = XactionStep::tlsBump3;
2950  Http::StreamPointer context = pipeline.front();
2951  ClientHttpRequest *http = context ? context->http : nullptr;
2952  // will call httpsPeeked() with certificate and connection, eventually
2954  } else {
2957  }
2958 }
2959 
2960 static void
2962 {
2963  ConnStateData *connState = (ConnStateData *) data;
2964 
2965  // if the connection is closed or closing, just return.
2966  if (!connState->isOpen())
2967  return;
2968 
2969  debugs(33, 5, "Answer: " << answer << " kind:" << answer.kind);
2970  assert(connState->serverBump());
2971  Ssl::BumpMode bumpAction;
2972  if (answer.allowed()) {
2973  bumpAction = (Ssl::BumpMode)answer.kind;
2974  } else
2975  bumpAction = Ssl::bumpSplice;
2976 
2977  connState->serverBump()->act.step2 = bumpAction;
2978  connState->sslBumpMode = bumpAction;
2979  Http::StreamPointer context = connState->pipeline.front();
2980  if (ClientHttpRequest *http = (context ? context->http : nullptr))
2981  http->al->ssl.bumpMode = bumpAction;
2982 
2983  if (bumpAction == Ssl::bumpTerminate) {
2984  connState->clientConnection->close();
2985  } else if (bumpAction != Ssl::bumpSplice) {
2986  connState->startPeekAndSplice();
2987  } else if (!connState->splice())
2988  connState->clientConnection->close();
2989 }
2990 
2991 bool
2993 {
2994  // normally we can splice here, because we just got client hello message
2995 
2996  // fde::ssl/tls_read_method() probably reads from our own inBuf. If so, then
2997  // we should not lose any raw bytes when switching to raw I/O here.
2998  if (fd_table[clientConnection->fd].ssl.get())
2999  fd_table[clientConnection->fd].useDefaultIo();
3000 
3001  // XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
3002  // reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
3004  assert(!pipeline.empty());
3005  Http::StreamPointer context = pipeline.front();
3006  Must(context);
3007  Must(context->http);
3008  ClientHttpRequest *http = context->http;
3010  context->finished();
3011  if (transparent()) {
3012  // For transparent connections, make a new fake CONNECT request, now
3013  // with SNI as target. doCallout() checks, adaptations may need that.
3014  return fakeAConnectRequest("splice", preservedClientData);
3015  } else {
3016  // For non transparent connections make a new tunneled CONNECT, which
3017  // also sets the HttpRequest::flags::forceTunnel flag to avoid
3018  // respond with "Connection Established" to the client.
3019  // This fake CONNECT request required to allow use of SNI in
3020  // doCallout() checks and adaptations.
3022  }
3023 }
3024 
3025 void
3027 {
3028  // This is the Step2 of the SSL bumping
3030  Http::StreamPointer context = pipeline.front();
3031  ClientHttpRequest *http = context ? context->http : nullptr;
3032 
3033  if (sslServerBump->at(XactionStep::tlsBump1)) {
3034  sslServerBump->step = XactionStep::tlsBump2;
3035  // Run a accessList check to check if want to splice or continue bumping
3036 
3041  fillChecklist(*acl_checklist);
3042  acl_checklist->nonBlockingCheck(httpsSslBumpStep2AccessCheckDone, this);
3043  return;
3044  }
3045 
3046  // will call httpsPeeked() with certificate and connection, eventually
3047  Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure));
3048  fd_table[clientConnection->fd].html?amicTlsContext = unConfiguredCTX;
3049 
3050  if (!httpsCreate(this, unConfiguredCTX))
3051  return;
3052 
3053  switchedToHttps_ = true;
3054 
3055  auto ssl = fd_table[clientConnection->fd].ssl.get();
3056  BIO *b = SSL_get_rbio(ssl);
3057  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3058  bio->setReadBufData(inBuf);
3059  bio->hold(true);
3060 
3061  // We have successfully parsed client Hello, but our TLS handshake parser is
3062  // forgiving. Now we use a TLS library to parse the same bytes, so that we
3063  // can honor on_unsupported_protocol if needed. If there are no errors, we
3064  // expect Security::Accept() to ask us to write (our) TLS server Hello. We
3065  // also allow an ioWantRead result in case some fancy TLS extension that
3066  // Squid does not yet understand requires reading post-Hello client bytes.
3067  const auto handshakeResult = acceptTls();
3068  if (!handshakeResult.wantsIo())
3069  return handleSslBumpHandshakeError(handshakeResult);
3070 
3071  // We need to reset inBuf here, to be used by incoming requests in the case
3072  // of SSL bump
3073  inBuf.clear();
3074 
3075  debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
3076  sslServerBump->step = XactionStep::tlsBump3;
3078 }
3079 
3081 void
3083 {
3084  auto errCategory = ERR_NONE;
3085 
3086  switch (handshakeResult.category) {
3088  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_SUCCESS");
3089  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3090  break;
3091  }
3092 
3094  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_READ");
3095  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3096  break;
3097  }
3098 
3100  static const auto d = MakeNamedErrorDetail("TLS_ACCEPT_UNEXPECTED_WRITE");
3101  updateError(errCategory = ERR_GATEWAY_FAILURE, d);
3102  break;
3103  }
3104 
3106  debugs(83, (handshakeResult.important ? DBG_IMPORTANT : 2), "ERROR: " << handshakeResult.errorDescription <<
3107  " while SslBump-accepting a TLS connection on " << clientConnection << ": " << handshakeResult.errorDetail);
3108  updateError(errCategory = ERR_SECURE_ACCEPT_FAIL, handshakeResult.errorDetail);
3109  break;
3110 
3111  }
3112 
3113  if (!tunnelOnError(errCategory))
3115 }
3116 
3117 void
3119 {
3120  auto ssl = fd_table[clientConnection->fd].ssl.get();
3121  BIO *b = SSL_get_rbio(ssl);
3122  assert(b);
3123  Ssl::ClientBio *bio = static_cast<Ssl::ClientBio *>(BIO_get_data(b));
3124 
3125  debugs(33, 5, "PeekAndSplice mode, proceed with client negotiation. Current state:" << SSL_state_string_long(ssl));
3126  bio->hold(false);
3127 
3129  switchedToHttps_ = true;
3130 }
3131 
3132 void
3134 {
3135  Must(sslServerBump != NULL);
3136  Must(sslServerBump->request == pic.request);
3137  Must(pipeline.empty() || pipeline.front()->http == nullptr || pipeline.front()->http->request == pic.request.getRaw());
3138 
3139  if (Comm::IsConnOpen(pic.connection)) {
3141  debugs(33, 5, "bumped HTTPS server: " << tlsConnectHostOrIp);
3142  } else
3143  debugs(33, 5, "Error while bumping: " << tlsConnectHostOrIp);
3144 
3146 }
3147 
3148 #endif /* USE_OPENSSL */
3149 
3150 bool
3151 ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, const char *reason, const SBuf &payload)
3152 {
3153  // fake a CONNECT request to force connState to tunnel
3154  SBuf connectHost;
3155  unsigned short connectPort = 0;
3156 
3157  if (pinning.serverConnection != nullptr) {
3158  static char ip[MAX_IPSTRLEN];
3159  connectHost = pinning.serverConnection->remote.toStr(ip, sizeof(ip));
3160  connectPort = pinning.serverConnection->remote.port();
3161  } else if (cause) {
3162  connectHost = cause->url.hostOrIp();
3163  connectPort = cause->url.port();
3164 #if USE_OPENSSL
3165  } else if (!tlsConnectHostOrIp.isEmpty()) {
3166  connectHost = tlsConnectHostOrIp;
3167  connectPort = tlsConnectPort;
3168 #endif
3169  } else if (transparent()) {
3170  static char ip[MAX_IPSTRLEN];
3171  connectHost = clientConnection->local.toStr(ip, sizeof(ip));
3172  connectPort = clientConnection->local.port();
3173  } else {
3174  // Typical cases are malformed HTTP requests on http_port and malformed
3175  // TLS handshakes on non-bumping https_port. TODO: Discover these
3176  // problems earlier so that they can be classified/detailed better.
3177  debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason);
3178  // TODO: throw when nonBlockingCheck() callbacks gain job protections
3179  static const auto d = MakeNamedErrorDetail("TUNNEL_TARGET");
3181  return false;
3182  }
3183 
3184  debugs(33, 2, "Request tunneling for " << reason);
3185  ClientHttpRequest *http = buildFakeRequest(connectHost, connectPort, payload);
3187  request->flags.forceTunnel = true;
3188  http->calloutContext = new ClientRequestContext(http);
3189  http->doCallouts();
3191  return true;
3192 }
3193 
3194 bool
3195 ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload)
3196 {
3197  debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason);
3198 
3199  SBuf connectHost;
3200  assert(transparent());
3201  const unsigned short connectPort = clientConnection->local.port();
3202 
3203 #if USE_OPENSSL
3204  if (!tlsClientSni_.isEmpty())
3205  connectHost.assign(tlsClientSni_);
3206  else
3207 #endif
3208  {
3209  static char ip[MAX_IPSTRLEN];
3210  clientConnection->local.toHostStr(ip, sizeof(ip));
3211  connectHost.assign(ip);
3212  }
3213 
3214  ClientHttpRequest *http = buildFakeRequest(connectHost, connectPort, payload);
3215 
3216  http->calloutContext = new ClientRequestContext(http);
3218  http->doCallouts();
3220  return true;
3221 }
3222 
3224 ConnStateData::buildFakeRequest(SBuf &useHost, unsigned short usePort, const SBuf &payload)
3225 {
3226  ClientHttpRequest *http = new ClientHttpRequest(this);
3227  Http::Stream *stream = new Http::Stream(clientConnection, http);
3228 
3229  StoreIOBuffer tempBuffer;
3230  tempBuffer.data = stream->reqbuf;
3231  tempBuffer.length = HTTP_REQBUF_SZ;
3232 
3233  ClientStreamData newServer = new clientReplyContext(http);
3234  ClientStreamData newClient = stream;
3237  clientSocketDetach, newClient, tempBuffer);
3238 
3239  stream->flags.parsed_ok = 1; // Do we need it?
3240  stream->mayUseConnection(true);
3241  extendLifetime();
3242  stream->registerWithConn();
3243 
3244  const auto mx = MasterXaction::MakePortful(port);
3245  mx->tcpClient = clientConnection;
3246  // Setup Http::Request object. Maybe should be replaced by a call to (modified)
3247  // clientProcessRequest
3249  request->url.setScheme(AnyP::PROTO_AUTHORITY_FORM, nullptr);
3251  request->url.host(useHost.c_str());
3252  request->url.port(usePort);
3253 
3254  http->uri = SBufToCstring(request->effectiveRequestUri());
3255  http->initRequest(request.getRaw());
3256 
3257  request->manager(this, http->al);
3258 
3259  request->header.putStr(Http::HOST, useHost.c_str());
3260 
3261  request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? Http::Message::srcHttps : Http::Message::srcHttp);
3262 #if USE_AUTH
3263  if (getAuth())
3264  request->auth_user_request = getAuth();
3265 #endif
3266 
3267  inBuf = payload;
3268  flags.readMore = false;
3269 
3270  return http;
3271 }
3272 
3274 static bool
3276 {
3277  if (!Comm::IsConnOpen(c)) {
3278  Must(NHttpSockets > 0); // we tried to open some
3279  --NHttpSockets; // there will be fewer sockets than planned
3280  Must(HttpSockets[NHttpSockets] < 0); // no extra fds received
3281 
3282  if (!NHttpSockets) // we could not open any listen sockets at all
3283  fatalf("Unable to open %s",FdNote(portType));
3284 
3285  return false;
3286  }
3287  return true;
3288 }
3289 
3291 static bool
3293 {
3294  bool found = false;
3295  for (int i = 0; i < NHttpSockets && !found; ++i) {
3296  if ((found = HttpSockets[i] < 0))
3297  HttpSockets[i] = conn->fd;
3298  }
3299  return found;
3300 }
3301 
3302 static void
3304 {
3305  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3306  const SBuf &scheme = AnyP::UriScheme(s->transport.protocol).image();
3307 
3309  debugs(1, DBG_IMPORTANT, "WARNING: You have too many '" << scheme << "_port' lines." <<
3310  Debug::Extra << "The limit is " << MAXTCPLISTENPORTS << " HTTP ports.");
3311  continue;
3312  }
3313 
3314 #if USE_OPENSSL
3315  if (s->flags.tunnelSslBumping) {
3316  if (!Config.accessList.ssl_bump) {
3317  debugs(33, DBG_IMPORTANT, "WARNING: No ssl_bump configured. Disabling ssl-bump on " << scheme << "_port " << s->s);
3318  s->flags.tunnelSslBumping = false;
3319  }
3320  if (!s->secure.staticContext && !s->secure.generateHostCertificates) {
3321  debugs(1, DBG_IMPORTANT, "Will not bump SSL at " << scheme << "_port " << s->s << " due to TLS initialization failure.");
3322  s->flags.tunnelSslBumping = false;
3323  if (s->transport.protocol == AnyP::PROTO_HTTP)
3324  s->secure.encryptTransport = false;
3325  }
3326  if (s->flags.tunnelSslBumping) {
3327  // Create ssl_ctx cache for this port.
3328  Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.html?amicCertMemCacheSize);
3329  }
3330  }
3331 #endif
3332 
3333  if (s->secure.encryptTransport && !s->secure.staticContext) {
3334  debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure.");
3335  continue;
3336  }
3337 
3338  // Fill out a Comm::Connection which IPC will open as a listener for us
3339  // then pass back when active so we can start a TcpAcceptor subscription.
3340  s->listenConn = new Comm::Connection;
3341  s->listenConn->local = s->s;
3342 
3343  s->listenConn->flags = COMM_NONBLOCKING | (s->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3344  (s->flags.natIntercept ? COMM_INTERCEPTION : 0) |
3345  (s->workerQueues ? COMM_REUSEPORT : 0);
3346 
3347  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3348  if (s->transport.protocol == AnyP::PROTO_HTTP) {
3349  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTP
3352 
3353  AsyncCall::Pointer listenCall = asyncCall(33,2, "clientListenerConnectionOpened",
3355  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall);
3356 
3357  } else if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3358  // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS
3361 
3362  AsyncCall::Pointer listenCall = asyncCall(33, 2, "clientListenerConnectionOpened",
3364  s, Ipc::fdnHttpsSocket, sub));
3365  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall);
3366  }
3367 
3368  HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened
3369  ++NHttpSockets;
3370  }
3371 }
3372 
3373 void
3375 {
3376  // Fill out a Comm::Connection which IPC will open as a listener for us
3377  port->listenConn = new Comm::Connection;
3378  port->listenConn->local = port->s;
3379  port->listenConn->flags =
3381  (port->flags.tproxyIntercept ? COMM_TRANSPARENT : 0) |
3382  (port->flags.natIntercept ? COMM_INTERCEPTION : 0);
3383 
3384  // route new connections to subCall
3385  typedef CommCbFunPtrCallT<CommAcceptCbPtrFun> AcceptCall;
3387  AsyncCall::Pointer listenCall =
3388  asyncCall(33, 2, "clientListenerConnectionOpened",
3390  port, fdNote, sub));
3391  Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, port->listenConn, fdNote, listenCall);
3392 
3394  HttpSockets[NHttpSockets] = -1;
3395  ++NHttpSockets;
3396 }
3397 
3399 static void
3401 {
3402  Must(s != NULL);
3403 
3404  if (!OpenedHttpSocket(s->listenConn, portTypeNote))
3405  return;
3406 
3407  Must(Comm::IsConnOpen(s->listenConn));
3408 
3409  // TCP: setup a job to handle accept() with subscribed handler
3410  AsyncJob::Start(new Comm::TcpAcceptor(s, FdNote(portTypeNote), sub));
3411 
3412  debugs(1, Important(13), "Accepting " <<
3413  (s->flags.natIntercept ? "NAT intercepted " : "") <<
3414  (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") <<
3415  (s->flags.tunnelSslBumping ? "SSL bumped " : "") <<
3416  (s->flags.accelSurrogate ? "reverse-proxy " : "")
3417  << FdNote(portTypeNote) << " connections at "
3418  << s->listenConn);
3419 
3420  Must(AddOpenedHttpSocket(s->listenConn)); // otherwise, we have received a fd we did not ask for
3421 
3422 #if USE_SYSTEMD
3423  // When the very first port opens, tell systemd we are able to serve connections.
3424  // Subsequent sd_notify() calls, including calls during reconfiguration,
3425  // do nothing because the first call parameter is 1.
3426  // XXX: Send the notification only after opening all configured ports.
3427  if (opt_foreground || opt_no_daemon) {
3428  const auto result = sd_notify(1, "READY=1");
3429  if (result < 0) {
3430  debugs(1, DBG_IMPORTANT, "WARNING: failed to send start-up notification to systemd" <<
3431  Debug::Extra << "sd_notify() error: " << xstrerr(-result));
3432  }
3433  }
3434 #endif
3435 }
3436 
3437 void
3439 {
3442 
3443  if (NHttpSockets < 1)
3444  fatal("No HTTP, HTTPS, or FTP ports configured");
3445 }
3446 
3447 void
3449 {
3450  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
3451  if (s->listenConn != NULL) {
3452  debugs(1, Important(14), "Closing HTTP(S) port " << s->listenConn->local);
3453  s->listenConn->close();
3454  s->listenConn = NULL;
3455  }
3456  }
3457 
3459 
3460  // TODO see if we can drop HttpSockets array entirely */
3461  for (int i = 0; i < NHttpSockets; ++i) {
3462  HttpSockets[i] = -1;
3463  }
3464 
3465  NHttpSockets = 0;
3466 }
3467 
3468 int
3470 {
3471  SBuf vary(request->vary_headers);
3472  const auto &reply = entry->mem().freshestReply();
3473  auto has_vary = reply.header.has(Http::HdrType::VARY);
3474 #if X_ACCELERATOR_VARY
3475 
3476  has_vary |=
3477  reply.header.has(Http::HdrType::HDR_X_ACCELERATOR_VARY);
3478 #endif
3479 
3480  if (!has_vary || entry->mem_obj->vary_headers.isEmpty()) {
3481  if (!vary.isEmpty()) {
3482  /* Oops... something odd is going on here.. */
3483  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary object on second attempt, '" <<
3484  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3485  request->vary_headers.clear();
3486  return VARY_CANCEL;
3487  }
3488 
3489  if (!has_vary) {
3490  /* This is not a varying object */
3491  return VARY_NONE;
3492  }
3493 
3494  /* virtual "vary" object found. Calculate the vary key and
3495  * continue the search
3496  */
3497  vary = httpMakeVaryMark(request, &reply);
3498 
3499  if (!vary.isEmpty()) {
3500  request->vary_headers = vary;
3501  return VARY_OTHER;
3502  } else {
3503  /* Ouch.. we cannot handle this kind of variance */
3504  /* XXX This cannot really happen, but just to be complete */
3505  return VARY_CANCEL;
3506  }
3507  } else {
3508  if (vary.isEmpty()) {
3509  vary = httpMakeVaryMark(request, &reply);
3510 
3511  if (!vary.isEmpty())
3512  request->vary_headers = vary;
3513  }
3514 
3515  if (vary.isEmpty()) {
3516  /* Ouch.. we cannot handle this kind of variance */
3517  /* XXX This cannot really happen, but just to be complete */
3518  return VARY_CANCEL;
3519  } else if (vary.cmp(entry->mem_obj->vary_headers) == 0) {
3520  return VARY_MATCH;
3521  } else {
3522  /* Oops.. we have already been here and still haven't
3523  * found the requested variant. Bail out
3524  */
3525  debugs(33, DBG_IMPORTANT, "varyEvaluateMatch: Oops. Not a Vary match on second attempt, '" <<
3526  entry->mem_obj->urlXXX() << "' '" << vary << "'");
3527  return VARY_CANCEL;
3528  }
3529  }
3530 }
3531 
3534 {
3535  const auto checklist = new ACLFilledChecklist(acl, nullptr, nullptr);
3536  clientAclChecklistFill(*checklist, http);
3537  return checklist;
3538 }
3539 
3540 void
3542 {
3543  assert(http);
3544 
3545  if (!checklist.request && http->request)
3546  checklist.setRequest(http->request);
3547 
3548  if (!checklist.al && http->al) {
3549  checklist.al = http->al;
3550  checklist.syncAle(http->request, http->log_uri);
3551  if (!checklist.reply && http->al->reply) {
3552  checklist.reply = http->al->reply.getRaw();
3553  HTTPMSGLOCK(checklist.reply);
3554  }
3555  }
3556 
3557  if (const auto conn = http->getConn())
3558  checklist.setConn(conn); // may already be set
3559 }
3560 
3561 void
3563 {
3564  const auto context = pipeline.front();
3565  if (const auto http = context ? context->http : nullptr)
3566  return clientAclChecklistFill(checklist, http); // calls checklist.setConn()
3567 
3568  // no requests, but we always have connection-level details
3569  // TODO: ACL checks should not require a mutable ConnStateData. Adjust the
3570  // code that accidentally violates that principle to remove this const_cast!
3571  checklist.setConn(const_cast<ConnStateData*>(this));
3572 
3573  // Set other checklist fields inside our fillConnectionLevelDetails() rather
3574  // than here because clientAclChecklistFill() code path calls that method
3575  // (via ACLFilledChecklist::setConn()) rather than calling us directly.
3576 }
3577 
3578 void
3580 {
3581  assert(checklist.conn() == this);
3583 
3584  if (!checklist.request) { // preserve (better) addresses supplied by setRequest()
3585  checklist.src_addr = clientConnection->remote;
3586  checklist.my_addr = clientConnection->local; // TODO: or port->s?
3587  }
3588 
3589 #if USE_OPENSSL
3590  if (!checklist.sslErrors && sslServerBump)
3592 #endif
3593 
3594  if (!checklist.rfc931[0]) // checklist creator may have supplied it already
3595  checklist.setIdent(clientConnection->rfc931);
3596 
3597 }
3598 
3599 bool
3601 {
3603 }
3604 
3607 {
3608  bodyPipe = new BodyPipe(this);
3609  if (size >= 0)
3611  else
3613  return bodyPipe;
3614 }
3615 
3616 int64_t
3618 {
3619  if (!bodyPipe)
3620  return 0; // request without a body or read/produced all body bytes
3621 
3622  if (!bodyPipe->bodySizeKnown())
3623  return -1; // probably need to read more, but we cannot be sure
3624 
3625  const int64_t needToProduce = bodyPipe->unproducedSize();
3626  const int64_t haveAvailable = static_cast<int64_t>(inBuf.length());
3627 
3628  if (needToProduce <= haveAvailable)
3629  return 0; // we have read what we need (but are waiting for pipe space)
3630 
3631  return needToProduce - haveAvailable;
3632 }
3633 
3634 void
3636 {
3637  debugs(33, 4, "receiving error (" << clientConnection << "): " << error <<
3638  "; old sending error: " <<
3639  (stoppedSending() ? stoppedSending_ : "none"));
3640 
3641  if (const char *oldError = stoppedReceiving()) {
3642  debugs(33, 3, "already stopped receiving: " << oldError);
3643  return; // nothing has changed as far as this connection is concerned
3644  }
3645 
3647 
3648  if (const char *sendError = stoppedSending()) {
3649  debugs(33, 3, "closing because also stopped sending: " << sendError);
3651  }
3652 }
3653 
3654 void
3656 {
3657  if (bodyPipe != NULL) {
3658  debugs(33, 4, "no consumer for virgin body " << bodyPipe->status());
3660  }
3661 }
3662 
3664 void
3666 {
3667  Must(bodyPipe != NULL);
3668  debugs(33, 5, "start dechunking" << bodyPipe->status());
3669  assert(!bodyParser);
3671 }
3672 
3674 void
3676 {
3677  debugs(33, 5, "finish dechunking: " << withSuccess);
3678 
3679  if (bodyPipe != NULL) {
3680  debugs(33, 7, "dechunked tail: " << bodyPipe->status());
3681  BodyPipe::Pointer myPipe = bodyPipe;
3682  stopProducingFor(bodyPipe, withSuccess); // sets bodyPipe->bodySize()
3683  Must(!bodyPipe); // we rely on it being nil after we are done with body
3684  if (withSuccess) {
3685  Must(myPipe->bodySizeKnown());
3686  Http::StreamPointer context = pipeline.front();
3687  if (context != NULL && context->http && context->http->request)
3688  context->http->request->setContentLength(myPipe->bodySize());
3689  }
3690  }
3691 
3692  delete bodyParser;
3693  bodyParser = NULL;
3694 }
3695 
3696 // XXX: this is an HTTP/1-only operation
3697 void
3699 {
3700  if (const auto context = pipeline.front()) {
3701  if (context->http)
3702  context->http->al->reply = msg.reply;
3703  }
3704 
3705  if (!isOpen()) {
3706  debugs(33, 3, "ignoring 1xx due to earlier closure");
3707  return;
3708  }
3709 
3710  // HTTP/1 1xx status messages are only valid when there is a transaction to trigger them
3711  if (!pipeline.empty()) {
3712  HttpReply::Pointer rep(msg.reply);
3713  Must(rep);
3714  // remember the callback
3716 
3719 
3720  if (!writeControlMsgAndCall(rep.getRaw(), call)) {
3721  // but still inform the caller (so it may resume its operation)
3723  }
3724  return;
3725  }
3726 
3727  debugs(33, 3, " closing due to missing context for 1xx");
3729 }
3730 
3731 void
3733 {
3735 
3736  if (Http::StreamPointer deferredRequest = pipeline.front()) {
3737  debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
3738  ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
3739  }
3740 }
3741 
3743 void
3745 {
3746  // FwdState might repin a failed connection sooner than this close
3747  // callback is called for the failed connection.
3748  assert(pinning.serverConnection == io.conn);
3749  pinning.closeHandler = NULL; // Comm unregisters handlers before calling
3750  const bool sawZeroReply = pinning.zeroReply; // reset when unpinning
3751  pinning.serverConnection->noteClosure();
3752  unpinConnection(false);
3753 
3754  if (sawZeroReply && clientConnection != NULL) {
3755  debugs(33, 3, "Closing client connection on pinned zero reply.");
3757  }
3758 
3759 }
3760 
3761 void
3763 {
3764  pinConnection(pinServer, *request);
3765 }
3766 
3767 void
3769 {
3770  Must(pic.connection);
3771  Must(pic.request);
3772  pinConnection(pic.connection, *pic.request);
3773 
3774  // monitor pinned server connection for remote-end closures.
3776 
3777  if (pipeline.empty())
3778  kick(); // in case clientParseRequests() was blocked by a busy pic.connection
3779 }
3780 
3782 void
3784 {
3785  if (Comm::IsConnOpen(pinning.serverConnection) &&
3786  pinning.serverConnection->fd == pinServer->fd) {
3787  debugs(33, 3, "already pinned" << pinServer);
3788  return;
3789  }
3790 
3791  unpinConnection(true); // closes pinned connection, if any, and resets fields
3792 
3793  pinning.serverConnection = pinServer;
3794 
3795  debugs(33, 3, pinning.serverConnection);
3796 
3797  Must(pinning.serverConnection != NULL);
3798 
3799  const char *pinnedHost = "[unknown]";
3800  pinning.host = xstrdup(request.url.host());
3801  pinning.port = request.url.port();
3802  pinnedHost = pinning.host;
3803  pinning.pinned = true;
3804  if (CachePeer *aPeer = pinServer->getPeer())
3805  pinning.peer = cbdataReference(aPeer);
3806  pinning.auth = request.flags.connectionAuth;
3807  char stmp[MAX_IPSTRLEN];
3808  char desc[FD_DESC_SZ];
3809  snprintf(desc, FD_DESC_SZ, "%s pinned connection for %s (%d)",
3810  (pinning.auth || !pinning.peer) ? pinnedHost : pinning.peer->name,
3812  clientConnection->fd);
3813  fd_note(pinning.serverConnection->fd, desc);
3814 
3816  pinning.closeHandler = JobCallback(33, 5,
3818  // remember the pinned connection so that cb does not unpin a fresher one
3819  typedef CommCloseCbParams Params;
3820  Params &params = GetCommParams<Params>(pinning.closeHandler);
3821  params.conn = pinning.serverConnection;
3822  comm_add_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3823 }
3824 
3827 void
3829 {
3830  if (pinning.readHandler != NULL)
3831  return; // already monitoring
3832 
3834  pinning.readHandler = JobCallback(33, 3,
3836  Comm::Read(pinning.serverConnection, pinning.readHandler);
3837 }
3838 
3839 void
3841 {
3842  if (pinning.readHandler != NULL) {
3843  Comm::ReadCancel(pinning.serverConnection->fd, pinning.readHandler);
3844  pinning.readHandler = NULL;
3845  }
3846 }
3847 
3848 #if USE_OPENSSL
3849 bool
3851 {
3852  // A ready-for-reading connection means that the TLS server either closed
3853  // the connection, sent us some unexpected HTTP data, or started TLS
3854  // renegotiations. We should close the connection except for the last case.
3855 
3856  Must(pinning.serverConnection != nullptr);
3857  auto ssl = fd_table[pinning.serverConnection->fd].ssl.get();
3858  if (!ssl)
3859  return false;
3860 
3861  char buf[1];
3862  const int readResult = SSL_read(ssl, buf, sizeof(buf));
3863 
3864  if (readResult > 0 || SSL_pending(ssl) > 0) {
3865  debugs(83, 2, pinning.serverConnection << " TLS application data read");
3866  return false;
3867  }
3868 
3869  switch(const int error = SSL_get_error(ssl, readResult)) {
3870  case SSL_ERROR_WANT_WRITE:
3871  debugs(83, DBG_IMPORTANT, pinning.serverConnection << " TLS SSL_ERROR_WANT_WRITE request for idle pinned connection");
3872  // fall through to restart monitoring, for now
3873  case SSL_ERROR_NONE:
3874  case SSL_ERROR_WANT_READ:
3876  return true;
3877 
3878  default:
3879  debugs(83, 2, pinning.serverConnection << " TLS error: " << error);
3880  return false;
3881  }
3882 
3883  // not reached
3884  return true;
3885 }
3886 #endif
3887 
3890 void
3892 {
3893  pinning.readHandler = NULL; // Comm unregisters handlers before calling
3894 
3895  if (io.flag == Comm::ERR_CLOSING)
3896  return; // close handler will clean up
3897 
3898  Must(pinning.serverConnection == io.conn);
3899 
3900 #if USE_OPENSSL
3902  return;
3903 #endif
3904 
3905  const bool clientIsIdle = pipeline.empty();
3906 
3907  debugs(33, 3, "idle pinned " << pinning.serverConnection << " read " <<
3908  io.size << (clientIsIdle ? " with idle client" : ""));
3909 
3910  pinning.serverConnection->close();
3911 
3912  // If we are still sending data to the client, do not close now. When we are done sending,
3913  // ConnStateData::kick() checks pinning.serverConnection and will close.
3914  // However, if we are idle, then we must close to inform the idle client and minimize races.
3915  if (clientIsIdle && clientConnection != NULL)
3917 }
3918 
3921 {
3922  debugs(33, 7, pinning.serverConnection);
3923  Must(request);
3924 
3925  const auto pinningError = [&](const err_type type) {
3926  unpinConnection(true);
3927  HttpRequestPointer requestPointer = request;
3928  return ErrorState::NewForwarding(type, requestPointer, ale);
3929  };
3930 
3931  if (!Comm::IsConnOpen(pinning.serverConnection))
3932  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3933 
3934  if (pinning.auth && pinning.host && strcasecmp(pinning.host, request->url.host()) != 0)
3935  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3936 
3937  if (pinning.port != request->url.port())
3938  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_CONFLICT_HOST
3939 
3940  if (pinning.peer && !cbdataReferenceValid(pinning.peer))
3941  throw pinningError(ERR_ZERO_SIZE_OBJECT);
3942 
3943  if (pinning.peerAccessDenied)
3944  throw pinningError(ERR_CANNOT_FORWARD); // or generalize ERR_FORWARDING_DENIED
3945 
3947  return pinning.serverConnection;
3948 }
3949 
3952 {
3953  if (const auto connManager = request ? request->pinnedConnection() : nullptr)
3954  return connManager->borrowPinnedConnection(request, ale);
3955 
3956  // ERR_CANNOT_FORWARD is somewhat misleading here; we can still forward, but
3957  // there is no point since the client connection is now gone
3958  HttpRequestPointer requestPointer = request;
3959  throw ErrorState::NewForwarding(ERR_CANNOT_FORWARD, requestPointer, ale);
3960 }
3961 
3962 void
3964 {
3965  debugs(33, 3, pinning.serverConnection);
3966 
3967  if (pinning.peer)
3969 
3970  if (Comm::IsConnOpen(pinning.serverConnection)) {
3971  if (pinning.closeHandler != NULL) {
3972  comm_remove_close_handler(pinning.serverConnection->fd, pinning.closeHandler);
3973  pinning.closeHandler = NULL;
3974  }
3975 
3977 
3978  // close the server side socket if requested
3979  if (andClose)
3980  pinning.serverConnection->close();
3981  pinning.serverConnection = NULL;
3982  }
3983 
3984  safe_free(pinning.host);
3985 
3986  pinning.zeroReply = false;
3987  pinning.peerAccessDenied = false;
3988 
3989  /* NOTE: pinning.pinned should be kept. This combined with fd == -1 at the end of a request indicates that the host
3990  * connection has gone away */
3991 }
3992 
3993 void
3995 {
3996  auto error = rawError; // (cheap) copy so that we can detail
3997  // We detail even ERR_NONE: There should be no transactions left, and
3998  // detailed ERR_NONE will be unused. Otherwise, this detail helps in triage.
3999  if (!error.detail) {
4000  static const auto d = MakeNamedErrorDetail("WITH_CLIENT");
4001  error.detail = d;
4002  }
4003 
4004  debugs(33, 3, pipeline.count() << '/' << pipeline.nrequests << " after " << error);
4005 
4006  if (pipeline.empty()) {
4007  bareError.update(error); // XXX: bareLogTagsErrors
4008  } else {
4009  // We terminate the current CONNECT/PUT/etc. context below, logging any
4010  // error details, but that context may leave unparsed bytes behind.
4011  // Consume them to stop checkLogging() from logging them again later.
4012  const auto intputToConsume =
4013 #if USE_OPENSSL
4014  parsingTlsHandshake ? "TLS handshake" : // more specific than CONNECT
4015 #endif
4016  bodyPipe ? "HTTP request body" :
4017  pipeline.back()->mayUseConnection() ? "HTTP CONNECT" :
4018  nullptr;
4019 
4020  while (const auto context = pipeline.front()) {
4021  context->noteIoError(error, lte);
4022  context->finished(); // cleanup and self-deregister
4023  assert(context != pipeline.front());
4024  }
4025 
4026  if (intputToConsume && !inBuf.isEmpty()) {
4027  debugs(83, 5, "forgetting client " << intputToConsume << " bytes: " << inBuf.length());
4028  inBuf.clear();
4029  }
4030  }
4031 
4033 }
4034 
4036 void
4038 {
4039  // to simplify our logic, we assume that terminateAll() has been called
4040  assert(pipeline.empty());
4041 
4042  // do not log connections that closed after a transaction (it is normal)
4043  // TODO: access_log needs ACLs to match received-no-bytes connections
4044  if (pipeline.nrequests && inBuf.isEmpty())
4045  return;
4046 
4047  /* Create a temporary ClientHttpRequest object. Its destructor will log. */
4048  ClientHttpRequest http(this);
4049  http.req_sz = inBuf.length();
4050  // XXX: Or we died while waiting for the pinned connection to become idle.
4051  http.setErrorUri("error:transaction-end-before-headers");
4052  http.updateError(bareError);
4053 }
4054 
4055 bool
4057 {
4058  // PROXY protocol bytes are meant for us and, hence, cannot be tunneled
4060  return false;
4061 
4062  // If our decision here is negative, configuration changes are irrelevant.
4063  // Otherwise, clientTunnelOnError() rechecks configuration before tunneling.
4065  return false;
4066 
4067  // TODO: Figure out whether/how we can support FTP tunneling.
4068  if (port->transport.protocol == AnyP::PROTO_FTP)
4069  return false;
4070 
4071 #if USE_OPENSSL
4072  if (parsingTlsHandshake)
4073  return true;
4074 
4075  // the 1st HTTP request on a bumped connection
4077  return true;
4078 #endif
4079 
4080  // the 1st HTTP(S) request on a connection to an intercepting port
4081  if (!pipeline.nrequests && transparent())
4082  return true;
4083 
4084  return false;
4085 }
4086 
4089 {
4090  if (!theNotes)
4091  theNotes = new NotePairs;
4092  return theNotes;
4093 }
4094 
4095 std::ostream &
4096 operator <<(std::ostream &os, const ConnStateData::PinnedIdleContext &pic)
4097 {
4098  return os << pic.connection << ", request=" << pic.request;
4099 }
4100 
4101 std::ostream &
4102 operator <<(std::ostream &os, const ConnStateData::ServerConnectionContext &scc)
4103 {
4104  return os << scc.conn_ << ", srv_bytes=" << scc.preReadServerBytes.length();
4105 }
4106 
const MemBuf & buf() const
Definition: BodyPipe.h:137
void Read(const Comm::ConnectionPointer &conn, AsyncCall::Pointer &callback)
Definition: Read.cc:40
#define FD_DESC_SZ
Definition: defines.h:32
struct SquidConfig::@96 Timeout
bool shouldPreserveClientData() const
void fatal(const char *message)
Definition: fatal.cc:28
void whenClientIpKnown()
const char * xstrerr(int error)
Definition: xstrerror.cc:83
Definition: parse.c:104
#define USER_IDENT_SZ
Definition: defines.h:37
virtual void noteBodyConsumerAborted(BodyPipe::Pointer)=0
@ bumpPeek
Definition: support.h:126
#define FQDN_LOOKUP_IF_MISS
Definition: defines.h:34
@ LOG_TCP_IMS_HIT
Definition: LogTags.h:47
AnyP::ProtocolVersion transferProtocol
Definition: Server.h:105
char method[16]
Definition: tcp-banger2.c:115
@ ERR_SECURE_CONNECT_FAIL
Definition: forward.h:31
char * buf
Definition: MemBuf.h:134
void checkpoint(const Connection &, const Acl::ChecklistFiller &)
Definition: KeyLogger.h:50
virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io)
Our close handler called by Comm when the pinned connection is closed.
AsyncCall::Pointer comm_add_close_handler(int fd, CLCB *handler, void *data)
Definition: comm.cc:921
void clientAfterReadingRequests()
SBuf tlsClientSni_
TLS client delivered SNI value. Empty string if none has been received.
Definition: client_side.h:489
int half_closed_clients
Definition: SquidConfig.h:295
void pinConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest &request)
Forward future client requests using the given server connection.
virtual void processParsedRequest(Http::StreamPointer &)=0
start processing a freshly parsed request
void fillConnectionLevelDetails(ACLFilledChecklist &) const
SQUIDCEXTERN CSR clientGetMoreData
Definition: client_side.h:528
void IOACB(const CommAcceptCbParams &params)
Definition: CommCalls.h:33
@ hoReply
Definition: HttpHeader.h:37
const char * findTrailingHTTPVersion(const char *uriAndHTTPVersion, const char *end)
SourceLocationId id() const
same-location exceptions have the same ID
Definition: TextException.h:40
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
unsigned int major
major version number
#define Here()
source code location of the caller
Definition: Here.h:15
int getMyPort(void)
Definition: tools.cc:1038
@ scMethodNotAllowed
Definition: StatusCode.h:49
void pinBusyConnection(const Comm::ConnectionPointer &pinServerConn, const HttpRequest::Pointer &request)
void clientProcessRequestFinished(ConnStateData *conn, const HttpRequest::Pointer &request)
void InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key)
Definition: support.cc:1387
@ HDR_X_ACCELERATOR_VARY
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
#define DBG_CRITICAL
Definition: Stream.h:40
SBuf & assign(const SBuf &S)
Definition: SBuf.cc:83
@ CLOSEST_PARENT_MISS
Definition: hier_code.h:21
void port(unsigned short p)
Definition: Uri.h:94
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
void stopPinnedConnectionMonitoring()
The caller assumes responsibility for connection closure detection.
SQUIDCEXTERN CSS clientReplyStatus
Definition: client_side.h:529
@ VARY_NONE
Definition: enums.h:193
CertSignAlgorithm
Definition: gadgets.h:150
void lifetimeTimeout(const CommTimeoutCbParams &params)
ClientHttpRequest * http
std::shared_ptr< SSL_CTX > ContextPointer
Definition: Context.h:29
Comm::ConnectionPointer connection
to-server connection to be pinned
Definition: client_side.h:188
void clientConnectionsClose()
virtual bool handleReadData()
const_reverse_iterator rbegin() const
Definition: SBuf.h:584
const char * stoppedSending() const
true if we stopped sending the response
Definition: client_side.h:162
@ ERR_GATEWAY_FAILURE
Definition: forward.h:67
Ip::Address src_addr
@ scBadRequest
Definition: StatusCode.h:44
ACLFilledChecklist * clientAclChecklistCreate(const acl_access *acl, ClientHttpRequest *http)
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:216
static std::ostream & Extra(std::ostream &os)
prefixes each grouped debugs() line after the first one in the group
Definition: Stream.h:117
@ scNone
Definition: StatusCode.h:21
Security::CertPointer signWithX509
Certificate to sign the generated request.
Definition: gadgets.h:217
void getSslContextStart()
Start to create dynamic Security::ContextPointer for host or uses static port SSL context.
SBuf inBuf
read I/O buffer for the client connection
Definition: Server.h:111
void setAuth(const Auth::UserRequest::Pointer &aur, const char *cause)
Definition: client_side.cc:506
struct ClientHttpRequest::Redirect redirect
mb_size_t size
Definition: MemBuf.h:135
void retrieveParsedInfo(Security::TlsDetails::Pointer const &details)
Extract information from parser stored in TlsDetails object.
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:22
void fd_note(int fd, const char *s)
Definition: fd.cc:216
HttpHeader header
Definition: Message.h:75
void resetSslCommonName(const char *name)
Definition: client_side.h:294
AsyncCall::Pointer cbControlMsgSent
Call to schedule when the control msg has been sent.
static void clientUpdateHierCounters(HierarchyLogEntry *)
Definition: client_side.cc:264
ByteCounter hit_kbytes_out
Definition: StatCounters.h:47
uint64_t unproducedSize() const
Definition: BodyPipe.cc:179
Security::ContextPointer GetFrom(Security::SessionPointer &s)
Helper function to retrieve a (non-locked) ContextPointer from a SessionPointer.
Definition: Session.h:105
@ PARENT_HIT
Definition: hier_code.h:16
acl_access * on_unsupported_protocol
Definition: SquidConfig.h:406
bool urlCheckRequest(const HttpRequest *r)
Definition: Uri.cc:833
bool isEmpty() const
Definition: SBuf.h:424
void initRequest(HttpRequest *)
MemObject * mem_obj
Definition: Store.h:219
StatHist nearHitSvcTime
Definition: StatCounters.h:50
void registerWithConn()
register this stream with the Server
Definition: Stream.cc:52
struct ConnStateData::@39 pinning
int64_t maxRequestBodySize
Definition: SquidConfig.h:133
bool proxyProtocolError(const char *reason)
int varyEvaluateMatch(StoreEntry *entry, HttpRequest *request)
void sslCrtdHandleReply(const Helper::Reply &reply)
Process response from ssl_crtd.
const EVP_MD * signHash
The signing hash to use.
Definition: gadgets.h:224
struct SquidConfig::@105 Addrs
bool empty() const
whether there are none or any requests currently pipelined
Definition: Pipeline.h:56
bool isTcpHit() const
determine if the log tag code indicates a cache HIT
Definition: LogTags.cc:101
NotePairs::Pointer theNotes
Definition: client_side.h:504
ErrorDetailPointer errorDetail
ioError case details (or nil)
Definition: Io.h:38
struct node * next
Definition: parse.c:105
AnyP::PortCfgPointer port
the configuration listening port this call relates to (may be nil)
Definition: CommCalls.h:105
int log_mime_hdrs
Definition: SquidConfig.h:291
ConnStateData * getConn() const
char * skipLeadingSpace(char *aString)
Callback cbSuccess
called after successfully writing the 1xx message
void updateError(const Error &)
sets (or updates the already stored) transaction error as needed
void setBodySize(uint64_t aSize)
Definition: BodyPipe.cc:147
void extendLifetime()
(re)sets client_lifetime timeout
Definition: client_side.cc:594
acl_access * cert_error
Definition: SquidConfig.h:525
MemObject & mem()
Definition: Store.h:51
struct StatCounters::@133 cd
void banAction(const Acl::Answer &action)
add action to the list of banned actions
Definition: Checklist.cc:395
Security::ContextPointer createSSLContext(Security::CertPointer &x509, Security::PrivateKeyPointer &pkey, Security::ServerOptions &)
Create SSL context and apply ssl certificate and private key to it.
Definition: support.cc:916
void doPeekAndSpliceStep()
Comm::ConnectionPointer borrowPinnedConnection(HttpRequest *, const AccessLogEntryPointer &)
ConnStateData-specific part of BorrowPinnedConnection()
void clientStartListeningOn(AnyP::PortCfgPointer &port, const RefCount< CommCbFunPtrCallT< CommAcceptCbPtrFun > > &subCall, const Ipc::FdNoteId fdNote)
accept requests to a given port and inform subCall about them
dials clientListenerConnectionOpened call
Definition: client_side.cc:149
char reqbuf[HTTP_REQBUF_SZ]
Definition: Stream.h:134
void error(char *format,...)
static void Submit(CrtdMessage const &message, HLPCB *callback, void *data)
Submit crtd message to external crtd server.
Definition: helper.cc:124
unsigned int minor
minor version number
Ip::Address log_addr
Definition: client_side.h:137
SBuf hostOrIp() const
Definition: Uri.cc:114
void setWriteLimiter(const int aWriteSpeedLimit, const double anInitialBurst, const double aHighWatermark)
Definition: comm.cc:1348
void readNextRequest()
Definition: client_side.cc:869
bool hasContent() const
Definition: MemBuf.h:54
std::vector< ClientDelayPool::Pointer > pools
#define SQUIDSTRINGPRINT(s)
Definition: SquidString.h:22
void hold(bool h)
Prevents or allow writing on socket.
Definition: bio.h:86
@ ERR_UNSUP_REQ
Definition: forward.h:44
void httpRequestFree(void *data)
Definition: client_side.cc:487
bool clientParseRequests()
Traffic parsing.
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
Definition: SBuf.h:87
virtual void sendControlMsg(HttpControlMsg)
called to send the 1xx message and notify the Source
BumpMode
Definition: support.h:126
struct timeval stop
Definition: PingData.h:37
Ip::Address client_netmask
Definition: SquidConfig.h:247
BodyPipe::Pointer bodyPipe
set when we are reading request body
Definition: client_side.h:432
bool needsMoreData() const
Definition: Parser.h:66
static void httpsSslBumpStep2AccessCheckDone(Acl::Answer answer, void *data)
@ ERR_REQUEST_PARSE_TIMEOUT
Definition: forward.h:82
ConnStateData * NewServer(const MasterXaction::Pointer &xact)
create a new HTTP connection handler; never returns NULL
Definition: Http1Server.cc:395
int commSetConnTimeout(const Comm::ConnectionPointer &conn, int timeout, AsyncCall::Pointer &callback)
Definition: comm.cc:563
void SBufToCstring(char *d, const SBuf &s)
Definition: SBuf.h:745
bool splice()
Splice a bumped client connection on peek-and-splice mode.
void setErrorUri(const char *)
const char * stoppedReceiving_
the reason why we no longer read the request or nil
Definition: client_side.h:500
#define xstrdup
void enableAutoConsumption()
start or continue consuming when producing without consumer
Definition: BodyPipe.cc:316
int64_t mayNeedToReadMoreBody() const
@ bumpTerminate
Definition: support.h:126
struct ClientHttpRequest::Flags flags
void clientdbUpdate(const Ip::Address &addr, const LogTags &ltype, AnyP::ProtocolType p, size_t size)
Definition: client_db.cc:138
Definition: Server.h:30
int clientdbEstablished(const Ip::Address &addr, int delta)
Definition: client_db.cc:182
@ LOG_TCP_CLIENT_REFRESH_MISS
Definition: LogTags.h:46
int fd
FD which the call was about. Set by the async call creator.
Definition: CommCalls.h:90
virtual void terminateAll(const Error &, const LogTagsErrors &)
abort any pending transactions and prevent new ones (by closing)
time_t request_start_timeout
Definition: SquidConfig.h:123
Security::KeyLogger keyLogger
managers logging of the being-accepted TLS connection secrets
Definition: client_side.h:385
@ METHOD_PRI
Definition: MethodType.h:89
int content_length
Definition: tcp-banger2.c:121
int type
Definition: errorpage.cc:152
struct ClientHttpRequest::Out out
C * getRaw() const
Definition: RefCount.h:80
virtual void append(const char *c, int sz)
Definition: MemBuf.cc:209
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
virtual void dial(AsyncCall &)
Definition: client_side.cc:161
struct timeval start_time
The time the master transaction started.
int cbdataReferenceValid(const void *p)
Definition: cbdata.cc:398
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
Acl::Answer const & fastCheck()
Definition: Checklist.cc:332
std::string const & getBody() const
Current body. If parsing is not finished the method returns incompleted body.
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
Http1::TeChunkedParser * bodyParser
parses HTTP/1.1 chunked request body
Definition: client_side.h:109
@ OK
Definition: Flag.h:16
const char * sslGetUserEmail(SSL *ssl)
Definition: support.cc:876
ConnStateData * NewServer(const MasterXaction::Pointer &xact)
create a new HTTPS connection handler; never returns NULL
Definition: Http1Server.cc:401
int global_internal_static
Definition: SquidConfig.h:328
void add(const Http::StreamPointer &)
register a new request context to the pipeline
Definition: Pipeline.cc:20
std::vector< HttpHdrRangeSpec * >::iterator iterator
struct ConnStateData::@38 flags
void accessLogLog(const AccessLogEntryPointer &, ACLChecklist *)
Definition: access_log.cc:147
a summary a TLS I/O operation outcome
Definition: Io.h:19
void StopListening()
reject new connections to any configured ftp_port
Definition: FtpServer.cc:284
void HTTPMSGUNLOCK(M *&a)
Definition: Message.h:150
bool commIsHalfClosed(int fd)
Definition: comm.h:97
char * toUrl(char *buf, unsigned int len) const
Definition: Address.cc:874
@ ERR_NONE
Definition: forward.h:15
@ CLOSEST_PARENT
Definition: hier_code.h:22
void handleSslBumpHandshakeError(const Security::IoResult &)
process a problematic Security::Accept() result on the SslBump code path
StatusCode
Definition: StatusCode.h:20
virtual void fillChecklist(ACLFilledChecklist &) const
configure the given checklist (to reflect the current transaction state)
err_type
Definition: forward.h:14
#define SQUIDSTRINGPH
Definition: SquidString.h:21
bool multipartRangeRequest() const
Definition: HttpRequest.cc:435
SBuf sslBumpCertKey
Key to use to store/retrieve generated certificate.
Definition: client_side.h:490
const char * FdNote(int fdNodeId)
converts FdNoteId into a string
Definition: FdNotes.cc:16
Notes notes
note
Definition: SquidConfig.h:487
void StartListening()
accept connections on all configured ftp_ports
Definition: FtpServer.cc:265
@ ERR_CLOSING
Definition: Flag.h:25
virtual bool shouldCloseOnEof() const
whether to stop serving our client after reading EOF on its connection
virtual void afterClientRead()
processing to be done after a Comm::Read()
#define cbdataReference(var)
Definition: cbdata.h:341
void * BIO_get_data(BIO *table)
Definition: openssl.h:62
Ssl::BumpStep step
The SSL bumping step.
Definition: ServerBump.h:63
static void Start(const Comm::ConnectionPointer &client, StoreEntry *, HttpRequest *, const AccessLogEntryPointer &alp)
Initiates request forwarding to a peer or origin server.
Definition: FwdState.cc:361
@ VARY_CANCEL
Definition: enums.h:196
@ LOG_TCP_HIT
Definition: LogTags.h:39
static void sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply)
Callback function. It is called when squid receive message from ssl_crtd.
int xerrno
The last errno to occur. non-zero if flag is Comm::COMM_ERROR.
Definition: CommCalls.h:88
void startDechunkingRequest()
initialize dechunking state
static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub)
process clientHttpConnectionsOpen result
ProtocolType protocol
which protocol this version is for
@ LOG_TCP_MISS
Definition: LogTags.h:40
static int port
Definition: ldap_backend.cc:69
Error error
the first transaction problem encountered (or falsy)
Definition: HttpRequest.h:161
bool checkX509ServerValidity(X509 *cert, const char *server)
Definition: support.cc:253
unsigned short tlsConnectPort
The TLS server port number as passed in the CONNECT request.
Definition: client_side.h:485
Pipeline pipeline
set of requests waiting to be serviced
Definition: Server.h:116
void clear()
Definition: SBuf.cc:175
SBuf httpMakeVaryMark(HttpRequest *request, HttpReply const *reply)
Definition: http.cc:585
#define COMM_NONBLOCKING
Definition: Connection.h:46
bool ResolveClientAddressesAsap
whether to do reverse DNS lookups for source IPs of accepted connections
Definition: fqdncache.cc:30
StoreEntry * entry
Definition: ServerBump.h:54
struct Http::Stream::@77 flags
static const CharacterSet ALPHA
Definition: CharacterSet.h:76
int tvSubMsec(struct timeval t1, struct timeval t2)
Definition: gadgets.cc:51
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:792
const Value * get(const Key &)
Definition: ClpMap.h:175
Security::IoResult acceptTls()
int opt_no_daemon
acl_access * stats_collection
Definition: SquidConfig.h:375
virtual void endingShutdown()
@ METHOD_OPTIONS
Definition: MethodType.h:31
void startPinnedConnectionMonitoring()
void finishDechunkingRequest(bool withSuccess)
put parsed content into input buffer and clean up
void stopReceiving(const char *error)
note request receiving error and close as soon as we write the response
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition: Stream.h:79
SBuf & chop(size_type pos, size_type n=npos)
Definition: SBuf.cc:530
void clientStreamDetach(clientStreamNode *thisObject, ClientHttpRequest *http)
int HttpSockets[MAXTCPLISTENPORTS]
Definition: PortCfg.cc:26
iterator end()
HttpHdrRangeIter range_iter
a transaction problem
Definition: Error.h:18
@ DISABLE_PMTU_ALWAYS
Definition: enums.h:233
void(* Handler)(AnyP::PortCfgPointer &portCfg, const Ipc::FdNoteId note, const Subscription::Pointer &sub)
Definition: client_side.cc:151
Http::Stream * parseHttpRequest(const Http1::RequestParserPointer &)
const char * CertAdaptAlgorithmStr[]
Definition: gadgets.cc:195
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
static void Reset()
forgets the current context, setting it to nil/unknown
Definition: CodeContext.cc:75
HttpRequest::Pointer request
faked, minimal request; required by Client API
Definition: ServerBump.h:53
#define COMM_INTERCEPTION
Definition: Connection.h:51
void ReadCancel(int fd, AsyncCall::Pointer &callback)
Cancel the read pending on FD. No action if none pending.
Definition: Read.cc:219
IdentConfig TheConfig
Definition: Ident.cc:81
void setIdent(const char *userIdentity)
configure rfc931 user identity for the first time
size_type rfind(char c, size_type endPos=npos) const
Definition: SBuf.cc:692
bool bodySizeKnown() const
Definition: BodyPipe.h:109
@ SIBLING_HIT
Definition: hier_code.h:15
HttpRequest * request
MemBuf & buf
Definition: BodyPipe.h:74
ConnStateData * conn() const
The client connection manager.
#define COMM_TRANSPARENT
Definition: Connection.h:50
void postHttpsAccept()
the second part of old httpsAccept, waiting for future HttpsServer home
Ssl::ServerBump * sslServerBump
HTTPS server cert. fetching state for bump-ssl-server-first.
Definition: client_side.h:493
bool multipartRangeRequest() const
Definition: client_side.cc:708
bool SessionIsResumed(const Security::SessionPointer &)
whether the session is a resumed one
Definition: Session.cc:212
acl_access * proxyProtocol
acceptable PROXY protocol clients
Definition: SquidConfig.h:401
bool mayUseConnection() const
Definition: Stream.h:140
const char * stoppedSending_
the reason why we no longer write the response or nil
Definition: client_side.h:498
void connStateClosed(const CommCloseCbParams &io)
Definition: client_side.cc:495
@ ERR_REQUEST_START_TIMEOUT
Definition: forward.h:81
unsigned int toHostStr(char *buf, const unsigned int len) const
Definition: Address.cc:842
virtual Http::Stream * parseOneRequest()=0
void applyClientMask(const Address &mask)
Definition: Address.cc:105
@ VARY_MATCH
Definition: enums.h:194
virtual void doneWithControlMsg()
@ ICP_INVALID
Definition: icp_opcode.h:15
Ssl::CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: client_side.h:494
unsigned short initial
@ bumpServerFirst
Definition: support.h:126
bool needProxyProtocolHeader_
whether PROXY protocol header is still expected
Definition: client_side.h:467
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
static const std::string code_new_certificate
String code for "new_certificate" messages.
Definition: crtd_message.h:76
virtual void swanSong()
Definition: Server.cc:51
void clearRequest()
resets the current request and log_uri to nil
char rfc931[USER_IDENT_SZ]
Definition: Connection.h:174
uint64_t bodySize() const
Definition: BodyPipe.cc:161
StatHist nearMissSvcTime
Definition: StatCounters.h:49
int size
Definition: ModDevPoll.cc:75
Comm::ConnectionPointer tcpClient
the client TCP connection which originated this transaction
Definition: MasterXaction.h:66
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:17
const MemBuf & other() const
Definition: Reply.h:42
parameters for the async notePinnedConnectionBecameIdle() call
Definition: client_side.h:184
const char * fqdncache_gethostbyaddr(const Ip::Address &addr, int flags)
Definition: fqdncache.cc:482
#define NULL
Definition: types.h:166
static void httpsAccept(const CommAcceptCbParams &params)
@ algSignTrusted
Definition: gadgets.h:150
SBuf consume(size_type n=npos)
Definition: SBuf.cc:481
@ ERR_PROTOCOL_UNKNOWN
Definition: forward.h:73
void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId fdNote, AsyncCall::Pointer &callback)
virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData)=0
Ssl::BumpMode sslBumpMode
ssl_bump decision (Ssl::bumpEnd if n/a).
Definition: client_side.h:305
ICP probing of cache_peers during peer selection.
Definition: PingData.h:26
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
void mustStop(const char *aReason)
Definition: AsyncJob.cc:70
struct StatCounters::@127 client_http
bundles HTTP 1xx reply and the "successfully forwarded" callback
time_t timeLeft(const time_t idleTimeout) const
Definition: Connection.cc:146
SBuf vary_headers
Definition: MemObject.h:204
sslproxy_cert_adapt * cert_adapt
Definition: SquidConfig.h:527
const EVP_MD * DefaultSignHash
Definition: support.cc:43
void updateError(const Error &)
if necessary, stores new error information (if any)
Definition: client_side.cc:640
void clientSocketRecipient(clientStreamNode *node, ClientHttpRequest *http, HttpReply *rep, StoreIOBuffer receivedData)
Definition: client_side.cc:812
@ scNotImplemented
Definition: StatusCode.h:72
static void httpsSslBumpAccessCheckDone(Acl::Answer answer, void *data)
@ ERR_SECURE_ACCEPT_FAIL
Definition: forward.h:80
Http::StreamPointer front() const
get the first request context in the pipeline
Definition: Pipeline.cc:28
LocalContextStorage * getLocalStorage(Ip::Address const &address)
Return the local storage for the given listening address/port.
uint64_t producedSize() const
Definition: BodyPipe.h:112
Category category
primary outcome classification
Definition: Io.h:40
bool parsingTlsHandshake
Definition: client_side.h:479
void append(char const *buf, int len)
Definition: String.cc:149
Subscription::Pointer sub
The handler to be subscribed for this connection listener.
Definition: client_side.cc:169
virtual void receivedFirstByte()
Update flags and timeout after the first byte received.
Helper::ResultCode result
The helper response 'result' field.
Definition: Reply.h:59
size_t count() const
how many requests are currently pipelined
Definition: Pipeline.h:53
@ algSignEnd
Definition: gadgets.h:150
@ LOG_TAG_NONE
Definition: LogTags.h:38
@ srcHttp
http_port or HTTP server
Definition: Message.h:39
std::string compose() const
unsigned short port() const
Definition: Address.cc:778
Definition: MemBuf.h:24
void setReplyToStoreEntry(StoreEntry *e, const char *reason)
replaces current response store entry with the given one
Ip::Address local
Definition: Connection.h:144
clientStreamNode * getClientReplyContext() const
Definition: Stream.cc:513
CachePeer * getPeer() const
Definition: Connection.cc:124
static char * prepareAcceleratedURL(ConnStateData *conn, const Http1::RequestParserPointer &hp)
static const CharacterSet HEXDIG
Definition: CharacterSet.h:88
int64_t contentLen() const
Definition: Store.h:256
void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &)
Definition: support.cc:986
void clean()
Definition: MemBuf.cc:110
StatHist hitSvcTime
Definition: StatCounters.h:51
virtual void doneWithControlMsg()
static void httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx)
bool concurrentRequestQueueFilled() const
Definition: ClpMap.h:41
acl_access * ssl_bump
Definition: SquidConfig.h:394
@ FIRST_PARENT_MISS
Definition: hier_code.h:20
bool initiateTunneledRequest(HttpRequest::Pointer const &cause, const char *reason, const SBuf &payload)
generates and sends to tunnel.cc a fake request with a given payload
void httpsPeeked(PinnedIdleContext pic)
called by FwdState when it is done bumping the server
bool preservingClientData_
whether preservedClientData is valid and should be kept up to date
Definition: client_side.h:435
@ METHOD_CONNECT
Definition: MethodType.h:29
virtual void print(std::ostream &os) const
Definition: client_side.cc:155
Comm::ConnectionPointer tcpClient
TCP/IP level details about the client connection.
void resetReadTimeout(time_t timeout)
(re)sets timeout for receiving more bytes from the client
Definition: client_side.cc:586
FdNoteId
We cannot send char* FD notes to other processes. Pass int IDs and convert.
Definition: FdNotes.h:20
void stopSending(const char *error)
note response sending error and close as soon as we read the request
Definition: client_side.cc:987
Comm::ConnectionPointer conn
Definition: CommCalls.h:85
const char * internalHostname(void)
Definition: internal.cc:140
bool handleIdleClientPinnedTlsRead()
#define safe_free(x)
Definition: xalloc.h:73
@ LOG_TCP_REFRESH_UNMODIFIED
Definition: LogTags.h:41
@ srcFtp
ftp_port or FTP server
Definition: Message.h:40
virtual int pipelinePrefetchMax() const
returning N allows a pipeline of 1+N requests (see pipeline_prefetch)
Ip::Address remote
Definition: Connection.h:147
SBuf tlsConnectHostOrIp
The TLS server host name appears in CONNECT request or the server ip address for the intercepted requ...
Definition: client_side.h:484
NotePairs::Pointer notes()
@ scRequestHeaderFieldsTooLarge
Definition: StatusCode.h:69
TlsDetails::Pointer details
TLS handshake meta info. Never nil.
Definition: Handshake.h:77
ClientHttpRequest * http
Definition: Stream.h:132
void parseTlsHandshake()
Http::StreamPointer back() const
get the last request context in the pipeline
Definition: Pipeline.cc:40
void count(double val)
Definition: StatHist.cc:55
CommCbFunPtrCallT< Dialer > * commCbCall(int debugSection, int debugLevel, const char *callName, const Dialer &dialer)
Definition: CommCalls.h:342
Http::Stream * abortRequestParsing(const char *const errUri)
stop parsing the request and create context for relaying error info
iterator begin()
void clientOpenListenSockets(void)
void comm_reset_close(const Comm::ConnectionPointer &conn)
Definition: comm.cc:753
@ ERR_ZERO_SIZE_OBJECT
Definition: forward.h:46
int conn
the current server connection FD
Definition: Transport.cc:26
const char * dash_str
#define assert(EX)
Definition: assert.h:19
#define COMM_REUSEPORT
Definition: Connection.h:52
@ Okay
Definition: ResultCode.h:18
@ scUriTooLong
Definition: StatusCode.h:58
SBuf ErrorDetail
Definition: Esi.h:29
bool parseHello(const SBuf &data)
Definition: Handshake.cc:641
@ algSetValidAfter
Definition: gadgets.h:188
StatHist missSvcTime
Definition: StatCounters.h:48
@ scContentTooLarge
Definition: StatusCode.h:57
bool transparent() const
void setPayloadBuffer(MemBuf *parsedContent)
set the buffer to be used to store decoded chunk data
SSL Connection
Definition: Session.h:45
void del(const Key &)
Remove the corresponding entry (if any)
Definition: ClpMap.h:255
SBuf image() const
Definition: UriScheme.h:50
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:220
class AccessLogEntry::CacheDetails cache
const Security::CertErrors * sslErrors() const
SSL [certificate validation] errors.
Definition: ServerBump.cc:69
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
HierarchyLogEntry hier
Definition: HttpRequest.h:157
Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char *data, Security::ServerOptions &, bool trusted)
Definition: support.cc:933
HttpReply::Pointer reply
the 1xx message being forwarded
bool switchedToHttps() const
Definition: client_side.h:285
virtual void syncAle(HttpRequest *adaptedRequest, const char *logUri) const
assigns uninitialized adapted_request and url ALE components
void HTTPMSGLOCK(Http::Message *a)
Definition: Message.h:161
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception