htcp.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 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 31 Hypertext Caching Protocol */
10 
11 #include "squid.h"
12 #include "AccessLogEntry.h"
13 #include "acl/Acl.h"
14 #include "acl/FilledChecklist.h"
15 #include "base/AsyncCallbacks.h"
16 #include "CachePeer.h"
17 #include "CachePeers.h"
18 #include "comm.h"
19 #include "comm/Connection.h"
20 #include "comm/Loops.h"
21 #include "compat/xalloc.h"
22 #include "debug/Messages.h"
23 #include "globals.h"
24 #include "htcp.h"
25 #include "http.h"
27 #include "HttpRequest.h"
28 #include "icmp/net_db.h"
29 #include "ip/tools.h"
30 #include "ipc/StartListening.h"
31 #include "md5.h"
32 #include "mem/forward.h"
33 #include "MemBuf.h"
34 #include "refresh.h"
35 #include "SquidConfig.h"
36 #include "StatCounters.h"
37 #include "Store.h"
38 #include "store_key_md5.h"
39 #include "StoreClient.h"
40 #include "tools.h"
41 
42 typedef struct _Countstr Countstr;
43 
44 typedef struct _htcpHeader htcpHeader;
45 
47 
49 
51 
52 struct _Countstr {
53  uint16_t length;
54  char *text;
55 };
56 
57 struct _htcpHeader {
58  uint16_t length;
59  u_char major;
60  u_char minor;
61 };
62 
64  uint16_t length;
65 
66 #if !WORDS_BIGENDIAN
67  unsigned int opcode:4;
68  unsigned int response:4;
69 #else
70  unsigned int response:4;
71  unsigned int opcode:4;
72 #endif
73 
74 #if !WORDS_BIGENDIAN
75  unsigned int reserved:6;
76  unsigned int F1:1;
77  unsigned int RR:1;
78 #else
79  unsigned int RR:1;
80  unsigned int F1:1;
81  unsigned int reserved:6;
82 #endif
83 
84  uint32_t msg_id;
85 };
86 
88  uint16_t length;
89 
90 #if WORDS_BIGENDIAN
91  uint8_t opcode:4;
92  uint8_t response:4;
93 #else
94  uint8_t response:4;
95  uint8_t opcode:4;
96 #endif
97 
98 #if WORDS_BIGENDIAN
99  uint8_t reserved:6;
100  uint8_t F1:1;
101  uint8_t RR:1;
102 #else
103  uint8_t RR:1;
104  uint8_t F1:1;
105  uint8_t reserved:6;
106 #endif
107 
108  uint32_t msg_id;
109 };
110 
111 /* RR == 0 --> F1 = RESPONSE DESIRED FLAG */
112 /* RR == 1 --> F1 = MESSAGE OVERALL FLAG */
113 /* RR == 0 --> REQUEST */
114 /* RR == 1 --> RESPONSE */
115 
117  uint16_t length;
118  time_t sig_time;
119  time_t sig_expire;
122 };
123 
124 class htcpSpecifier: public CodeContext, public StoreClient
125 {
127 
128 public:
130 
131  void checkHit();
132  void checkedHit(StoreEntry *);
133 
134  void setFrom(Ip::Address &anIp) { from = anIp; }
135  void setDataHeader(htcpDataHeader *aDataHeader) {
136  dhdr = aDataHeader;
137  }
138 
139  /* CodeContext API */
140  ScopedId codeContextGist() const override; // override
141  std::ostream &detailCodeContext(std::ostream &os) const override; // override
142 
143  /* StoreClient API */
144  LogTags *loggingTags() const override;
145  void fillChecklist(ACLFilledChecklist &) const override;
146 
147 public:
148  const char *method = nullptr;
149  const char *uri = nullptr;
150  char *version = nullptr;
151  char *req_hdrs = nullptr;
152  size_t reqHdrsSz = 0;
154 
157 
158 private:
160 
162  htcpDataHeader *dhdr = nullptr;
163 };
164 
166 {
168 public:
169  char *resp_hdrs = nullptr;
170  size_t respHdrsSz = 0;
171 
172  char *entity_hdrs = nullptr;
173  size_t entityHdrsSz = 0;
174 
175  char *cache_hdrs = nullptr;
176  size_t cacheHdrsSz = 0;
177 };
178 
180 {
181 public:
182  htcpStuff(uint32_t id, int o, int r, int f) :
183  op(o),
184  rr(r),
185  f1(f),
186  msg_id(id)
187  {}
188 
189  int op = 0;
190  int rr = 0;
191  int f1 = 0;
192  int response = 0;
193  int reason = 0;
194  uint32_t msg_id;
197 };
198 
199 enum {
206 };
207 
208 static const char *const htcpOpcodeStr[] = {
209  "HTCP_NOP",
210  "HTCP_TST",
211  "HTCP_MON",
212  "HTCP_SET",
213  "HTCP_CLR",
214  "HTCP_END"
215 };
216 
217 /*
218  * values for htcpDataHeader->response
219  */
220 enum {
227 };
228 
229 /*
230  * values for htcpDataHeader->RR
231  */
232 enum {
235 };
236 
238 static uint32_t msg_id_counter = 0;
239 
242 #define N_QUERIED_KEYS 8192
243 static uint32_t queried_id[N_QUERIED_KEYS];
245 
247 
248 static int old_squid_format = 0;
249 
250 static ssize_t htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff);
251 static htcpDetail *htcpUnpackDetail(char *buf, int sz);
252 static ssize_t htcpBuildAuth(char *buf, size_t buflen);
253 static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s, size_t len);
254 static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff);
255 static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff);
256 static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff);
257 static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff);
258 static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff);
259 
260 static void htcpHandleMsg(char *buf, int sz, Ip::Address &from);
261 
262 static void htcpLogHtcp(Ip::Address &, const int, const LogTags_ot, const char *, AccessLogEntryPointer);
263 static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, Ip::Address &from);
264 
265 static void htcpRecv(int fd, void *data);
266 
267 static void htcpSend(const char *buf, int len, Ip::Address &to);
268 
270 
271 static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, Ip::Address &from);
272 
273 static void htcpHandleTstResponse(htcpDataHeader *, char *, int, Ip::Address &);
274 
275 static void
276 htcpSyncAle(AccessLogEntryPointer &al, const Ip::Address &caddr, const int opcode, const char *url)
277 {
278  if (!al)
279  al = new AccessLogEntry();
280  al->cache.caddr = caddr;
281  al->htcp.opcode = htcpOpcodeStr[opcode];
282  al->url = url;
284  // HTCP transactions do not wait
286  al->cache.trTime.tv_sec = 0;
287  al->cache.trTime.tv_usec = 0;
288 }
289 
290 static void
291 htcpHexdump(const char *tag, const char *s, int sz)
292 {
293 #if USE_HEXDUMP
294  char hex[80];
295  debugs(31, 3, "htcpHexdump " << tag);
296  memset(hex, '\0', sizeof(hex));
297 
298  for (int i = 0; i < sz; ++i) {
299  int k = i % 16;
300  snprintf(&hex[k * 3], 4, " %02x", (int) *(s + i));
301 
302  if (k < 15 && i < (sz - 1))
303  continue;
304 
305  debugs(31, 3, "\t" << hex);
306 
307  memset(hex, '\0', sizeof(hex));
308  }
309 #else
310  (void)tag;
311  (void)s;
312  (void)sz;
313 #endif
314 }
315 
316 /*
317  * STUFF FOR SENDING HTCP MESSAGES
318  */
319 
320 static ssize_t
321 htcpBuildAuth(char *buf, size_t buflen)
322 {
323  htcpAuthHeader auth;
324  size_t copy_sz = 0;
325  assert(2 == sizeof(uint16_t));
326  auth.length = htons(2);
327  copy_sz += 2;
328  if (buflen < copy_sz)
329  return -1;
330  memcpy(buf, &auth, copy_sz);
331  return copy_sz;
332 }
333 
334 static ssize_t
335 htcpBuildCountstr(char *buf, size_t buflen, const char *s, size_t len)
336 {
337  int off = 0;
338 
339  if (buflen - off < 2)
340  return -1;
341 
342  debugs(31, 3, "htcpBuildCountstr: LENGTH = " << len);
343 
344  debugs(31, 3, "htcpBuildCountstr: TEXT = {" << (s ? s : "<NULL>") << "}");
345 
346  uint16_t length = htons((uint16_t) len);
347 
348  memcpy(buf + off, &length, 2);
349 
350  off += 2;
351 
352  if (buflen - off < len)
353  return -1;
354 
355  if (len)
356  memcpy(buf + off, s, len);
357 
358  off += len;
359 
360  return off;
361 }
362 
363 static ssize_t
364 htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff * stuff)
365 {
366  ssize_t off = 0;
367  ssize_t s;
368  s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.method, (stuff->S.method?strlen(stuff->S.method):0));
369 
370  if (s < 0)
371  return s;
372 
373  off += s;
374 
375  s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.uri, (stuff->S.uri?strlen(stuff->S.uri):0));
376 
377  if (s < 0)
378  return s;
379 
380  off += s;
381 
382  s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.version, (stuff->S.version?strlen(stuff->S.version):0));
383 
384  if (s < 0)
385  return s;
386 
387  off += s;
388 
389  s = htcpBuildCountstr(buf + off, buflen - off, stuff->S.req_hdrs, stuff->S.reqHdrsSz);
390 
391  if (s < 0)
392  return s;
393 
394  off += s;
395 
396  debugs(31, 3, "htcpBuildSpecifier: size " << off);
397 
398  return off;
399 }
400 
401 static ssize_t
402 htcpBuildDetail(char *buf, size_t buflen, htcpStuff * stuff)
403 {
404  ssize_t off = 0;
405  ssize_t s;
406  s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.resp_hdrs, stuff->D.respHdrsSz);
407 
408  if (s < 0)
409  return s;
410 
411  off += s;
412 
413  s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.entity_hdrs, stuff->D.entityHdrsSz);
414 
415  if (s < 0)
416  return s;
417 
418  off += s;
419 
420  s = htcpBuildCountstr(buf + off, buflen - off, stuff->D.cache_hdrs, stuff->D.cacheHdrsSz);
421 
422  if (s < 0)
423  return s;
424 
425  off += s;
426 
427  return off;
428 }
429 
430 static ssize_t
431 htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff * stuff)
432 {
433  switch (stuff->rr) {
434 
435  case RR_REQUEST:
436  debugs(31, 3, "htcpBuildTstOpData: RR_REQUEST");
437  return htcpBuildSpecifier(buf, buflen, stuff);
438 
439  case RR_RESPONSE:
440  debugs(31, 3, "htcpBuildTstOpData: RR_RESPONSE");
441  debugs(31, 3, "htcpBuildTstOpData: F1 = " << stuff->f1);
442 
443  if (stuff->f1) /* cache miss */
444  return 0;
445  else /* cache hit */
446  return htcpBuildDetail(buf, buflen, stuff);
447 
448  default:
449  fatal_dump("htcpBuildTstOpData: bad RR value");
450  }
451 
452  return 0;
453 }
454 
455 static ssize_t
456 htcpBuildClrOpData(char *buf, size_t buflen, htcpStuff * stuff)
457 {
458  unsigned short reason;
459 
460  switch (stuff->rr) {
461  case RR_REQUEST:
462  debugs(31, 3, "htcpBuildClrOpData: RR_REQUEST");
463  reason = htons((unsigned short)stuff->reason);
464  memcpy(buf, &reason, 2);
465  return htcpBuildSpecifier(buf + 2, buflen - 2, stuff) + 2;
466  case RR_RESPONSE:
467  break;
468  default:
469  fatal_dump("htcpBuildClrOpData: bad RR value");
470  }
471 
472  return 0;
473 }
474 
475 static ssize_t
476 htcpBuildOpData(char *buf, size_t buflen, htcpStuff * stuff)
477 {
478  ssize_t off = 0;
479  debugs(31, 3, "htcpBuildOpData: opcode " << htcpOpcodeStr[stuff->op]);
480 
481  switch (stuff->op) {
482 
483  case HTCP_TST:
484  off = htcpBuildTstOpData(buf + off, buflen, stuff);
485  break;
486 
487  case HTCP_CLR:
488  off = htcpBuildClrOpData(buf + off, buflen, stuff);
489  break;
490 
491  default:
492  assert(0);
493  break;
494  }
495 
496  return off;
497 }
498 
499 static ssize_t
500 htcpBuildData(char *buf, size_t buflen, htcpStuff * stuff)
501 {
502  ssize_t off = 0;
503  ssize_t op_data_sz;
504  size_t hdr_sz = sizeof(htcpDataHeader);
505 
506  if (buflen < hdr_sz)
507  return -1;
508 
509  off += hdr_sz; /* skip! */
510 
511  op_data_sz = htcpBuildOpData(buf + off, buflen - off, stuff);
512 
513  if (op_data_sz < 0)
514  return op_data_sz;
515 
516  off += op_data_sz;
517 
518  debugs(31, 3, "htcpBuildData: hdr.length = " << off);
519 
520  if (!old_squid_format) {
521  htcpDataHeader hdr;
522  memset(&hdr, 0, sizeof(hdr));
523  /* convert multi-byte fields */
524  hdr.msg_id = htonl(stuff->msg_id);
525  hdr.length = htons(static_cast<uint16_t>(off));
526  hdr.opcode = stuff->op;
527  hdr.response = stuff->response;
528  hdr.RR = stuff->rr;
529  hdr.F1 = stuff->f1;
530  memcpy(buf, &hdr, hdr_sz);
531  } else {
532  htcpDataHeaderSquid hdrSquid;
533  memset(&hdrSquid, 0, sizeof(hdrSquid));
534  hdrSquid.length = htons(static_cast<uint16_t>(off));
535  hdrSquid.opcode = stuff->op;
536  hdrSquid.response = stuff->response;
537  hdrSquid.F1 = stuff->f1;
538  hdrSquid.RR = stuff->rr;
539  memcpy(buf, &hdrSquid, hdr_sz);
540  }
541 
542  debugs(31, 3, "htcpBuildData: size " << off);
543 
544  return off;
545 }
546 
547 /*
548  * Build an HTCP packet into buf, maximum length buflen.
549  * Returns the packet length, or zero on failure.
550  */
551 static ssize_t
552 htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff)
553 {
554  ssize_t s;
555  ssize_t off = 0;
556  size_t hdr_sz = sizeof(htcpHeader);
557  htcpHeader hdr;
558  /* skip the header -- we don't know the overall length */
559 
560  if (buflen < hdr_sz) {
561  return 0;
562  }
563 
564  off += hdr_sz;
565  s = htcpBuildData(buf + off, buflen - off, stuff);
566 
567  if (s < 0) {
568  return 0;
569  }
570 
571  off += s;
572  s = htcpBuildAuth(buf + off, buflen - off);
573 
574  if (s < 0) {
575  return 0;
576  }
577 
578  off += s;
579  hdr.length = htons((uint16_t) off);
580  hdr.major = 0;
581 
582  if (old_squid_format)
583  hdr.minor = 0;
584  else
585  hdr.minor = 1;
586 
587  memcpy(buf, &hdr, hdr_sz);
588 
589  debugs(31, 3, "htcpBuildPacket: size " << off);
590 
591  return off;
592 }
593 
594 static void
595 htcpSend(const char *buf, int len, Ip::Address &to)
596 {
597  debugs(31, 3, to);
598  htcpHexdump("htcpSend", buf, len);
599 
600  if (comm_udp_sendto(htcpOutgoingConn->fd, to, buf, len) < 0) {
601  int xerrno = errno;
602  debugs(31, 3, htcpOutgoingConn << " sendto: " << xstrerr(xerrno));
603  } else
605 }
606 
607 /*
608  * Unpack an HTCP SPECIFIER in place
609  * This will overwrite any following AUTH block
610  */
611 // XXX: this needs to be turned into an Htcp1::Parser inheriting from Http1::RequestParser
612 // but with different first-line and block unpacking logic.
614 htcpUnpackSpecifier(char *buf, int sz)
615 {
616  static const htcpSpecifier::Pointer nil;
618  HttpRequestMethod method;
619 
620  /* Find length of METHOD */
621  uint16_t l = ntohs(*(uint16_t *) buf);
622  sz -= 2;
623  buf += 2;
624 
625  if (l > sz) {
626  debugs(31, 3, "htcpUnpackSpecifier: failed to unpack METHOD");
627  return nil;
628  }
629 
630  /* Set METHOD */
631  s->method = buf;
632  buf += l;
633  sz -= l;
634  debugs(31, 6, "htcpUnpackSpecifier: METHOD (" << l << "/" << sz << ") '" << s->method << "'");
635 
636  /* Find length of URI */
637  l = ntohs(*(uint16_t *) buf);
638  sz -= 2;
639 
640  if (l > sz) {
641  debugs(31, 3, "htcpUnpackSpecifier: failed to unpack URI");
642  return nil;
643  }
644 
645  /* Add terminating null to METHOD */
646  *buf = '\0';
647  buf += 2;
648 
649  /* Set URI */
650  s->uri = buf;
651  buf += l;
652  sz -= l;
653  debugs(31, 6, "htcpUnpackSpecifier: URI (" << l << "/" << sz << ") '" << s->uri << "'");
654 
655  /* Find length of VERSION */
656  l = ntohs(*(uint16_t *) buf);
657  sz -= 2;
658 
659  if (l > sz) {
660  debugs(31, 3, "htcpUnpackSpecifier: failed to unpack VERSION");
661  return nil;
662  }
663 
664  /* Add terminating null to URI */
665  *buf = '\0';
666  buf += 2;
667 
668  /* Set VERSION */
669  s->version = buf;
670  buf += l;
671  sz -= l;
672  debugs(31, 6, "htcpUnpackSpecifier: VERSION (" << l << "/" << sz << ") '" << s->version << "'");
673 
674  /* Find length of REQ-HDRS */
675  l = ntohs(*(uint16_t *) buf);
676  sz -= 2;
677 
678  if (l > sz) {
679  debugs(31, 3, "htcpUnpackSpecifier: failed to unpack REQ-HDRS");
680  return nil;
681  }
682 
683  /* Add terminating null to URI */
684  *buf = '\0';
685  buf += 2;
686 
687  /* Set REQ-HDRS */
688  s->req_hdrs = buf;
689  buf += l;
690  sz -= l;
691  s->reqHdrsSz = l;
692  debugs(31, 6, "htcpUnpackSpecifier: REQ-HDRS (" << l << "/" << sz << ") '" << s->req_hdrs << "'");
693 
694  debugs(31, 3, "htcpUnpackSpecifier: " << sz << " bytes left");
695 
696  /*
697  * Add terminating null to REQ-HDRS. This is possible because we allocated
698  * an extra byte when we received the packet. This will overwrite any following
699  * AUTH block.
700  */
701  *buf = '\0';
702 
703  // Parse the request
704  method.HttpRequestMethodXXX(s->method);
705 
706  const auto mx = MasterXaction::MakePortless<XactionInitiator::initHtcp>();
707  s->request = HttpRequest::FromUrlXXX(s->uri, mx, method == Http::METHOD_NONE ? HttpRequestMethod(Http::METHOD_GET) : method);
708  if (!s->request) {
709  debugs(31, 3, "failed to create request. Invalid URI?");
710  return nil;
711  }
712 
713  return s;
714 }
715 
716 /*
717  * Unpack an HTCP DETAIL in place
718  * This will overwrite any following AUTH block
719  */
720 static htcpDetail *
721 htcpUnpackDetail(char *buf, int sz)
722 {
723  htcpDetail *d = new htcpDetail;
724 
725  /* Find length of RESP-HDRS */
726  uint16_t l = ntohs(*(uint16_t *) buf);
727  sz -= 2;
728  buf += 2;
729 
730  if (l > sz) {
731  debugs(31, 3, "htcpUnpackDetail: failed to unpack RESP_HDRS");
732  delete d;
733  return nullptr;
734  }
735 
736  /* Set RESP-HDRS */
737  d->resp_hdrs = buf;
738  buf += l;
739  d->respHdrsSz = l;
740  sz -= l;
741 
742  /* Find length of ENTITY-HDRS */
743  l = ntohs(*(uint16_t *) buf);
744 
745  sz -= 2;
746 
747  if (l > sz) {
748  debugs(31, 3, "htcpUnpackDetail: failed to unpack ENTITY_HDRS");
749  delete d;
750  return nullptr;
751  }
752 
753  /* Add terminating null to RESP-HDRS */
754  *buf = '\0';
755 
756  /* Set ENTITY-HDRS */
757  buf += 2;
758 
759  d->entity_hdrs = buf;
760  buf += l;
761  d->entityHdrsSz = l;
762  sz -= l;
763 
764  /* Find length of CACHE-HDRS */
765  l = ntohs(*(uint16_t *) buf);
766 
767  sz -= 2;
768 
769  if (l > sz) {
770  debugs(31, 3, "htcpUnpackDetail: failed to unpack CACHE_HDRS");
771  delete d;
772  return nullptr;
773  }
774 
775  /* Add terminating null to ENTITY-HDRS */
776  *buf = '\0';
777 
778  /* Set CACHE-HDRS */
779  buf += 2;
780 
781  d->cache_hdrs = buf;
782  buf += l;
783  d->cacheHdrsSz = l;
784  sz -= l;
785 
786  debugs(31, 3, "htcpUnpackDetail: " << sz << " bytes left");
787 
788  /*
789  * Add terminating null to CACHE-HDRS. This is possible because we allocated
790  * an extra byte when we received the packet. This will overwrite any following
791  * AUTH block.
792  */
793  *buf = '\0';
794 
795  return d;
796 }
797 
798 static bool
800 {
801  /* default deny if no access list present */
802  if (!acl)
803  return false;
804 
805  ACLFilledChecklist checklist(acl, s->request.getRaw());
806  checklist.src_addr = from;
807  checklist.my_addr.setNoAddr();
808  return checklist.fastCheck().allowed();
809 }
810 
811 static void
813 {
814  static char pkt[8192];
815  HttpHeader hdr(hoHtcpReply);
816  ssize_t pktlen;
817 
818  htcpStuff stuff(dhdr->msg_id, HTCP_TST, RR_RESPONSE, 0);
819  stuff.response = e ? 0 : 1;
820  debugs(31, 3, "htcpTstReply: response = " << stuff.response);
821 
822  if (spec) {
823  stuff.S.method = spec->method;
824  stuff.S.request = spec->request;
825  stuff.S.uri = spec->uri;
826  stuff.S.version = spec->version;
827  stuff.S.req_hdrs = spec->req_hdrs;
828  stuff.S.reqHdrsSz = spec->reqHdrsSz;
829  if (e)
831  else
832  hdr.putInt(Http::HdrType::AGE, 0);
833  MemBuf mb;
834  mb.init();
835  hdr.packInto(&mb);
836  stuff.D.resp_hdrs = xstrdup(mb.buf);
837  stuff.D.respHdrsSz = mb.contentSize();
838  debugs(31, 3, "htcpTstReply: resp_hdrs = {" << stuff.D.resp_hdrs << "}");
839  mb.reset();
840  hdr.clean();
841 
842  if (e && e->expires > -1)
844 
845  if (e && e->lastModified() > -1)
847 
848  hdr.packInto(&mb);
849 
850  stuff.D.entity_hdrs = xstrdup(mb.buf);
851  stuff.D.entityHdrsSz = mb.contentSize();
852 
853  debugs(31, 3, "htcpTstReply: entity_hdrs = {" << stuff.D.entity_hdrs << "}");
854 
855  mb.reset();
856  hdr.clean();
857 
858 #if USE_ICMP
859  if (const char *host = spec->request->url.host()) {
860  int rtt = 0;
861  int hops = 0;
862  int samp = 0;
863  netdbHostData(host, &samp, &rtt, &hops);
864 
865  if (rtt || hops) {
866  char cto_buf[SQUIDHOSTNAMELEN+128];
867  snprintf(cto_buf, sizeof(cto_buf), "%s %d %f %d",
868  host, samp, 0.001 * rtt, hops);
869  hdr.putExt("Cache-to-Origin", cto_buf);
870  }
871  }
872 #endif /* USE_ICMP */
873 
874  hdr.packInto(&mb);
875  stuff.D.cache_hdrs = xstrdup(mb.buf);
876  stuff.D.cacheHdrsSz = mb.contentSize();
877  debugs(31, 3, "htcpTstReply: cache_hdrs = {" << stuff.D.cache_hdrs << "}");
878  mb.clean();
879  hdr.clean();
880  }
881 
882  pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
883 
884  safe_free(stuff.D.resp_hdrs);
885  stuff.D.respHdrsSz = 0;
886  safe_free(stuff.D.entity_hdrs);
887  stuff.D.entityHdrsSz = 0;
888  safe_free(stuff.D.cache_hdrs);
889  stuff.D.cacheHdrsSz = 0;
890 
891  if (!pktlen) {
892  debugs(31, 3, "htcpTstReply: htcpBuildPacket() failed");
893  return;
894  }
895 
896  htcpSend(pkt, (int) pktlen, from);
897 }
898 
899 static void
900 
901 htcpClrReply(htcpDataHeader * dhdr, int purgeSucceeded, Ip::Address &from)
902 {
903  static char pkt[8192];
904  ssize_t pktlen;
905 
906  /* If dhdr->F1 == 0, no response desired */
907 
908  if (dhdr->F1 == 0)
909  return;
910 
911  htcpStuff stuff(dhdr->msg_id, HTCP_CLR, RR_RESPONSE, 0);
912 
913  stuff.response = purgeSucceeded ? 0 : 2;
914 
915  debugs(31, 3, "htcpClrReply: response = " << stuff.response);
916 
917  pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
918 
919  if (pktlen == 0) {
920  debugs(31, 3, "htcpClrReply: htcpBuildPacket() failed");
921  return;
922  }
923 
924  htcpSend(pkt, (int) pktlen, from);
925 }
926 
927 ScopedId
929 {
930  if (al) {
931  const auto gist = al->codeContextGist();
932  if (gist.value)
933  return gist;
934  }
935 
936  if (request) {
937  if (const auto &mx = request->masterXaction)
938  return mx->id.detach();
939  }
940 
941  return ScopedId("HTCP w/o master");
942 }
943 
944 std::ostream &
945 htcpSpecifier::detailCodeContext(std::ostream &os) const
946 {
947  if (al)
948  return al->detailCodeContext(os);
949 
950  if (request) {
951  if (const auto &mx = request->masterXaction)
952  return os << Debug::Extra << "current master transaction: " << mx->id;
953  }
954 
955  // TODO: Report method, uri, and version if they have been set
956  return os;
957 }
958 
959 void
961 {
963 
964  if (!checkHitRequest) {
965  debugs(31, 3, "htcpCheckHit: NO; failed to parse URL");
966  checkedHit(nullptr);
967  return;
968  }
969 
971  debugs(31, 3, "htcpCheckHit: NO; failed to parse request headers");
972  checkHitRequest = nullptr;
973  checkedHit(nullptr);
974  return;
975  }
976 
978  StoreEntry *hit = nullptr;
979 
980  if (!e) {
981  debugs(31, 3, "NO; public object not found");
982  } else if (!e->validToSend()) {
983  debugs(31, 3, "NO; entry not valid to send" );
984  } else if (e->hittingRequiresCollapsing() && !startCollapsingOn(*e, false)) {
985  debugs(31, 3, "NO; prohibited CF hit: " << *e);
986  } else if (!didCollapse && refreshCheckHTCP(e, checkHitRequest.getRaw())) {
987  debugs(31, 3, "NO; cached response is stale");
988  } else {
989  debugs(31, 3, "YES!?");
990  hit = e;
991  }
992 
993  checkedHit(hit);
994 
995  // TODO: StoreClients must either store/lock or abandon found entries.
996  //if (e)
997  // e->abandon();
998 }
999 
1000 LogTags *
1002 {
1003  // calling htcpSyncAle() here would not change cache.code
1004  if (!al)
1005  al = new AccessLogEntry();
1006  return &al->cache.code;
1007 }
1008 
1009 void
1011 {
1012  checklist.setRequest(request.getRaw());
1014  checklist.al = al;
1015 }
1016 
1017 static void
1019 {
1020  debugs(31, 4, "htcpClrStoreEntry: Clearing store for entry: " << e->url() );
1021  e->releaseRequest();
1022 }
1023 
1024 static int
1026 {
1027  HttpRequestPointer request(s->request);
1028  if (!request) {
1029  debugs(31, 3, "htcpClrStore: failed to parse URL");
1030  return -1;
1031  }
1032 
1033  /* Parse request headers */
1034  if (!request->parseHeader(s->req_hdrs, s->reqHdrsSz)) {
1035  debugs(31, 2, "htcpClrStore: failed to parse request headers");
1036  return -1;
1037  }
1038 
1039  StoreEntry *e = nullptr;
1040  int released = 0;
1041  /* Lookup matching entries. This matches both GET and HEAD */
1042  while ((e = storeGetPublicByRequest(request.getRaw()))) {
1043  htcpClrStoreEntry(e);
1044  ++released;
1045  }
1046 
1047  if (released) {
1048  debugs(31, 4, "htcpClrStore: Cleared " << released << " matching entries");
1049  return 1;
1050  } else {
1051  debugs(31, 4, "htcpClrStore: No matching entry found");
1052  return 0;
1053  }
1054 }
1055 
1056 static void
1057 
1058 htcpHandleTst(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
1059 {
1060  debugs(31, 3, "htcpHandleTst: sz = " << sz);
1061 
1062  if (hdr->RR == RR_REQUEST)
1063  htcpHandleTstRequest(hdr, buf, sz, from);
1064  else
1065  htcpHandleTstResponse(hdr, buf, sz, from);
1066 }
1067 
1069  hit(0), hdr(hoHtcpReply), msg_id(0), version(0.0)
1070 {
1071  memset(&cto, 0, sizeof(cto));
1072 }
1073 
1074 bool
1075 HtcpReplyData::parseHeader(const char *buffer, const size_t size)
1076 {
1077  Http::ContentLengthInterpreter interpreter;
1078  // no applyStatusCodeRules() -- HTCP replies lack cached HTTP status code
1079  return hdr.parse(buffer, size, interpreter);
1080 }
1081 
1082 static void
1083 
1084 htcpHandleTstResponse(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
1085 {
1086  HtcpReplyData htcpReply;
1087  cache_key *key = nullptr;
1088 
1089  Ip::Address *peer;
1090  htcpDetail *d = nullptr;
1091  char *t;
1092 
1093  if (queried_id[hdr->msg_id % N_QUERIED_KEYS] != hdr->msg_id) {
1094  debugs(31, 2, "htcpHandleTstResponse: No matching query id '" <<
1095  hdr->msg_id << "' (expected " <<
1096  queried_id[hdr->msg_id % N_QUERIED_KEYS] << ") from '" <<
1097  from << "'");
1098 
1099  return;
1100  }
1101 
1102  key = queried_keys[hdr->msg_id % N_QUERIED_KEYS];
1103 
1104  if (!key) {
1105  debugs(31, 3, "htcpHandleTstResponse: No query key for response id '" << hdr->msg_id << "' from '" << from << "'");
1106  return;
1107  }
1108 
1109  peer = &queried_addr[hdr->msg_id % N_QUERIED_KEYS];
1110 
1111  if ( *peer != from || peer->port() != from.port() ) {
1112  debugs(31, 3, "htcpHandleTstResponse: Unexpected response source " << from );
1113  return;
1114  }
1115 
1116  if (hdr->F1 == 1) {
1117  debugs(31, 2, "htcpHandleTstResponse: error condition, F1/MO == 1");
1118  return;
1119  }
1120 
1121  htcpReply.msg_id = hdr->msg_id;
1122  debugs(31, 3, "htcpHandleTstResponse: msg_id = " << htcpReply.msg_id);
1123  htcpReply.hit = hdr->response ? 0 : 1;
1124 
1125  if (hdr->F1) {
1126  debugs(31, 3, "htcpHandleTstResponse: MISS");
1127  } else {
1128  debugs(31, 3, "htcpHandleTstResponse: HIT");
1129  d = htcpUnpackDetail(buf, sz);
1130 
1131  if (d == nullptr) {
1132  debugs(31, 3, "htcpHandleTstResponse: bad DETAIL");
1133  return;
1134  }
1135 
1136  if ((t = d->resp_hdrs))
1137  htcpReply.parseHeader(t, d->respHdrsSz);
1138 
1139  if ((t = d->entity_hdrs))
1140  htcpReply.parseHeader(t, d->entityHdrsSz);
1141 
1142  if ((t = d->cache_hdrs))
1143  htcpReply.parseHeader(t, d->cacheHdrsSz);
1144  }
1145 
1146  debugs(31, 3, "htcpHandleTstResponse: key (" << key << ") " << storeKeyText(key));
1147  neighborsHtcpReply(key, &htcpReply, from);
1148  htcpReply.hdr.clean();
1149 
1150  delete d;
1151 }
1152 
1153 static void
1154 htcpHandleTstRequest(htcpDataHeader * dhdr, char *buf, int sz, Ip::Address &from)
1155 {
1156  if (sz == 0) {
1157  debugs(31, 3, "htcpHandleTst: nothing to do");
1158  return;
1159  }
1160 
1161  if (dhdr->F1 == 0)
1162  return;
1163 
1164  /* buf should be a SPECIFIER */
1166 
1167  if (!s) {
1168  debugs(31, 3, "htcpHandleTstRequest: htcpUnpackSpecifier failed");
1169  htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str, nullptr);
1170  return;
1171  } else {
1172  s->setFrom(from);
1173  s->setDataHeader(dhdr);
1174  }
1175 
1176  if (!s->request) {
1177  debugs(31, 3, "htcpHandleTstRequest: failed to parse request");
1178  htcpLogHtcp(from, dhdr->opcode, LOG_UDP_INVALID, dash_str, s->al);
1179  return;
1180  }
1181 
1182  if (!htcpAccessAllowed(Config.accessList.htcp, s, from)) {
1183  debugs(31, 3, "htcpHandleTstRequest: Access denied");
1184  htcpLogHtcp(from, dhdr->opcode, LOG_UDP_DENIED, s->uri, s->al);
1185  return;
1186  }
1187 
1188  debugs(31, 2, "HTCP TST request: " << s->method << " " << s->uri << " " << s->version);
1189  debugs(31, 2, "HTCP TST headers: " << s->req_hdrs);
1190  s->checkHit();
1191 }
1192 
1193 void
1195 {
1196  if (e) {
1197  htcpTstReply(dhdr, e, this, from); /* hit */
1199  } else {
1200  htcpTstReply(dhdr, nullptr, nullptr, from); /* cache miss */
1202  }
1203 }
1204 
1205 static void
1206 htcpHandleClr(htcpDataHeader * hdr, char *buf, int sz, Ip::Address &from)
1207 {
1208  /* buf[0/1] is reserved and reason */
1209  int reason = buf[1] << 4;
1210  debugs(31, 2, "HTCP CLR reason: " << reason);
1211  buf += 2;
1212  sz -= 2;
1213 
1214  /* buf should be a SPECIFIER */
1215 
1216  if (sz == 0) {
1217  debugs(31, 4, "htcpHandleClr: nothing to do");
1218  htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str, nullptr);
1219  return;
1220  }
1221 
1223 
1224  if (!s) {
1225  debugs(31, 3, "htcpHandleClr: htcpUnpackSpecifier failed");
1226  htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str, nullptr);
1227  return;
1228  } else {
1229  s->setFrom(from);
1230  s->setDataHeader(hdr);
1231  }
1232 
1233  if (!s->request) {
1234  debugs(31, 3, "htcpHandleTstRequest: failed to parse request");
1235  htcpLogHtcp(from, hdr->opcode, LOG_UDP_INVALID, dash_str, s->al);
1236  return;
1237  }
1238 
1239  if (!htcpAccessAllowed(Config.accessList.htcp_clr, s, from)) {
1240  debugs(31, 3, "htcpHandleClr: Access denied");
1241  htcpLogHtcp(from, hdr->opcode, LOG_UDP_DENIED, s->uri, s->al);
1242  return;
1243  }
1244 
1245  debugs(31, 2, "HTCP CLR request: " << s->method << " " << s->uri << " " << s->version);
1246  debugs(31, 2, "HTCP CLR headers: " << s->req_hdrs);
1247 
1248  /* Release objects from cache
1249  * analog to clientPurgeRequest in client_side.c
1250  */
1251 
1252  switch (htcpClrStore(s)) {
1253 
1254  case 1:
1255  htcpClrReply(hdr, 1, from); /* hit */
1256  htcpLogHtcp(from, hdr->opcode, LOG_UDP_HIT, s->uri, s->al);
1257  break;
1258 
1259  case 0:
1260  htcpClrReply(hdr, 0, from); /* miss */
1261  htcpLogHtcp(from, hdr->opcode, LOG_UDP_MISS, s->uri, s->al);
1262  break;
1263 
1264  default:
1265  break;
1266  }
1267 }
1268 
1269 /*
1270  * Forward a CLR request to all peers who have requested that CLRs be
1271  * forwarded to them.
1272  */
1273 static void
1274 htcpForwardClr(char *buf, int sz)
1275 {
1276  for (const auto &p: CurrentCachePeers()) {
1277  if (!p->options.htcp) {
1278  continue;
1279  }
1280  if (!p->options.htcp_forward_clr) {
1281  continue;
1282  }
1283 
1284  htcpSend(buf, sz, p->in_addr);
1285  }
1286 }
1287 
1288 /*
1289  * Do the first pass of handling an HTCP message. This used to be two
1290  * separate functions, htcpHandle and htcpHandleData. They were merged to
1291  * allow for forwarding HTCP packets easily to other peers if desired.
1292  *
1293  * This function now works out what type of message we have received and then
1294  * hands it off to other functions to break apart message-specific data.
1295  */
1296 static void
1297 htcpHandleMsg(char *buf, int sz, Ip::Address &from)
1298 {
1299  // TODO: function-scoped CodeContext::Reset(...("HTCP message from", from))
1300 
1301  htcpHeader htcpHdr;
1302  htcpDataHeader hdr;
1303  char *hbuf;
1304  int hsz;
1305 
1306  if (sz < 0 || (size_t)sz < sizeof(htcpHeader)) {
1307  // These are highly likely to be attack packets. Should probably get a bigger warning.
1308  debugs(31, 2, "htcpHandle: msg size less than htcpHeader size from " << from);
1309  return;
1310  }
1311 
1312  htcpHexdump("htcpHandle", buf, sz);
1313  memcpy(&htcpHdr, buf, sizeof(htcpHeader));
1314  htcpHdr.length = ntohs(htcpHdr.length);
1315 
1316  if (htcpHdr.minor == 0)
1317  old_squid_format = 1;
1318  else
1319  old_squid_format = 0;
1320 
1321  debugs(31, 3, "htcpHandle: htcpHdr.length = " << htcpHdr.length);
1322  debugs(31, 3, "htcpHandle: htcpHdr.major = " << htcpHdr.major);
1323  debugs(31, 3, "htcpHandle: htcpHdr.minor = " << htcpHdr.minor);
1324 
1325  if (sz != htcpHdr.length) {
1326  debugs(31, 3, "htcpHandle: sz/" << sz << " != htcpHdr.length/" <<
1327  htcpHdr.length << " from " << from );
1328 
1329  return;
1330  }
1331 
1332  if (htcpHdr.major != 0) {
1333  debugs(31, 3, "htcpHandle: Unknown major version " << htcpHdr.major << " from " << from );
1334 
1335  return;
1336  }
1337 
1338  hbuf = buf + sizeof(htcpHeader);
1339  hsz = sz - sizeof(htcpHeader);
1340 
1341  if ((size_t)hsz < sizeof(htcpDataHeader)) {
1342  debugs(31, 3, "htcpHandleData: msg size less than htcpDataHeader size");
1343  return;
1344  }
1345 
1346  if (!old_squid_format) {
1347  memcpy(&hdr, hbuf, sizeof(hdr));
1348  } else {
1349  htcpDataHeaderSquid hdrSquid;
1350  memcpy(&hdrSquid, hbuf, sizeof(hdrSquid));
1351  hdr.length = hdrSquid.length;
1352  hdr.opcode = hdrSquid.opcode;
1353  hdr.response = hdrSquid.response;
1354  hdr.F1 = hdrSquid.F1;
1355  hdr.RR = hdrSquid.RR;
1356  hdr.reserved = 0;
1357  hdr.msg_id = hdrSquid.msg_id;
1358  }
1359 
1360  hdr.length = ntohs(hdr.length);
1361  hdr.msg_id = ntohl(hdr.msg_id);
1362  debugs(31, 3, "htcpHandleData: hsz = " << hsz);
1363  debugs(31, 3, "htcpHandleData: length = " << hdr.length);
1364 
1365  if (hdr.opcode >= HTCP_END) {
1366  debugs(31, 3, "htcpHandleData: client " << from << ", opcode " << hdr.opcode << " out of range");
1367  return;
1368  }
1369 
1370  debugs(31, 3, "htcpHandleData: opcode = " << hdr.opcode << " " << htcpOpcodeStr[hdr.opcode]);
1371  debugs(31, 3, "htcpHandleData: response = " << hdr.response);
1372  debugs(31, 3, "htcpHandleData: F1 = " << hdr.F1);
1373  debugs(31, 3, "htcpHandleData: RR = " << hdr.RR);
1374  debugs(31, 3, "htcpHandleData: msg_id = " << hdr.msg_id);
1375 
1376  if (hsz < hdr.length) {
1377  debugs(31, 3, "htcpHandleData: sz < hdr.length");
1378  return;
1379  }
1380 
1381  /*
1382  * set sz = hdr.length so we ignore any AUTH fields following
1383  * the DATA.
1384  */
1385  hsz = (int) hdr.length;
1386  hbuf += sizeof(htcpDataHeader);
1387  hsz -= sizeof(htcpDataHeader);
1388  debugs(31, 3, "htcpHandleData: hsz = " << hsz);
1389 
1390  htcpHexdump("htcpHandleData", hbuf, hsz);
1391 
1392  switch (hdr.opcode) {
1393  case HTCP_NOP:
1394  debugs(31, 3, "HTCP NOP not implemented");
1395  break;
1396  case HTCP_TST:
1397  htcpHandleTst(&hdr, hbuf, hsz, from);
1398  break;
1399  case HTCP_MON:
1400  debugs(31, 3, "HTCP MON not implemented");
1401  break;
1402  case HTCP_SET:
1403  debugs(31, 3, "HTCP SET not implemented");
1404  break;
1405  case HTCP_CLR:
1406  htcpHandleClr(&hdr, hbuf, hsz, from);
1407  htcpForwardClr(buf, sz);
1408  break;
1409  default:
1410  break;
1411  }
1412 }
1413 
1414 static void
1415 htcpRecv(int fd, void *)
1416 {
1417  static char buf[8192];
1418  int len;
1419  static Ip::Address from;
1420 
1421  /* Receive up to 8191 bytes, leaving room for a null */
1422 
1423  len = comm_udp_recvfrom(fd, buf, sizeof(buf) - 1, 0, from);
1424 
1425  debugs(31, 3, "htcpRecv: FD " << fd << ", " << len << " bytes from " << from );
1426 
1427  if (len)
1429 
1430  htcpHandleMsg(buf, len, from);
1431 
1432  Comm::SetSelect(fd, COMM_SELECT_READ, htcpRecv, nullptr, 0);
1433 }
1434 
1435 /*
1436  * ======================================================================
1437  * PUBLIC FUNCTIONS
1438  * ======================================================================
1439  */
1440 
1441 void
1443 {
1444  if (Config.Port.htcp <= 0) {
1445  debugs(31, Important(21), "HTCP Disabled.");
1446  return;
1447  }
1448 
1452 
1454  debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpIncomingConn->local << " is not an IPv4 address.");
1455  fatal("HTCP port cannot be opened.");
1456  }
1457  /* split-stack for now requires default IPv4-only HTCP */
1460  }
1461 
1462  auto call = asyncCallbackFun(31, 2, htcpIncomingConnectionOpened);
1463  Ipc::StartListening(SOCK_DGRAM,
1464  IPPROTO_UDP,
1466  Ipc::fdnInHtcpSocket, call);
1467 
1468  if (!Config.Addrs.udp_outgoing.isNoAddr()) {
1472 
1474  debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpOutgoingConn->local << " is not an IPv4 address.");
1475  fatal("HTCP port cannot be opened.");
1476  }
1477  /* split-stack for now requires default IPv4-only HTCP */
1480  }
1481 
1482  enter_suid();
1483  comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, htcpOutgoingConn, "Outgoing HTCP Socket");
1484  leave_suid();
1485 
1487  fatal("Cannot open Outgoing HTCP Socket");
1488 
1490 
1491  debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local);
1492  }
1493 
1494 }
1495 
1496 static void
1498 {
1499  const auto &conn = answer.conn;
1500 
1501  if (!Comm::IsConnOpen(conn))
1502  fatal("Cannot open HTCP Socket");
1503 
1504  Comm::SetSelect(conn->fd, COMM_SELECT_READ, htcpRecv, nullptr, 0);
1505 
1506  debugs(31, DBG_CRITICAL, "Accepting HTCP messages on " << conn->local);
1507 
1509  htcpOutgoingConn = conn;
1510  debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local);
1511  }
1512 }
1513 
1514 int
1516 {
1517  cache_key *save_key;
1518  static char pkt[8192];
1519  ssize_t pktlen;
1520  char vbuf[32];
1521  HttpHeader hdr(hoRequest);
1522  Http::StateFlags flags;
1523 
1525  return 0;
1526 
1528  snprintf(vbuf, sizeof(vbuf), "%d/%d",
1529  req->http_ver.major, req->http_ver.minor);
1530 
1532  SBuf sb = req->method.image();
1533  stuff.S.method = sb.c_str();
1534  stuff.S.uri = (char *) e->url();
1535  stuff.S.version = vbuf;
1536  HttpStateData::httpBuildRequestHeader(req, e, nullptr, &hdr, flags);
1537  MemBuf mb;
1538  mb.init();
1539  hdr.packInto(&mb);
1540  hdr.clean();
1541  stuff.S.req_hdrs = mb.buf;
1542  pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
1543  mb.clean();
1544  if (!pktlen) {
1545  debugs(31, 3, "htcpQuery: htcpBuildPacket() failed");
1546  return -1;
1547  }
1548 
1549  htcpSend(pkt, (int) pktlen, p->in_addr);
1550 
1551  queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id;
1552  save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS];
1553  storeKeyCopy(save_key, (const cache_key *)e->key);
1554  queried_addr[stuff.msg_id % N_QUERIED_KEYS] = p->in_addr;
1555  debugs(31, 3, "htcpQuery: key (" << save_key << ") " << storeKeyText(save_key));
1556 
1557  return 1;
1558 }
1559 
1560 /*
1561  * Send an HTCP CLR message for a specified item to a given CachePeer.
1562  */
1563 void
1565 {
1566  static char pkt[8192];
1567  ssize_t pktlen;
1568  char vbuf[32];
1569  HttpHeader hdr(hoRequest);
1570  MemBuf mb;
1571  Http::StateFlags flags;
1572 
1574  return;
1575 
1577  snprintf(vbuf, sizeof(vbuf), "%d/%d",
1578  req->http_ver.major, req->http_ver.minor);
1579 
1581  if (reason == HTCP_CLR_INVALIDATION)
1582  stuff.reason = 1;
1583 
1584  SBuf sb = req->method.image();
1585  stuff.S.method = sb.c_str();
1586  stuff.S.request = req;
1587  SBuf uri = req->effectiveRequestUri();
1588  stuff.S.uri = uri.c_str();
1589  stuff.S.version = vbuf;
1590  if (reason != HTCP_CLR_INVALIDATION) {
1591  HttpStateData::httpBuildRequestHeader(req, e, nullptr, &hdr, flags);
1592  mb.init();
1593  hdr.packInto(&mb);
1594  hdr.clean();
1595  stuff.S.req_hdrs = mb.buf;
1596  } else {
1597  stuff.S.req_hdrs = nullptr;
1598  }
1599  pktlen = htcpBuildPacket(pkt, sizeof(pkt), &stuff);
1600  if (reason != HTCP_CLR_INVALIDATION) {
1601  mb.clean();
1602  }
1603  if (!pktlen) {
1604  debugs(31, 3, "htcpClear: htcpBuildPacket() failed");
1605  return;
1606  }
1607 
1608  htcpSend(pkt, (int) pktlen, p->in_addr);
1609 }
1610 
1611 /*
1612  * htcpSocketShutdown only closes the 'in' socket if it is
1613  * different than the 'out' socket.
1614  */
1615 void
1617 {
1619  return;
1620 
1621  debugs(12, DBG_IMPORTANT, "Stop accepting HTCP on " << htcpIncomingConn->local);
1622  /*
1623  * Here we just unlink htcpIncomingConn because the HTCP 'in'
1624  * and 'out' sockets might be just one FD. This prevents this
1625  * function from executing repeatedly. When we are really ready to
1626  * exit or restart, main will comm_close the 'out' descriptor.
1627  */
1628  htcpIncomingConn = nullptr;
1629 
1630  /*
1631  * Normally we only write to the outgoing HTCP socket, but
1632  * we also have a read handler there to catch messages sent
1633  * to that specific interface. During shutdown, we must
1634  * disable reading on the outgoing socket.
1635  */
1636  /* XXX Don't we need this handler to read replies while shutting down?
1637  * I think there should be a separate handler for reading replies..
1638  */
1640 
1641  Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, nullptr, nullptr, 0);
1642 }
1643 
1644 void
1646 {
1648 
1649  if (htcpOutgoingConn != nullptr) {
1650  debugs(12, DBG_IMPORTANT, "Stop sending HTCP from " << htcpOutgoingConn->local);
1651  htcpOutgoingConn = nullptr;
1652  }
1653 }
1654 
1655 static void
1656 htcpLogHtcp(Ip::Address &caddr, const int opcode, const LogTags_ot logcode, const char *url, AccessLogEntryPointer al)
1657 {
1658  if (!Config.onoff.log_udp)
1659  return;
1660 
1661  htcpSyncAle(al, caddr, opcode, url);
1662 
1663  assert(logcode != LOG_TAG_NONE);
1664  al->cache.code.update(logcode);
1665 
1666  accessLogLog(al, nullptr);
1667 }
1668 
@ MINOR_VERSION_UNSUPPORTED
Definition: htcp.cc:225
void fatal(const char *message)
Definition: fatal.cc:28
const char * xstrerr(int error)
Definition: xstrerror.cc:83
char * resp_hdrs
Definition: htcp.cc:169
static ssize_t htcpBuildDetail(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:402
size_t respHdrsSz
Definition: htcp.cc:170
char * buf
Definition: MemBuf.h:134
size_t reqHdrsSz
size of the req_hdrs content
Definition: htcp.cc:152
uint16_t length
Definition: htcp.cc:53
unsigned int major
major version number
std::ostream & detailCodeContext(std::ostream &os) const override
appends human-friendly context description line(s) to a cache.log record
Definition: htcp.cc:945
static ssize_t htcpBuildClrOpData(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:456
unsigned int RR
Definition: htcp.cc:77
time_t timestamp
Definition: Store.h:223
AnyP::ProtocolVersion http_ver
Definition: Message.h:72
#define DBG_CRITICAL
Definition: Stream.h:37
char * version
Definition: htcp.cc:150
AnyP::Uri url
the request URI
Definition: HttpRequest.h:115
bool parseHeader(Http1::Parser &hp)
Definition: HttpRequest.cc:711
static void htcpSend(const char *buf, int len, Ip::Address &to)
Definition: htcp.cc:595
Ip::Address udp_incoming
Definition: SquidConfig.h:235
void releaseRequest(const bool shareable=false)
Definition: store.cc:458
static ssize_t htcpBuildData(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:500
Ip::Address in_addr
Definition: CachePeer.h:70
struct SquidConfig::@85 Port
Ip::Address src_addr
@ HTCP_NOP
Definition: htcp.cc:200
struct SquidConfig::@98 accessList
unsigned char cache_key
Store key.
Definition: forward.h:29
AccessLogEntryPointer al
optimization: nil until needed
Definition: htcp.cc:156
const char * uri
Definition: htcp.cc:149
htcpStuff(uint32_t id, int o, int r, int f)
Definition: htcp.cc:182
const char * url() const
Definition: store.cc:1566
class AccessLogEntry::HtcpDetails htcp
bool isAnyAddr() const
Definition: Address.cc:190
RefCount< htcpSpecifier > Pointer
Definition: htcp.cc:129
int comm_udp_sendto(int fd, const Ip::Address &to_addr, const void *buf, int len)
Definition: comm.cc:921
unsigned int minor
minor version number
int parse(const char *header_start, size_t len, Http::ContentLengthInterpreter &interpreter)
Definition: HttpHeader.cc:349
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
static uint32_t queried_id[N_QUERIED_KEYS]
Definition: htcp.cc:243
Definition: SBuf.h:93
uint16_t length
Definition: htcp.cc:117
void htcpOpenPorts(void)
Definition: htcp.cc:1442
time_t sig_expire
Definition: htcp.cc:119
Ip::Address from
Definition: htcp.cc:161
@ HTCP_MON
Definition: htcp.cc:202
void setVirginUrlForMissingRequest(const SBuf &vu)
Remember Client URI (or equivalent) when there is no HttpRequest.
#define xstrdup
static ssize_t htcpBuildAuth(char *buf, size_t buflen)
Definition: htcp.cc:321
struct SquidConfig::@97 onoff
@ RR_RESPONSE
Definition: htcp.cc:234
static ssize_t htcpBuildOpData(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:476
int refreshCheckHTCP(const StoreEntry *entry, HttpRequest *request)
Definition: refresh.cc:604
C * getRaw() const
Definition: RefCount.h:89
struct timeval start_time
The time the master transaction started.
AccessLogEntry::Pointer al
info for the future access.log, and external ACL
const SBuf & image() const
bool IsConnOpen(const Comm::ConnectionPointer &conn)
Definition: Connection.cc:27
struct timeval trTime
The response time.
time_t expires
Definition: Store.h:225
void accessLogLog(const AccessLogEntryPointer &, ACLChecklist *)
Definition: access_log.cc:136
unsigned int opcode
Definition: htcp.cc:67
acl_access * htcp_clr
Definition: SquidConfig.h:384
int hit
Definition: htcp.h:30
@ HTCP_TST
Definition: htcp.cc:201
char * entity_hdrs
Definition: htcp.cc:172
static void htcpRecv(int fd, void *data)
Definition: htcp.cc:1415
StoreEntry * storeGetPublicByRequest(HttpRequest *req, const KeyScope keyScope)
Definition: store.cc:516
void htcpClear(StoreEntry *e, HttpRequest *req, const HttpRequestMethod &, CachePeer *p, htcp_clr_reason reason)
Definition: htcp.cc:1564
uint8_t reserved
Definition: htcp.cc:105
HtcpReplyData()
Definition: htcp.cc:1068
void neighborsHtcpReply(const cache_key *, HtcpReplyData *, const Ip::Address &)
Definition: neighbors.cc:1601
uint16_t length
Definition: htcp.cc:88
static Comm::ConnectionPointer htcpOutgoingConn
Definition: htcp.cc:240
bool parseHeader(const char *buffer, const size_t size)
parses request header from the buffer
Definition: htcp.cc:1075
void comm_open_listener(int sock_type, int proto, Comm::ConnectionPointer &conn, const char *note)
Definition: comm.cc:257
uint16_t length
Definition: htcp.cc:64
static void htcpClrReply(htcpDataHeader *dhdr, int purgeSucceeded, Ip::Address &from)
Definition: htcp.cc:901
int response
Definition: htcp.cc:192
StartListening() result.
a storeGetPublic*() caller
Definition: StoreClient.h:40
u_char minor
Definition: htcp.cc:60
@ HTCP_CLR_INVALIDATION
Definition: enums.h:236
uint8_t response
Definition: htcp.cc:94
void update(const LogTags_ot t)
Definition: LogTags.cc:63
void leave_suid(void)
Definition: tools.cc:559
void StartListening(int sock_type, int proto, const Comm::ConnectionPointer &listenConn, FdNoteId, StartListeningCallback &)
#define SQUID_MD5_DIGEST_LENGTH
Definition: md5.h:66
unsigned int response
Definition: htcp.cc:68
mb_size_t contentSize() const
available data size
Definition: MemBuf.h:47
@ HTCP_END
Definition: htcp.cc:205
int size
Definition: ModDevPoll.cc:69
struct timeval current_time
the current UNIX time in timeval {seconds, microseconds} format
Definition: gadgets.cc:18
static void htcpHandleClr(htcpDataHeader *hdr, char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1206
Comm::ConnectionPointer conn
opened listening socket
@ LOG_UDP_HIT
Definition: LogTags.h:60
void checkHit()
Definition: htcp.cc:960
static Ip::Address queried_addr[N_QUERIED_KEYS]
Definition: htcp.cc:246
static void htcpHandleMsg(char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1297
void setNoAddr()
Definition: Address.cc:312
static ssize_t htcpBuildCountstr(char *buf, size_t buflen, const char *s, size_t len)
Definition: htcp.cc:335
static int old_squid_format
Definition: htcp.cc:248
const Acl::Answer & fastCheck()
Definition: Checklist.cc:298
size_t cacheHdrsSz
Definition: htcp.cc:176
@ LOG_TAG_NONE
Definition: LogTags.h:41
u_char major
Definition: htcp.cc:59
static Comm::ConnectionPointer htcpIncomingConn
Definition: htcp.cc:241
void htcpClosePorts(void)
Definition: htcp.cc:1645
unsigned short port() const
Definition: Address.cc:798
Definition: MemBuf.h:23
static void htcpHexdump(const char *tag, const char *s, int sz)
Definition: htcp.cc:291
Ip::Address local
Definition: Connection.h:146
int reason
Definition: htcp.cc:193
void clean()
Definition: MemBuf.cc:110
MEMPROXY_CLASS(htcpSpecifier)
uint32_t msg_id
Definition: htcp.cc:194
Ip::Address udp_outgoing
Definition: SquidConfig.h:236
static ssize_t htcpBuildPacket(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:552
HttpHeader hdr
Definition: htcp.h:31
void putExt(const char *name, const char *value)
Definition: HttpHeader.cc:1075
MEMPROXY_CLASS(htcpDetail)
char * req_hdrs
Definition: htcp.cc:151
#define safe_free(x)
Definition: xalloc.h:73
uint8_t F1
Definition: htcp.cc:104
MasterXaction::Pointer masterXaction
the master transaction this request belongs to. Never nil.
Definition: HttpRequest.h:238
void putTime(Http::HdrType id, time_t htime)
Definition: HttpHeader.cc:986
cache_key * storeKeyCopy(cache_key *dst, const cache_key *src)
const char * dash_str
@ LOG_UDP_INVALID
Definition: LogTags.h:63
#define assert(EX)
Definition: assert.h:17
struct HtcpReplyData::cto_t cto
static void htcpLogHtcp(Ip::Address &, const int, const LogTags_ot, const char *, AccessLogEntryPointer)
Definition: htcp.cc:1656
char * text
Definition: htcp.cc:54
SSL Connection
Definition: Session.h:49
static void htcpIncomingConnectionOpened(Ipc::StartListeningAnswer &)
Definition: htcp.cc:1497
class AccessLogEntry::CacheDetails cache
#define IPV6_SPECIAL_SPLITSTACK
Definition: tools.h:22
static htcpDetail * htcpUnpackDetail(char *buf, int sz)
Definition: htcp.cc:721
bool setIPv4()
Definition: Address.cc:244
static int version
#define COMM_SELECT_READ
Definition: defines.h:24
void HttpRequestMethodXXX(char const *)
static void htcpHandleTst(htcpDataHeader *, char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1058
void packInto(Packable *p, bool mask_sensitive_info=false) const
Definition: HttpHeader.cc:539
int f1
Definition: htcp.cc:191
htcpSpecifier S
Definition: htcp.cc:195
HttpRequest::Pointer checkHitRequest
Definition: htcp.cc:159
const char * c_str()
Definition: SBuf.cc:516
HttpRequest::Pointer request
Definition: htcp.cc:153
void fatal_dump(const char *message)
Definition: fatal.cc:78
time_t squid_curtime
Definition: stub_libtime.cc:20
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1316
bool isNoAddr() const
Definition: Address.cc:304
static void htcpForwardClr(char *buf, int sz)
Definition: htcp.cc:1274
uint32_t msg_id
Definition: htcp.h:32
htcpDataHeader * dhdr
Definition: htcp.cc:162
@ HTCP_CLR
Definition: htcp.cc:204
static void htcpHandleTstRequest(htcpDataHeader *, char *buf, int sz, Ip::Address &from)
Definition: htcp.cc:1154
static ssize_t htcpBuildTstOpData(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:431
@ hoHtcpReply
Definition: HttpHeader.h:34
bool startCollapsingOn(const StoreEntry &, const bool doingRevalidation) const
Definition: store_client.cc:66
std::ostream & detailCodeContext(std::ostream &os) const override
appends human-friendly context description line(s) to a cache.log record
htcpDetail D
Definition: htcp.cc:196
void htcpSocketShutdown(void)
Definition: htcp.cc:1616
bool didCollapse
whether startCollapsingOn() was called and returned true
Definition: StoreClient.h:64
LogTags * loggingTags() const override
Definition: htcp.cc:1001
ScopedId codeContextGist() const override
Definition: htcp.cc:928
char * cache_hdrs
Definition: htcp.cc:175
void putInt(Http::HdrType id, int number)
Definition: HttpHeader.cc:968
HttpRequestMethod method
Definition: HttpRequest.h:114
void fillChecklist(ACLFilledChecklist &) const override
configure the given checklist (to reflect the current transaction state)
Definition: htcp.cc:1010
bool allowed() const
Definition: Acl.h:82
int htcpQuery(StoreEntry *e, HttpRequest *req, CachePeer *p)
Definition: htcp.cc:1515
static const char *const htcpOpcodeStr[]
Definition: htcp.cc:208
size_t entityHdrsSz
Definition: htcp.cc:173
bool htcp_oldsquid
Definition: CachePeer.h:120
void checkedHit(StoreEntry *)
Definition: htcp.cc:1194
void setFrom(Ip::Address &anIp)
Definition: htcp.cc:134
Countstr key_name
Definition: htcp.cc:120
void SetSelect(int, unsigned int, PF *, void *, time_t)
Mark an FD to be watched for its IO status.
Definition: ModDevPoll.cc:220
#define N_QUERIED_KEYS
Definition: htcp.cc:242
@ RR_REQUEST
Definition: htcp.cc:233
int op
Definition: htcp.cc:189
struct _htcpHeader htcpHeader
Definition: htcp.cc:44
@ HTCP_SET
Definition: htcp.cc:203
void setRequest(HttpRequest *)
configure client request-related fields for the first time
static void htcpSyncAle(AccessLogEntryPointer &al, const Ip::Address &caddr, const int opcode, const char *url)
Definition: htcp.cc:276
@ METHOD_NONE
Definition: MethodType.h:22
uint32_t msg_id
Definition: htcp.cc:108
static HttpRequest * FromUrlXXX(const char *url, const MasterXaction::Pointer &, const HttpRequestMethod &method=Http::METHOD_GET)
Definition: HttpRequest.cc:528
#define Important(id)
Definition: Messages.h:93
@ AUTH_FAILURE
Definition: htcp.cc:222
@ fdnInHtcpSocket
Definition: FdNotes.h:24
void enter_suid(void)
Definition: tools.cc:623
static int htcpClrStore(const htcpSpecifier::Pointer &s)
Definition: htcp.cc:1025
LogTags_ot
Definition: LogTags.h:40
void setDataHeader(htcpDataHeader *aDataHeader)
Definition: htcp.cc:135
#define DBG_IMPORTANT
Definition: Stream.h:38
const char * storeKeyText(const cache_key *key)
unsigned int F1
Definition: htcp.cc:76
static cache_key queried_keys[N_QUERIED_KEYS][SQUID_MD5_DIGEST_LENGTH]
Definition: htcp.cc:244
struct CachePeer::@27 options
void reset()
Definition: MemBuf.cc:129
static void htcpClrStoreEntry(StoreEntry *e)
Definition: htcp.cc:1018
@ AUTH_REQUIRED
Definition: htcp.cc:221
ScopedId codeContextGist() const override
Countstr signature
Definition: htcp.cc:121
time_t sig_time
Definition: htcp.cc:118
int comm_udp_recvfrom(int fd, void *buf, size_t len, int flags, Ip::Address &from)
Definition: comm.cc:126
uint8_t opcode
Definition: htcp.cc:95
static bool htcpAccessAllowed(acl_access *acl, const htcpSpecifier::Pointer &s, Ip::Address &from)
Definition: htcp.cc:799
static void httpBuildRequestHeader(HttpRequest *request, StoreEntry *entry, const AccessLogEntryPointer &al, HttpHeader *hdr_out, const Http::StateFlags &flags)
Definition: http.cc:1904
void netdbHostData(const char *host, int *samp, int *rtt, int *hops)
Definition: net_db.cc:961
static uint32_t msg_id_counter
Definition: htcp.cc:238
void lastModified(const time_t when)
Definition: Store.h:175
const char * method
Definition: htcp.cc:148
const CachePeers & CurrentCachePeers()
Definition: CachePeers.cc:43
uint16_t length
Definition: htcp.cc:58
@ INVALID_OPCODE
Definition: htcp.cc:226
#define asyncCallbackFun(dbgSection, dbgLevel, function)
AsyncCall for calling back a function.
@ METHOD_GET
Definition: MethodType.h:25
struct SquidConfig::@92 Addrs
@ LOG_UDP_DENIED
Definition: LogTags.h:62
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
const SBuf & effectiveRequestUri() const
RFC 7230 section 5.5 - Effective Request URI.
Definition: HttpRequest.cc:744
void host(const char *src)
Definition: Uri.cc:123
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
htcp_clr_reason
Definition: enums.h:234
@ hoRequest
Definition: HttpHeader.h:36
uint8_t RR
Definition: htcp.cc:103
static void htcpTstReply(htcpDataHeader *, StoreEntry *, htcpSpecifier *, Ip::Address &)
Definition: htcp.cc:812
struct StatCounters::@114 htcp
static void htcpHandleTstResponse(htcpDataHeader *, char *, int, Ip::Address &)
Definition: htcp.cc:1084
void clean()
Definition: HttpHeader.cc:185
unsigned short htcp
Definition: SquidConfig.h:144
#define SQUIDHOSTNAMELEN
Definition: rfc2181.h:30
static ssize_t htcpBuildSpecifier(char *buf, size_t buflen, htcpStuff *stuff)
Definition: htcp.cc:364
class SquidConfig Config
Definition: SquidConfig.cc:12
int unsigned int
Definition: stub_fd.cc:19
struct _htcpDataHeader htcpDataHeader
Definition: htcp.cc:46
StatCounters statCounter
Definition: StatCounters.cc:12
@ MAJOR_VERSION_UNSUPPORTED
Definition: htcp.cc:224
@ LOG_UDP_MISS
Definition: LogTags.h:61
uint32_t msg_id
Definition: htcp.cc:84
unsigned int reserved
Definition: htcp.cc:75
@ OPCODE_UNIMPLEMENTED
Definition: htcp.cc:223
int rr
Definition: htcp.cc:190
static htcpSpecifier::Pointer htcpUnpackSpecifier(char *buf, int sz)
Definition: htcp.cc:614

 

Introduction

Documentation

Support

Miscellaneous