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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors