cache_cf.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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 03 Configuration File Parsing */
10 
11 #include "squid.h"
12 #include "acl/Acl.h"
13 #include "acl/AclDenyInfoList.h"
14 #include "acl/AclSizeLimit.h"
15 #include "acl/Address.h"
16 #include "acl/Gadgets.h"
17 #include "acl/MethodData.h"
18 #include "acl/Node.h"
19 #include "acl/Tree.h"
20 #include "anyp/PortCfg.h"
21 #include "anyp/UriScheme.h"
22 #include "auth/Config.h"
23 #include "auth/Scheme.h"
24 #include "AuthReg.h"
25 #include "base/CharacterSet.h"
26 #include "base/PackableStream.h"
27 #include "base/RunnersRegistry.h"
28 #include "cache_cf.h"
29 #include "CachePeer.h"
30 #include "CachePeers.h"
31 #include "compat/netdb.h"
32 #include "compat/socket.h"
33 #include "ConfigOption.h"
34 #include "ConfigParser.h"
35 #include "CpuAffinityMap.h"
36 #include "debug/Messages.h"
37 #include "DiskIO/DiskIOModule.h"
38 #include "eui/Config.h"
39 #include "ExternalACL.h"
40 #include "format/Format.h"
41 #include "fqdncache.h"
42 #include "ftp/Elements.h"
43 #include "globals.h"
44 #include "HeaderMangling.h"
46 #include "icmp/IcmpConfig.h"
47 #include "ip/Intercept.h"
48 #include "ip/NfMarkConfig.h"
49 #include "ip/QosConfig.h"
50 #include "ip/tools.h"
51 #include "ipc/Kids.h"
52 #include "log/Config.h"
53 #include "log/CustomLog.h"
54 #include "MemBuf.h"
55 #include "MessageDelayPools.h"
56 #include "mgr/ActionPasswordList.h"
57 #include "mgr/Registration.h"
58 #include "neighbors.h"
59 #include "NeighborTypeDomainList.h"
60 #include "Parsing.h"
61 #include "pconn.h"
62 #include "PeerDigest.h"
63 #include "PeerPoolMgr.h"
64 #include "redirect.h"
65 #include "RefreshPattern.h"
66 #include "rfc1738.h"
67 #include "sbuf/List.h"
68 #include "sbuf/Stream.h"
69 #include "SquidConfig.h"
70 #include "SquidString.h"
71 #include "ssl/ProxyCerts.h"
72 #include "Store.h"
73 #include "store/Disks.h"
74 #include "tools.h"
75 #include "util.h"
76 #include "wordlist.h"
77 /* wccp2 has its own conditional definitions */
78 #include "wccp2.h"
79 #if USE_ADAPTATION
80 #include "adaptation/Config.h"
81 #endif
82 #if ICAP_CLIENT
83 #include "adaptation/icap/Config.h"
84 #endif
85 #if USE_ECAP
86 #include "adaptation/ecap/Config.h"
87 #endif
88 #if USE_OPENSSL
89 #include "ssl/Config.h"
90 #include "ssl/support.h"
91 #endif
92 #if SQUID_SNMP
93 #include "snmp.h"
94 #endif
95 
96 #include <algorithm>
97 #if HAVE_GLOB_H
98 #include <glob.h>
99 #endif
100 #include <chrono>
101 #include <limits>
102 #include <list>
103 #if HAVE_PWD_H
104 #include <pwd.h>
105 #endif
106 #if HAVE_GRP_H
107 #include <grp.h>
108 #endif
109 #if HAVE_SYS_STAT_H
110 #include <sys/stat.h>
111 #endif
112 
113 #if USE_OPENSSL
114 #include "ssl/gadgets.h"
115 #endif
116 
117 #if USE_ADAPTATION
120 static void parse_adaptation_access_type();
121 #endif
122 
123 #if ICAP_CLIENT
125 static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &);
127 static void parse_icap_class_type();
128 static void parse_icap_access_type();
129 
131 static void dump_icap_service_failure_limit(StoreEntry *, const char *, const Adaptation::Icap::Config &);
133 #endif
134 
135 #if USE_ECAP
137 static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &);
139 #endif
140 
141 static peer_t parseNeighborType(const char *s);
142 
143 static const char *const T_NANOSECOND_STR = "nanosecond";
144 static const char *const T_MICROSECOND_STR = "microsecond";
145 static const char *const T_MILLISECOND_STR = "millisecond";
146 static const char *const T_SECOND_STR = "second";
147 static const char *const T_MINUTE_STR = "minute";
148 static const char *const T_HOUR_STR = "hour";
149 static const char *const T_DAY_STR = "day";
150 static const char *const T_WEEK_STR = "week";
151 static const char *const T_FORTNIGHT_STR = "fortnight";
152 static const char *const T_MONTH_STR = "month";
153 static const char *const T_YEAR_STR = "year";
154 static const char *const T_DECADE_STR = "decade";
155 
156 static const char *const B_BYTES_STR = "bytes";
157 static const char *const B_KBYTES_STR = "KB";
158 static const char *const B_MBYTES_STR = "MB";
159 static const char *const B_GBYTES_STR = "GB";
160 
161 // std::chrono::years requires C++20. Do our own rough calculation for now.
162 static const double HoursPerYear = 24*365.2522;
163 
164 static void parse_cache_log_message(DebugMessages **messages);
165 static void dump_cache_log_message(StoreEntry *entry, const char *name, const DebugMessages *messages);
166 static void free_cache_log_message(DebugMessages **messages);
167 
168 static void parse_access_log(CustomLog ** customlog_definitions);
169 static int check_null_access_log(CustomLog *customlog_definitions);
170 static void dump_access_log(StoreEntry * entry, const char *name, CustomLog * definitions);
171 static void free_access_log(CustomLog ** definitions);
172 
173 static void configDoConfigure(void);
174 static void parse_refreshpattern(RefreshPattern **);
175 static void parse_u_short(unsigned short * var);
176 static void parse_string(char **);
177 static void default_all(void);
178 static void defaults_if_none(void);
179 static void defaults_postscriptum(void);
180 static int parse_line(char *);
181 static void parse_obsolete(const char *);
182 static void parseBytesLine(size_t * bptr, const char *units);
183 static void parseBytesLineSigned(ssize_t * bptr, const char *units);
184 static size_t parseBytesUnits(const char *unit);
185 static void free_all(void);
186 void requirePathnameExists(const char *name, const char *path);
188 #if USE_HTTP_VIOLATIONS
189 static void free_HeaderManglers(HeaderManglers **pm);
190 static void dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers);
191 static void parse_http_header_access(HeaderManglers **manglers);
192 #define free_http_header_access free_HeaderManglers
193 static void dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers);
194 static void parse_http_header_replace(HeaderManglers **manglers);
195 #define free_http_header_replace free_HeaderManglers
196 #endif
197 static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers);
198 static void parse_HeaderWithAclList(HeaderWithAclList **header);
199 static void free_HeaderWithAclList(HeaderWithAclList **header);
200 static void parse_note(Notes *);
201 static void dump_note(StoreEntry *, const char *, Notes &);
202 static void free_note(Notes *);
203 static void parse_denyinfo(AclDenyInfoList ** var);
204 static void dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var);
205 static void free_denyinfo(AclDenyInfoList ** var);
206 
207 #if USE_WCCPv2
208 static void parse_IpAddress_list(Ip::Address_list **);
209 static void dump_IpAddress_list(StoreEntry *, const char *, const Ip::Address_list *);
210 static void free_IpAddress_list(Ip::Address_list **);
211 #if CURRENTLY_UNUSED
212 static int check_null_IpAddress_list(const Ip::Address_list *);
213 #endif /* CURRENTLY_UNUSED */
214 #endif /* USE_WCCPv2 */
215 
216 static void parsePortCfg(AnyP::PortCfgPointer *, const char *protocol);
217 #define parse_PortCfg(l) parsePortCfg((l), token)
218 static void dump_PortCfg(StoreEntry *, const char *, const AnyP::PortCfgPointer &);
219 #define free_PortCfg(h) *(h)=NULL
220 
221 #if USE_OPENSSL
222 static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign);
223 static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign);
224 static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign);
225 static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
226 static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt);
227 static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
228 static void parse_sslproxy_ssl_bump(acl_access **ssl_bump);
229 static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump);
230 static void free_sslproxy_ssl_bump(acl_access **ssl_bump);
231 #endif /* USE_OPENSSL */
232 
233 static void parse_ftp_epsv(acl_access **ftp_epsv);
234 static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv);
235 static void free_ftp_epsv(acl_access **ftp_epsv);
236 
237 static void parse_b_size_t(size_t * var);
238 static void parse_b_int64_t(int64_t * var);
239 
240 static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
241 static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap);
242 static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
243 
245 static void dump_UrlHelperTimeout(StoreEntry *, const char *, SquidConfig::UrlHelperTimeout &);
247 
248 static int parseOneConfigFile(const char *file_name, unsigned int depth);
249 
250 static void parse_configuration_includes_quoted_values(bool *recognizeQuotedValues);
251 static void dump_configuration_includes_quoted_values(StoreEntry *const entry, const char *const name, bool recognizeQuotedValues);
252 static void free_configuration_includes_quoted_values(bool *recognizeQuotedValues);
253 static void parse_on_unsupported_protocol(acl_access **access);
254 static void dump_on_unsupported_protocol(StoreEntry *entry, const char *name, acl_access *access);
255 static void free_on_unsupported_protocol(acl_access **access);
256 static void ParseAclWithAction(acl_access **access, const Acl::Answer &action, const char *desc, Acl::Node *acl = nullptr);
258 static void dump_http_upgrade_request_protocols(StoreEntry *entry, const char *name, HttpUpgradeProtocolAccess *protoGuards);
260 
261 /*
262  * LegacyParser is a parser for legacy code that uses the global
263  * approach. This is static so that it is only exposed to cache_cf.
264  * Other modules needing access to a ConfigParser should have it
265  * provided to them in their parserFOO methods.
266  */
268 
269 const char *cfg_directive = nullptr;
270 const char *cfg_filename = nullptr;
273 
274 void
276 {
278 }
279 
280 static void
281 SetConfigFilename(char const *file_name, bool is_pipe)
282 {
283  if (is_pipe)
284  cfg_filename = file_name + 1;
285  else
286  cfg_filename = file_name;
287 }
288 
295 static bool
296 IsSpace(const char ch)
297 {
298  return CharacterSet::WSP[ch];
299 }
300 
301 static const char*
302 skip_ws(const char* s)
303 {
304  while (IsSpace(*s))
305  ++s;
306 
307  return s;
308 }
309 
310 static int
311 parseManyConfigFiles(char* files, int depth)
312 {
313  int error_count = 0;
314  char* saveptr = nullptr;
315 #if HAVE_GLOB
316  char *path;
317  glob_t globbuf;
318  int i;
319  memset(&globbuf, 0, sizeof(globbuf));
320  for (path = strwordtok(files, &saveptr); path; path = strwordtok(nullptr, &saveptr)) {
321  if (glob(path, globbuf.gl_pathc ? GLOB_APPEND : 0, nullptr, &globbuf) != 0) {
322  int xerrno = errno;
323  fatalf("Unable to find configuration file: %s: %s", path, xstrerr(xerrno));
324  }
325  }
326  for (i = 0; i < (int)globbuf.gl_pathc; ++i) {
327  error_count += parseOneConfigFile(globbuf.gl_pathv[i], depth);
328  }
329  globfree(&globbuf);
330 #else
331  char* file = strwordtok(files, &saveptr);
332  while (file != NULL) {
333  error_count += parseOneConfigFile(file, depth);
334  file = strwordtok(nullptr, &saveptr);
335  }
336 #endif /* HAVE_GLOB */
337  return error_count;
338 }
339 
340 static void
341 ReplaceSubstr(char*& str, int& len, unsigned substrIdx, unsigned substrLen, const char* newSubstr)
342 {
343  assert(str != nullptr);
344  assert(newSubstr != nullptr);
345 
346  unsigned newSubstrLen = strlen(newSubstr);
347  if (newSubstrLen > substrLen)
348  str = (char*)realloc(str, len - substrLen + newSubstrLen + 1);
349 
350  // move tail part including zero
351  memmove(str + substrIdx + newSubstrLen, str + substrIdx + substrLen, len - substrIdx - substrLen + 1);
352  // copy new substring in place
353  memcpy(str + substrIdx, newSubstr, newSubstrLen);
354 
355  len = strlen(str);
356 }
357 
358 static void
359 SubstituteMacro(char*& line, int& len, const char* macroName, const char* substStr)
360 {
361  assert(line != nullptr);
362  assert(macroName != nullptr);
363  assert(substStr != nullptr);
364  unsigned macroNameLen = strlen(macroName);
365  while (const char* macroPos = strstr(line, macroName)) // we would replace all occurrences
366  ReplaceSubstr(line, len, macroPos - line, macroNameLen, substStr);
367 }
368 
369 static void
370 ProcessMacros(char*& line, int& len)
371 {
372  SubstituteMacro(line, len, "${service_name}", service_name.c_str());
373  SubstituteMacro(line, len, "${process_name}", TheKidName.c_str());
374  SubstituteMacro(line, len, "${process_number}", xitoa(KidIdentifier));
375 }
376 
377 static void
379 {
380  assert(str != nullptr);
381  unsigned i = strlen(str);
382  while ((i > 0) && IsSpace(str[i - 1]))
383  --i;
384  str[i] = '\0';
385 }
386 
387 static const char*
388 FindStatement(const char* line, const char* statement)
389 {
390  assert(line != nullptr);
391  assert(statement != nullptr);
392 
393  const char* str = skip_ws(line);
394  unsigned len = strlen(statement);
395  if (strncmp(str, statement, len) == 0) {
396  str += len;
397  if (*str == '\0')
398  return str;
399  else if (IsSpace(*str))
400  return skip_ws(str);
401  }
402 
403  return nullptr;
404 }
405 
406 static bool
407 StrToInt(const char* str, long& number)
408 {
409  assert(str != nullptr);
410 
411  char* end;
412  number = strtol(str, &end, 0);
413 
414  return (end != str) && (*end == '\0'); // returns true if string contains nothing except number
415 }
416 
417 static bool
418 EvalBoolExpr(const char* expr)
419 {
420  assert(expr != nullptr);
421  if (strcmp(expr, "true") == 0) {
422  return true;
423  } else if (strcmp(expr, "false") == 0) {
424  return false;
425  } else if (const char* equation = strchr(expr, '=')) {
426  const char* rvalue = skip_ws(equation + 1);
427  char* lvalue = (char*)xmalloc(equation - expr + 1);
428  xstrncpy(lvalue, expr, equation - expr + 1);
429  trim_trailing_ws(lvalue);
430 
431  long number1;
432  if (!StrToInt(lvalue, number1))
433  fatalf("String is not a integer number: '%s'\n", lvalue);
434  long number2;
435  if (!StrToInt(rvalue, number2))
436  fatalf("String is not a integer number: '%s'\n", rvalue);
437 
438  xfree(lvalue);
439  return number1 == number2;
440  }
441  fatalf("Unable to evaluate expression '%s'\n", expr);
442  return false; // this place cannot be reached
443 }
444 
445 static int
446 parseOneConfigFile(const char *file_name, unsigned int depth)
447 {
448  FILE *fp = nullptr;
449  const char *orig_cfg_filename = cfg_filename;
450  const int orig_config_lineno = config_lineno;
451  char *token = nullptr;
452  char *tmp_line = nullptr;
453  int tmp_line_len = 0;
454  int err_count = 0;
455  int is_pipe = 0;
456 
457  debugs(3, Important(68), "Processing Configuration File: " << file_name << " (depth " << depth << ")");
458  if (depth > 16) {
459  fatalf("WARNING: can't include %s: includes are nested too deeply (>16)!\n", file_name);
460  return 1;
461  }
462 
463  if (file_name[0] == '!' || file_name[0] == '|') {
464  fp = popen(file_name + 1, "r");
465  is_pipe = 1;
466  } else {
467  fp = fopen(file_name, "r");
468  }
469 
470  if (!fp) {
471  int xerrno = errno;
472  fatalf("Unable to open configuration file: %s: %s", file_name, xstrerr(xerrno));
473  }
474 
475 #if _SQUID_WINDOWS_
476  setmode(fileno(fp), O_TEXT);
477 #endif
478 
479  SetConfigFilename(file_name, bool(is_pipe));
480 
481  memset(config_input_line, '\0', BUFSIZ);
482 
483  config_lineno = 0;
484 
485  std::vector<bool> if_states;
486  while (fgets(config_input_line, BUFSIZ, fp)) {
487  ++config_lineno;
488 
489  if ((token = strchr(config_input_line, '\n')))
490  *token = '\0';
491 
492  if ((token = strchr(config_input_line, '\r')))
493  *token = '\0';
494 
495  // strip any prefix whitespace off the line.
496  const char *p = skip_ws(config_input_line);
497  if (config_input_line != p)
498  memmove(config_input_line, p, strlen(p)+1);
499 
500  if (strncmp(config_input_line, "#line ", 6) == 0) {
501  static char new_file_name[1024];
502  static char *file;
503  static char new_lineno;
504  token = config_input_line + 6;
505  new_lineno = strtol(token, &file, 0) - 1;
506 
507  if (file == token)
508  continue; /* Not a valid #line directive, may be a comment */
509 
510  while (*file && IsSpace(*file))
511  ++file;
512 
513  if (*file) {
514  if (*file != '"')
515  continue; /* Not a valid #line directive, may be a comment */
516 
517  xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
518 
519  if ((token = strchr(new_file_name, '"')))
520  *token = '\0';
521 
522  SetConfigFilename(new_file_name, false);
523  }
524 
525  config_lineno = new_lineno;
526  }
527 
528  if (config_input_line[0] == '#')
529  continue;
530 
531  if (config_input_line[0] == '\0')
532  continue;
533 
534  const char* append = tmp_line_len ? skip_ws(config_input_line) : config_input_line;
535 
536  size_t append_len = strlen(append);
537 
538  tmp_line = (char*)xrealloc(tmp_line, tmp_line_len + append_len + 1);
539 
540  strcpy(tmp_line + tmp_line_len, append);
541 
542  tmp_line_len += append_len;
543 
544  if (tmp_line[tmp_line_len-1] == '\\') {
545  debugs(3, 5, "parseConfigFile: tmp_line='" << tmp_line << "'");
546  tmp_line[--tmp_line_len] = '\0';
547  continue;
548  }
549 
550  trim_trailing_ws(tmp_line);
551  ProcessMacros(tmp_line, tmp_line_len);
552  debugs(3, (opt_parse_cfg_only?1:5), "Processing: " << tmp_line);
553 
554  if (const char* expr = FindStatement(tmp_line, "if")) {
555  if_states.push_back(EvalBoolExpr(expr)); // store last if-statement meaning
556  } else if (FindStatement(tmp_line, "endif")) {
557  if (!if_states.empty())
558  if_states.pop_back(); // remove last if-statement meaning
559  else
560  fatalf("'endif' without 'if'\n");
561  } else if (FindStatement(tmp_line, "else")) {
562  if (!if_states.empty())
563  if_states.back() = !if_states.back();
564  else
565  fatalf("'else' without 'if'\n");
566  } else if (if_states.empty() || if_states.back()) { // test last if-statement meaning if present
567  /* Handle includes here */
568  if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && IsSpace(tmp_line[7])) {
569  err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
570  } else {
571  try {
572  if (!parse_line(tmp_line)) {
573  debugs(3, DBG_CRITICAL, "ERROR: unrecognized directive near '" << tmp_line << "'" <<
574  Debug::Extra << "directive location: " << ConfigParser::CurrentLocation());
575  ++err_count;
576  }
577  } catch (...) {
578  // fatal for now
579  debugs(3, DBG_CRITICAL, "ERROR: configuration failure: " << CurrentException);
580  self_destruct();
581  }
582  }
583  }
584 
585  safe_free(tmp_line);
586  tmp_line_len = 0;
587 
588  }
589  if (!if_states.empty())
590  fatalf("if-statement without 'endif'\n");
591 
592  if (is_pipe) {
593  int ret = pclose(fp);
594 
595  if (ret != 0)
596  fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
597  } else {
598  fclose(fp);
599  }
600 
601  SetConfigFilename(orig_cfg_filename, false);
602  config_lineno = orig_config_lineno;
603 
604  xfree(tmp_line);
605  return err_count;
606 }
607 
608 void
610 {
611  debugs(5, 4, MYNAME);
612 
614 
616  default_all();
617 
618  const auto unrecognizedDirectives = parseOneConfigFile(ConfigFile, 0);
619 
621 
623 
624  if (unrecognizedDirectives)
625  throw TextException(ToSBuf("Found ", unrecognizedDirectives, " unrecognized directive(s)"), Here());
626 
627  /*
628  * We must call configDoConfigure() before leave_suid() because
629  * configDoConfigure() is where we turn username strings into
630  * uid values.
631  */
633 
634  if (opt_send_signal == -1) {
635  Mgr::RegisterAction("config",
636  "Current Squid Configuration",
637  dump_config,
638  1, 1);
639  }
640 }
641 
642 /*
643  * The templated functions below are essentially ConfigParser methods. They are
644  * not implemented as such because our generated code calling them is the only
645  * code that can instantiate implementations for each T -- we cannot place these
646  * definitions into ConfigParser.cc unless cf_parser.cci is moved there.
647  */
648 
649 // TODO: When adding Ts incompatible with this trivial API and implementation,
650 // replace both with a ConfigParser-maintained table of seen directives.
652 template <typename T>
653 static bool
654 SawDirective(const T &raw)
655 {
656  return bool(raw);
657 }
658 
661 template <typename T>
662 static void
663 ParseDirective(T &raw, ConfigParser &parser)
664 {
665  if (SawDirective(raw))
666  parser.rejectDuplicateDirective();
667 
668  // TODO: parser.openDirective(directiveName);
669  Must(!raw);
671  Must(raw);
672  parser.closeDirective();
673 }
674 
677 template <typename T>
678 static void
679 DumpDirective(const T &raw, StoreEntry *entry, const char *name)
680 {
681  if (!SawDirective(raw))
682  return; // not configured
683 
684  entry->append(name, strlen(name));
685  SBufStream os;
687  const auto buf = os.buf();
688  if (buf.length()) {
689  entry->append(" ", 1);
690  entry->append(buf.rawContent(), buf.length());
691  }
692  entry->append("\n", 1);
693 }
694 
696 template <typename T>
697 static void
699 {
701 
702  // While the implementation may change, there is no way to avoid zeroing.
703  // Even migration to a proper SquidConfig class would not help: While
704  // ordinary destructors do not need to zero data members, a SquidConfig
705  // destructor would have to zero to protect any SquidConfig::x destruction
706  // code from accidentally dereferencing an already destroyed Config.y.
707  static_assert(std::is_trivial<T>::value, "SquidConfig member is trivial");
708  memset(&raw, 0, sizeof(raw));
709 }
710 
711 static void
713 {
714  Config2.clear();
715  /* init memory as early as possible */
716  memConfigure();
717  /* Sanity checks */
718 
719  if (Debug::rotateNumber < 0) {
721  }
722 
723 #if SIZEOF_OFF_T <= 4
724  if (Config.Store.maxObjectSize > 0x7FFF0000) {
725  debugs(3, DBG_CRITICAL, "WARNING: This Squid binary can not handle files larger than 2GB. Limiting maximum_object_size to just below 2GB");
726  Config.Store.maxObjectSize = 0x7FFF0000;
727  }
728 #endif
729 
732  else
733  visible_appname_string = (char const *)APP_FULLNAME;
734 
735  if (Config.Program.redirect) {
736  if (Config.redirectChildren.n_max < 1) {
739  }
740  }
741 
742  if (Config.Program.store_id) {
743  if (Config.storeIdChildren.n_max < 1) {
746  }
747  }
748 
749  if (Config.appendDomain)
750  if (*Config.appendDomain != '.')
751  fatal("append_domain must begin with a '.'");
752 
753  if (Config.errHtmlText == nullptr)
755 
756 #if !HAVE_SETRLIMIT || !defined(RLIMIT_NOFILE)
757  if (Config.max_filedescriptors > 0) {
758  debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors disabled. Operating System setrlimit(RLIMIT_NOFILE) is missing.");
759  }
760 #elif USE_SELECT
761  if (Config.max_filedescriptors > FD_SETSIZE) {
762  debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors limited to " << FD_SETSIZE << " by select() algorithm.");
763  }
764 #endif
765 
766  storeConfigure();
767 
768  snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
769  uniqueHostname(),
771 
772  /*
773  * the extra space is for loop detection in client_side.c -- we search
774  * for substrings in the Via header.
775  */
776  snprintf(ThisCache2, sizeof(ThisCache2), " %s (%s)",
777  uniqueHostname(),
779 
780  /* Use visible_hostname as default surrogate_id */
781  if (!Config.Accel.surrogate_id) {
782  const char *t = getMyHostname();
783  Config.Accel.surrogate_id = xstrdup( (t?t:"unset-id") );
784  }
785 
788 
789  if (Config.appendDomain)
791  else
793 
794  if (Config.connect_retries > 10) {
795  debugs(0,DBG_CRITICAL, "WARNING: connect_retries cannot be larger than 10. Resetting to 10.");
796  Config.connect_retries = 10;
797  }
798 
799  requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
800 #if USE_UNLINKD
801 
802  requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
803 #endif
804  bool logDaemonUsed = false;
805  for (const auto *log = Config.Log.accesslogs; !logDaemonUsed && log; log = log->next)
806  logDaemonUsed = log->usesDaemon();
807 #if ICAP_CLIENT
808  for (const auto *log = Config.Log.icaplogs; !logDaemonUsed && log; log = log->next)
809  logDaemonUsed = log->usesDaemon();
810 #endif
811  if (logDaemonUsed)
812  requirePathnameExists("logfile_daemon", Log::TheConfig.logfile_daemon);
813 
814  if (Config.Program.redirect)
815  requirePathnameExists("redirect_program", Config.Program.redirect->key);
816 
817  if (Config.Program.store_id)
818  requirePathnameExists("store_id_program", Config.Program.store_id->key);
819 
820  requirePathnameExists("Icon Directory", Config.icons.directory);
821 
823  requirePathnameExists("Error Directory", Config.errorDirectory);
824 
825 #if USE_HTTP_VIOLATIONS
826 
827  {
828  const RefreshPattern *R;
829 
830  for (R = Config.Refresh; R; R = R->next) {
831  if (!R->flags.override_expire)
832  continue;
833 
834  debugs(22, DBG_IMPORTANT, "WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP");
835 
836  break;
837  }
838 
839  for (R = Config.Refresh; R; R = R->next) {
840  if (!R->flags.override_lastmod)
841  continue;
842 
843  debugs(22, DBG_IMPORTANT, "WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP");
844 
845  break;
846  }
847 
848  for (R = Config.Refresh; R; R = R->next) {
849  if (!R->flags.reload_into_ims)
850  continue;
851 
852  debugs(22, DBG_IMPORTANT, "WARNING: use of 'reload-into-ims' in 'refresh_pattern' violates HTTP");
853 
854  break;
855  }
856 
857  for (R = Config.Refresh; R; R = R->next) {
858  if (!R->flags.ignore_reload)
859  continue;
860 
861  debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-reload' in 'refresh_pattern' violates HTTP");
862 
863  break;
864  }
865 
866  for (R = Config.Refresh; R; R = R->next) {
867  if (!R->flags.ignore_no_store)
868  continue;
869 
870  debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-no-store' in 'refresh_pattern' violates HTTP");
871 
872  break;
873  }
874 
875  for (R = Config.Refresh; R; R = R->next) {
876  if (!R->flags.ignore_private)
877  continue;
878 
879  debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-private' in 'refresh_pattern' violates HTTP");
880 
881  break;
882  }
883  }
884 #endif
885 #if !USE_HTTP_VIOLATIONS
886  Config.onoff.via = 1;
887 #else
888 
889  if (!Config.onoff.via)
890  debugs(22, DBG_IMPORTANT, "WARNING: HTTP requires the use of Via");
891 
892 #endif
893 
894  // we enable runtime PURGE checks if there is at least one PURGE method ACL
895  // TODO: replace with a dedicated "purge" ACL option?
897 
898  if (geteuid() == 0) {
899  if (nullptr != Config.effectiveUser) {
900 
901  struct passwd *pwd = getpwnam(Config.effectiveUser);
902 
903  if (nullptr == pwd) {
904  /*
905  * Andres Kroonmaa <andre@online.ee>:
906  * Some getpwnam() implementations (Solaris?) require
907  * an available FD < 256 for opening a FILE* to the
908  * passwd file.
909  * DW:
910  * This should be safe at startup, but might still fail
911  * during reconfigure.
912  */
913  fatalf("getpwnam failed to find userid for effective user '%s'",
915  return;
916  }
917 
918  Config2.effectiveUserID = pwd->pw_uid;
919 
920  Config2.effectiveGroupID = pwd->pw_gid;
921 
922  if (pwd->pw_dir && *pwd->pw_dir)
923  (void)setenv("HOME", pwd->pw_dir, 1);
924  }
925  } else {
926  Config2.effectiveUserID = geteuid();
927  Config2.effectiveGroupID = getegid();
928  }
929 
930  if (nullptr != Config.effectiveGroup) {
931 
932  struct group *grp = getgrnam(Config.effectiveGroup);
933 
934  if (nullptr == grp) {
935  fatalf("getgrnam failed to find groupid for effective group '%s'",
937  return;
938  }
939 
940  Config2.effectiveGroupID = grp->gr_gid;
941  }
942 
943 #if USE_OPENSSL
946 #endif
947 
948  if (Security::ProxyOutgoingConfig().encryptTransport) {
949  debugs(3, 2, "initializing https:// proxy context");
950 
951  const auto rawSslContext = Security::ProxyOutgoingConfig().createClientContext(false);
952  Config.ssl_client.sslContext_ = rawSslContext ? new Security::ContextPointer(rawSslContext) : nullptr;
954 #if USE_OPENSSL
955  fatal("ERROR: Could not initialize https:// proxy context");
956 #else
957  debugs(3, DBG_IMPORTANT, "ERROR: proxying https:// currently still requires --with-openssl");
958 #endif
959  }
960 #if USE_OPENSSL
962 #endif
964  }
965 
966  for (const auto &p: CurrentCachePeers()) {
967 
968  // default value for ssldomain= is the peer host/IP
969  if (p->secure.sslDomain.isEmpty())
970  p->secure.sslDomain = p->host;
971 
972  if (p->secure.encryptTransport) {
973  debugs(3, 2, "initializing TLS context for cache_peer " << *p);
974  p->sslContext = p->secure.createClientContext(true);
975  if (!p->sslContext) {
976  debugs(3, DBG_CRITICAL, "ERROR: Could not initialize TLS context for cache_peer " << *p);
977  self_destruct();
978  return;
979  }
980  }
981  }
982 
983  for (AnyP::PortCfgPointer s = HttpPortList; s != nullptr; s = s->next) {
984  if (!s->secure.encryptTransport)
985  continue;
986  debugs(3, 2, "initializing " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s << " TLS contexts");
987  s->secure.initServerContexts(*s);
988  }
989 
990  // prevent infinite fetch loops in the request parser
991  // due to buffer full but not enough data received to finish parse
993  fatalf("Client request buffer of %u bytes cannot hold a request with %u bytes of headers." \
994  " Change client_request_buffer_max or request_header_max_size limits.",
996  }
997 
998  // Warn about the dangers of exceeding String limits when manipulating HTTP
999  // headers. Technically, we do not concatenate _requests_, so we could relax
1000  // their check, but we keep the two checks the same for simplicity sake.
1001  const auto safeRawHeaderValueSizeMax = (String::SizeMaxXXX()+1)/3;
1002  // TODO: static_assert(safeRawHeaderValueSizeMax >= 64*1024); // no WARNINGs for default settings
1003  if (Config.maxRequestHeaderSize > safeRawHeaderValueSizeMax)
1004  debugs(3, DBG_CRITICAL, "WARNING: Increasing request_header_max_size beyond " << safeRawHeaderValueSizeMax <<
1005  " bytes makes Squid more vulnerable to denial-of-service attacks; configured value: " << Config.maxRequestHeaderSize << " bytes");
1006  if (Config.maxReplyHeaderSize > safeRawHeaderValueSizeMax)
1007  debugs(3, DBG_CRITICAL, "WARNING: Increasing reply_header_max_size beyond " << safeRawHeaderValueSizeMax <<
1008  " bytes makes Squid more vulnerable to denial-of-service attacks; configured value: " << Config.maxReplyHeaderSize << " bytes");
1009 
1010  /*
1011  * Disable client side request pipelining if client_persistent_connections OFF.
1012  * Waste of resources queueing any pipelined requests when the first will close the connection.
1013  */
1015  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch " << Config.pipeline_max_prefetch <<
1016  " requires client_persistent_connections ON. Forced pipeline_prefetch 0.");
1018  }
1019 
1020 #if USE_AUTH
1021  /*
1022  * disable client side request pipelining. There is a race with
1023  * Negotiate and NTLM when the client sends a second request on an
1024  * connection before the authenticate challenge is sent. With
1025  * pipelining OFF, the client may fail to authenticate, but squid's
1026  * state will be preserved.
1027  */
1028  if (Config.pipeline_max_prefetch > 0) {
1029  Auth::SchemeConfig *nego = Auth::SchemeConfig::Find("Negotiate");
1031  if ((nego && nego->active()) || (ntlm && ntlm->active())) {
1032  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch breaks NTLM and Negotiate authentication. Forced pipeline_prefetch 0.");
1034  }
1035  }
1036 
1037  for (auto &authSchemes : Auth::TheConfig.schemeLists) {
1038  authSchemes.expand();
1039  if (authSchemes.authConfigs.empty()) {
1040  debugs(3, DBG_CRITICAL, "auth_schemes: at least one scheme name is required; got: " << authSchemes.rawSchemes);
1041  self_destruct();
1042  }
1043  }
1044 #endif
1045 }
1046 
1053 void
1054 parse_obsolete(const char *name)
1055 {
1056  // Directives which have been radically changed rather than removed
1057  if (!strcmp(name, "url_rewrite_concurrency")) {
1058  int cval;
1059  parse_int(&cval);
1060  debugs(3, DBG_CRITICAL, "WARNING: url_rewrite_concurrency upgrade overriding url_rewrite_children settings.");
1062  }
1063 
1064  if (!strcmp(name, "ignore_ims_on_miss")) {
1065  // the replacement directive cache_revalidate_on_miss has opposite meanings for ON/OFF value
1066  // than the 2.7 directive. We need to parse and invert the configured value.
1067  int temp = 0;
1068  parse_onoff(&temp);
1070  }
1071 
1072  if (!strncmp(name, "sslproxy_", 9)) {
1073  // the replacement directive tls_outgoing_options uses options instead of whole-line input
1074  SBuf tmp;
1075  if (!strcmp(name, "sslproxy_cafile"))
1076  tmp.append("cafile=");
1077  else if (!strcmp(name, "sslproxy_capath"))
1078  tmp.append("capath=");
1079  else if (!strcmp(name, "sslproxy_cipher"))
1080  tmp.append("cipher=");
1081  else if (!strcmp(name, "sslproxy_client_certificate"))
1082  tmp.append("cert=");
1083  else if (!strcmp(name, "sslproxy_client_key"))
1084  tmp.append("key=");
1085  else if (!strcmp(name, "sslproxy_flags"))
1086  tmp.append("flags=");
1087  else if (!strcmp(name, "sslproxy_options"))
1088  tmp.append("options=");
1089  else if (!strcmp(name, "sslproxy_version"))
1090  tmp.append("version=");
1091  else {
1092  debugs(3, DBG_CRITICAL, "ERROR: unknown directive: " << name);
1093  self_destruct();
1094  return;
1095  }
1096 
1097  // add the value as unquoted-string because the old values did not support whitespace
1098  const char *token = ConfigParser::NextQuotedOrToEol();
1099  if (!token)
1100  throw TextException(ToSBuf("missing required parameter for obsolete directive: ", name), Here());
1101 
1102  tmp.append(token, strlen(token));
1104  }
1105 }
1106 
1107 template <class MinimalUnit>
1108 static const char *
1110 {
1111  const auto minUnit = MinimalUnit(1);
1112  if(minUnit == std::chrono::nanoseconds(1))
1113  return T_NANOSECOND_STR;
1114  else if (minUnit == std::chrono::microseconds(1))
1115  return T_MICROSECOND_STR;
1116  else if (minUnit == std::chrono::milliseconds(1))
1117  return T_MILLISECOND_STR;
1118  else {
1119  assert(minUnit >= std::chrono::seconds(1));
1120  return T_SECOND_STR;
1121  }
1122 }
1123 
1129 template <class MinimalUnit>
1130 static bool
1131 parseTimeUnit(const char *unitName, std::chrono::nanoseconds &ns)
1132 {
1133  if (!unitName)
1134  throw TexcHere("missing time unit");
1135 
1136  if (!strncasecmp(unitName, T_NANOSECOND_STR, strlen(T_NANOSECOND_STR)))
1137  ns = std::chrono::nanoseconds(1);
1138  else if (!strncasecmp(unitName, T_MICROSECOND_STR, strlen(T_MICROSECOND_STR)))
1139  ns = std::chrono::microseconds(1);
1140  else if (!strncasecmp(unitName, T_MILLISECOND_STR, strlen(T_MILLISECOND_STR)))
1141  ns = std::chrono::milliseconds(1);
1142  else if (!strncasecmp(unitName, T_SECOND_STR, strlen(T_SECOND_STR)))
1143  ns = std::chrono::seconds(1);
1144  else if (!strncasecmp(unitName, T_MINUTE_STR, strlen(T_MINUTE_STR)))
1145  ns = std::chrono::minutes(1);
1146  else if (!strncasecmp(unitName, T_HOUR_STR, strlen(T_HOUR_STR)))
1147  ns = std::chrono::hours(1);
1148  else if (!strncasecmp(unitName, T_DAY_STR, strlen(T_DAY_STR)))
1149  ns = std::chrono::hours(24);
1150  else if (!strncasecmp(unitName, T_WEEK_STR, strlen(T_WEEK_STR)))
1151  ns = std::chrono::hours(24 * 7);
1152  else if (!strncasecmp(unitName, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
1153  ns = std::chrono::hours(24 * 14);
1154  else if (!strncasecmp(unitName, T_MONTH_STR, strlen(T_MONTH_STR)))
1155  ns = std::chrono::hours(24 * 30);
1156  else if (!strncasecmp(unitName, T_YEAR_STR, strlen(T_YEAR_STR)))
1157  ns = std::chrono::hours(static_cast<std::chrono::hours::rep>(HoursPerYear));
1158  else if (!strncasecmp(unitName, T_DECADE_STR, strlen(T_DECADE_STR)))
1159  ns = std::chrono::hours(static_cast<std::chrono::hours::rep>(HoursPerYear * 10));
1160  else
1161  return false;
1162 
1163  if (ns < MinimalUnit(1)) {
1164  throw TexcHere(ToSBuf("time unit '", unitName, "' is too small to be used in this context, the minimal unit is ",
1165  TimeUnitToString<MinimalUnit>()));
1166  }
1167 
1168  return true;
1169 }
1170 
1171 static std::chrono::nanoseconds
1172 ToNanoSeconds(const double value, const std::chrono::nanoseconds &unit)
1173 {
1174  if (value < 0.0)
1175  throw TexcHere("time must have a positive value");
1176 
1177  if (value > (static_cast<double>(std::chrono::nanoseconds::max().count()) / unit.count())) {
1178  const auto maxYears = std::chrono::duration_cast<std::chrono::hours>(std::chrono::nanoseconds::max()).count()/HoursPerYear;
1179  throw TexcHere(ToSBuf("time values cannot exceed ", maxYears, " years"));
1180  }
1181 
1182  return std::chrono::duration_cast<std::chrono::nanoseconds>(unit * value);
1183 }
1184 
1185 template <class TimeUnit>
1186 static TimeUnit
1187 FromNanoseconds(const std::chrono::nanoseconds &ns, const double parsedValue)
1188 {
1189  const auto result = std::chrono::duration_cast<TimeUnit>(ns);
1190  if (!result.count()) {
1191  throw TexcHere(ToSBuf("time value '", parsedValue,
1192  "' is too small to be used in this context, the minimal value is 1 ",
1193  TimeUnitToString<TimeUnit>()));
1194  }
1195  return result;
1196 }
1197 
1200 template <class TimeUnit>
1201 static TimeUnit
1203 {
1204  const auto valueToken = ConfigParser::NextToken();
1205  if (!valueToken)
1206  throw TexcHere("cannot read a time value");
1207 
1208  const auto parsedValue = xatof(valueToken);
1209 
1210  if (parsedValue == 0)
1211  return TimeUnit::zero();
1212 
1213  std::chrono::nanoseconds parsedUnitDuration;
1214 
1215  const auto token = ConfigParser::PeekAtToken();
1216 
1217  if (!parseTimeUnit<TimeUnit>(token, parsedUnitDuration))
1218  throw TexcHere(ToSBuf("unknown time unit '", token, "'"));
1219 
1220  (void)ConfigParser::NextToken();
1221 
1222  const auto nanoseconds = ToNanoSeconds(parsedValue, parsedUnitDuration);
1223 
1224  // validate precisions (time-units-small only)
1225  if (TimeUnit(1) <= std::chrono::microseconds(1)) {
1226  if (0 < nanoseconds.count() && nanoseconds.count() < 3) {
1228  "Squid time measurement precision is likely to be far worse than " <<
1229  "the nanosecond-level precision implied by the configured value: " << parsedValue << ' ' << token);
1230  }
1231  }
1232 
1233  return FromNanoseconds<TimeUnit>(nanoseconds, parsedValue);
1234 }
1235 
1236 static void
1237 parseBytesLine64(int64_t * bptr, const char *units)
1238 {
1239  char *token;
1240  double d;
1241  int64_t m;
1242  int64_t u;
1243 
1244  if ((u = parseBytesUnits(units)) == 0) {
1245  self_destruct();
1246  return;
1247  }
1248 
1249  if ((token = ConfigParser::NextToken()) == nullptr) {
1250  self_destruct();
1251  return;
1252  }
1253 
1254  if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
1255  *bptr = -1;
1256  return;
1257  }
1258 
1259  d = xatof(token);
1260 
1261  m = u; /* default to 'units' if none specified */
1262 
1263  if (0.0 == d)
1264  (void) 0;
1265  else if ((token = ConfigParser::NextToken()) == nullptr)
1266  debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
1267  config_input_line << "', assuming " <<
1268  d << " " << units );
1269  else if ((m = parseBytesUnits(token)) == 0) {
1270  self_destruct();
1271  return;
1272  }
1273 
1274  *bptr = static_cast<int64_t>(m * d / u);
1275 
1276  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
1277  debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
1278  d << " " << token << ": integer overflow (int64_t).");
1279  self_destruct();
1280  }
1281 }
1282 
1283 static void
1284 parseBytesLine(size_t * bptr, const char *units)
1285 {
1286  char *token;
1287  double d;
1288  int m;
1289  int u;
1290 
1291  if ((u = parseBytesUnits(units)) == 0) {
1292  self_destruct();
1293  return;
1294  }
1295 
1296  if ((token = ConfigParser::NextToken()) == nullptr) {
1297  self_destruct();
1298  return;
1299  }
1300 
1301  if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
1302  *bptr = static_cast<size_t>(-1);
1303  return;
1304  }
1305 
1306  d = xatof(token);
1307 
1308  m = u; /* default to 'units' if none specified */
1309 
1310  if (0.0 == d)
1311  (void) 0;
1312  else if ((token = ConfigParser::NextToken()) == nullptr)
1313  debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
1314  config_input_line << "', assuming " <<
1315  d << " " << units );
1316  else if ((m = parseBytesUnits(token)) == 0) {
1317  self_destruct();
1318  return;
1319  }
1320 
1321  *bptr = static_cast<size_t>(m * d / u);
1322 
1323  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
1324  debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
1325  d << " " << token << ": integer overflow (size_t).");
1326  self_destruct();
1327  }
1328 }
1329 
1330 static void
1331 parseBytesLineSigned(ssize_t * bptr, const char *units)
1332 {
1333  char *token;
1334  double d;
1335  int m;
1336  int u;
1337 
1338  if ((u = parseBytesUnits(units)) == 0) {
1339  self_destruct();
1340  return;
1341  }
1342 
1343  if ((token = ConfigParser::NextToken()) == nullptr) {
1344  self_destruct();
1345  return;
1346  }
1347 
1348  if (strcmp(token, "none") == 0 || token[0] == '-' /* -N */) {
1349  *bptr = -1;
1350  return;
1351  }
1352 
1353  d = xatof(token);
1354 
1355  m = u; /* default to 'units' if none specified */
1356 
1357  if (0.0 == d)
1358  (void) 0;
1359  else if ((token = ConfigParser::NextToken()) == nullptr)
1360  debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
1361  config_input_line << "', assuming " <<
1362  d << " " << units );
1363  else if ((m = parseBytesUnits(token)) == 0) {
1364  self_destruct();
1365  return;
1366  }
1367 
1368  *bptr = static_cast<ssize_t>(m * d / u);
1369 
1370  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
1371  debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
1372  d << " " << token << ": integer overflow (ssize_t).");
1373  self_destruct();
1374  }
1375 }
1376 
1382 void
1383 parseBytesOptionValue(size_t * bptr, const char *units, char const * value)
1384 {
1385  int u;
1386  if ((u = parseBytesUnits(units)) == 0) {
1387  self_destruct();
1388  return;
1389  }
1390 
1391  // Find number from string beginning.
1392  char const * number_begin = value;
1393  char const * number_end = value;
1394 
1395  while ((*number_end >= '0' && *number_end <= '9')) {
1396  ++number_end;
1397  }
1398 
1399  String number;
1400  number.assign(number_begin, number_end - number_begin);
1401 
1402  int d = xatoi(number.termedBuf());
1403  int m;
1404  if ((m = parseBytesUnits(number_end)) == 0) {
1405  self_destruct();
1406  return;
1407  }
1408 
1409  *bptr = static_cast<size_t>(m * d / u);
1410  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2)
1411  self_destruct();
1412 }
1413 
1414 static size_t
1415 parseBytesUnits(const char *unit)
1416 {
1417  if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
1418  return 1;
1419 
1420  if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
1421  return 1 << 10;
1422 
1423  if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
1424  return 1 << 20;
1425 
1426  if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
1427  return 1 << 30;
1428 
1429  debugs(3, DBG_CRITICAL, "WARNING: Unknown bytes unit '" << unit << "'");
1430 
1431  return 0;
1432 }
1433 
1434 static void
1436 {
1437  while (char *token = ConfigParser::NextQuotedToken())
1438  list->push_back(SBuf(token));
1439 }
1440 
1441 // just dump a list, no directive name
1442 static void
1443 dump_SBufList(StoreEntry * entry, const SBufList &words)
1444 {
1445  for (const auto &i : words) {
1446  entry->append(i.rawContent(), i.length());
1447  entry->append(" ",1);
1448  }
1449  entry->append("\n",1);
1450 }
1451 
1452 // dump a SBufList type directive with name
1453 static void
1454 dump_SBufList(StoreEntry * entry, const char *name, SBufList &list)
1455 {
1456  if (!list.empty()) {
1457  entry->append(name, strlen(name));
1458  entry->append(" ", 1);
1459  dump_SBufList(entry, list);
1460  }
1461 }
1462 
1463 static void
1465 {
1466  if (list)
1467  list->clear();
1468 }
1469 
1470 static void
1471 dump_acl(StoreEntry *entry, const char *directiveName, Acl::NamedAcls *config)
1472 {
1473  PackableStream os(*entry);
1474  Acl::DumpNamedAcls(os, directiveName, config);
1475 }
1476 
1477 static void
1479 {
1480  assert(config);
1482 }
1483 
1484 static void
1486 {
1487  Acl::FreeNamedAcls(config);
1488 }
1489 
1490 void
1492 {
1493  // XXX: Should dump ACL names like "foo !bar" but dumps parsing context like
1494  // "(clientside_tos 0x11 line)".
1495  dump_SBufList(entry, ToTree(head).dump());
1496 }
1497 
1498 void
1499 dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
1500 {
1501  if (head)
1502  dump_SBufList(entry, ToTree(head).treeDump(name, &Acl::AllowOrDeny));
1503 }
1504 
1505 static void
1507 {
1509 }
1510 
1511 static void
1513 {
1515 }
1516 
1517 static void
1518 dump_address(StoreEntry * entry, const char *name, Ip::Address &addr)
1519 {
1520  char buf[MAX_IPSTRLEN];
1521  storeAppendPrintf(entry, "%s %s\n", name, addr.toStr(buf,MAX_IPSTRLEN) );
1522 }
1523 
1524 static void
1526 {
1527  char *token = ConfigParser::NextToken();
1528 
1529  if (!token) {
1530  self_destruct();
1531  return;
1532  }
1533 
1534  if (!strcmp(token,"any_addr"))
1535  addr->setAnyAddr();
1536  else if ( (!strcmp(token,"no_addr")) || (!strcmp(token,"full_mask")) )
1537  addr->setNoAddr();
1538  else if ( (*addr = token) ) // try parse numeric/IPA
1539  (void) 0;
1540  else if (addr->GetHostByName(token)) // do not use ipcache
1541  (void) 0;
1542  else { // not an IP and not a hostname
1543  debugs(3, DBG_CRITICAL, "FATAL: invalid IP address or domain name '" << token << "'");
1544  self_destruct();
1545  }
1546 }
1547 
1548 static void
1550 {
1551  addr->setEmpty();
1552 }
1553 
1554 static void
1555 dump_acl_address(StoreEntry * entry, const char *name, Acl::Address * head)
1556 {
1557  char buf[MAX_IPSTRLEN];
1558 
1559  for (Acl::Address *l = head; l; l = l->next) {
1560  if (!l->addr.isAnyAddr())
1561  storeAppendPrintf(entry, "%s %s", name, l->addr.toStr(buf,MAX_IPSTRLEN));
1562  else
1563  storeAppendPrintf(entry, "%s autoselect", name);
1564 
1565  dump_acl_list(entry, l->aclList);
1566 
1567  storeAppendPrintf(entry, "\n");
1568  }
1569 }
1570 
1571 static void
1573 {
1574  Acl::Address *l = new Acl::Address;
1575  parse_address(&l->addr);
1577 
1578  Acl::Address **tail = head;
1579  while (*tail)
1580  tail = &(*tail)->next;
1581 
1582  *tail = l;
1583 }
1584 
1585 static void
1587 {
1588  delete *head;
1589  *head = nullptr;
1590 }
1591 
1592 static void
1593 dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
1594 {
1595  acl_tos *l;
1596 
1597  for (l = head; l; l = l->next) {
1598  if (l->tos > 0)
1599  storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
1600  else
1601  storeAppendPrintf(entry, "%s none", name);
1602 
1603  dump_acl_list(entry, l->aclList);
1604 
1605  storeAppendPrintf(entry, "\n");
1606  }
1607 }
1608 
1609 static void
1611 {
1612  unsigned int tos; /* Initially uint for strtoui. Casted to tos_t before return */
1613  char *token = ConfigParser::NextToken();
1614 
1615  if (!token) {
1616  self_destruct();
1617  return;
1618  }
1619 
1620  if (!xstrtoui(token, nullptr, &tos, 0, std::numeric_limits<tos_t>::max())) {
1621  self_destruct();
1622  return;
1623  }
1624 
1625  const unsigned int chTos = tos & 0xFC;
1626  if (chTos != tos) {
1627  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Tos value '" << tos << "' adjusted to '" << chTos << "'");
1628  tos = chTos;
1629  }
1630 
1631  acl_tos *l = new acl_tos;
1632 
1633  l->tos = (tos_t)tos;
1634 
1635  aclParseAclList(LegacyParser, &l->aclList, token);
1636 
1637  acl_tos **tail = head; /* sane name below */
1638  while (*tail)
1639  tail = &(*tail)->next;
1640 
1641  *tail = l;
1642 }
1643 
1644 static void
1646 {
1647  delete *head;
1648  *head = nullptr;
1649 }
1650 
1651 #if HAVE_LIBCAP && SO_MARK
1652 
1653 static void
1654 dump_acl_nfmark(StoreEntry * entry, const char *name, acl_nfmark * head)
1655 {
1656  for (acl_nfmark *l = head; l; l = l->next) {
1657  storeAppendPrintf(entry, "%s %s", name, ToSBuf(l->markConfig).c_str());
1658 
1659  dump_acl_list(entry, l->aclList);
1660 
1661  storeAppendPrintf(entry, "\n");
1662  }
1663 }
1664 
1665 static void
1666 parse_acl_nfmark(acl_nfmark ** head)
1667 {
1668  SBuf token(ConfigParser::NextToken());
1669  const auto mc = Ip::NfMarkConfig::Parse(token);
1670 
1671  // Packet marking directives should not allow to use masks.
1672  const auto pkt_dirs = {"mark_client_packet", "clientside_mark", "tcp_outgoing_mark"};
1673  if (mc.hasMask() && std::find(pkt_dirs.begin(), pkt_dirs.end(), cfg_directive) != pkt_dirs.end())
1674  throw TexcHere(ToSBuf("'", cfg_directive, "' does not support masked marks"));
1675 
1676  acl_nfmark *l = new acl_nfmark;
1677  l->markConfig = mc;
1678 
1679  aclParseAclList(LegacyParser, &l->aclList, token.c_str());
1680 
1681  acl_nfmark **tail = head; /* sane name below */
1682  while (*tail)
1683  tail = &(*tail)->next;
1684 
1685  *tail = l;
1686 }
1687 
1688 static void
1689 free_acl_nfmark(acl_nfmark ** head)
1690 {
1691  delete *head;
1692  *head = nullptr;
1693 }
1694 #endif /* HAVE_LIBCAP && SO_MARK */
1695 
1696 static void
1697 dump_acl_b_size_t(StoreEntry * entry, const char *name, AclSizeLimit * head)
1698 {
1699  for (AclSizeLimit *l = head; l; l = l->next) {
1700  if (l->size != -1)
1701  storeAppendPrintf(entry, "%s %d %s\n", name, (int) l->size, B_BYTES_STR);
1702  else
1703  storeAppendPrintf(entry, "%s none", name);
1704 
1705  dump_acl_list(entry, l->aclList);
1706 
1707  storeAppendPrintf(entry, "\n");
1708  }
1709 }
1710 
1711 static void
1713 {
1714  AclSizeLimit *l = new AclSizeLimit;
1715 
1716  parse_b_int64_t(&l->size);
1717 
1719 
1720  AclSizeLimit **tail = head; /* sane name below */
1721  while (*tail)
1722  tail = &(*tail)->next;
1723 
1724  *tail = l;
1725 }
1726 
1727 static void
1729 {
1730  delete *head;
1731  *head = nullptr;
1732 }
1733 
1734 #if USE_DELAY_POOLS
1735 
1736 #include "DelayConfig.h"
1737 #include "DelayPools.h"
1738 /* do nothing - free_delay_pool_count is the magic free function.
1739  * this is why delay_pool_count isn't just marked TYPE: u_short
1740  */
1741 #define free_delay_pool_class(X)
1742 #define free_delay_pool_access(X)
1743 #define free_delay_pool_rates(X)
1744 #define dump_delay_pool_class(X, Y, Z)
1745 #define dump_delay_pool_access(X, Y, Z)
1746 #define dump_delay_pool_rates(X, Y, Z)
1747 
1748 static void
1750 {
1751  cfg->freePoolCount();
1752 }
1753 
1754 static void
1755 dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
1756 {
1757  cfg.dumpPoolCount (entry, name);
1758 }
1759 
1760 static void
1762 {
1763  cfg->parsePoolCount();
1764 }
1765 
1766 static void
1768 {
1769  cfg->parsePoolClass();
1770 }
1771 
1772 static void
1774 {
1775  cfg->parsePoolRates();
1776 }
1777 
1778 static void
1780 {
1782 }
1783 
1784 #endif
1785 
1786 #if USE_DELAY_POOLS
1787 #include "ClientDelayConfig.h"
1788 /* do nothing - free_client_delay_pool_count is the magic free function.
1789  * this is why client_delay_pool_count isn't just marked TYPE: u_short
1790  */
1791 
1792 #define free_client_delay_pool_access(X)
1793 #define free_client_delay_pool_rates(X)
1794 #define dump_client_delay_pool_access(X, Y, Z)
1795 #define dump_client_delay_pool_rates(X, Y, Z)
1796 
1797 static void
1799 {
1800  cfg->freePools();
1801 }
1802 
1803 static void
1805 {
1806  cfg.dumpPoolCount (entry, name);
1807 }
1808 
1809 static void
1811 {
1812  cfg->parsePoolCount();
1813 }
1814 
1815 static void
1817 {
1818  cfg->parsePoolRates();
1819 }
1820 
1821 static void
1823 {
1825 }
1826 #endif
1827 
1828 #if USE_HTTP_VIOLATIONS
1829 static void
1830 dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers)
1831 {
1832  if (manglers)
1833  manglers->dumpAccess(entry, name);
1834 }
1835 
1836 static void
1838 {
1839  char *t = nullptr;
1840 
1841  if ((t = ConfigParser::NextToken()) == nullptr) {
1842  debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1843  debugs(3, DBG_CRITICAL, "ERROR: parse_http_header_access: missing header name.");
1844  return;
1845  }
1846 
1847  if (!*pm)
1848  *pm = new HeaderManglers;
1849  HeaderManglers *manglers = *pm;
1850  headerMangler *mangler = manglers->track(t);
1851  assert(mangler);
1852 
1853  std::string directive = "http_header_access ";
1854  directive += t;
1855  aclParseAccessLine(directive.c_str(), LegacyParser, &mangler->access_list);
1856 }
1857 
1858 static void
1860 {
1861  // we delete the entire http_header_* mangler configuration at once
1862  if (const HeaderManglers *manglers = *pm) {
1863  delete manglers;
1864  *pm = nullptr;
1865  }
1866 }
1867 
1868 static void
1869 dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers)
1870 {
1871  if (manglers)
1872  manglers->dumpReplacement(entry, name);
1873 }
1874 
1875 static void
1877 {
1878  char *t = nullptr;
1879 
1880  if ((t = ConfigParser::NextToken()) == nullptr) {
1881  debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1882  debugs(3, DBG_CRITICAL, "ERROR: parse_http_header_replace: missing header name.");
1883  return;
1884  }
1885 
1886  const char *value = ConfigParser::NextQuotedOrToEol();
1887 
1888  if (!*pm)
1889  *pm = new HeaderManglers;
1890  HeaderManglers *manglers = *pm;
1891  manglers->setReplacement(t, value);
1892 }
1893 
1894 #endif
1895 
1896 static void
1897 dump_cachedir(StoreEntry * entry, const char *name, const Store::DiskConfig &swap)
1898 {
1899  Store::Disks::Dump(swap, *entry, name);
1900 }
1901 
1902 static int
1904 {
1905  return s == nullptr;
1906 }
1907 
1908 #if USE_AUTH
1909 static void
1911 {
1912  char *type_str = ConfigParser::NextToken();
1913  if (!type_str) {
1914  self_destruct();
1915  return;
1916  }
1917 
1918  char *param_str = ConfigParser::NextToken();
1919  if (!param_str) {
1920  self_destruct();
1921  return;
1922  }
1923 
1924  /* find a configuration for the scheme in the currently parsed configs... */
1925  Auth::SchemeConfig *schemeCfg = Auth::SchemeConfig::Find(type_str);
1926 
1927  if (schemeCfg == nullptr) {
1928  /* Create a configuration based on the scheme info */
1929  Auth::Scheme::Pointer theScheme = Auth::Scheme::Find(type_str);
1930 
1931  if (theScheme == nullptr) {
1932  debugs(3, DBG_CRITICAL, "ERROR: Failure while parsing Config File: Unknown authentication scheme '" << type_str << "'.");
1933  self_destruct();
1934  return;
1935  }
1936 
1937  config->push_back(theScheme->createConfig());
1938  schemeCfg = Auth::SchemeConfig::Find(type_str);
1939  if (schemeCfg == nullptr) {
1940  debugs(3, DBG_CRITICAL, "Parsing Config File: Corruption configuring authentication scheme '" << type_str << "'.");
1941  self_destruct();
1942  return;
1943  }
1944  }
1945 
1946  schemeCfg->parse(schemeCfg, config->size(), param_str);
1947 }
1948 
1949 static void
1951 {
1952  /* Wipe the Auth globals and Detach/Destruct component config + state. */
1953  cfg->clear();
1954 
1955  /* on reconfigure initialize new auth schemes for the new config. */
1956  if (reconfiguring) {
1957  Auth::Init();
1958  }
1959 }
1960 
1961 static void
1962 dump_authparam(StoreEntry * entry, const char *name, Auth::ConfigVector cfg)
1963 {
1964  for (auto *scheme : cfg)
1965  scheme->dump(entry, name, scheme);
1966 }
1967 
1968 static void
1970 {
1971  const char *tok = ConfigParser::NextQuotedToken();
1972  if (!tok) {
1973  debugs(29, DBG_CRITICAL, "FATAL: auth_schemes missing the parameter");
1974  self_destruct();
1975  return;
1976  }
1978  const auto action = Acl::Answer(ACCESS_ALLOWED, Auth::TheConfig.schemeLists.size() - 1);
1979  ParseAclWithAction(authSchemes, action, "auth_schemes");
1980 }
1981 
1982 static void
1984 {
1985  Auth::TheConfig.schemeLists.clear();
1986  free_acl_access(authSchemes);
1987 }
1988 
1989 static void
1990 dump_AuthSchemes(StoreEntry *entry, const char *name, acl_access *authSchemes)
1991 {
1992  if (authSchemes)
1993  dump_SBufList(entry, ToTree(authSchemes).treeDump(name, [](const Acl::Answer &action) {
1994  return Auth::TheConfig.schemeLists.at(action.kind).rawSchemes;
1995  }));
1996 }
1997 
1998 #endif /* USE_AUTH */
1999 
2000 static void
2001 ParseAclWithAction(acl_access **config, const Acl::Answer &action, const char *desc, Acl::Node *acl)
2002 {
2003  assert(config);
2004  auto &access = *config;
2005  if (!access) {
2006  const auto tree = new Acl::Tree;
2007  tree->context(ToSBuf('(', desc, " rules)"), config_input_line);
2008  access = new acl_access(tree);
2009  }
2010  assert(access);
2011 
2012  Acl::AndNode *rule = new Acl::AndNode;
2013  rule->context(ToSBuf('(', desc, " rule)"), config_input_line);
2014  if (acl)
2015  rule->add(acl);
2016  else
2017  rule->lineParse();
2018  (*access)->add(rule, action);
2019 }
2020 
2021 static void
2023 {
2024  assert(swap);
2025  Store::Disks::Parse(*swap);
2026 }
2027 
2028 static const char *
2030 {
2031  const char * result;
2032 
2033  switch (type) {
2034 
2035  case PEER_PARENT:
2036  result = "parent";
2037  break;
2038 
2039  case PEER_SIBLING:
2040  result = "sibling";
2041  break;
2042 
2043  case PEER_MULTICAST:
2044  result = "multicast";
2045  break;
2046 
2047  default:
2048  result = "unknown";
2049  break;
2050  }
2051 
2052  return result;
2053 }
2054 
2055 static void
2056 dump_peer(StoreEntry * entry, const char *name, const CachePeers *peers)
2057 {
2058  if (!peers)
2059  return;
2060 
2062  LOCAL_ARRAY(char, xname, 128);
2063 
2064  for (const auto &peer: *peers) {
2065  const auto p = peer.get();
2066  storeAppendPrintf(entry, "%s %s %s %d %d name=%s",
2067  name,
2068  p->host,
2069  neighborTypeStr(p),
2070  p->http_port,
2071  p->icp.port,
2072  p->name);
2073  dump_peer_options(entry, p);
2074 
2075  if (p->access) {
2076  snprintf(xname, 128, "cache_peer_access %s", p->name);
2077  dump_acl_access(entry, xname, p->access);
2078  }
2079 
2080  for (t = p->typelist; t; t = t->next) {
2081  storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
2082  p->host,
2083  peer_type_str(t->type),
2084  t->domain);
2085  }
2086  }
2087 }
2088 
2093 static bool
2094 isUnsignedNumeric(const char *str, size_t len)
2095 {
2096  if (len < 1) return false;
2097 
2098  for (; len >0 && *str; ++str, --len) {
2099  if (! isdigit(*str))
2100  return false;
2101  }
2102  return true;
2103 }
2104 
2109 static unsigned short
2110 GetService(const char *proto)
2111 {
2112  struct servent *port = nullptr;
2114  char *token = ConfigParser::NextToken();
2115  if (token == nullptr) {
2116  self_destruct();
2117  return 0; /* NEVER REACHED */
2118  }
2120  if ( !isUnsignedNumeric(token, strlen(token)) )
2121  port = xgetservbyname(token, proto);
2122  if (port != nullptr) {
2123  return ntohs((unsigned short)port->s_port);
2124  }
2126  return xatos(token);
2127 }
2128 
2133 inline unsigned short
2135 {
2136  return GetService("tcp");
2137 }
2138 
2143 inline unsigned short
2145 {
2146  return GetService("udp");
2147 }
2148 
2149 static void
2151 {
2152  char *host_str = ConfigParser::NextToken();
2153  if (!host_str) {
2154  self_destruct();
2155  return;
2156  }
2157 
2158  char *token = ConfigParser::NextToken();
2159  if (!token) {
2160  self_destruct();
2161  return;
2162  }
2163 
2164  const auto p = new CachePeer(host_str);
2165 
2166  p->type = parseNeighborType(token);
2167 
2168  if (p->type == PEER_MULTICAST) {
2169  p->options.no_digest = true;
2170  p->options.no_netdb_exchange = true;
2171  }
2172 
2173  p->http_port = GetTcpService();
2174 
2175  if (!p->http_port) {
2176  delete p;
2177  self_destruct();
2178  return;
2179  }
2180 
2181  p->icp.port = GetUdpService();
2182 
2183  while ((token = ConfigParser::NextToken())) {
2184  if (!strcmp(token, "proxy-only")) {
2185  p->options.proxy_only = true;
2186  } else if (!strcmp(token, "no-query")) {
2187  p->options.no_query = true;
2188  } else if (!strcmp(token, "background-ping")) {
2189  p->options.background_ping = true;
2190  } else if (!strcmp(token, "no-digest")) {
2191  p->options.no_digest = true;
2192  } else if (!strcmp(token, "no-tproxy")) {
2193  p->options.no_tproxy = true;
2194  } else if (!strcmp(token, "multicast-responder")) {
2195  p->options.mcast_responder = true;
2196  } else if (!strcmp(token, "multicast-siblings")) {
2197  p->options.mcast_siblings = true;
2198  } else if (!strncmp(token, "weight=", 7)) {
2199  p->weight = xatoi(token + 7);
2200  } else if (!strncmp(token, "basetime=", 9)) {
2201  p->basetime = xatoi(token + 9);
2202  } else if (!strcmp(token, "closest-only")) {
2203  p->options.closest_only = true;
2204  } else if (!strncmp(token, "ttl=", 4)) {
2205  p->mcast.ttl = xatoi(token + 4);
2206 
2207  if (p->mcast.ttl < 0)
2208  p->mcast.ttl = 0;
2209 
2210  if (p->mcast.ttl > 128)
2211  p->mcast.ttl = 128;
2212  } else if (!strcmp(token, "default")) {
2213  p->options.default_parent = true;
2214  } else if (!strcmp(token, "round-robin")) {
2215  p->options.roundrobin = true;
2216  } else if (!strcmp(token, "weighted-round-robin")) {
2217  p->options.weighted_roundrobin = true;
2218 #if USE_HTCP
2219  } else if (!strcmp(token, "htcp")) {
2220  p->options.htcp = true;
2221  } else if (!strncmp(token, "htcp=", 5) || !strncmp(token, "htcp-", 5)) {
2222  /* Note: The htcp- form is deprecated, replaced by htcp= */
2223  p->options.htcp = true;
2224  char *tmp = xstrdup(token+5);
2225  char *mode, *nextmode;
2226  for (mode = nextmode = tmp; mode; mode = nextmode) {
2227  nextmode = strchr(mode, ',');
2228  if (nextmode) {
2229  *nextmode = '\0';
2230  ++nextmode;
2231  }
2232  if (!strcmp(mode, "no-clr")) {
2233  if (p->options.htcp_only_clr)
2234  fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
2235  p->options.htcp_no_clr = true;
2236  } else if (!strcmp(mode, "no-purge-clr")) {
2237  p->options.htcp_no_purge_clr = true;
2238  } else if (!strcmp(mode, "only-clr")) {
2239  if (p->options.htcp_no_clr)
2240  fatalf("parse_peer: can't set htcp no-clr and only-clr simultaneously");
2241  p->options.htcp_only_clr = true;
2242  } else if (!strcmp(mode, "forward-clr")) {
2243  p->options.htcp_forward_clr = true;
2244  } else if (!strcmp(mode, "oldsquid")) {
2245  p->options.htcp_oldsquid = true;
2246  } else {
2247  fatalf("invalid HTCP mode '%s'", mode);
2248  }
2249  }
2250  safe_free(tmp);
2251 #endif
2252  } else if (!strcmp(token, "no-netdb-exchange")) {
2253  p->options.no_netdb_exchange = true;
2254 
2255  } else if (!strcmp(token, "carp")) {
2256  if (p->type != PEER_PARENT)
2257  throw TextException(ToSBuf("non-parent carp cache_peer ", *p), Here());
2258 
2259  p->options.carp = true;
2260  } else if (!strncmp(token, "carp-key=", 9)) {
2261  if (p->options.carp != true)
2262  throw TextException(ToSBuf("carp-key specified on non-carp cache_peer ", *p), Here());
2263  p->options.carp_key.set = true;
2264  char *nextkey=token+strlen("carp-key="), *key=nextkey;
2265  for (; key; key = nextkey) {
2266  nextkey=strchr(key,',');
2267  if (nextkey) ++nextkey; // skip the comma, any
2268  if (0==strncmp(key,"scheme",6)) {
2269  p->options.carp_key.scheme = true;
2270  } else if (0==strncmp(key,"host",4)) {
2271  p->options.carp_key.host = true;
2272  } else if (0==strncmp(key,"port",4)) {
2273  p->options.carp_key.port = true;
2274  } else if (0==strncmp(key,"path",4)) {
2275  p->options.carp_key.path = true;
2276  } else if (0==strncmp(key,"params",6)) {
2277  p->options.carp_key.params = true;
2278  } else {
2279  fatalf("invalid carp-key '%s'",key);
2280  }
2281  }
2282  } else if (!strcmp(token, "userhash")) {
2283 #if USE_AUTH
2284  if (p->type != PEER_PARENT)
2285  throw TextException(ToSBuf("non-parent userhash cache_peer ", *p), Here());
2286 
2287  p->options.userhash = true;
2288 #else
2289  throw TextException(ToSBuf("missing authentication support; required for userhash cache_peer ", *p), Here());
2290 #endif
2291  } else if (!strcmp(token, "sourcehash")) {
2292  if (p->type != PEER_PARENT)
2293  throw TextException(ToSBuf("non-parent sourcehash cache_peer ", *p), Here());
2294 
2295  p->options.sourcehash = true;
2296 
2297  } else if (!strcmp(token, "no-delay")) {
2298 #if USE_DELAY_POOLS
2299  p->options.no_delay = true;
2300 #else
2301  debugs(0, DBG_CRITICAL, "WARNING: cache_peer option 'no-delay' requires --enable-delay-pools");
2302 #endif
2303  } else if (!strncmp(token, "login=", 6)) {
2304  p->login = xstrdup(token + 6);
2305  rfc1738_unescape(p->login);
2306  } else if (!strcmp(token, "auth-no-keytab")) {
2307  p->options.auth_no_keytab = 1;
2308  } else if (!strncmp(token, "connect-timeout=", 16)) {
2309  p->connect_timeout_raw = xatoi(token + 16);
2310  } else if (!strncmp(token, "connect-fail-limit=", 19)) {
2311  p->connect_fail_limit = xatoi(token + 19);
2312 #if USE_CACHE_DIGESTS
2313  } else if (!strncmp(token, "digest-url=", 11)) {
2314  p->digest_url = xstrdup(token + 11);
2315 #endif
2316 
2317  } else if (!strcmp(token, "allow-miss")) {
2318  p->options.allow_miss = true;
2319  } else if (!strncmp(token, "max-conn=", 9)) {
2320  p->max_conn = xatoi(token + 9);
2321  } else if (!strncmp(token, "standby=", 8)) {
2322  p->standby.limit = xatoi(token + 8);
2323  } else if (!strcmp(token, "originserver")) {
2324  p->options.originserver = true;
2325  } else if (!strncmp(token, "name=", 5)) {
2326  p->rename(token + 5);
2327  } else if (!strncmp(token, "forceddomain=", 13)) {
2328  safe_free(p->domain);
2329  if (token[13])
2330  p->domain = xstrdup(token + 13);
2331 
2332  } else if (strncmp(token, "ssl", 3) == 0) {
2333 #if !USE_OPENSSL
2334  debugs(0, DBG_CRITICAL, "WARNING: cache_peer option '" << token << "' requires --with-openssl");
2335 #else
2336  p->secure.parse(token+3);
2337 #endif
2338  } else if (strncmp(token, "tls-", 4) == 0) {
2339  p->secure.parse(token+4);
2340  } else if (strncmp(token, "tls", 3) == 0) {
2341  p->secure.parse(token+3);
2342  } else if (strcmp(token, "front-end-https") == 0) {
2343  p->front_end_https = 1;
2344  } else if (strcmp(token, "front-end-https=on") == 0) {
2345  p->front_end_https = 1;
2346  } else if (strcmp(token, "front-end-https=auto") == 0) {
2347  p->front_end_https = 2;
2348  } else if (strcmp(token, "connection-auth=off") == 0) {
2349  p->connection_auth = 0;
2350  } else if (strcmp(token, "connection-auth") == 0) {
2351  p->connection_auth = 1;
2352  } else if (strcmp(token, "connection-auth=on") == 0) {
2353  p->connection_auth = 1;
2354  } else if (strcmp(token, "connection-auth=auto") == 0) {
2355  p->connection_auth = 2;
2356  } else if (token[0] == '#') {
2357  // start of a text comment. stop reading this line.
2358  break;
2359  } else {
2360  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Ignoring unknown cache_peer option '" << token << "'");
2361  }
2362  }
2363 
2364  if (findCachePeerByName(p->name))
2365  throw TextException(ToSBuf("cache_peer ", *p, " specified twice"), Here());
2366 
2367  if (p->max_conn > 0 && p->max_conn < p->standby.limit)
2368  throw TextException(ToSBuf("cache_peer ", *p, " max-conn=", p->max_conn,
2369  " is lower than its standby=", p->standby.limit), Here());
2370 
2371  if (p->weight < 1)
2372  p->weight = 1;
2373 
2374  if (p->connect_fail_limit < 1)
2375  p->connect_fail_limit = 10;
2376 
2377 #if USE_CACHE_DIGESTS
2378  if (!p->options.no_digest)
2379  p->digest = new PeerDigest(p);
2380 #endif
2381 
2382  if (p->secure.encryptTransport)
2383  p->secure.parseOptions();
2384 
2385  if (!*peers)
2386  *peers = new CachePeers;
2387 
2388  (*peers)->add(p);
2389 
2390  p->index = (*peers)->size();
2391 
2392  peerClearRRStart();
2393 }
2394 
2395 static void
2396 free_peer(CachePeers ** const peers)
2397 {
2398  delete *peers;
2399  *peers = nullptr;
2400 }
2401 
2402 static void
2403 dump_cachemgrpasswd(StoreEntry * entry, const char *name, Mgr::ActionPasswordList * list)
2404 {
2405  while (list) {
2406  if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
2407  storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
2408  else
2409  storeAppendPrintf(entry, "%s %s", name, list->passwd);
2410 
2411  for (auto w : list->actions)
2412  entry->appendf(" " SQUIDSBUFPH, SQUIDSBUFPRINT(w));
2413 
2414  storeAppendPrintf(entry, "\n");
2415  list = list->next;
2416  }
2417 }
2418 
2419 static void
2421 {
2422  char *passwd = nullptr;
2423  parse_string(&passwd);
2424 
2426  p->passwd = passwd;
2427 
2428  while (char *token = ConfigParser::NextQuotedToken())
2429  p->actions.push_back(SBuf(token));
2430 
2432  for (P = head; *P; P = &(*P)->next) {
2433  /*
2434  * See if any of the actions from this line already have a
2435  * password from previous lines. The password checking
2436  * routines in cache_manager.c take the the password from
2437  * the first Mgr::ActionPasswordList that contains the
2438  * requested action. Thus, we should warn users who might
2439  * think they can have two passwords for the same action.
2440  */
2441  for (const auto &w : (*P)->actions) {
2442  for (const auto &u : p->actions) {
2443  if (w != u)
2444  continue;
2445 
2446  debugs(0, DBG_PARSE_NOTE(1), "ERROR: action '" << u << "' (line " << config_lineno << ") already has a password");
2447  }
2448  }
2449  }
2450 
2451  *P = p;
2452 }
2453 
2454 static void
2456 {
2457  delete *head;
2458  *head = nullptr;
2459 }
2460 
2461 static void
2462 dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var)
2463 {
2464  while (var != nullptr) {
2465  storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
2466 
2467  for (const auto &aclName: var->acl_list)
2468  storeAppendPrintf(entry, " " SQUIDSBUFPH, SQUIDSBUFPRINT(aclName));
2469 
2470  storeAppendPrintf(entry, "\n");
2471 
2472  var = var->next;
2473  }
2474 }
2475 
2476 static void
2478 {
2479  aclParseDenyInfoLine(var);
2480 }
2481 
2482 void
2484 {
2485  delete *list;
2486  *list = nullptr;
2487 }
2488 
2489 static void
2491 {
2492  auto &p = LegacyParser.cachePeer("cache_peer_access peer-name");
2493  std::string directive = "peer_access ";
2494  directive += p.name;
2495  aclParseAccessLine(directive.c_str(), LegacyParser, &p.access);
2496 }
2497 
2498 static void
2500 {
2501  auto &p = LegacyParser.cachePeer("neighbor_type_domain peer-name");
2502 
2503  char *type = ConfigParser::NextToken();
2504  if (!type) {
2505  self_destruct();
2506  return;
2507  }
2508 
2509  char *domain = nullptr;
2510  while ((domain = ConfigParser::NextToken())) {
2511  auto *l = static_cast<NeighborTypeDomainList *>(xcalloc(1, sizeof(NeighborTypeDomainList)));
2512  l->type = parseNeighborType(type);
2513  l->domain = xstrdup(domain);
2514 
2515  NeighborTypeDomainList **L = nullptr;
2516  for (L = &p.typelist; *L; L = &((*L)->next));
2517  *L = l;
2518  }
2519 }
2520 
2521 static void
2522 dump_int(StoreEntry * entry, const char *name, int var)
2523 {
2524  storeAppendPrintf(entry, "%s %d\n", name, var);
2525 }
2526 
2527 void
2528 parse_int(int *var)
2529 {
2530  int i;
2531  i = GetInteger();
2532  *var = i;
2533 }
2534 
2535 static void
2536 free_int(int *var)
2537 {
2538  *var = 0;
2539 }
2540 
2541 static void
2542 dump_int64_t(StoreEntry * entry, const char *name, int64_t var)
2543 {
2544  storeAppendPrintf(entry, "%s %" PRId64 "\n", name, var);
2545 }
2546 
2547 static void
2548 parse_int64_t(int64_t *var)
2549 {
2550  int64_t i;
2551  i = GetInteger64();
2552  *var = i;
2553 }
2554 
2555 static void
2556 free_int64_t(int64_t *var)
2557 {
2558  *var = 0;
2559 }
2560 
2561 static void
2562 dump_onoff(StoreEntry * entry, const char *name, int var)
2563 {
2564  storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
2565 }
2566 
2567 void
2568 parse_onoff(int *var)
2569 {
2570  char *token = ConfigParser::NextToken();
2571  if (!token) {
2572  self_destruct();
2573  return;
2574  }
2575 
2576  if (!strcmp(token, "on")) {
2577  *var = 1;
2578  } else if (!strcmp(token, "enable")) {
2579  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' is deprecated. Please update to use 'on'.");
2580  *var = 1;
2581  } else if (!strcmp(token, "off")) {
2582  *var = 0;
2583  } else if (!strcmp(token, "disable")) {
2584  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'disable' is deprecated. Please update to use 'off'.");
2585  *var = 0;
2586  } else {
2587  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Boolean options can only be 'on' or 'off'.");
2588  self_destruct();
2589  }
2590 }
2591 
2592 #define free_onoff free_int
2593 
2594 static void
2595 dump_tristate(StoreEntry * entry, const char *name, int var)
2596 {
2597  const char *state;
2598 
2599  if (var > 0)
2600  state = "on";
2601  else if (var < 0)
2602  state = "warn";
2603  else
2604  state = "off";
2605 
2606  storeAppendPrintf(entry, "%s %s\n", name, state);
2607 }
2608 
2609 static void
2611 {
2612  char *token = ConfigParser::NextToken();
2613  if (!token) {
2614  self_destruct();
2615  return;
2616  }
2617 
2618  if (!strcmp(token, "on")) {
2619  *var = 1;
2620  } else if (!strcmp(token, "enable")) {
2621  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' is deprecated. Please update to use value 'on'.");
2622  *var = 1;
2623  } else if (!strcmp(token, "warn")) {
2624  *var = -1;
2625  } else if (!strcmp(token, "off")) {
2626  *var = 0;
2627  } else if (!strcmp(token, "disable")) {
2628  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'disable' is deprecated. Please update to use value 'off'.");
2629  *var = 0;
2630  } else {
2631  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Tristate options can only be 'on', 'off', or 'warn'.");
2632  self_destruct();
2633  }
2634 }
2635 
2636 #define free_tristate free_int
2637 
2638 static void
2640 {
2641  char *token = ConfigParser::PeekAtToken();
2642  if (!token) {
2643  self_destruct();
2644  return;
2645  }
2646 
2647  if (!strcmp(token, "on")) {
2648  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'pipeline_prefetch on' is deprecated. Please update to use 1 (or a higher number).");
2649  *var = 1;
2650  //pop the token
2651  (void)ConfigParser::NextToken();
2652  } else if (!strcmp(token, "off")) {
2653  debugs(0, DBG_PARSE_NOTE(2), "WARNING: 'pipeline_prefetch off' is deprecated. Please update to use '0'.");
2654  *var = 0;
2655  //pop the token
2656  (void)ConfigParser::NextToken();
2657  } else
2658  parse_int(var);
2659 }
2660 
2661 #define free_pipelinePrefetch free_int
2662 #define dump_pipelinePrefetch dump_int
2663 
2664 static void
2665 dump_refreshpattern(StoreEntry * entry, const char *name, RefreshPattern * head)
2666 {
2667  while (head != nullptr) {
2668  PackableStream os(*entry);
2669  os << name << ' ';
2670  head->printHead(os);
2671 
2672  if (head->max_stale >= 0)
2673  storeAppendPrintf(entry, " max-stale=%d", head->max_stale);
2674 
2675  if (head->flags.refresh_ims)
2676  storeAppendPrintf(entry, " refresh-ims");
2677 
2678  if (head->flags.store_stale)
2679  storeAppendPrintf(entry, " store-stale");
2680 
2681 #if USE_HTTP_VIOLATIONS
2682 
2683  if (head->flags.override_expire)
2684  storeAppendPrintf(entry, " override-expire");
2685 
2686  if (head->flags.override_lastmod)
2687  storeAppendPrintf(entry, " override-lastmod");
2688 
2689  if (head->flags.reload_into_ims)
2690  storeAppendPrintf(entry, " reload-into-ims");
2691 
2692  if (head->flags.ignore_reload)
2693  storeAppendPrintf(entry, " ignore-reload");
2694 
2695  if (head->flags.ignore_no_store)
2696  storeAppendPrintf(entry, " ignore-no-store");
2697 
2698  if (head->flags.ignore_private)
2699  storeAppendPrintf(entry, " ignore-private");
2700 #endif
2701 
2702  storeAppendPrintf(entry, "\n");
2703 
2704  head = head->next;
2705  }
2706 }
2707 
2708 static void
2710 {
2711  char *token;
2712  time_t min = 0;
2713  double pct = 0.0;
2714  time_t max = 0;
2715  int refresh_ims = 0;
2716  int store_stale = 0;
2717  int max_stale = -1;
2718 
2719 #if USE_HTTP_VIOLATIONS
2720 
2721  int override_expire = 0;
2722  int override_lastmod = 0;
2723  int reload_into_ims = 0;
2724  int ignore_reload = 0;
2725  int ignore_no_store = 0;
2726  int ignore_private = 0;
2727 #endif
2728 
2729  int i;
2730  RefreshPattern *t;
2731 
2732  auto regex = LegacyParser.regex("refresh_pattern regex");
2733 
2734  i = GetInteger(); /* token: min */
2735 
2736  /* catch negative and insanely huge values close to 32-bit wrap */
2737  if (i < 0) {
2738  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age negative. Cropped back to zero.");
2739  i = 0;
2740  }
2741  if (i > 60*24*365) {
2742  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age too high. Cropped back to 1 year.");
2743  i = 60*24*365;
2744  }
2745 
2746  min = (time_t) (i * 60); /* convert minutes to seconds */
2747 
2748  pct = GetPercentage(false); /* token: pct . with no limit on size */
2749 
2750  i = GetInteger(); /* token: max */
2751 
2752  /* catch negative and insanely huge values close to 32-bit wrap */
2753  if (i < 0) {
2754  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age negative. Cropped back to zero.");
2755  i = 0;
2756  }
2757  if (i > 60*24*365) {
2758  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age too high. Cropped back to 1 year.");
2759  i = 60*24*365;
2760  }
2761 
2762  max = (time_t) (i * 60); /* convert minutes to seconds */
2763 
2764  /* Options */
2765  while ((token = ConfigParser::NextToken()) != nullptr) {
2766  if (!strcmp(token, "refresh-ims")) {
2767  refresh_ims = 1;
2768  } else if (!strcmp(token, "store-stale")) {
2769  store_stale = 1;
2770  } else if (!strncmp(token, "max-stale=", 10)) {
2771  max_stale = xatoi(token + 10);
2772 
2773 #if USE_HTTP_VIOLATIONS
2774 
2775  } else if (!strcmp(token, "override-expire"))
2776  override_expire = 1;
2777  else if (!strcmp(token, "override-lastmod"))
2778  override_lastmod = 1;
2779  else if (!strcmp(token, "ignore-no-store"))
2780  ignore_no_store = 1;
2781  else if (!strcmp(token, "ignore-private"))
2782  ignore_private = 1;
2783  else if (!strcmp(token, "reload-into-ims")) {
2784  reload_into_ims = 1;
2786  /* tell client_side.c that this is used */
2787  } else if (!strcmp(token, "ignore-reload")) {
2788  ignore_reload = 1;
2790  /* tell client_side.c that this is used */
2791 #endif
2792 
2793  } else if (!strcmp(token, "ignore-no-cache") ||
2794  !strcmp(token, "ignore-must-revalidate") ||
2795  !strcmp(token, "ignore-auth")
2796  ) {
2797  debugs(22, DBG_PARSE_NOTE(2), "UPGRADE: refresh_pattern option '" << token << "' is obsolete. Remove it.");
2798  } else
2799  debugs(22, DBG_CRITICAL, "ERROR: Unknown refresh_pattern option: " << token);
2800  }
2801 
2802  pct = pct < 0.0 ? 0.0 : pct;
2803  max = max < 0 ? 0 : max;
2804  t = new RefreshPattern(std::move(regex));
2805  t->min = min;
2806  t->pct = pct;
2807  t->max = max;
2808 
2809  if (refresh_ims)
2810  t->flags.refresh_ims = true;
2811 
2812  if (store_stale)
2813  t->flags.store_stale = true;
2814 
2815  t->max_stale = max_stale;
2816 
2817 #if USE_HTTP_VIOLATIONS
2818 
2819  if (override_expire)
2820  t->flags.override_expire = true;
2821 
2822  if (override_lastmod)
2823  t->flags.override_lastmod = true;
2824 
2825  if (reload_into_ims)
2826  t->flags.reload_into_ims = true;
2827 
2828  if (ignore_reload)
2829  t->flags.ignore_reload = true;
2830 
2831  if (ignore_no_store)
2832  t->flags.ignore_no_store = true;
2833 
2834  if (ignore_private)
2835  t->flags.ignore_private = true;
2836 #endif
2837 
2838  t->next = nullptr;
2839 
2840  while (*head)
2841  head = &(*head)->next;
2842 
2843  *head = t;
2844 }
2845 
2846 static void
2848 {
2849  delete *head;
2850  *head = nullptr;
2851 
2852 #if USE_HTTP_VIOLATIONS
2854 
2855 #endif
2856 }
2857 
2858 static void
2859 dump_string(StoreEntry * entry, const char *name, char *var)
2860 {
2861  if (var != nullptr)
2862  storeAppendPrintf(entry, "%s %s\n", name, var);
2863 }
2864 
2865 static void
2866 parse_string(char **var)
2867 {
2868  safe_free(*var);
2869 
2870  char *token = ConfigParser::NextToken();
2871  if (!token) {
2872  self_destruct();
2873  return;
2874  }
2875 
2876  *var = xstrdup(token);
2877 }
2878 
2879 static void
2880 free_string(char **var)
2881 {
2882  safe_free(*var);
2883 }
2884 
2885 void
2886 parse_eol(char *volatile *var)
2887 {
2888  if (!var) {
2889  self_destruct();
2890  return;
2891  }
2892 
2893  unsigned char *token = (unsigned char *) ConfigParser::NextQuotedOrToEol();
2894  safe_free(*var);
2895 
2896  if (!token) {
2897  self_destruct();
2898  return;
2899  }
2900 
2901  while (*token && xisspace(*token))
2902  ++token;
2903 
2904  if (!*token) {
2905  self_destruct();
2906  return;
2907  }
2908 
2909  *var = xstrdup((char *) token);
2910 }
2911 
2912 #define dump_eol dump_string
2913 #define free_eol free_string
2914 
2915 static void
2917 {
2918  safe_free(*var);
2919 
2920  char *token = ConfigParser::NextQuotedToken();
2921  if (!token) {
2922  self_destruct();
2923  return;
2924  }
2925 
2926  *var = xstrdup(token);
2927 }
2928 
2929 #define dump_TokenOrQuotedString dump_string
2930 #define free_TokenOrQuotedString free_string
2931 
2932 static void
2933 dump_time_t(StoreEntry * entry, const char *name, time_t var)
2934 {
2935  PackableStream os(*entry);
2936  os << name << ' ' << var << " seconds\n";
2937 }
2938 
2939 void
2940 parse_time_t(time_t * var)
2941 {
2942  const auto maxTime = std::numeric_limits<time_t>::max();
2943  const auto seconds = parseTimeLine<std::chrono::seconds>();
2944  if (maxTime < seconds.count())
2945  throw TexcHere(ToSBuf("directive supports time values up to ", maxTime, " but is given ", seconds.count(), " seconds"));
2946  *var = static_cast<time_t>(seconds.count());
2947 }
2948 
2949 static void
2950 free_time_t(time_t * var)
2951 {
2952  *var = 0;
2953 }
2954 
2955 static void
2956 dump_time_msec(StoreEntry * entry, const char *name, time_msec_t var)
2957 {
2958  PackableStream os(*entry);
2959  if (var % 1000)
2960  os << name << ' ' << var << " milliseconds\n";
2961  else
2962  os << name << ' ' << (var/1000) << " seconds\n";
2963 }
2964 
2965 static void
2967 {
2968  *var = parseTimeLine<std::chrono::milliseconds>().count();
2969 }
2970 
2971 static void
2973 {
2974  *var = 0;
2975 }
2976 
2977 static void
2978 dump_time_nanoseconds(StoreEntry *entry, const char *name, const std::chrono::nanoseconds &var)
2979 {
2980  // std::chrono::nanoseconds::rep is unknown a priori so we cast to (and print) the largest supported integer
2981  storeAppendPrintf(entry, "%s %jd nanoseconds\n", name, static_cast<intmax_t>(var.count()));
2982 }
2983 
2984 static void
2985 parse_time_nanoseconds(std::chrono::nanoseconds *var)
2986 {
2987  *var = parseTimeLine<std::chrono::nanoseconds>();
2988 }
2989 
2990 static void
2991 free_time_nanoseconds(std::chrono::nanoseconds *var)
2992 {
2993  *var = std::chrono::nanoseconds::zero();
2994 }
2995 
2996 static void
2997 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
2998 {
2999  storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
3000 }
3001 
3002 static void
3003 dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
3004 {
3005  storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
3006 }
3007 
3008 static void
3009 dump_b_int64_t(StoreEntry * entry, const char *name, int64_t var)
3010 {
3011  storeAppendPrintf(entry, "%s %" PRId64 " %s\n", name, var, B_BYTES_STR);
3012 }
3013 
3014 static void
3015 dump_kb_int64_t(StoreEntry * entry, const char *name, int64_t var)
3016 {
3017  storeAppendPrintf(entry, "%s %" PRId64 " %s\n", name, var, B_KBYTES_STR);
3018 }
3019 
3020 static void
3021 parse_b_size_t(size_t * var)
3022 {
3024 }
3025 
3026 static void
3027 parse_b_ssize_t(ssize_t * var)
3028 {
3030 }
3031 
3032 static void
3033 parse_b_int64_t(int64_t * var)
3034 {
3036 }
3037 
3038 static void
3039 parse_kb_int64_t(int64_t * var)
3040 {
3042 }
3043 
3044 static void
3045 free_size_t(size_t * var)
3046 {
3047  *var = 0;
3048 }
3049 
3050 static void
3051 free_ssize_t(ssize_t * var)
3052 {
3053  *var = 0;
3054 }
3055 
3056 static void
3057 free_b_int64_t(int64_t * var)
3058 {
3059  *var = 0;
3060 }
3061 
3062 #define free_b_size_t free_size_t
3063 #define free_b_ssize_t free_ssize_t
3064 #define free_kb_size_t free_size_t
3065 #define free_mb_size_t free_size_t
3066 #define free_gb_size_t free_size_t
3067 #define free_kb_int64_t free_b_int64_t
3068 
3069 static void
3070 dump_u_short(StoreEntry * entry, const char *name, unsigned short var)
3071 {
3072  storeAppendPrintf(entry, "%s %d\n", name, var);
3073 }
3074 
3075 static void
3076 free_u_short(unsigned short * u)
3077 {
3078  *u = 0;
3079 }
3080 
3081 static void
3082 parse_u_short(unsigned short * var)
3083 {
3085 }
3086 
3087 void
3088 ConfigParser::ParseUShort(unsigned short *var)
3089 {
3090  *var = GetShort();
3091 }
3092 
3093 void
3095 {
3096  int i = GetInteger();
3097 
3098  if (0 == i)
3099  *var = false;
3100  else if (1 == i)
3101  *var = true;
3102  else
3103  self_destruct();
3104 }
3105 
3106 static void
3107 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
3108 {
3109  while (list != nullptr) {
3110  storeAppendPrintf(entry, "%s %s\n", name, list->key);
3111  list = list->next;
3112  }
3113 }
3114 
3115 void
3117 {
3118  parse_wordlist(list);
3119 }
3120 
3121 void
3123 {
3124  char *token;
3125  while ((token = ConfigParser::NextQuotedToken()))
3126  wordlistAdd(list, token);
3127 }
3128 
3129 static int
3131 {
3132  return a == nullptr;
3133 }
3134 
3135 #define free_wordlist wordlistDestroy
3136 
3137 #define free_uri_whitespace free_int
3138 
3139 static void
3141 {
3142  char *token = ConfigParser::NextToken();
3143  if (!token) {
3144  self_destruct();
3145  return;
3146  }
3147 
3148  if (!strcmp(token, "strip"))
3149  *var = URI_WHITESPACE_STRIP;
3150  else if (!strcmp(token, "deny"))
3151  *var = URI_WHITESPACE_DENY;
3152  else if (!strcmp(token, "allow"))
3153  *var = URI_WHITESPACE_ALLOW;
3154  else if (!strcmp(token, "encode"))
3155  *var = URI_WHITESPACE_ENCODE;
3156  else if (!strcmp(token, "chop"))
3157  *var = URI_WHITESPACE_CHOP;
3158  else {
3159  debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'uri_whitespace' accepts 'strip', 'deny', 'allow', 'encode', and 'chop'.");
3160  self_destruct();
3161  }
3162 }
3163 
3164 static void
3165 dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
3166 {
3167  const char *s;
3168 
3169  if (var == URI_WHITESPACE_ALLOW)
3170  s = "allow";
3171  else if (var == URI_WHITESPACE_ENCODE)
3172  s = "encode";
3173  else if (var == URI_WHITESPACE_CHOP)
3174  s = "chop";
3175  else if (var == URI_WHITESPACE_DENY)
3176  s = "deny";
3177  else
3178  s = "strip";
3179 
3180  storeAppendPrintf(entry, "%s %s\n", name, s);
3181 }
3182 
3183 static void
3185 {
3186  if (!*settings)
3187  return;
3188 
3189  free_string(&(*settings)->type);
3190 
3191  free_wordlist(&(*settings)->args);
3192 
3193  delete *settings;
3194 
3195  *settings = nullptr;
3196 }
3197 
3198 static void
3200 {
3201  if (*settings)
3202  free_removalpolicy(settings);
3203 
3204  *settings = new RemovalPolicySettings;
3205 
3206  parse_string(&(*settings)->type);
3207 
3208  parse_wordlist(&(*settings)->args);
3209 }
3210 
3211 static void
3212 dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
3213 {
3214  wordlist *args;
3215  storeAppendPrintf(entry, "%s %s", name, settings->type);
3216  args = settings->args;
3217 
3218  while (args) {
3219  storeAppendPrintf(entry, " %s", args->key);
3220  args = args->next;
3221  }
3222 
3223  storeAppendPrintf(entry, "\n");
3224 }
3225 
3226 inline void
3228 {}
3229 
3230 static void
3232 {
3233  int value = 0;
3234  parse_onoff(&value);
3235  option->configure(value > 0);
3236 }
3237 
3238 static void
3239 dump_YesNoNone(StoreEntry * entry, const char *name, YesNoNone &option)
3240 {
3241  if (option.configured())
3242  dump_onoff(entry, name, option ? 1 : 0);
3243 }
3244 
3245 static void
3247 {}
3248 
3249 static void
3251 {
3252  char *token = ConfigParser::NextToken();
3253  if (!token) {
3254  self_destruct();
3255  return;
3256  }
3257 
3258  if (strcmp(token, "always") == 0) {
3261  } else if (strcmp(token, "disk") == 0) {
3264  } else if (strncmp(token, "net", 3) == 0) {
3267  } else if (strcmp(token, "never") == 0) {
3270  } else {
3271  debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'memory_cache_mode' accepts 'always', 'disk', 'network', and 'never'.");
3272  self_destruct();
3273  }
3274 }
3275 
3276 static void
3277 dump_memcachemode(StoreEntry * entry, const char *name, SquidConfig &)
3278 {
3279  storeAppendPrintf(entry, "%s ", name);
3281  storeAppendPrintf(entry, "always");
3283  storeAppendPrintf(entry, "disk");
3285  storeAppendPrintf(entry, "network");
3287  storeAppendPrintf(entry, "none");
3288  storeAppendPrintf(entry, "\n");
3289 }
3290 
3291 #include "cf_parser.cci"
3292 
3293 peer_t
3294 parseNeighborType(const char *s)
3295 {
3296  if (!strcmp(s, "parent"))
3297  return PEER_PARENT;
3298 
3299  if (!strcmp(s, "neighbor"))
3300  return PEER_SIBLING;
3301 
3302  if (!strcmp(s, "neighbour"))
3303  return PEER_SIBLING;
3304 
3305  if (!strcmp(s, "sibling"))
3306  return PEER_SIBLING;
3307 
3308  if (!strcmp(s, "multicast"))
3309  return PEER_MULTICAST;
3310 
3311  debugs(15, DBG_CRITICAL, "WARNING: Unknown neighbor type: " << s);
3312 
3313  return PEER_SIBLING;
3314 }
3315 
3316 #if USE_WCCPv2
3317 static void
3319 {
3320  char *token;
3321  Ip::Address_list *s;
3322  Ip::Address ipa;
3323 
3324  while ((token = ConfigParser::NextToken())) {
3325  if (GetHostWithPort(token, &ipa)) {
3326 
3327  while (*head)
3328  head = &(*head)->next;
3329 
3330  s = static_cast<Ip::Address_list *>(xcalloc(1, sizeof(*s)));
3331  s->s = ipa;
3332 
3333  *head = s;
3334  } else {
3335  self_destruct();
3336  return;
3337  }
3338  }
3339 }
3340 
3341 static void
3342 dump_IpAddress_list(StoreEntry * e, const char *n, const Ip::Address_list * s)
3343 {
3344  char ntoabuf[MAX_IPSTRLEN];
3345 
3346  while (s) {
3347  storeAppendPrintf(e, "%s %s\n",
3348  n,
3349  s->s.toStr(ntoabuf,MAX_IPSTRLEN));
3350  s = s->next;
3351  }
3352 }
3353 
3354 static void
3356 {
3357  if (*head) delete *head;
3358  *head = nullptr;
3359 }
3360 
3361 #if CURRENTLY_UNUSED
3362 /* This code was previously used by http_port. Left as it really should
3363  * be used by icp_port and htcp_port
3364  */
3365 static int
3366 check_null_IpAddress_list(const Ip::Address_list * s)
3367 {
3368  return NULL == s;
3369 }
3370 
3371 #endif /* CURRENTLY_UNUSED */
3372 #endif /* USE_WCCPv2 */
3373 
3374 static void
3376 {
3377  char *host = nullptr;
3378  unsigned short port = 0;
3379  char *t = nullptr;
3380  char *junk = nullptr;
3381 
3382  s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3383  s->name = xstrdup(token);
3384  s->connection_auth_disabled = false;
3385 
3386  const SBuf &portType = AnyP::UriScheme(s->transport.protocol).image();
3387 
3388  if (*token == '[') {
3389  /* [ipv6]:port */
3390  host = token + 1;
3391  t = strchr(host, ']');
3392  if (!t) {
3393  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing ']' on IPv6 address: " << token);
3394  self_destruct();
3395  return;
3396  }
3397  *t = '\0';
3398  ++t;
3399  if (*t != ':') {
3400  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port in: " << token);
3401  self_destruct();
3402  return;
3403  }
3404  if (!Ip::EnableIpv6) {
3405  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: IPv6 is not available.");
3406  self_destruct();
3407  return;
3408  }
3409  port = xatos(t + 1);
3410  } else if ((t = strchr(token, ':'))) {
3411  /* host:port */
3412  /* ipv4:port */
3413  host = token;
3414  *t = '\0';
3415  port = xatos(t + 1);
3416 
3417  } else if (strtol(token, &junk, 10) && !*junk) {
3418  port = xatos(token);
3419  debugs(3, 3, portType << "_port: found Listen on Port: " << port);
3420  } else {
3421  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port: " << token);
3422  self_destruct();
3423  return;
3424  }
3425 
3426  if (port == 0 && host != nullptr) {
3427  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: Port cannot be 0: " << token);
3428  self_destruct();
3429  return;
3430  }
3431 
3432  if (nullptr == host) {
3433  s->s.setAnyAddr();
3434  s->s.port(port);
3435  if (!Ip::EnableIpv6)
3436  s->s.setIPv4();
3437  debugs(3, 3, portType << "_port: found Listen on wildcard address: *:" << s->s.port());
3438  } else if ( (s->s = host) ) { /* check/parse numeric IPA */
3439  s->s.port(port);
3440  if (!Ip::EnableIpv6)
3441  s->s.setIPv4();
3442  debugs(3, 3, portType << "_port: Listen on Host/IP: " << host << " --> " << s->s);
3443  } else if ( s->s.GetHostByName(host) ) { /* check/parse for FQDN */
3444  /* do not use ipcache */
3445  s->defaultsite = xstrdup(host);
3446  s->s.port(port);
3447  if (!Ip::EnableIpv6)
3448  s->s.setIPv4();
3449  debugs(3, 3, portType << "_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s);
3450  } else {
3451  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: failed to resolve Host/IP: " << host);
3452  self_destruct();
3453  }
3454 }
3455 
3459 static AnyP::ProtocolVersion
3461 {
3462  // HTTP/1.0 not supported because we are version 1.1 which contains a superset of 1.0
3463  // and RFC 2616 requires us to upgrade 1.0 to 1.1
3464  if (value.cmp("HTTP") == 0 || value.cmp("HTTP/1.1") == 0)
3465  return Http::ProtocolVersion(1,1);
3466 
3467  if (value.cmp("HTTPS") == 0 || value.cmp("HTTPS/1.1") == 0)
3469 
3470  if (value.cmp("FTP") == 0)
3471  return Ftp::ProtocolVersion();
3472 
3473  fatalf("%s directive does not support protocol=" SQUIDSBUFPH "\n", cfg_directive, SQUIDSBUFPRINT(value));
3474  return AnyP::ProtocolVersion(); // not reached
3475 }
3476 
3477 static void
3479 {
3480  /* modes first */
3481 
3482  if (strcmp(token, "accel") == 0) {
3483  if (s->flags.isIntercepted()) {
3484  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Accelerator mode requires its own port. It cannot be shared with other modes.");
3485  self_destruct();
3486  return;
3487  }
3488  s->flags.accelSurrogate = true;
3489  s->vhost = true;
3490  } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) {
3491  if (s->flags.accelSurrogate || s->flags.tproxyIntercept) {
3492  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Intercept mode requires its own interception port. It cannot be shared with other modes.");
3493  self_destruct();
3494  return;
3495  }
3496  s->flags.natIntercept = true;
3498  /* Log information regarding the port modes under interception. */
3499  debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s);
3500  debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (interception enabled)");
3501  } else if (strcmp(token, "tproxy") == 0) {
3502  if (s->flags.natIntercept || s->flags.accelSurrogate) {
3503  debugs(3,DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY option requires its own interception port. It cannot be shared with other modes.");
3504  self_destruct();
3505  return;
3506  }
3507  s->flags.tproxyIntercept = true;
3509  /* Log information regarding the port modes under transparency. */
3510  debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (TPROXY enabled)");
3511 
3512  if (s->flags.proxySurrogate) {
3513  debugs(3, DBG_IMPORTANT, "Disabling TPROXY Spoofing on port " << s->s << " (require-proxy-header enabled)");
3514  }
3515 
3516  if (!Ip::Interceptor.ProbeForTproxy(s->s)) {
3517  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY support in the system does not work.");
3518  self_destruct();
3519  return;
3520  }
3521 
3522  } else if (strcmp(token, "require-proxy-header") == 0) {
3523  s->flags.proxySurrogate = true;
3524  if (s->flags.tproxyIntercept) {
3525  // receiving is still permitted, so we do not unset the TPROXY flag
3526  // spoofing access control override takes care of the spoof disable later
3527  debugs(3, DBG_IMPORTANT, "Disabling TPROXY Spoofing on port " << s->s << " (require-proxy-header enabled)");
3528  }
3529 
3530  } else if (strncmp(token, "defaultsite=", 12) == 0) {
3531  if (!s->flags.accelSurrogate) {
3532  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": defaultsite option requires Acceleration mode flag.");
3533  self_destruct();
3534  return;
3535  }
3536  safe_free(s->defaultsite);
3537  s->defaultsite = xstrdup(token + 12);
3538  } else if (strcmp(token, "vhost") == 0) {
3539  if (!s->flags.accelSurrogate) {
3540  debugs(3, DBG_CRITICAL, "WARNING: " << cfg_directive << ": vhost option is deprecated. Use 'accel' mode flag instead.");
3541  }
3542  s->flags.accelSurrogate = true;
3543  s->vhost = true;
3544  } else if (strcmp(token, "no-vhost") == 0) {
3545  if (!s->flags.accelSurrogate) {
3546  debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": no-vhost option requires Acceleration mode flag.");
3547  }
3548  s->vhost = false;
3549  } else if (strcmp(token, "vport") == 0) {
3550  if (!s->flags.accelSurrogate) {
3551  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag.");
3552  self_destruct();
3553  return;
3554  }
3555  s->vport = -1;
3556  } else if (strncmp(token, "vport=", 6) == 0) {
3557  if (!s->flags.accelSurrogate) {
3558  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag.");
3559  self_destruct();
3560  return;
3561  }
3562  s->vport = xatos(token + 6);
3563  } else if (strncmp(token, "protocol=", 9) == 0) {
3564  if (!s->flags.accelSurrogate) {
3565  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": protocol option requires Acceleration mode flag.");
3566  self_destruct();
3567  return;
3568  }
3569  s->transport = parsePortProtocol(ToUpper(SBuf(token + 9)));
3570  } else if (strcmp(token, "allow-direct") == 0) {
3571  if (!s->flags.accelSurrogate) {
3572  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": allow-direct option requires Acceleration mode flag.");
3573  self_destruct();
3574  return;
3575  }
3576  s->allow_direct = true;
3577  } else if (strcmp(token, "act-as-origin") == 0) {
3578  if (!s->flags.accelSurrogate) {
3579  debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": act-as-origin option requires Acceleration mode flag.");
3580  } else
3581  s->actAsOrigin = true;
3582  } else if (strcmp(token, "ignore-cc") == 0) {
3583 #if !USE_HTTP_VIOLATIONS
3584  if (!s->flags.accelSurrogate) {
3585  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": ignore-cc option requires Acceleration mode flag.");
3586  self_destruct();
3587  return;
3588  }
3589 #endif
3590  s->ignore_cc = true;
3591  } else if (strncmp(token, "name=", 5) == 0) {
3592  safe_free(s->name);
3593  s->name = xstrdup(token + 5);
3594  } else if (strcmp(token, "no-connection-auth") == 0) {
3595  s->connection_auth_disabled = true;
3596  } else if (strcmp(token, "connection-auth=off") == 0) {
3597  s->connection_auth_disabled = true;
3598  } else if (strcmp(token, "connection-auth") == 0) {
3599  s->connection_auth_disabled = false;
3600  } else if (strcmp(token, "connection-auth=on") == 0) {
3601  s->connection_auth_disabled = false;
3602  } else if (strncmp(token, "disable-pmtu-discovery=", 23) == 0) {
3603  if (!strcmp(token + 23, "off"))
3604  s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3605  else if (!strcmp(token + 23, "transparent"))
3606  s->disable_pmtu_discovery = DISABLE_PMTU_TRANSPARENT;
3607  else if (!strcmp(token + 23, "always"))
3608  s->disable_pmtu_discovery = DISABLE_PMTU_ALWAYS;
3609  else {
3610  self_destruct();
3611  return;
3612  }
3613  } else if (strcmp(token, "ipv4") == 0) {
3614  if ( !s->s.setIPv4() ) {
3615  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": IPv6 addresses cannot be used as IPv4-Only. " << s->s );
3616  self_destruct();
3617  return;
3618  }
3619  } else if (strcmp(token, "tcpkeepalive") == 0) {
3620  s->tcp_keepalive.enabled = true;
3621  } else if (strncmp(token, "tcpkeepalive=", 13) == 0) {
3622  char *t = token + 13;
3623  s->tcp_keepalive.enabled = true;
3624  s->tcp_keepalive.idle = xatoui(t,',');
3625  t = strchr(t, ',');
3626  if (t) {
3627  ++t;
3628  s->tcp_keepalive.interval = xatoui(t,',');
3629  t = strchr(t, ',');
3630  }
3631  if (t) {
3632  ++t;
3633  s->tcp_keepalive.timeout = xatoui(t);
3634  }
3635 #if USE_OPENSSL
3636  } else if (strcmp(token, "sslBump") == 0) {
3637  debugs(3, DBG_PARSE_NOTE(1), "WARNING: '" << token << "' is deprecated " <<
3638  "in " << cfg_directive << ". Use 'ssl-bump' instead.");
3639  s->flags.tunnelSslBumping = true;
3640  } else if (strcmp(token, "ssl-bump") == 0) {
3641  s->flags.tunnelSslBumping = true;
3642  } else if (strncmp(token, "cert=", 5) == 0) {
3643  s->secure.parse(token);
3644  } else if (strncmp(token, "key=", 4) == 0) {
3645  s->secure.parse(token);
3646  } else if (strncmp(token, "version=", 8) == 0) {
3647  debugs(3, DBG_PARSE_NOTE(1), "WARNING: UPGRADE: '" << token << "' is deprecated " <<
3648  "in " << cfg_directive << ". Use 'options=' instead.");
3649  s->secure.parse(token);
3650  } else if (strncmp(token, "options=", 8) == 0) {
3651  s->secure.parse(token);
3652  } else if (strncmp(token, "cipher=", 7) == 0) {
3653  s->secure.parse(token);
3654  } else if (strncmp(token, "clientca=", 9) == 0) {
3655  s->secure.parse(token);
3656  } else if (strncmp(token, "cafile=", 7) == 0) {
3657  debugs(3, DBG_PARSE_NOTE(1), "WARNING: UPGRADE: '" << token << "' is deprecated " <<
3658  "in " << cfg_directive << ". Use 'tls-cafile=' instead.");
3659  s->secure.parse(token);
3660  } else if (strncmp(token, "capath=", 7) == 0) {
3661  s->secure.parse(token);
3662  } else if (strncmp(token, "crlfile=", 8) == 0) {
3663  s->secure.parse(token);
3664  } else if (strncmp(token, "dhparams=", 9) == 0) {
3665  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: '" << token << "' is deprecated " <<
3666  "in " << cfg_directive << ". Use 'tls-dh=' instead.");
3667  s->secure.parse(token);
3668  } else if (strncmp(token, "sslflags=", 9) == 0) {
3669  // NP: deprecation warnings output by secure.parse() when relevant
3670  s->secure.parse(token+3);
3671  } else if (strncmp(token, "sslcontext=", 11) == 0) {
3672  // NP: deprecation warnings output by secure.parse() when relevant
3673  s->secure.parse(token+3);
3674  } else if (strncmp(token, "generate-host-certificates", 26) == 0) {
3675  s->secure.parse(token);
3676 #endif
3677  } else if (strncmp(token, "dynamic_cert_mem_cache_size=", 28) == 0) {
3678  s->secure.parse(token);
3679  } else if (strncmp(token, "tls-", 4) == 0) {
3680  s->secure.parse(token+4);
3681  } else if (strcmp(token, "ftp-track-dirs") == 0) {
3682  s->ftp_track_dirs = true;
3683  } else if (strcmp(token, "worker-queues") == 0) {
3684 #if !defined(SO_REUSEADDR)
3685 #error missing system #include that #defines SO_* constants
3686 #endif
3687 #if !defined(SO_REUSEPORT)
3688  throw TexcHere(ToSBuf(cfg_directive, ' ', token, " option requires building Squid where SO_REUSEPORT is supported by the TCP stack"));
3689 #endif
3690  s->workerQueues = true;
3691  } else {
3692  debugs(3, DBG_CRITICAL, "FATAL: Unknown " << cfg_directive << " option '" << token << "'.");
3693  self_destruct();
3694  }
3695 }
3696 
3697 void
3698 add_http_port(char *portspec)
3699 {
3701  s->transport = parsePortProtocol(SBuf("HTTP"));
3702  parsePortSpecification(s, portspec);
3703  // we may need to merge better if the above returns a list with clones
3704  assert(s->next == nullptr);
3705  s->next = HttpPortList;
3706  HttpPortList = s;
3707 }
3708 
3709 static void
3710 parsePortCfg(AnyP::PortCfgPointer *head, const char *optionName)
3711 {
3712  SBuf protoName;
3713  if (strcmp(optionName, "http_port") == 0 ||
3714  strcmp(optionName, "ascii_port") == 0)
3715  protoName = "HTTP";
3716  else if (strcmp(optionName, "https_port") == 0)
3717  protoName = "HTTPS";
3718  else if (strcmp(optionName, "ftp_port") == 0)
3719  protoName = "FTP";
3720  if (protoName.isEmpty()) {
3721  self_destruct();
3722  return;
3723  }
3724 
3725  char *token = ConfigParser::NextToken();
3726 
3727  if (!token) {
3728  self_destruct();
3729  return;
3730  }
3731 
3733  s->transport = parsePortProtocol(protoName); // default; protocol=... overwrites
3734  parsePortSpecification(s, token);
3735 
3736  /* parse options ... */
3737  while ((token = ConfigParser::NextToken())) {
3738  parse_port_option(s, token);
3739  }
3740 
3741  s->secure.syncCaFiles();
3742 
3743  if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3744  s->secure.encryptTransport = true;
3745 #if USE_OPENSSL
3746  /* ssl-bump on https_port configuration requires either tproxy or intercept, and vice versa */
3747  const bool hijacked = s->flags.isIntercepted();
3748  if (s->flags.tunnelSslBumping && !hijacked) {
3749  debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercept which is missing.");
3750  self_destruct();
3751  return;
3752  }
3753  if (hijacked && !s->flags.tunnelSslBumping) {
3754  debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercept on https_port requires ssl-bump which is missing.");
3755  self_destruct();
3756  return;
3757  }
3758 #endif
3759  if (s->flags.proxySurrogate) {
3760  debugs(3,DBG_CRITICAL, "FATAL: https_port: require-proxy-header option is not supported on HTTPS ports.");
3761  self_destruct();
3762  return;
3763  }
3764  } else if (protoName.cmp("FTP") == 0) {
3765  /* ftp_port does not support ssl-bump */
3766  if (s->flags.tunnelSslBumping) {
3767  debugs(3, DBG_CRITICAL, "FATAL: ssl-bump is not supported for ftp_port.");
3768  self_destruct();
3769  return;
3770  }
3771  if (s->flags.proxySurrogate) {
3772  // Passive FTP data channel does not work without deep protocol inspection in the frontend.
3773  debugs(3,DBG_CRITICAL, "FATAL: require-proxy-header option is not supported on ftp_port.");
3774  self_destruct();
3775  return;
3776  }
3777  }
3778 
3779  if (s->secure.encryptTransport) {
3780  if (s->secure.certs.empty()) {
3781  debugs(3, DBG_CRITICAL, "FATAL: " << AnyP::UriScheme(s->transport.protocol) << "_port requires a cert= parameter");
3782  self_destruct();
3783  return;
3784  }
3785  s->secure.parseOptions();
3786  }
3787 
3788  // *_port line should now be fully valid so we can clone it if necessary
3789  if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.isAnyAddr()) {
3790  s->next = s->ipV4clone();
3791  }
3792 
3793  while (*head != nullptr)
3794  head = &((*head)->next);
3795 
3796  *head = s;
3797 }
3798 
3799 static void
3801 {
3802  char buf[MAX_IPSTRLEN];
3803 
3804  storeAppendPrintf(e, "%s %s",
3805  n,
3806  s->s.toUrl(buf,MAX_IPSTRLEN));
3807 
3808  // MODES and specific sub-options.
3809  if (s->flags.natIntercept)
3810  storeAppendPrintf(e, " intercept");
3811 
3812  else if (s->flags.tproxyIntercept)
3813  storeAppendPrintf(e, " tproxy");
3814 
3815  else if (s->flags.proxySurrogate)
3816  storeAppendPrintf(e, " require-proxy-header");
3817 
3818  else if (s->flags.accelSurrogate) {
3819  storeAppendPrintf(e, " accel");
3820 
3821  if (s->vhost)
3822  storeAppendPrintf(e, " vhost");
3823 
3824  if (s->vport < 0)
3825  storeAppendPrintf(e, " vport");
3826  else if (s->vport > 0)
3827  storeAppendPrintf(e, " vport=%d", s->vport);
3828 
3829  if (s->defaultsite)
3830  storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
3831 
3832  // TODO: compare against prefix of 'n' instead of assuming http_port
3833  if (s->transport.protocol != AnyP::PROTO_HTTP)
3834  storeAppendPrintf(e, " protocol=%s", AnyP::ProtocolType_str[s->transport.protocol]);
3835 
3836  if (s->allow_direct)
3837  storeAppendPrintf(e, " allow-direct");
3838 
3839  if (s->ignore_cc)
3840  storeAppendPrintf(e, " ignore-cc");
3841 
3842  }
3843 
3844  // Generic independent options
3845 
3846  if (s->name)
3847  storeAppendPrintf(e, " name=%s", s->name);
3848 
3849 #if USE_HTTP_VIOLATIONS
3850  if (!s->flags.accelSurrogate && s->ignore_cc)
3851  storeAppendPrintf(e, " ignore-cc");
3852 #endif
3853 
3854  if (s->connection_auth_disabled)
3855  storeAppendPrintf(e, " connection-auth=off");
3856  else
3857  storeAppendPrintf(e, " connection-auth=on");
3858 
3859  if (s->disable_pmtu_discovery != DISABLE_PMTU_OFF) {
3860  const char *pmtu;
3861 
3862  if (s->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)
3863  pmtu = "always";
3864  else
3865  pmtu = "transparent";
3866 
3867  storeAppendPrintf(e, " disable-pmtu-discovery=%s", pmtu);
3868  }
3869 
3870  if (s->s.isAnyAddr() && !s->s.isIPv6())
3871  storeAppendPrintf(e, " ipv4");
3872 
3873  if (s->tcp_keepalive.enabled) {
3874  if (s->tcp_keepalive.idle || s->tcp_keepalive.interval || s->tcp_keepalive.timeout) {
3875  storeAppendPrintf(e, " tcpkeepalive=%d,%d,%d", s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
3876  } else {
3877  storeAppendPrintf(e, " tcpkeepalive");
3878  }
3879  }
3880 
3881 #if USE_OPENSSL
3882  if (s->flags.tunnelSslBumping)
3883  storeAppendPrintf(e, " ssl-bump");
3884 #endif
3885 
3886  PackableStream os(*e);
3887  s->secure.dumpCfg(os, "tls-");
3888 }
3889 
3890 static void
3891 dump_PortCfg(StoreEntry * e, const char *n, const AnyP::PortCfgPointer &s)
3892 {
3893  for (AnyP::PortCfgPointer p = s; p != nullptr; p = p->next) {
3894  dump_generic_port(e, n, p);
3895  storeAppendPrintf(e, "\n");
3896  }
3897 }
3898 
3899 void
3901 {
3902  free_all();
3906  delete Config.ssl_client.sslContext_;
3907  Config.ssl_client.sslContext_ = nullptr;
3908 #if USE_OPENSSL
3910 #endif
3911 }
3912 
3913 void
3914 requirePathnameExists(const char *name, const char *path)
3915 {
3916 
3917  struct stat sb;
3918  char pathbuf[BUFSIZ];
3919  assert(path != nullptr);
3920 
3921  if (Config.chroot_dir && (geteuid() == 0)) {
3922  snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
3923  path = pathbuf;
3924  }
3925 
3926  if (stat(path, &sb) < 0) {
3927  int xerrno = errno;
3928  debugs(0, DBG_CRITICAL, (opt_parse_cfg_only?"FATAL: ":"ERROR: ") << name << " " << path << ": " << xstrerr(xerrno));
3929  // keep going to find more issues if we are only checking the config file with "-k parse"
3930  if (opt_parse_cfg_only)
3931  return;
3932  // this is fatal if it is found during startup or reconfigure
3933  if (opt_send_signal == -1 || opt_send_signal == SIGHUP)
3934  fatalf("%s %s: %s", name, path, xstrerr(xerrno));
3935  }
3936 }
3937 
3938 #include "AccessLogEntry.h"
3939 
3962 static void
3964 {
3965  const char *filename = ConfigParser::NextToken();
3966  if (!filename) {
3967  self_destruct();
3968  return;
3969  }
3970 
3971  const auto cl = new CustomLog();
3972 
3973  cl->filename = xstrdup(filename);
3974 
3975  if (strcmp(filename, "none") == 0) {
3976  cl->type = Log::Format::CLF_NONE;
3977  aclParseAclList(LegacyParser, &cl->aclList, filename);
3978  while (*logs)
3979  logs = &(*logs)->next;
3980  *logs = cl;
3981  return;
3982  }
3983 
3984  const char *token = ConfigParser::PeekAtToken();
3985  if (token && !strchr(token, '=')) { // style #3
3986  // TODO: Deprecate this style to avoid this dangerous guessing.
3987  if (Log::TheConfig.knownFormat(token)) {
3988  cl->setLogformat(token);
3989  (void)ConfigParser::NextToken(); // consume the token used above
3990  } else {
3991  // assume there is no explicit logformat name and use the default
3992  cl->setLogformat("squid");
3993  }
3994  } else { // style #1 or style #4
3995  // TODO: Drop deprecated style #1 support. We already warn about it, and
3996  // its exceptional treatment makes detecting "module" typos impractical!
3997  cl->parseOptions(LegacyParser, "squid");
3998  }
3999  assert(cl->type); // setLogformat() was called
4000 
4001  aclParseAclList(LegacyParser, &cl->aclList, cl->filename);
4002 
4003  while (*logs)
4004  logs = &(*logs)->next;
4005 
4006  *logs = cl;
4007 }
4008 
4009 static int
4010 check_null_access_log(CustomLog *customlog_definitions)
4011 {
4012  return customlog_definitions == nullptr;
4013 }
4014 
4015 static void
4016 dump_access_log(StoreEntry * entry, const char *name, CustomLog * logs)
4017 {
4018  assert(entry);
4019  for (auto log = logs; log; log = log->next) {
4020  {
4021  PackableStream os(*entry);
4022  os << name; // directive name
4023  os << ' ' << log->filename; // including "none"
4024  log->dumpOptions(os);
4025  }
4026 
4027  if (log->aclList)
4028  dump_acl_list(entry, log->aclList);
4029 
4030  storeAppendPrintf(entry, "\n");
4031  }
4032 }
4033 
4034 static void
4036 {
4037  while (*definitions) {
4038  CustomLog *log = *definitions;
4039  *definitions = log->next;
4040  delete log;
4041  }
4042 }
4043 
4044 #if HAVE_CPU_AFFINITY /* until somebody else needs this general code */
4045 static bool
4047 parseNamedIntList(const char *data, const String &name, std::vector<int> &list)
4048 {
4049  if (data && (strncmp(data, name.rawBuf(), name.size()) == 0)) {
4050  data += name.size();
4051  if (*data == '=') {
4052  while (true) {
4053  ++data;
4054  int value = 0;
4055  if (!StringToInt(data, value, &data, 10))
4056  break;
4057  list.push_back(value);
4058  if (*data == '\0' || *data != ',')
4059  break;
4060  }
4061  }
4062  }
4063  return data && *data == '\0';
4064 }
4065 #endif
4066 
4067 static void
4068 parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4069 {
4070 #if !HAVE_CPU_AFFINITY
4071  (void)cpuAffinityMap;
4072  debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " <<
4073  "support, do not set 'cpu_affinity_map'");
4074  self_destruct();
4075 
4076 #else /* HAVE_CPU_AFFINITY */
4077  if (!*cpuAffinityMap)
4078  *cpuAffinityMap = new CpuAffinityMap;
4079 
4080  const char *const pToken = ConfigParser::NextToken();
4081  const char *const cToken = ConfigParser::NextToken();
4082  std::vector<int> processes, cores;
4083  if (!parseNamedIntList(pToken, "process_numbers", processes)) {
4084  debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " <<
4085  "in 'cpu_affinity_map'");
4086  self_destruct();
4087  } else if (!parseNamedIntList(cToken, "cores", cores)) {
4088  debugs(3, DBG_CRITICAL, "FATAL: bad 'cores' parameter in " <<
4089  "'cpu_affinity_map'");
4090  self_destruct();
4091  } else if (!(*cpuAffinityMap)->add(processes, cores)) {
4092  debugs(3, DBG_CRITICAL, "FATAL: bad 'cpu_affinity_map'; " <<
4093  "process_numbers and cores lists differ in length or " <<
4094  "contain numbers <= 0");
4095  self_destruct();
4096  }
4097 #endif
4098 }
4099 
4100 static void
4101 dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap)
4102 {
4103  if (cpuAffinityMap) {
4104  storeAppendPrintf(entry, "%s process_numbers=", name);
4105  for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
4106  storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4107  cpuAffinityMap->processes()[i]);
4108  }
4109  storeAppendPrintf(entry, " cores=");
4110  for (size_t i = 0; i < cpuAffinityMap->cores().size(); ++i) {
4111  storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4112  cpuAffinityMap->cores()[i]);
4113  }
4114  storeAppendPrintf(entry, "\n");
4115  }
4116 }
4117 
4118 static void
4119 free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4120 {
4121  delete *cpuAffinityMap;
4122  *cpuAffinityMap = nullptr;
4123 }
4124 
4125 #if USE_ADAPTATION
4126 
4127 static void
4129 {
4131 }
4132 
4133 static void
4135 {
4137 }
4138 
4139 static void
4141 {
4143 }
4144 #endif /* USE_ADAPTATION */
4145 
4146 #if ICAP_CLIENT
4147 
4148 static void
4150 {
4151  cfg->parseService();
4152 }
4153 
4154 static void
4156 {
4157  cfg->freeService();
4158 }
4159 
4160 static void
4161 dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::Icap::Config &cfg)
4162 {
4163  cfg.dumpService(entry, name);
4164 }
4165 
4166 static void
4168 {
4169  debugs(93, DBG_CRITICAL, "WARNING: 'icap_class' is deprecated. " <<
4170  "Use 'adaptation_service_set' instead");
4172 }
4173 
4174 static void
4176 {
4177  debugs(93, DBG_CRITICAL, "WARNING: 'icap_access' is deprecated. " <<
4178  "Use 'adaptation_access' instead");
4180 }
4181 
4182 #endif
4183 
4184 #if USE_ECAP
4185 
4186 static void
4188 {
4189  cfg->parseService();
4190 }
4191 
4192 static void
4194 {
4195  cfg->freeService();
4196 }
4197 
4198 static void
4199 dump_ecap_service_type(StoreEntry * entry, const char *name, const Adaptation::Ecap::Config &cfg)
4200 {
4201  cfg.dumpService(entry, name);
4202 }
4203 
4204 #endif /* USE_ECAP */
4205 
4206 #if ICAP_CLIENT
4208 {
4209  char *token;
4211 
4212  if ((token = ConfigParser::NextToken()) == nullptr)
4213  return;
4214 
4215  if (strcmp(token,"in") != 0) {
4216  debugs(3, DBG_CRITICAL, "expecting 'in' on'" << config_input_line << "'");
4217  self_destruct();
4218  return;
4219  }
4220 
4222 }
4223 
4224 static void dump_icap_service_failure_limit(StoreEntry *entry, const char *name, const Adaptation::Icap::Config &cfg)
4225 {
4226  storeAppendPrintf(entry, "%s %d", name, cfg.service_failure_limit);
4227  if (cfg.oldest_service_failure > 0) {
4228  storeAppendPrintf(entry, " in %d seconds", (int)cfg.oldest_service_failure);
4229  }
4230  storeAppendPrintf(entry, "\n");
4231 }
4232 
4234 {
4235  cfg->oldest_service_failure = 0;
4236  cfg->service_failure_limit = 0;
4237 }
4238 #endif
4239 
4240 #if USE_OPENSSL
4242 {
4243  auto *al = ConfigParser::NextToken();
4244  if (!al) {
4245  self_destruct();
4246  return;
4247  }
4248 
4249  const char *param;
4250  if ( char *s = strchr(al, '{')) {
4251  *s = '\0'; // terminate the al string
4252  ++s;
4253  param = s;
4254  s = strchr(s, '}');
4255  if (!s) {
4256  self_destruct();
4257  return;
4258  }
4259  *s = '\0';
4260  } else
4261  param = nullptr;
4262 
4263  std::unique_ptr<sslproxy_cert_adapt> ca(new sslproxy_cert_adapt);
4264  if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidAfter]) == 0) {
4265  ca->alg = Ssl::algSetValidAfter;
4266  ca->param = xstrdup("on");
4267  } else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidBefore]) == 0) {
4269  ca->param = xstrdup("on");
4270  } else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetCommonName]) == 0) {
4271  ca->alg = Ssl::algSetCommonName;
4272  if (param) {
4273  if (strlen(param) > 64) {
4274  debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: setCommonName{" <<param << "} : using common name longer than 64 bytes is not supported");
4275  self_destruct();
4276  return;
4277  }
4278  ca->param = xstrdup(param);
4279  }
4280  } else {
4281  debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: unknown cert adaptation algorithm: " << al);
4282  self_destruct();
4283  return;
4284  }
4285 
4287 
4288  while (*cert_adapt)
4289  cert_adapt = &(*cert_adapt)->next;
4290 
4291  *cert_adapt = ca.release();
4292 }
4293 
4294 static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt)
4295 {
4296  for (const auto *ca = cert_adapt; ca; ca = ca->next) {
4297  storeAppendPrintf(entry, "%s ", name);
4298  storeAppendPrintf(entry, "%s{%s} ", Ssl::sslCertAdaptAlgoritm(ca->alg), ca->param);
4299  if (ca->aclList)
4300  dump_acl_list(entry, ca->aclList);
4301  storeAppendPrintf(entry, "\n");
4302  }
4303 }
4304 
4306 {
4307  delete *cert_adapt;
4308  *cert_adapt = nullptr;
4309 }
4310 
4312 {
4313  const auto al = ConfigParser::NextToken();
4314  if (!al) {
4315  self_destruct();
4316  return;
4317  }
4318 
4319  std::unique_ptr<sslproxy_cert_sign> cs(new sslproxy_cert_sign);
4320  if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignTrusted]) == 0)
4321  cs->alg = Ssl::algSignTrusted;
4322  else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignUntrusted]) == 0)
4323  cs->alg = Ssl::algSignUntrusted;
4324  else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignSelf]) == 0)
4325  cs->alg = Ssl::algSignSelf;
4326  else {
4327  debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_sign: unknown cert signing algorithm: " << al);
4328  self_destruct();
4329  return;
4330  }
4331 
4333 
4334  while (*cert_sign)
4335  cert_sign = &(*cert_sign)->next;
4336 
4337  *cert_sign = cs.release();
4338 }
4339 
4340 static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign)
4341 {
4342  for (const auto *cs = cert_sign; cs; cs = cs->next) {
4343  storeAppendPrintf(entry, "%s ", name);
4344  storeAppendPrintf(entry, "%s ", Ssl::certSignAlgorithm(cs->alg));
4345  if (cs->aclList)
4346  dump_acl_list(entry, cs->aclList);
4347  storeAppendPrintf(entry, "\n");
4348  }
4349 }
4350 
4352 {
4353  delete *cert_sign;
4354  *cert_sign = nullptr;
4355 }
4356 
4358 {
4359 public:
4361  /* RegisteredRunner API */
4362  void finalizeConfig() override;
4363 };
4364 
4366 
4368 
4369 void
4371 {
4374  static char buf[1024];
4376  strcpy(buf, "ssl_bump deny all");
4377  debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated implicit "
4378  "\"ssl_bump deny all\" to \"ssl_bump none all\". New ssl_bump configurations "
4379  "must not use implicit rules. Update your ssl_bump rules.");
4380  } else {
4381  strcpy(buf, "ssl_bump allow all");
4382  debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated implicit "
4383  "\"ssl_bump allow all\" to \"ssl_bump client-first all\" which is usually "
4384  "inferior to the newer server-first bumping mode. New ssl_bump"
4385  " configurations must not use implicit rules. Update your ssl_bump rules.");
4386  }
4387  parse_line(buf);
4388  }
4389 }
4390 
4391 static void parse_sslproxy_ssl_bump(acl_access **ssl_bump)
4392 {
4393  typedef const char *BumpCfgStyle;
4394  BumpCfgStyle bcsNone = nullptr;
4395  BumpCfgStyle bcsNew = "new client/server-first/none";
4396  BumpCfgStyle bcsOld = "deprecated allow/deny";
4397  static BumpCfgStyle bumpCfgStyleLast = bcsNone;
4398  BumpCfgStyle bumpCfgStyleNow = bcsNone;
4399  char *bm;
4400  if ((bm = ConfigParser::NextToken()) == nullptr) {
4401  self_destruct();
4402  return;
4403  }
4404 
4405  // if this is the first rule processed
4406  if (*ssl_bump == nullptr) {
4407  bumpCfgStyleLast = bcsNone;
4409  }
4410 
4411  auto action = Acl::Answer(ACCESS_ALLOWED);
4412 
4413  if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0) {
4414  action.kind = Ssl::bumpClientFirst;
4415  bumpCfgStyleNow = bcsNew;
4416  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0) {
4417  action.kind = Ssl::bumpServerFirst;
4418  bumpCfgStyleNow = bcsNew;
4419  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpPeek]) == 0) {
4420  action.kind = Ssl::bumpPeek;
4421  bumpCfgStyleNow = bcsNew;
4422  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpStare]) == 0) {
4423  action.kind = Ssl::bumpStare;
4424  bumpCfgStyleNow = bcsNew;
4425  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpSplice]) == 0) {
4426  action.kind = Ssl::bumpSplice;
4427  bumpCfgStyleNow = bcsNew;
4428  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpBump]) == 0) {
4429  action.kind = Ssl::bumpBump;
4430  bumpCfgStyleNow = bcsNew;
4431  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpTerminate]) == 0) {
4432  action.kind = Ssl::bumpTerminate;
4433  bumpCfgStyleNow = bcsNew;
4434  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpNone]) == 0) {
4435  action.kind = Ssl::bumpNone;
4436  bumpCfgStyleNow = bcsNew;
4437  } else if (strcmp(bm, "allow") == 0) {
4438  debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated "
4439  "\"ssl_bump allow <acl>\" to \"ssl_bump client-first <acl>\" which "
4440  "is usually inferior to the newer server-first "
4441  "bumping mode. Update your ssl_bump rules.");
4442  action.kind = Ssl::bumpClientFirst;
4443  bumpCfgStyleNow = bcsOld;
4445  } else if (strcmp(bm, "deny") == 0) {
4446  debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated "
4447  "\"ssl_bump deny <acl>\" to \"ssl_bump none <acl>\". Update "
4448  "your ssl_bump rules.");
4449  action.kind = Ssl::bumpNone;
4450  bumpCfgStyleNow = bcsOld;
4452  } else {
4453  debugs(3, DBG_CRITICAL, "FATAL: unknown ssl_bump mode: " << bm);
4454  self_destruct();
4455  return;
4456  }
4457 
4458  if (bumpCfgStyleLast != bcsNone && bumpCfgStyleNow != bumpCfgStyleLast) {
4459  debugs(3, DBG_CRITICAL, "FATAL: do not mix " << bumpCfgStyleNow << " actions with " <<
4460  bumpCfgStyleLast << " actions. Update your ssl_bump rules.");
4461  self_destruct();
4462  return;
4463  }
4464 
4465  bumpCfgStyleLast = bumpCfgStyleNow;
4466 
4467  // empty rule OK
4468  ParseAclWithAction(ssl_bump, action, "ssl_bump");
4469 }
4470 
4471 static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump)
4472 {
4473  if (ssl_bump)
4474  dump_SBufList(entry, ToTree(ssl_bump).treeDump(name, [](const Acl::Answer &action) {
4475  return Ssl::BumpModeStr.at(action.kind);
4476  }));
4477 }
4478 
4479 static void free_sslproxy_ssl_bump(acl_access **ssl_bump)
4480 {
4481  free_acl_access(ssl_bump);
4482 }
4483 
4484 #endif
4485 
4486 static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers)
4487 {
4488  if (!headers)
4489  return;
4490 
4491  for (HeaderWithAclList::iterator hwa = headers->begin(); hwa != headers->end(); ++hwa) {
4492  storeAppendPrintf(entry, "%s %s %s", name, hwa->fieldName.c_str(), hwa->fieldValue.c_str());
4493  if (hwa->aclList)
4494  dump_acl_list(entry, hwa->aclList);
4495  storeAppendPrintf(entry, "\n");
4496  }
4497 }
4498 
4500 {
4501  char *fn;
4502  if (!*headers) {
4503  *headers = new HeaderWithAclList;
4504  }
4505  if ((fn = ConfigParser::NextToken()) == nullptr) {
4506  self_destruct();
4507  return;
4508  }
4509  HeaderWithAcl hwa;
4510  hwa.fieldName = fn;
4512  if (hwa.fieldId == Http::HdrType::BAD_HDR)
4514 
4515  Format::Format *nlf = new ::Format::Format("hdrWithAcl");
4519  hwa.fieldValue = buf.termedBuf();
4521  if (hwa.quoted) {
4522  if (!nlf->parse(hwa.fieldValue.c_str())) {
4523  self_destruct();
4524  return;
4525  }
4526  hwa.valueFormat = nlf;
4527  } else
4528  delete nlf;
4529  aclParseAclList(LegacyParser, &hwa.aclList, (hwa.fieldName + ':' + hwa.fieldValue).c_str());
4530  (*headers)->push_back(hwa);
4531 }
4532 
4534 {
4535  if (!(*header))
4536  return;
4537 
4538  for (HeaderWithAclList::iterator hwa = (*header)->begin(); hwa != (*header)->end(); ++hwa) {
4539  if (hwa->aclList)
4540  aclDestroyAclList(&hwa->aclList);
4541 
4542  if (hwa->valueFormat) {
4543  delete hwa->valueFormat;
4544  hwa->valueFormat = nullptr;
4545  }
4546  }
4547  delete *header;
4548  *header = nullptr;
4549 }
4550 
4551 static void parse_note(Notes *notes)
4552 {
4553  assert(notes);
4554  notes->parse(LegacyParser);
4555 }
4556 
4557 static void dump_note(StoreEntry *entry, const char *name, Notes &notes)
4558 {
4559  notes.printAsNoteDirectives(entry, name);
4560 }
4561 
4562 static void free_note(Notes *notes)
4563 {
4564  notes->clean();
4565 }
4566 
4567 static DebugMessageId ParseDebugMessageId(const char *value, const char eov)
4568 {
4569  const auto id = xatoui(value, eov);
4570  if (!(0 < id && id < DebugMessageIdUpperBound))
4571  throw TextException(ToSBuf("unknown cache_log_message ID: ", value), Here());
4572  return static_cast<DebugMessageId>(id);
4573 }
4574 
4575 static void parse_cache_log_message(DebugMessages **debugMessages)
4576 {
4577  DebugMessage msg;
4578  DebugMessageId minId = 0;
4579  DebugMessageId maxId = 0;
4580 
4581  char *key = nullptr;
4582  char *value = nullptr;
4583  while (ConfigParser::NextKvPair(key, value)) {
4584  if (strcmp(key, "id") == 0) {
4585  if (minId > 0)
4586  break;
4587  minId = maxId = ParseDebugMessageId(value, '\0');
4588  } else if (strcmp(key, "ids") == 0) {
4589  if (minId > 0)
4590  break;
4591  const auto dash = strchr(value, '-');
4592  if (!dash)
4593  throw TextException(ToSBuf("malformed cache_log_message ID range: ", key, '=', value), Here());
4594  minId = ParseDebugMessageId(value, '-');
4595  maxId = ParseDebugMessageId(dash+1, '\0');
4596  if (minId > maxId)
4597  throw TextException(ToSBuf("invalid cache_log_message ID range: ", key, '=', value), Here());
4598  } else if (strcmp(key, "level") == 0) {
4599  if (msg.levelled())
4600  break;
4601  const auto level = xatoi(value);
4602  if (level < 0)
4603  throw TextException(ToSBuf("negative cache_log_message level: ", value), Here());
4604  msg.level = level;
4605  } else if (strcmp(key, "limit") == 0) {
4606  if (msg.limited())
4607  break;
4608  msg.limit = xatoull(value, 10);
4609  } else {
4610  throw TextException(ToSBuf("unsupported cache_log_message option: ", key), Here());
4611  }
4612  key = value = nullptr;
4613  }
4614 
4615  if (key && value)
4616  throw TextException(ToSBuf("repeated or conflicting cache_log_message option: ", key, '=', value), Here());
4617 
4618  if (!minId)
4619  throw TextException("cache_log_message is missing a required id=... or ids=... option", Here());
4620 
4621  if (!(msg.levelled() || msg.limited()))
4622  throw TextException("cache_log_message is missing a required level=... or limit=... option", Here());
4623 
4624  assert(debugMessages);
4625  if (!*debugMessages)
4626  *debugMessages = new DebugMessages();
4627 
4628  for (auto id = minId; id <= maxId; ++id) {
4629  msg.id = id;
4630  (*debugMessages)->messages.at(id) = msg;
4631  }
4632 }
4633 
4634 static void dump_cache_log_message(StoreEntry *entry, const char *name, const DebugMessages *debugMessages)
4635 {
4636  if (!debugMessages)
4637  return;
4638 
4639  SBufStream out;
4640  for (const auto &msg: debugMessages->messages) {
4641  if (!msg.configured())
4642  continue;
4643  out << name << " id=" << msg.id;
4644  if (msg.levelled())
4645  out << " level=" << msg.level;
4646  if (msg.limited())
4647  out << " limit=" << msg.limit;
4648  out << "\n";
4649  }
4650  const auto buf = out.buf();
4651  entry->append(buf.rawContent(), buf.length()); // may be empty
4652 }
4653 
4654 static void free_cache_log_message(DebugMessages **debugMessages)
4655 {
4656  // clear old messages to avoid cumulative effect across (re)configurations
4657  assert(debugMessages);
4658  delete *debugMessages;
4659  *debugMessages = nullptr;
4660 }
4661 
4662 static bool FtpEspvDeprecated = false;
4663 static void parse_ftp_epsv(acl_access **ftp_epsv)
4664 {
4665  Acl::Answer ftpEpsvDeprecatedAction;
4666  bool ftpEpsvIsDeprecatedRule = false;
4667 
4668  char *t = ConfigParser::PeekAtToken();
4669  if (!t) {
4670  self_destruct();
4671  return;
4672  }
4673 
4674  if (!strcmp(t, "off")) {
4675  (void)ConfigParser::NextToken();
4676  ftpEpsvIsDeprecatedRule = true;
4677  ftpEpsvDeprecatedAction = Acl::Answer(ACCESS_DENIED);
4678  } else if (!strcmp(t, "on")) {
4679  (void)ConfigParser::NextToken();
4680  ftpEpsvIsDeprecatedRule = true;
4681  ftpEpsvDeprecatedAction = Acl::Answer(ACCESS_ALLOWED);
4682  }
4683 
4684  // Check for mixing "ftp_epsv on|off" and "ftp_epsv allow|deny .." rules:
4685  // 1) if this line is "ftp_epsv allow|deny ..." and already exist rules of "ftp_epsv on|off"
4686  // 2) if this line is "ftp_epsv on|off" and already exist rules of "ftp_epsv allow|deny ..."
4687  // then abort
4688  if ((!ftpEpsvIsDeprecatedRule && FtpEspvDeprecated) ||
4689  (ftpEpsvIsDeprecatedRule && !FtpEspvDeprecated && *ftp_epsv != nullptr)) {
4690  debugs(3, DBG_CRITICAL, "FATAL: do not mix \"ftp_epsv on|off\" cfg lines with \"ftp_epsv allow|deny ...\" cfg lines. Update your ftp_epsv rules.");
4691  self_destruct();
4692  return;
4693  }
4694 
4695  if (ftpEpsvIsDeprecatedRule) {
4696  // overwrite previous ftp_epsv lines
4697  delete *ftp_epsv;
4698  *ftp_epsv = nullptr;
4699 
4700  if (ftpEpsvDeprecatedAction == Acl::Answer(ACCESS_DENIED)) {
4701  static const auto all = new SBuf("all");
4702  if (const auto a = Acl::Node::FindByName(*all))
4703  ParseAclWithAction(ftp_epsv, ftpEpsvDeprecatedAction, "ftp_epsv", a);
4704  else {
4705  self_destruct();
4706  return;
4707  }
4708  }
4709  FtpEspvDeprecated = true;
4710  } else {
4712  }
4713 }
4714 
4715 static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv)
4716 {
4717  if (ftp_epsv)
4718  dump_SBufList(entry, ToTree(ftp_epsv).treeDump(name, Acl::AllowOrDeny));
4719 }
4720 
4721 static void free_ftp_epsv(acl_access **ftp_epsv)
4722 {
4723  free_acl_access(ftp_epsv);
4724  FtpEspvDeprecated = false;
4725 }
4726 
4729 static std::chrono::seconds
4731 {
4732  const auto timeValueToken = ConfigParser::NextToken();
4733  if (!timeValueToken)
4734  throw TexcHere("cannot read a time value");
4735 
4736  using Seconds = std::chrono::seconds;
4737 
4738  const auto parsedTimeValue = xatof(timeValueToken);
4739 
4740  if (parsedTimeValue == 0)
4741  return std::chrono::seconds::zero();
4742 
4743  std::chrono::nanoseconds parsedUnitDuration;
4744 
4745  const auto unitToken = ConfigParser::PeekAtToken();
4746  if (parseTimeUnit<Seconds>(unitToken, parsedUnitDuration))
4747  (void)ConfigParser::NextToken();
4748  else {
4749  const auto defaultParsed = parseTimeUnit<Seconds>(T_SECOND_STR, parsedUnitDuration);
4750  assert(defaultParsed);
4752  ": WARNING: missing time unit, using deprecated default '" << T_SECOND_STR << "'");
4753  }
4754 
4755  const auto nanoseconds = ToNanoSeconds(parsedTimeValue, parsedUnitDuration);
4756 
4757  return FromNanoseconds<Seconds>(nanoseconds, parsedTimeValue);
4758 }
4759 
4760 static void
4762 {
4763  // TODO: do not allow optional timeunit (as the documentation prescribes)
4764  // and use parseTimeLine() instead.
4766 
4767  char *key, *value;
4768  while(ConfigParser::NextKvPair(key, value)) {
4769  if (strcasecmp(key, "on_timeout") == 0) {
4770  if (strcasecmp(value, "bypass") == 0)
4771  config->action = toutActBypass;
4772  else if (strcasecmp(value, "fail") == 0)
4773  config->action = toutActFail;
4774  else if (strcasecmp(value, "retry") == 0)
4775  config->action = toutActRetry;
4776  else if (strcasecmp(value, "use_configured_response") == 0) {
4778  } else {
4779  debugs(3, DBG_CRITICAL, "FATAL: unsupported \"on_timeout\" action: " << value);
4780  self_destruct();
4781  return;
4782  }
4783  } else if (strcasecmp(key, "response") == 0) {
4784  config->response = xstrdup(value);
4785  } else {
4786  debugs(3, DBG_CRITICAL, "FATAL: unsupported option " << key);
4787  self_destruct();
4788  return;
4789  }
4790  }
4791 
4792  if (config->action == toutActUseConfiguredResponse && !config->response) {
4793  debugs(3, DBG_CRITICAL, "FATAL: Expected 'response=' option after 'on_timeout=use_configured_response' option");
4794  self_destruct();
4795  }
4796 
4797  if (config->action != toutActUseConfiguredResponse && config->response) {
4798  debugs(3, DBG_CRITICAL, "FATAL: 'response=' option is valid only when used with the 'on_timeout=use_configured_response' option");
4799  self_destruct();
4800  }
4801 }
4802 
4803 static void
4805 {
4806  const char *onTimedOutActions[] = {"bypass", "fail", "retry", "use_configured_response"};
4807  assert(config.action >= 0 && config.action <= toutActUseConfiguredResponse);
4808 
4809  dump_time_t(entry, name, Config.Timeout.urlRewrite);
4810  storeAppendPrintf(entry, " on_timeout=%s", onTimedOutActions[config.action]);
4811 
4812  if (config.response)
4813  storeAppendPrintf(entry, " response=\"%s\"", config.response);
4814 
4815  storeAppendPrintf(entry, "\n");
4816 }
4817 
4818 static void
4820 {
4822  config->action = 0;
4823  safe_free(config->response);
4824 }
4825 
4826 static void
4828 {
4829  int val = 0;
4830  parse_onoff(&val);
4831 
4832  // If quoted values is set to on then enable new strict mode parsing
4833  if (val) {
4835  ConfigParser::StrictMode = true;
4836  } else {
4838  ConfigParser::StrictMode = false;
4839  }
4840 }
4841 
4842 static void
4843 dump_configuration_includes_quoted_values(StoreEntry *const entry, const char *const name, bool)
4844 {
4845  int val = ConfigParser::RecognizeQuotedValues ? 1 : 0;
4846  dump_onoff(entry, name, val);
4847 }
4848 
4849 static void
4851 {
4853  ConfigParser::StrictMode = false;
4854 }
4855 
4856 static void
4858 {
4859  char *tm;
4860  if ((tm = ConfigParser::NextToken()) == nullptr) {
4861  self_destruct();
4862  return;
4863  }
4864 
4865  auto action = Acl::Answer(ACCESS_ALLOWED);
4866  if (strcmp(tm, "tunnel") == 0)
4867  action.kind = 1;
4868  else if (strcmp(tm, "respond") == 0)
4869  action.kind = 2;
4870  else {
4871  debugs(3, DBG_CRITICAL, "FATAL: unknown on_unsupported_protocol mode: " << tm);
4872  self_destruct();
4873  return;
4874  }
4875 
4876  // empty rule OK
4877  ParseAclWithAction(access, action, "on_unsupported_protocol");
4878 }
4879 
4880 static void
4881 dump_on_unsupported_protocol(StoreEntry *entry, const char *name, acl_access *access)
4882 {
4883  static const std::vector<const char *> onErrorTunnelMode = {
4884  "none",
4885  "tunnel",
4886  "respond"
4887  };
4888  if (access) {
4889  const auto lines = ToTree(access).treeDump(name, [](const Acl::Answer &action) {
4890  return onErrorTunnelMode.at(action.kind);
4891  });
4892  dump_SBufList(entry, lines);
4893  }
4894 }
4895 
4896 static void
4898 {
4899  free_acl_access(access);
4900 }
4901 
4902 static void
4904 {
4905  assert(protoGuardsPtr);
4906  auto &protoGuards = *protoGuardsPtr;
4907  if (!protoGuards)
4908  protoGuards = new HttpUpgradeProtocolAccess();
4909  protoGuards->configureGuard(LegacyParser);
4910 }
4911 
4912 static void
4914 {
4915  if (!protoGuards)
4916  return;
4917 
4918  const SBuf name(rawName);
4919  protoGuards->forEach([entry,&name](const SBuf &proto, const acl_access *acls) {
4920  SBufList line;
4921  line.push_back(name);
4922  line.push_back(proto);
4923  const auto acld = ToTree(acls).treeDump("", &Acl::AllowOrDeny);
4924  line.insert(line.end(), acld.begin(), acld.end());
4925  dump_SBufList(entry, line);
4926  });
4927 }
4928 
4929 static void
4931 {
4932  assert(protoGuardsPtr);
4933  auto &protoGuards = *protoGuardsPtr;
4934  delete protoGuards;
4935  protoGuards = nullptr;
4936 }
4937 
static void parse_peer(CachePeers **peers)
Definition: cache_cf.cc:2150
char * errorDirectory
Definition: SquidConfig.h:429
static peer_t parseNeighborType(const char *s)
Definition: cache_cf.cc:3294
acl_access * access_list
static void parse_http_header_access(HeaderManglers **manglers)
Definition: cache_cf.cc:1837
static void dump_wordlist(StoreEntry *entry, const char *name, wordlist *list)
Definition: cache_cf.cc:3107
void fatal(const char *message)
Definition: fatal.cc:28
const char * xstrerr(int error)
Definition: xstrerror.cc:83
#define URI_WHITESPACE_ENCODE
Definition: defines.h:126
@ bumpPeek
Definition: support.h:132
static void parse_adaptation_access_type()
Definition: cache_cf.cc:4140
static void dump_access_log(StoreEntry *entry, const char *name, CustomLog *definitions)
Definition: cache_cf.cc:4016
void parse_int(int *var)
Definition: cache_cf.cc:2528
static const char * FindStatement(const char *line, const char *statement)
Definition: cache_cf.cc:388
struct SquidConfig::@84 Accel
static void parsePortSpecification(const AnyP::PortCfgPointer &s, char *token)
Definition: cache_cf.cc:3375
static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &)
Definition: cache_cf.cc:4161
static void dump_time_msec(StoreEntry *entry, const char *name, time_msec_t var)
Definition: cache_cf.cc:2956
@ PEER_MULTICAST
Definition: enums.h:26
virtual bool active() const =0
static void ParseAccess(ConfigParser &parser)
Definition: Config.cc:284
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:71
#define Here()
source code location of the caller
Definition: Here.h:15
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
static std::chrono::nanoseconds ToNanoSeconds(const double value, const std::chrono::nanoseconds &unit)
Definition: cache_cf.cc:1172
struct SquidConfig::@93 icons
static SBuf CurrentLocation()
std::list< HeaderWithAcl > HeaderWithAclList
static void parse_TokenOrQuotedString(char **var)
Definition: cache_cf.cc:2916
void DumpNamedAcls(std::ostream &, const char *directiveName, NamedAcls *)
report the given list of "acl" directives (using squid.conf syntax)
Definition: Acl.cc:335
int opt_send_signal
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
#define DBG_CRITICAL
Definition: Stream.h:37
const char * rawBuf() const
Definition: SquidString.h:87
#define BUFSIZ
Definition: defines.h:20
ACLList * aclList
Definition: QosConfig.h:41
static const char * peer_type_str(const peer_t type)
Definition: cache_cf.cc:2029
const char * uniqueHostname(void)
Definition: tools.cc:548
static void free_int(int *var)
Definition: cache_cf.cc:2536
static size_t parseBytesUnits(const char *unit)
Definition: cache_cf.cc:1415
static char * NextQuotedToken()
static void parse_icap_service_type(Adaptation::Icap::Config *)
Definition: cache_cf.cc:4149
static void parse_u_short(unsigned short *var)
Definition: cache_cf.cc:3082
CustomLog * icaplogs
Definition: SquidConfig.h:188
#define xmalloc
static void free_acl_tos(acl_tos **head)
Definition: cache_cf.cc:1645
struct squidaio_request_t * next
Definition: aiops.cc:53
#define URI_WHITESPACE_STRIP
Definition: defines.h:124
bool xstrtoui(const char *s, char **end, unsigned int *value, unsigned int min, unsigned int max)
Definition: xstrto.cc:86
static T Parse(ConfigParser &)
creates a new T instance using the given parser; never returns nil
static void dump_tristate(StoreEntry *entry, const char *name, int var)
Definition: cache_cf.cc:2595
static void parse_http_upgrade_request_protocols(HttpUpgradeProtocolAccess **protoGuards)
Definition: cache_cf.cc:4903
std::shared_ptr< SSL_CTX > ContextPointer
Definition: Context.h:29
static void parse_acl(Acl::NamedAcls **config)
Definition: cache_cf.cc:1478
void parsePoolClass()
Definition: DelayConfig.cc:31
static void dump_time_nanoseconds(StoreEntry *entry, const char *name, const std::chrono::nanoseconds &var)
Definition: cache_cf.cc:2978
static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
Definition: cache_cf.cc:4119
char * unlinkd
Definition: SquidConfig.h:205
static void parse_ecap_service_type(Adaptation::Ecap::Config *)
Definition: cache_cf.cc:4187
static void parse_delay_pool_class(DelayConfig *cfg)
Definition: cache_cf.cc:1767
#define URI_WHITESPACE_CHOP
Definition: defines.h:127
void useSquidUntrusted(SSL_CTX *sslContext)
Definition: support.cc:1441
Security::ContextPointer createClientContext(bool setOptions)
generate a security client-context from these configured options
Definition: PeerOptions.cc:276
static void dump_kb_int64_t(StoreEntry *entry, const char *name, int64_t var)
Definition: cache_cf.cc:3015
static int parseManyConfigFiles(char *files, int depth)
Definition: cache_cf.cc:311
static ConfigParser LegacyParser
Definition: cache_cf.cc:267
double GetPercentage(bool limit)
Definition: Parsing.cc:178
static int parse_line(char *)
AnyP::ProtocolVersion ProtocolVersion()
Protocol version to use in Http::Message structures wrapping FTP messages.
Definition: Elements.cc:24
static void free_removalpolicy(RemovalPolicySettings **settings)
Definition: cache_cf.cc:3184
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:62
static const char *const T_HOUR_STR
Definition: cache_cf.cc:148
static void parse_kb_int64_t(int64_t *var)
Definition: cache_cf.cc:3039
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:22
static int check_null_acl_access(acl_access *a)
Definition: cache_cf.cc:3130
static void parse_refreshpattern(RefreshPattern **)
Definition: cache_cf.cc:2709
static void parse_address(Ip::Address *addr)
Definition: cache_cf.cc:1525
int memory_cache_first
Definition: SquidConfig.h:335
static void parse_acl_tos(acl_tos **head)
Definition: cache_cf.cc:1610
SBuf TheKidName
current Squid process name (e.g., "squid-coord")
Definition: Kids.cc:19
void log(char *format,...)
bool isEmpty() const
Definition: SBuf.h:435
static void free_acl_access(acl_access **head)
Definition: cache_cf.cc:1512
static void free_cachemgrpasswd(Mgr::ActionPasswordList **head)
Definition: cache_cf.cc:2455
representation of a class of Size-limit ACLs
Definition: AclSizeLimit.h:16
static void parse_pipelinePrefetch(int *var)
Definition: cache_cf.cc:2639
ACLList * aclList
Definition: QosConfig.h:55
int KidIdentifier
void append(char const *, int) override
Appends a c-string to existing packed data.
Definition: store.cc:803
static void EnableMacros()
Allow macros inside quoted strings.
Definition: ConfigParser.h:144
static int check_null_string(char *s)
Definition: cache_cf.cc:1903
static void dump_acl(StoreEntry *entry, const char *directiveName, Acl::NamedAcls *config)
Definition: cache_cf.cc:1471
#define O_TEXT
Definition: defines.h:131
std::list< SBuf > SBufList
Definition: forward.h:22
static void trim_trailing_ws(char *str)
Definition: cache_cf.cc:378
static void parse_acl_access(acl_access **head)
Definition: cache_cf.cc:1506
static void free_sslproxy_ssl_bump(acl_access **ssl_bump)
Definition: cache_cf.cc:4479
static void ParseBool(bool *var)
Definition: cache_cf.cc:3094
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:855
static void dump_time_t(StoreEntry *entry, const char *name, time_t var)
Definition: cache_cf.cc:2933
static bool StrictMode
Definition: ConfigParser.h:160
const char * sslCertAdaptAlgoritm(int alg)
Definition: gadgets.h:219
static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv)
Definition: cache_cf.cc:4715
Note::Pointer parse(ConfigParser &parser)
Parses a notes line and returns a pointer to the parsed Note object.
Definition: Notes.cc:210
static void dump_http_upgrade_request_protocols(StoreEntry *entry, const char *name, HttpUpgradeProtocolAccess *protoGuards)
Definition: cache_cf.cc:4913
bool GetHostByName(const char *s)
Definition: Address.cc:392
Helper::ChildConfig storeIdChildren
Definition: SquidConfig.h:217
Security::FuturePeerContext * defaultPeerContext
Definition: SquidConfig.h:506
void StartTransparency()
Definition: Intercept.cc:154
#define SQUID_UDP_SO_SNDBUF
Definition: squid.h:43
void clear()
Definition: SquidConfig.h:557
size_t udpMaxHitObjsz
Definition: SquidConfig.h:245
static bool LastTokenWasQuoted()
Definition: ConfigParser.h:117
const char * ProtocolType_str[]
static void parse_obsolete(const char *)
Definition: cache_cf.cc:1054
Address_list * next
Definition: Address.h:389
Definition: SBuf.h:93
const char * certSignAlgorithm(int sg)
Definition: gadgets.h:182
BumpMode
Definition: support.h:132
static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump)
Definition: cache_cf.cc:4471
size_t maxReplyHeaderSize
Definition: SquidConfig.h:137
static bool RecognizeQuotedValues
configuration_includes_quoted_values in squid.conf
Definition: ConfigParser.h:152
unsigned short xatos(const char *token)
Definition: Parsing.cc:114
static char * PeekAtToken()
time_t oldest_service_failure
Definition: Config.h:55
stores cpu_affinity_map configuration
static void dump_onoff(StoreEntry *entry, const char *name, int var)
Definition: cache_cf.cc:2562
static void free_size_t(size_t *var)
Definition: cache_cf.cc:3045
tos_t tos
Definition: QosConfig.h:42
static void parse_b_ssize_t(ssize_t *var)
Definition: cache_cf.cc:3027
static void parse_acl_b_size_t(AclSizeLimit **head)
Definition: cache_cf.cc:1712
static void free_access_log(CustomLog **definitions)
Definition: cache_cf.cc:4035
static const char * TimeUnitToString()
Definition: cache_cf.cc:1109
static const char *const T_MONTH_STR
Definition: cache_cf.cc:152
static const char *const T_SECOND_STR
Definition: cache_cf.cc:146
#define xstrdup
static void dump_int(StoreEntry *entry, const char *name, int var)
Definition: cache_cf.cc:2522
CustomLog * accesslogs
Definition: SquidConfig.h:186
void FreeNamedAcls(NamedAcls **)
delete the given list of "acl" directives
Definition: Acl.cc:346
static const char *const B_MBYTES_STR
Definition: cache_cf.cc:158
LogConfig TheConfig
Definition: Config.cc:15
std::vector< Auth::SchemeConfig * > ConfigVector
Definition: forward.h:23
@ bumpTerminate
Definition: support.h:132
a representation of a refresh pattern.
ActionPasswordList * next
const A & max(A const &lhs, A const &rhs)
static void free_memcachemode(SquidConfig *)
Definition: cache_cf.cc:3246
void add(CachePeer *p)
stores a being-configured cache_peer
Definition: CachePeers.h:27
void parseBytesOptionValue(size_t *bptr, const char *units, char const *value)
Parse bytes number from a string.
Definition: cache_cf.cc:1383
static const char *const T_MICROSECOND_STR
Definition: cache_cf.cc:144
static void dump_authparam(StoreEntry *entry, const char *name, Auth::ConfigVector cfg)
Definition: cache_cf.cc:1962
Ip::Address addr
Definition: Address.h:31
SBuf service_name(APP_SHORTNAME)
@ bumpEnd
Definition: support.h:132
static void free_cache_log_message(DebugMessages **messages)
Definition: cache_cf.cc:4654
static void free_client_delay_pool_count(ClientDelayConfig *cfg)
Definition: cache_cf.cc:1798
static void dump_AuthSchemes(StoreEntry *entry, const char *name, acl_access *authSchemes)
Definition: cache_cf.cc:1990
unsigned char tos_t
Definition: forward.h:27
static void dump_http_header_access(StoreEntry *entry, const char *name, const HeaderManglers *manglers)
Definition: cache_cf.cc:1830
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
void context(const SBuf &aName, const char *configuration)
sets user-specified ACL name and squid.conf context
Definition: Acl.cc:220
Auth::Config TheConfig
Definition: Config.cc:15
Ssl::CertAdaptAlgorithm alg
Definition: ProxyCerts.h:55
struct SquidConfig::@83 Program
int service_failure_limit
Definition: Config.h:54
static void dump_http_header_replace(StoreEntry *entry, const char *name, const HeaderManglers *manglers)
Definition: cache_cf.cc:1869
static void parse_icap_access_type()
Definition: cache_cf.cc:4175
static void free_ssize_t(ssize_t *var)
Definition: cache_cf.cc:3051
char * errHtmlText
Definition: SquidConfig.h:231
struct SquidConfig::@77 Timeout
static bool EvalBoolExpr(const char *expr)
Definition: cache_cf.cc:418
int rotateNumber
Definition: SquidConfig.h:191
A combination of PeerOptions and the corresponding Context.
Definition: PeerOptions.h:154
static void dump_cache_log_message(StoreEntry *entry, const char *name, const DebugMessages *messages)
Definition: cache_cf.cc:4634
void parsePoolAccess(ConfigParser &parser)
static const char *const T_YEAR_STR
Definition: cache_cf.cc:153
static void dump_memcachemode(StoreEntry *entry, const char *name, SquidConfig &)
Definition: cache_cf.cc:3277
static void parse_b_int64_t(int64_t *var)
Definition: cache_cf.cc:3033
static void parse_time_msec(time_msec_t *var)
Definition: cache_cf.cc:2966
static void free_ftp_epsv(acl_access **ftp_epsv)
Definition: cache_cf.cc:4721
headerMangler * track(const char *name)
returns a mangler for the named header (known or custom)
void dumpService(StoreEntry *, const char *) const
Definition: Config.cc:163
Acl::Address * next
Definition: Address.h:28
static void dump_UrlHelperTimeout(StoreEntry *, const char *, SquidConfig::UrlHelperTimeout &)
Definition: cache_cf.cc:4804
static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap)
Definition: cache_cf.cc:4101
char ThisCache[RFC2181_MAXHOSTNAMELEN<< 1]
static void free_acl_address(Acl::Address **head)
Definition: cache_cf.cc:1586
std::unique_ptr< RegexPattern > regex(const char *expectedRegexDescription)
extracts and returns a regex (including any optional flags)
size_t lineParse()
Definition: InnerNode.cc:44
bool parse(const char *def)
Definition: Format.cc:66
char * name
Definition: CachePeer.h:61
static void ParseNamedAcl(ConfigParser &, NamedAcls *&)
parses acl directive parts that follow directive name (i.e. "acl")
Definition: Acl.cc:229
static void free_HeaderManglers(HeaderManglers **pm)
Definition: cache_cf.cc:1859
static void parse_http_header_replace(HeaderManglers **manglers)
Definition: cache_cf.cc:1876
static int port
Definition: ldap_backend.cc:70
static NfMarkConfig Parse(const SBuf &token)
parses a token and returns an object, expects a "mark[/mask]" format
Definition: NfMarkConfig.cc:32
void parsePoolAccess(ConfigParser &parser)
Definition: DelayConfig.cc:77
static void parse_HeaderWithAclList(HeaderWithAclList **header)
Definition: cache_cf.cc:4499
static void parsePortCfg(AnyP::PortCfgPointer *, const char *protocol)
Definition: cache_cf.cc:3710
parsed "acl aclname ..." directives indexed by aclname
Definition: Acl.cc:36
static void parse_int64_t(int64_t *var)
Definition: cache_cf.cc:2548
static void free_acl(Acl::NamedAcls **config)
Definition: cache_cf.cc:1485
void free_YesNoNone(YesNoNone *)
Definition: cache_cf.cc:3227
void self_destruct(void)
Definition: cache_cf.cc:275
static void dump_delay_pool_count(StoreEntry *entry, const char *name, DelayConfig &cfg)
Definition: cache_cf.cc:1755
void finalizeConfig() override
Definition: cache_cf.cc:4370
static void dump_cachedir(StoreEntry *entry, const char *name, const Store::DiskConfig &swap)
Definition: cache_cf.cc:1897
bool ResolveClientAddressesAsap
whether to do reverse DNS lookups for source IPs of accepted connections
Definition: fqdncache.cc:30
char * toStr(char *buf, const unsigned int blen, int force=AF_UNSPEC) const
Definition: Address.cc:804
ACLList * aclList
when the header field should be added (always if nil)
const char * AllowOrDeny(const Answer &action)
Definition: Tree.h:53
void requirePathnameExists(const char *name, const char *path)
Definition: cache_cf.cc:3914
#define TexcHere(msg)
legacy convenience macro; it is not difficult to type Here() now
Definition: TextException.h:63
static SchemeConfig * Find(const char *proxy_auth)
Definition: SchemeConfig.cc:59
number
Definition: testStatHist.cc:32
list of address-based ACLs.
Definition: Address.h:20
DefineRunnerRegistrator(sslBumpCfgRr)
static void dump_icap_service_failure_limit(StoreEntry *, const char *, const Adaptation::Icap::Config &)
Definition: cache_cf.cc:4224
static OBJH dump_config
Definition: cache_cf.cc:187
static void dump_acl_b_size_t(StoreEntry *entry, const char *name, AclSizeLimit *head)
Definition: cache_cf.cc:1697
const char * CertAdaptAlgorithmStr[]
Definition: gadgets.cc:285
#define MAX_IPSTRLEN
Length of buffer that needs to be allocated to old a null-terminated IP-string.
Definition: forward.h:25
static void parse_configuration_includes_quoted_values(bool *recognizeQuotedValues)
Definition: cache_cf.cc:4827
static void parse_delay_pool_count(DelayConfig *cfg)
Definition: cache_cf.cc:1761
size_t DebugMessageId
an identifier for messages supporting configuration via cache_log_message
Definition: Messages.h:22
static void dump_denyinfo(StoreEntry *entry, const char *name, AclDenyInfoList *var)
Definition: cache_cf.cc:2462
class SquidConfig2 Config2
Definition: SquidConfig.cc:14
RefreshPattern * Refresh
Definition: SquidConfig.h:421
size_t aclParseAclList(ConfigParser &, ACLList **config, const char *label)
Definition: Gadgets.cc:184
static void parse_authparam(Auth::ConfigVector *config)
Definition: cache_cf.cc:1910
static void dump_cachemgrpasswd(StoreEntry *entry, const char *name, Mgr::ActionPasswordList *list)
Definition: cache_cf.cc:2403
MemBuf & buf
Definition: BodyPipe.h:74
int connect_retries
Definition: SquidConfig.h:352
static size_type SizeMaxXXX()
Definition: SquidString.h:72
DebugMessageId id
message identifier or, if the message has not been configured, zero
Definition: Messages.h:48
static void Print(std::ostream &, const T &)
reports the current T instance configuration in squid.conf format
int level
debugging level (i.e., the second debugs() parameter) or -1
Definition: Messages.h:53
static std::chrono::seconds ParseUrlRewriteTimeout()
Definition: cache_cf.cc:4730
int memory_cache_disk
Definition: SquidConfig.h:336
double xatof(const char *token)
Definition: Parsing.cc:25
@ bumpServerFirst
Definition: support.h:132
#define URI_WHITESPACE_DENY
Definition: defines.h:128
peer_t
Definition: enums.h:22
const std::vector< int > & cores() const
returns list of cores
static void DisableMacros()
Do not allow macros inside quoted strings.
Definition: ConfigParser.h:147
static void Free(T)
destroys Parse() result
static void parse_cache_log_message(DebugMessages **messages)
Definition: cache_cf.cc:4575
struct SquidConfig::@88 Store
static const CharacterSet WSP
Definition: CharacterSet.h:98
CachePeer * findCachePeerByName(const char *const name)
cache_peer with a given name (or nil)
Definition: neighbors.cc:1048
static void dump_b_int64_t(StoreEntry *entry, const char *name, int64_t var)
Definition: cache_cf.cc:3009
int size
Definition: ModDevPoll.cc:70
static const double HoursPerYear
Definition: cache_cf.cc:162
void memConfigure(void)
Definition: old_api.cc:254
static void free_note(Notes *)
Definition: cache_cf.cc:4562
void parse_time_t(time_t *var)
Definition: cache_cf.cc:2940
static void ProcessMacros(char *&line, int &len)
Definition: cache_cf.cc:370
void configure(bool beSet)
enables or disables the option; updating to 'configured' state
Definition: YesNoNone.h:53
uid_t effectiveUserID
Definition: SquidConfig.h:564
void OBJH(StoreEntry *)
Definition: forward.h:44
#define NULL
Definition: types.h:145
int64_t GetInteger64(void)
Definition: Parsing.cc:132
void freePoolCount()
Definition: DelayConfig.cc:93
@ algSignTrusted
Definition: gadgets.h:169
@ DISABLE_PMTU_TRANSPARENT
Definition: enums.h:227
Definition: Notes.h:113
static unsigned short GetService(const char *proto)
Definition: cache_cf.cc:2110
void rfc1738_unescape(char *url)
Definition: rfc1738.c:146
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
void dump_peer_options(StoreEntry *sentry, CachePeer *p)
Definition: neighbors.cc:1382
static bool StrToInt(const char *str, long &number)
Definition: cache_cf.cc:407
char ThisCache2[RFC2181_MAXHOSTNAMELEN<< 1]
@ PEER_PARENT
Definition: enums.h:25
#define DBG_PARSE_NOTE(x)
Definition: Stream.h:42
static void free_u_short(unsigned short *u)
Definition: cache_cf.cc:3076
static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
Definition: cache_cf.cc:4241
void dump_acl_access(StoreEntry *entry, const char *name, acl_access *head)
Definition: cache_cf.cc:1499
void setNoAddr()
Definition: Address.cc:312
wordlist * store_id
Definition: SquidConfig.h:202
static void dump_on_unsupported_protocol(StoreEntry *entry, const char *name, acl_access *access)
Definition: cache_cf.cc:4881
General eCAP configuration.
Definition: Config.h:38
void parse_eol(char *volatile *var)
Definition: cache_cf.cc:2886
static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign)
Definition: cache_cf.cc:4311
static void parse_tristate(int *var)
Definition: cache_cf.cc:2610
static Acl::Node * FindByName(const SBuf &)
A configured ACL with a given name or nil.
Definition: Acl.cc:159
static int parseOneConfigFile(const char *file_name, unsigned int depth)
Definition: cache_cf.cc:446
static void parse_client_delay_pool_rates(ClientDelayConfig *cfg)
Definition: cache_cf.cc:1816
static void parse_delay_pool_rates(DelayConfig *cfg)
Definition: cache_cf.cc:1773
char * strwordtok(char *buf, char **t)
Definition: String.cc:321
static void free_icap_service_failure_limit(Adaptation::Icap::Config *)
Definition: cache_cf.cc:4233
void rejectDuplicateDirective()
rejects configuration due to a repeated directive
A collection of headerMangler objects for a given message kind.
char * chroot_dir
Definition: SquidConfig.h:473
void destruct()
Definition: ConfigParser.cc:38
static void dump_u_short(StoreEntry *entry, const char *name, unsigned short var)
Definition: cache_cf.cc:3070
acl_tos * next
Definition: QosConfig.h:40
int refresh_nocache_hack
static void parse_SBufList(SBufList *list)
Definition: cache_cf.cc:1435
static AnyP::ProtocolVersion parsePortProtocol(const SBuf &value)
Definition: cache_cf.cc:3460
SBuf ToUpper(SBuf buf)
Returns a lower-cased copy of its parameter.
Definition: SBuf.h:725
static void ParseAclWithAction(acl_access **access, const Acl::Answer &action, const char *desc, Acl::Node *acl=nullptr)
Definition: cache_cf.cc:2001
static void SubstituteMacro(char *&line, int &len, const char *macroName, const char *substStr)
Definition: cache_cf.cc:359
representation of a neighbor_type_domain configuration directive. A POD
static void dump_client_delay_pool_count(StoreEntry *entry, const char *name, ClientDelayConfig &cfg)
Definition: cache_cf.cc:1804
AclDenyInfoList * next
void dumpPoolCount(StoreEntry *entry, const char *name) const
Definition: DelayConfig.cc:100
int reconfiguring
static const char *const T_MILLISECOND_STR
Definition: cache_cf.cc:145
bool StringToInt(const char *s, int &result, const char **p, int base)
Definition: Parsing.cc:217
static void dump_acl_address(StoreEntry *entry, const char *name, Acl::Address *head)
Definition: cache_cf.cc:1555
const char * CertSignAlgorithmStr[]
Definition: gadgets.cc:278
int xatoi(const char *token)
Definition: Parsing.cc:44
static void parse_string(char **)
Definition: cache_cf.cc:2866
static void Parse(DiskConfig &)
parses a single cache_dir configuration line
Definition: Disks.cc:414
#define safe_free(x)
Definition: xalloc.h:73
static const char *const B_GBYTES_STR
Definition: cache_cf.cc:159
const char * visible_appname_string
Definition: Tree.h:22
static void Dump(const DiskConfig &, StoreEntry &, const char *name)
prints the configuration into the provided StoreEntry
Definition: Disks.cc:467
Storage messages
Definition: Messages.h:72
static void free_address(Ip::Address *addr)
Definition: cache_cf.cc:1549
#define assert(EX)
Definition: assert.h:17
static bool FtpEspvDeprecated
Definition: cache_cf.cc:4662
@ algSetValidAfter
Definition: gadgets.h:207
static void free_http_upgrade_request_protocols(HttpUpgradeProtocolAccess **protoGuards)
Definition: cache_cf.cc:4930
static void parse_icap_class_type()
Definition: cache_cf.cc:4167
manages configurable aspects of a debugs() message
Definition: Messages.h:25
static void parse_acl_address(Acl::Address **head)
Definition: cache_cf.cc:1572
int httpd_suppress_version_string
Definition: SquidConfig.h:321
SBuf image() const
Definition: UriScheme.h:57
const char * appname_string
const char * cfg_filename
Definition: cache_cf.cc:270
#define IPV6_SPECIAL_SPLITSTACK
Definition: tools.h:22
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
unsigned int n_max
Definition: ChildConfig.h:48
@ toutActRetry
Definition: redirect.h:16
static int rotateNumber
Definition: Stream.h:82
static void free_b_int64_t(int64_t *var)
Definition: cache_cf.cc:3057
static void defaults_postscriptum(void)
CachePeer & cachePeer(const char *peerNameTokenDescription)
extracts a cache_peer name token and returns the corresponding CachePeer
@ toutActUseConfiguredResponse
Definition: redirect.h:16
static void parse_sslproxy_ssl_bump(acl_access **ssl_bump)
Definition: cache_cf.cc:4391
static void free_peer(CachePeers **const peers)
Definition: cache_cf.cc:2396
SBuf buf()
bytes written so far
Definition: Stream.h:41
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
static void parse_cachemgrpasswd(Mgr::ActionPasswordList **head)
Definition: cache_cf.cc:2420
static void ParseDirective(T &raw, ConfigParser &parser)
Definition: cache_cf.cc:663
Http::HdrType fieldId
internal ID for "known" headers or HDR_OTHER
const HeaderTableRecord & lookup(const char *buf, const std::size_t len) const
look record type up by name (C-string and length)
static void dump_uri_whitespace(StoreEntry *entry, const char *name, int var)
Definition: cache_cf.cc:3165
static void free_time_nanoseconds(std::chrono::nanoseconds *var)
Definition: cache_cf.cc:2991
Format
whether Action report uses valid YAML or unspecified/legacy formatting
static void dump_b_ssize_t(StoreEntry *entry, const char *name, ssize_t var)
Definition: cache_cf.cc:3003
@ algSetCommonName
Definition: gadgets.h:207
uint64_t limit
logging attempts beyond this limit are logged at the DBG_DATA level
Definition: Messages.h:56
@ algSignSelf
Definition: gadgets.h:169
@ toutActBypass
Definition: redirect.h:16
SBufList treeDump(const char *name, ActionToStringConverter converter) const
Definition: Tree.h:60
char * effectiveGroup
Definition: SquidConfig.h:198
bool configured() const
Definition: YesNoNone.h:67
std::string fieldName
HTTP header field name.
static void parse_cachedir(Store::DiskConfig *swap)
Definition: cache_cf.cc:2022
static bool NextKvPair(char *&key, char *&value)
unsigned short GetUdpService(void)
Definition: cache_cf.cc:2144
static void dump_IpAddress_list(StoreEntry *, const char *, const Ip::Address_list *)
Definition: cache_cf.cc:3342
void configFreeMemory(void)
Definition: cache_cf.cc:3900
int config_lineno
Definition: cache_cf.cc:271
void add(Acl::Node *node)
appends the node to the collection and takes control over it
Definition: InnerNode.cc:36
const char * null_string
const char * c_str()
Definition: SBuf.cc:516
void closeDirective()
stops parsing the current configuration directive
ACLList * aclList
Definition: AclSizeLimit.h:25
static int check_null_access_log(CustomLog *customlog_definitions)
Definition: cache_cf.cc:4010
size_t maxRequestHeaderSize
Definition: SquidConfig.h:134
const char * xitoa(int num)
Definition: util.cc:60
static const char *const T_FORTNIGHT_STR
Definition: cache_cf.cc:151
unsigned int xatoui(const char *token, char eov)
Definition: Parsing.cc:58
char * effectiveUser
Definition: SquidConfig.h:196
void setEmpty()
Fast reset of the stored content to what would be after default constructor.
Definition: Address.cc:204
void unloadSquidUntrusted()
Definition: support.cc:1453
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1316
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
static void parseBytesLine(size_t *bptr, const char *units)
Definition: cache_cf.cc:1284
#define xfree
the representation of the configuration. POD.
Definition: SquidConfig.h:78
@ bumpStare
Definition: support.h:132
static char * NextToken()
int client_pconns
Definition: SquidConfig.h:304
static void parse_adaptation_service_set_type()
Definition: cache_cf.cc:4128
static void dump_configuration_includes_quoted_values(StoreEntry *const entry, const char *const name, bool recognizeQuotedValues)
Definition: cache_cf.cc:4843
static void parse_note(Notes *)
Definition: cache_cf.cc:4551
static void free_HeaderWithAclList(HeaderWithAclList **header)
Definition: cache_cf.cc:4533
static void free_acl_b_size_t(AclSizeLimit **head)
Definition: cache_cf.cc:1728
void StartInterception()
Definition: Intercept.cc:169
Security::ContextPointer * sslContext_
Definition: SquidConfig.h:509
struct SquidConfig::@99 ssl_client
void storeConfigure(void)
Definition: store.cc:1270
struct SquidConfig2::@102 onoff
static void ParseWordList(wordlist **list)
Definition: cache_cf.cc:3116
wordlist * next
Definition: wordlist.h:60
void dumpReplacement(StoreEntry *entry, const char *optionName) const
report the *_header_replace part of the configuration
static void dump_peer(StoreEntry *entry, const char *name, const CachePeers *peers)
Definition: cache_cf.cc:2056
static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt)
Definition: cache_cf.cc:4305
unsigned short GetShort(void)
Definition: Parsing.cc:205
const HeaderLookupTable_t HeaderLookupTable
a collection of DebugMessage objects (with fast access by message IDs)
Definition: Messages.h:67
static void parse_client_delay_pool_count(ClientDelayConfig *cfg)
Definition: cache_cf.cc:1810
std::vector< const char * > BumpModeStr
Definition: support.cc:46
static void SetConfigFilename(char const *file_name, bool is_pipe)
Definition: cache_cf.cc:281
static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign)
Definition: cache_cf.cc:4351
void aclDestroyAccessList(acl_access **list)
Definition: Gadgets.cc:223
static const char *const T_DAY_STR
Definition: cache_cf.cc:149
static void ParseServiceChain(void)
Definition: Config.cc:253
char * mimeTablePathname
Definition: SquidConfig.h:226
Intercept Interceptor
Definition: Intercept.h:135
const std::vector< int > & processes() const
returns list of process numbers
static void parse_denyinfo(AclDenyInfoList **var)
Definition: cache_cf.cc:2477
static const char *const T_WEEK_STR
Definition: cache_cf.cc:150
static void parse_time_nanoseconds(std::chrono::nanoseconds *var)
Definition: cache_cf.cc:2985
static void parse_b_size_t(size_t *var)
Definition: cache_cf.cc:3021
static void parse_memcachemode(SquidConfig *)
Definition: cache_cf.cc:3250
static void dump_address(StoreEntry *entry, const char *name, Ip::Address &addr)
Definition: cache_cf.cc:1518
void Parse()
interprets (and partially applies) squid.conf or equivalent configuration
Definition: cache_cf.cc:609
static void dump_generic_port(StoreEntry *e, const char *n, const AnyP::PortCfgPointer &s)
Definition: cache_cf.cc:3800
void dump_acl_list(StoreEntry *entry, ACLList *head)
Definition: cache_cf.cc:1491
void dumpPoolCount(StoreEntry *entry, const char *name) const
@ PROTO_HTTPS
Definition: ProtocolType.h:27
@ algSignUntrusted
Definition: gadgets.h:169
AclSizeLimit * next
Definition: AclSizeLimit.h:24
static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt)
Definition: cache_cf.cc:4294
static void parse_delay_pool_access(DelayConfig *cfg)
Definition: cache_cf.cc:1779
static void dump_YesNoNone(StoreEntry *entry, const char *name, YesNoNone &option)
Definition: cache_cf.cc:3239
static void free_on_unsupported_protocol(acl_access **access)
Definition: cache_cf.cc:4897
void dumpAccess(StoreEntry *entry, const char *optionName) const
report the *_header_access part of the configuration
NeighborTypeDomainList * next
Format::Format * valueFormat
compiled HTTP header field value (no macros)
static bool SawDirective(const T &raw)
whether we have seen (and, hence, configured) the given directive
Definition: cache_cf.cc:654
static void free_time_t(time_t *var)
Definition: cache_cf.cc:2950
bool GetHostWithPort(char *token, Ip::Address *ipa)
Definition: Parsing.cc:257
static const char *const T_DECADE_STR
Definition: cache_cf.cc:154
static void free_AuthSchemes(acl_access **authSchemes)
Definition: cache_cf.cc:1983
ACLList * aclList
Definition: ProxyCerts.h:57
@ PROTO_HTTP
Definition: ProtocolType.h:25
const char * termedBuf() const
Definition: SquidString.h:93
char * key
Definition: wordlist.h:59
void printAsNoteDirectives(StoreEntry *, const char *directiveName) const
Prints notes using "note" squid.conf directive format, one directive per stored note.
Definition: Notes.cc:263
static char * NextQuotedOrToEol()
time_t urlRewrite
Definition: SquidConfig.h:132
cache_peer configuration storage
Definition: CachePeers.h:20
char * foreignIntermediateCertsPath
Definition: SquidConfig.h:511
int cache_miss_revalidate
Definition: SquidConfig.h:319
wordlist * redirect
Definition: SquidConfig.h:201
static Ssl::BumpMode lastDeprecatedRule
Definition: cache_cf.cc:4360
Definition: parse.c:160
int cmp(const SBuf &S, const size_type n) const
shorthand version for compare()
Definition: SBuf.h:279
Acl::TreePointer acl_access
Definition: forward.h:46
int pipeline_max_prefetch
Definition: SquidConfig.h:347
char * ConfigFile
@ bumpNone
Definition: support.h:132
static TimeUnit parseTimeLine()
Definition: cache_cf.cc:1202
squidaio_request_t * head
Definition: aiops.cc:129
@ algSetValidBefore
Definition: gadgets.h:207
@ DISABLE_PMTU_ALWAYS
Definition: enums.h:226
Definition: Node.h:25
an std::runtime_error with thrower location info
Definition: TextException.h:20
static void free_time_msec(time_msec_t *var)
Definition: cache_cf.cc:2972
static void free_icap_service_type(Adaptation::Icap::Config *)
Definition: cache_cf.cc:4155
#define free_wordlist
Definition: cache_cf.cc:3135
std::vector< Auth::SchemesConfig > schemeLists
set of auth_schemes directives
Definition: Config.h:32
list of cachemgr password authorization definitions. Currently a POD.
size_type size() const
Definition: SquidString.h:74
static void dump_string(StoreEntry *entry, const char *name, char *var)
Definition: cache_cf.cc:2859
static void free_string(char **var)
Definition: cache_cf.cc:2880
const char * getMyHostname(void)
Definition: tools.cc:468
uint64_t xatoull(const char *token, int base, char eov)
Definition: Parsing.cc:105
static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
Definition: cache_cf.cc:4068
void RegisterAction(char const *action, char const *desc, OBJH *handler, Protected, Atomic, Format)
Definition: Registration.cc:54
Ssl::CertSignAlgorithm alg
Definition: ProxyCerts.h:33
acl_nfmark * next
Definition: QosConfig.h:54
static void dump_PortCfg(StoreEntry *, const char *, const AnyP::PortCfgPointer &)
Definition: cache_cf.cc:3891
@ bumpBump
Definition: support.h:132
@ DISABLE_PMTU_OFF
Definition: enums.h:225
static void ParseServiceSet(void)
Definition: Config.cc:247
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
int opt_parse_cfg_only
static const char * skip_ws(const char *s)
Definition: cache_cf.cc:302
static void DumpDirective(const T &raw, StoreEntry *entry, const char *name)
Definition: cache_cf.cc:679
#define Must(condition)
Definition: TextException.h:75
#define Important(id)
Definition: Messages.h:93
Allows or blocks HTTP Upgrade protocols (see http_upgrade_request_protocols)
ACLList * aclList
Definition: ProxyCerts.h:34
@ ACCESS_ALLOWED
Definition: Acl.h:42
static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign)
Definition: cache_cf.cc:4340
struct servent * xgetservbyname(const char *name, const char *proto)
POSIX getservbyname(3) equivalent.
Definition: netdb.h:31
void setAnyAddr()
NOTE: Does NOT clear the Port stored. Only the Address and Type.
Definition: Address.cc:197
static bool IsSpace(const char ch)
Definition: cache_cf.cc:296
static TimeUnit FromNanoseconds(const std::chrono::nanoseconds &ns, const double parsedValue)
Definition: cache_cf.cc:1187
@ ACCESS_DENIED
Definition: Acl.h:41
struct SquidConfig::@82 Log
static void dump_removalpolicy(StoreEntry *entry, const char *name, RemovalPolicySettings *settings)
Definition: cache_cf.cc:3212
std::string fieldValue
HTTP header field value, possibly with macros.
static Scheme::Pointer Find(const char *)
Definition: Scheme.cc:31
CustomLog * next
next _log line (if any); maintained by cache_cf.cc
Definition: CustomLog.h:21
#define DBG_IMPORTANT
Definition: Stream.h:38
static void FreeDirective(T &raw)
frees any resources associated with the given raw SquidConfig data member
Definition: cache_cf.cc:698
static const char *const T_NANOSECOND_STR
Definition: cache_cf.cc:143
char * surrogate_id
Definition: SquidConfig.h:220
Helper::ChildConfig redirectChildren
Definition: SquidConfig.h:216
const char * neighborTypeStr(const CachePeer *p)
Definition: neighbors.cc:84
int64_t maxObjectSize
Definition: SquidConfig.h:266
#define MYNAME
Definition: Stream.h:219
static void dump_refreshpattern(StoreEntry *entry, const char *name, RefreshPattern *head)
Definition: cache_cf.cc:2665
static void free_int64_t(int64_t *var)
Definition: cache_cf.cc:2556
static void dump_int64_t(StoreEntry *entry, const char *name, int64_t var)
Definition: cache_cf.cc:2542
static void dump_acl_tos(StoreEntry *entry, const char *name, acl_tos *head)
Definition: cache_cf.cc:1593
void parse_onoff(int *var)
Definition: cache_cf.cc:2568
sslproxy_cert_adapt * next
Definition: ProxyCerts.h:58
int kind
the matched custom access list verb (or zero)
Definition: Acl.h:99
static const char *const B_BYTES_STR
Definition: cache_cf.cc:156
#define PRId64
Definition: types.h:104
int64_t size
Definition: AclSizeLimit.h:26
void aclParseAccessLine(const char *directive, ConfigParser &, acl_access **config)
Parses a single line of a "action followed by acls" directive (e.g., http_access).
Definition: Gadgets.cc:132
sslproxy_cert_sign * next
Definition: ProxyCerts.h:35
static bool isUnsignedNumeric(const char *str, size_t len)
Definition: cache_cf.cc:2094
static void free_refreshpattern(RefreshPattern **head)
Definition: cache_cf.cc:2847
virtual void parse(SchemeConfig *, size_t, char *)
Definition: SchemeConfig.cc:84
size_t maxRequestBufferSize
Definition: SquidConfig.h:136
bool quoted
whether fieldValue may contain macros
static void configDoConfigure(void)
Definition: cache_cf.cc:712
Ip::NfMarkConfig markConfig
Definition: QosConfig.h:56
static void parse_UrlHelperTimeout(SquidConfig::UrlHelperTimeout *)
Definition: cache_cf.cc:4761
static void parse_removalpolicy(RemovalPolicySettings **settings)
Definition: cache_cf.cc:3199
gid_t effectiveGroupID
Definition: SquidConfig.h:565
ACLList * aclList
Definition: Address.h:29
void clean()
clean the notes list
Definition: Notes.h:138
static void parse_YesNoNone(YesNoNone *option)
Definition: cache_cf.cc:3231
static bool parseTimeUnit(const char *unitName, std::chrono::nanoseconds &ns)
Definition: cache_cf.cc:1131
static void dump_SBufList(StoreEntry *entry, const SBufList &words)
Definition: cache_cf.cc:1443
static int ThePurgeCount
PURGE methods seen by parse()
Definition: MethodData.h:32
static const char *const B_KBYTES_STR
Definition: cache_cf.cc:157
SBufList acl_list
ACL names in configured order.
const Tree & ToTree(const TreePointer *cfg)
Definition: Gadgets.cc:123
#define xisspace(x)
Definition: xis.h:15
void parseService(void)
Definition: Config.cc:141
@ toutActFail
Definition: redirect.h:16
const CachePeers & CurrentCachePeers()
Definition: CachePeers.cc:43
void aclDestroyAclList(ACLList **list)
Definition: Gadgets.cc:214
static void parse_on_unsupported_protocol(acl_access **access)
Definition: cache_cf.cc:4857
static void default_all(void)
int max_filedescriptors
Definition: SquidConfig.h:520
char * appendDomain
Definition: SquidConfig.h:222
static void free_SBufList(SBufList *list)
Definition: cache_cf.cc:1464
void forEach(const Visitor &) const
iterates over all configured rules, calling the given visitor
unsigned int concurrency
Definition: ChildConfig.h:72
static void defaults_if_none(void)
size_t appendDomainLen
Definition: SquidConfig.h:223
static void free_ecap_service_type(Adaptation::Ecap::Config *)
Definition: cache_cf.cc:4193
void parse_wordlist(wordlist **list)
Definition: cache_cf.cc:3122
void aclParseDenyInfoLine(AclDenyInfoList **head)
Definition: Gadgets.cc:88
static void parse_IpAddress_list(Ip::Address_list **)
Definition: cache_cf.cc:3318
@ bumpClientFirst
Definition: support.h:132
static void free_all(void)
const char * cfg_directive
During parsing, the name of the current squid.conf directive being parsed.
Definition: cache_cf.cc:269
struct SquidConfig::@90 onoff
static void free_denyinfo(AclDenyInfoList **var)
Definition: cache_cf.cc:2483
const char * wordlistAdd(wordlist **list, const char *key)
Definition: wordlist.cc:25
RefreshPattern * next
static void free_delay_pool_count(DelayConfig *cfg)
Definition: cache_cf.cc:1749
@ CLF_NONE
Definition: Formats.h:37
int EnableIpv6
Whether IPv6 is supported and type of support.
Definition: tools.h:25
#define APP_FULLNAME
Definition: version.h:25
struct RefreshPattern::@73 flags
void * xrealloc(void *s, size_t sz)
Definition: xalloc.cc:126
static void parse_client_delay_pool_access(ClientDelayConfig *cfg)
Definition: cache_cf.cc:1822
static void dump_HeaderWithAclList(StoreEntry *entry, const char *name, HeaderWithAclList *headers)
Definition: cache_cf.cc:4486
static void parse_uri_whitespace(int *var)
Definition: cache_cf.cc:3140
char config_input_line[BUFSIZ]
Definition: cache_cf.cc:272
static void parseBytesLineSigned(ssize_t *bptr, const char *units)
Definition: cache_cf.cc:1331
uint64_t time_msec_t
Definition: gadgets.h:16
static void parse_peer_access(void)
Definition: cache_cf.cc:2490
PeerOptions & ProxyOutgoingConfig()
configuration options for DIRECT server access
Definition: PeerOptions.cc:25
@ PEER_SIBLING
Definition: enums.h:24
static void free_IpAddress_list(Ip::Address_list **)
Definition: cache_cf.cc:3355
static void parse_adaptation_service_chain_type()
Definition: cache_cf.cc:4134
static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &)
Definition: cache_cf.cc:4199
static void parse_hostdomaintype(void)
Definition: cache_cf.cc:2499
static void ParseUShort(unsigned short *var)
Definition: cache_cf.cc:3088
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
void parsePoolRates()
Definition: DelayConfig.cc:56
const A & min(A const &lhs, A const &rhs)
static DebugMessageId ParseDebugMessageId(const char *value, const char eov)
Definition: cache_cf.cc:4567
void parsePoolCount()
Definition: DelayConfig.cc:23
void peerClearRRStart(void)
Definition: neighbors.cc:426
void freeService(void)
Definition: Config.cc:152
deny_info representation. Currently a POD.
bool loadSquidUntrusted(const char *path)
Definition: support.cc:1447
unsigned short GetTcpService(void)
Definition: cache_cf.cc:2134
static const char *const T_MINUTE_STR
Definition: cache_cf.cc:147
static void parse_port_option(AnyP::PortCfgPointer &s, char *token)
Definition: cache_cf.cc:3478
bool levelled() const
whether the default logging level of this message has been altered
Definition: Messages.h:32
static void parse_access_log(CustomLog **customlog_definitions)
Definition: cache_cf.cc:3963
#define SQUIDSBUFPH
Definition: SBuf.h:31
static void parse_ftp_epsv(acl_access **ftp_epsv)
Definition: cache_cf.cc:4663
void Init(void)
Initialize Auth subsystem.
Definition: AuthReg.cc:31
static void dump_b_size_t(StoreEntry *entry, const char *name, size_t var)
Definition: cache_cf.cc:2997
char * directory
Definition: SquidConfig.h:426
void setReplacement(const char *name, const char *replacementValue)
updates mangler for the named header with a replacement value
static void parse_AuthSchemes(acl_access **authSchemes)
Definition: cache_cf.cc:1969
class SquidConfig Config
Definition: SquidConfig.cc:12
void add_http_port(char *portspec)
Definition: cache_cf.cc:3698
static void dump_note(StoreEntry *, const char *, Notes &)
Definition: cache_cf.cc:4557
int unsigned int
Definition: stub_fd.cc:19
static void free_authparam(Auth::ConfigVector *cfg)
Definition: cache_cf.cc:1950
static void free_configuration_includes_quoted_values(bool *recognizeQuotedValues)
Definition: cache_cf.cc:4850
constexpr DebugMessageId DebugMessageIdUpperBound
The maximum used DebugMessage::id plus 1. Increase as you add new IDs.
Definition: Messages.h:64
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
virtual void parse(const char *)
parse a TLS squid.conf option
Definition: PeerOptions.cc:38
static void parse_icap_service_failure_limit(Adaptation::Icap::Config *)
Definition: cache_cf.cc:4207
#define URI_WHITESPACE_ALLOW
Definition: defines.h:125
static void free_UrlHelperTimeout(SquidConfig::UrlHelperTimeout *)
Definition: cache_cf.cc:4819
@ bumpSplice
Definition: support.h:132
bool limited() const
whether the number of logging attempts have been limited
Definition: Messages.h:35
static void parseBytesLine64(int64_t *bptr, const char *units)
Definition: cache_cf.cc:1237
int GetInteger(void)
Definition: Parsing.cc:148
static void ReplaceSubstr(char *&str, int &len, unsigned substrIdx, unsigned substrLen, const char *newSubstr)
Definition: cache_cf.cc:341

 

Introduction

Documentation

Support

Miscellaneous