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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors