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