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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors