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