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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors