tools.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 21 Misc Functions */
10 
11 #include "squid.h"
12 #include "anyp/PortCfg.h"
13 #include "base/Subscription.h"
14 #include "client_side.h"
15 #include "compat/unistd.h"
16 #include "fatal.h"
17 #include "fde.h"
18 #include "fqdncache.h"
19 #include "fs_io.h"
20 #include "htcp.h"
21 #include "http/Stream.h"
22 #include "ICP.h"
23 #include "ip/Intercept.h"
24 #include "ip/QosConfig.h"
25 #include "ipc/Coordinator.h"
26 #include "ipc/Kids.h"
27 #include "ipcache.h"
28 #include "MemBuf.h"
29 #include "sbuf/Stream.h"
30 #include "SquidConfig.h"
31 #include "SquidMath.h"
32 #include "store/Disks.h"
33 #include "tools.h"
34 #include "wordlist.h"
35 
36 #include <cerrno>
37 #if HAVE_SYS_CAPABILITY_H
38 #include <sys/capability.h>
39 #endif
40 #if HAVE_SYS_PRCTL_H
41 #include <sys/prctl.h>
42 #endif
43 #if HAVE_SYS_PROCCTL_H
44 #include <sys/procctl.h>
45 #endif
46 #if HAVE_PRIV_H
47 #include <priv.h>
48 #endif
49 #if HAVE_PSAPI_H
50 #include <psapi.h>
51 #endif
52 #if HAVE_SYS_STAT_H
53 #include <sys/stat.h>
54 #endif
55 #if HAVE_SYS_WAIT_H
56 #include <sys/wait.h>
57 #endif
58 #if HAVE_GRP_H
59 #include <grp.h>
60 #endif
61 
62 #define DEAD_MSG "\
63 The Squid Cache (version %s) died.\n\
64 \n\
65 You've encountered a fatal error in the Squid Cache version %s.\n\
66 If a core file was created (possibly in the swap directory),\n\
67 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
68 and report the trace back to squid-bugs@lists.squid-cache.org.\n\
69 \n\
70 Thanks!\n"
71 
72 static void mail_warranty(void);
73 static void restoreCapabilities(bool keep);
74 int DebugSignal = -1;
76 
77 #if _SQUID_LINUX_
78 /* Workaround for crappy glic header files */
79 SQUIDCEXTERN int backtrace(void *, int);
80 SQUIDCEXTERN void backtrace_symbols_fd(void *, int, int);
81 SQUIDCEXTERN int setresuid(uid_t, uid_t, uid_t);
82 #else /* _SQUID_LINUX_ */
83 /* needed on Opensolaris for backtrace_symbols_fd */
84 #if HAVE_EXECINFO_H
85 #include <execinfo.h>
86 #endif /* HAVE_EXECINFO_H */
87 
88 #endif /* _SQUID_LINUX */
89 
90 static char tmp_error_buf[32768]; /* 32KB */
91 
92 void
94 {
95  // Release the main ports as early as possible
96 
97  // clear http_port, https_port, and ftp_port lists
99 
100  // clear icp_port's
101  icpClosePorts();
102 
103  // XXX: Why not the HTCP, SNMP, DNS ports as well?
104  // XXX: why does this differ from main closeServerConnections() anyway ?
105 }
106 
107 static char *
108 dead_msg(void)
109 {
110  LOCAL_ARRAY(char, msg, 1024);
111  snprintf(msg, 1024, DEAD_MSG, version_string, version_string);
112  return msg;
113 }
114 
115 static void
117 {
118  FILE *fp = nullptr;
119  static char command[256];
120 
121  /*
122  * NP: umask() takes the mask of bits we DONT want set.
123  *
124  * We want the current user to have read/write access
125  * and since this file will be passed to mailsystem,
126  * the group and other must have read access.
127  */
128  const mode_t prev_umask=umask(S_IXUSR|S_IXGRP|S_IWGRP|S_IWOTH|S_IXOTH);
129 
130 #if HAVE_MKSTEMP
131  char filename[] = "/tmp/squid-XXXXXX";
132  int tfd = mkstemp(filename);
133  if (tfd < 0 || (fp = fdopen(tfd, "w")) == nullptr) {
134  umask(prev_umask);
135  return;
136  }
137 #else
138  char *filename;
139  // XXX tempnam is obsolete since POSIX.2008-1
140  // tmpfile is not an option, we want the created files to stick around
141  if ((filename = tempnam(nullptr, APP_SHORTNAME)) == NULL ||
142  (fp = fopen(filename, "w")) == NULL) {
143  umask(prev_umask);
144  return;
145  }
146 #endif
147  umask(prev_umask);
148 
149  if (Config.EmailFrom)
150  fprintf(fp, "From: %s\n", Config.EmailFrom);
151  else
152  fprintf(fp, "From: %s@%s\n", APP_SHORTNAME, uniqueHostname());
153 
154  fprintf(fp, "To: %s\n", Config.adminEmail);
155  fprintf(fp, "Subject: %s\n", dead_msg());
156  fclose(fp);
157 
158  snprintf(command, 256, "%s %s < %s", Config.EmailProgram, Config.adminEmail, filename);
159  if (system(command)) {} /* XXX should avoid system(3) */
160  unlink(filename);
161 #if !HAVE_MKSTEMP
162  xfree(filename); // tempnam() requires us to free its allocation
163 #endif
164 }
165 
166 void
168 {
169 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
170 
171  struct mstats ms = mstats();
172  fprintf(DebugStream(), "\ttotal space in arena: %6d KB\n",
173  (int) (ms.bytes_total >> 10));
174  fprintf(DebugStream(), "\tTotal free: %6d KB %d%%\n",
175  (int) (ms.bytes_free >> 10),
176  Math::intPercent(ms.bytes_free, ms.bytes_total));
177 #endif
178 }
179 
180 void
182 {
183  memset(r, '\0', sizeof(struct rusage));
184 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
185 #if _SQUID_SOLARIS_
186  /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
187  enter_suid();
188 #endif
189 
190  getrusage(RUSAGE_SELF, r);
191 
192 #if _SQUID_SOLARIS_
193  leave_suid();
194 #endif
195 
196 #elif defined(PSAPI_VERSION)
197  // Windows has an alternative method if there is no POSIX getrusage defined.
198  if (WIN32_OS_version >= _WIN_OS_WINNT) {
199  /* On Windows NT and later call PSAPI.DLL for process Memory */
200  /* information -- Guido Serassio */
201  HANDLE hProcess;
202  PROCESS_MEMORY_COUNTERS pmc;
203  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
204  PROCESS_VM_READ,
205  FALSE, GetCurrentProcessId());
206  {
207  /* Microsoft CRT doesn't have getrusage function, */
208  /* so we get process CPU time information from PSAPI.DLL. */
209  FILETIME ftCreate, ftExit, ftKernel, ftUser;
210  if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
211  int64_t *ptUser = (int64_t *)&ftUser;
212  int64_t tUser64 = *ptUser / 10;
213  int64_t *ptKernel = (int64_t *)&ftKernel;
214  int64_t tKernel64 = *ptKernel / 10;
215  r->ru_utime.tv_sec =(long)(tUser64 / 1000000);
216  r->ru_stime.tv_sec =(long)(tKernel64 / 1000000);
217  r->ru_utime.tv_usec =(long)(tUser64 % 1000000);
218  r->ru_stime.tv_usec =(long)(tKernel64 % 1000000);
219  } else {
220  CloseHandle( hProcess );
221  return;
222  }
223  }
224  if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) {
225  r->ru_maxrss=(DWORD)(pmc.WorkingSetSize / getpagesize());
226  r->ru_majflt=pmc.PageFaultCount;
227  } else {
228  CloseHandle( hProcess );
229  return;
230  }
231 
232  CloseHandle( hProcess );
233  }
234 #endif
235 }
236 
237 double
238 
240 {
241  return (double) r->ru_stime.tv_sec +
242  (double) r->ru_utime.tv_sec +
243  (double) r->ru_stime.tv_usec / 1000000.0 +
244  (double) r->ru_utime.tv_usec / 1000000.0;
245 }
246 
247 /* Hack for some HP-UX preprocessors */
248 #ifndef HAVE_GETPAGESIZE
249 #define HAVE_GETPAGESIZE 0
250 #endif
251 
252 int
253 
255 {
256 #if _SQUID_SGI_ && _ABIAPI
257  return r->ru_pad[0];
258 #elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
259 
260  return r->ru_maxrss;
261 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
262 
263  return (r->ru_maxrss * getpagesize()) >> 10;
264 #elif defined(PAGESIZE)
265 
266  return (r->ru_maxrss * PAGESIZE) >> 10;
267 #else
268 
269  return r->ru_maxrss;
270 #endif
271 }
272 
273 int
274 
276 {
277 #if _SQUID_SGI_ && _ABIAPI
278  return r->ru_pad[5];
279 #else
280 
281  return r->ru_majflt;
282 #endif
283 }
284 
288 static void
290 {
291  const auto handleError = [](const char * const syscall, const int savedErrno) {
292  throw TextException(ToSBuf(syscall, " failure: ", xstrerr(savedErrno)), Here());
293  };
294 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
295  if (prctl(PR_SET_DUMPABLE, 1) != 0)
296  handleError("prctl(PR_SET_DUMPABLE)", errno);
297 #elif HAVE_PROCCTL && defined(PROC_TRACE_CTL)
298  // TODO: when FreeBSD 14 becomes the lowest version, we can
299  // possibly save one getpid syscall, for now still necessary.
300  int traceable = PROC_TRACE_CTL_ENABLE;
301  if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) != 0)
302  handleError("procctl(PROC_TRACE_CTL_ENABLE)", errno);
303 #elif HAVE_SETPFLAGS
304  if (setpflags(__PROC_PROTECT, 0) != 0)
305  handleError("setpflags(__PROC_PROTECT)", errno);
306 #else
307  debugs(50, 2, "WARNING: Assuming this process is traceable");
308  (void)handleError; // just "use" the variable; there is no error here
309 #endif
310 }
311 
314 static void
316 {
317  // for now, setting coredump_dir is required to make the process traceable
318  if (!Config.coredump_dir)
319  return;
320 
321  try {
322  makeTraceable();
323  } catch (...) {
324  debugs(50, DBG_IMPORTANT, "ERROR: Cannot make the process traceable:" <<
325  Debug::Extra << "exception: " << CurrentException);
326  }
327 }
328 
329 void
331 {
332 
333  struct rusage rusage;
335  fprintf(DebugStream(), "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
337  rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
338  rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
339  fprintf(DebugStream(), "Maximum Resident Size: %d KB\n",
341  fprintf(DebugStream(), "Page faults with physical i/o: %d\n",
343 }
344 
345 void
346 death(int sig)
347 {
348  if (sig == SIGSEGV)
349  debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Segment Violation...dying.");
350  else if (sig == SIGBUS)
351  debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Bus Error...dying.");
352  else
353  debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received signal " << sig << "...dying.");
354 
355 #if PRINT_STACK_TRACE
356 #if _SQUID_HPUX_
357  {
358  extern void U_STACK_TRACE(void); /* link with -lcl */
359  fflush(DebugStream());
360  dup2(fileno(DebugStream()), 2);
361  U_STACK_TRACE();
362  }
363 
364 #endif /* _SQUID_HPUX_ */
365 #if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
366  { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
367  extern void opcom_stack_trace(void); /* link with -lopcom_stack */
368  fflush(DebugStream());
369  dup2(fileno(DebugStream()), fileno(stdout));
370  opcom_stack_trace();
371  fflush(stdout);
372  }
373 
374 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
375 #if HAVE_BACKTRACE_SYMBOLS_FD
376  {
377  static void *callarray[8192];
378  int n;
379  n = backtrace(callarray, 8192);
380  backtrace_symbols_fd(callarray, n, fileno(DebugStream()));
381  }
382 
383 #endif
384 #endif /* PRINT_STACK_TRACE */
385 
386 #if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
387  signal(SIGSEGV, SIG_DFL);
388 
389  signal(SIGBUS, SIG_DFL);
390 
391  signal(sig, SIG_DFL);
392 
393 #endif
394 
396 
398 
399  if (!shutting_down) {
400  PrintRusage();
401 
402  dumpMallocStats();
403  }
404 
405  if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
406  /* skip if more than 10 days old */
407 
408  if (Config.adminEmail)
409  mail_warranty();
410 
411  puts(dead_msg());
412  }
413 
415  abort();
416 }
417 
418 void
420 {
421  if (sig > 0) {
422  if (IamMasterProcess()) {
423  for (int i = TheKids.count() - 1; i >= 0; --i) {
424  const auto &kid = TheKids.get(i);
425  if (kid.running())
426  kill(kid.getPid(), sig);
427  }
428  }
429  sig = -1;
430  }
431 }
432 
433 void
435 {
436  static int state = 0;
437  /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
438 
439  DebugSignal = sig;
440 
441  if (state == 0) {
442  Debug::parseOptions("ALL,7");
443  state = 1;
444  } else {
446  state = 0;
447  }
448 
449 #if !HAVE_SIGACTION
450  /* reinstall */
451  if (signal(sig, sigusr2_handle) == SIG_ERR) {
452  int xerrno = errno;
453  debugs(50, DBG_CRITICAL, "signal: sig=" << sig << " func=sigusr2_handle: " << xstrerr(xerrno));
454  }
455 #endif
456 }
457 
458 void
459 debug_trap(const char *message)
460 {
461  if (!opt_catch_signals)
462  fatal_dump(message);
463 
464  debugs(50, DBG_CRITICAL, "WARNING: " << message);
465 }
466 
467 const char *
469 {
470  LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
471  static int present = 0;
472  struct addrinfo *AI = nullptr;
473  Ip::Address sa;
474 
475  if (Config.visibleHostname != nullptr)
476  return Config.visibleHostname;
477 
478  if (present)
479  return host;
480 
481  host[0] = '\0';
482 
483  if (HttpPortList != nullptr && sa.isAnyAddr())
484  sa = HttpPortList->s;
485 
486  /*
487  * If the first http_port address has a specific address, try a
488  * reverse DNS lookup on it.
489  */
490  if ( !sa.isAnyAddr() ) {
491 
492  sa.getAddrInfo(AI);
493  /* we are looking for a name. */
494  if (getnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, nullptr, 0, NI_NAMEREQD ) == 0) {
495  /* DNS lookup successful */
496  /* use the official name from DNS lookup */
497  debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
498 
499  present = 1;
500 
502 
503  if (strchr(host, '.'))
504  return host;
505  }
506 
508  debugs(50, 2, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
509  }
510 
511  // still no host. fallback to gethostname()
512  if (xgethostname(host, SQUIDHOSTNAMELEN) < 0) {
513  int xerrno = errno;
514  debugs(50, DBG_IMPORTANT, "WARNING: gethostname failed: " << xstrerr(xerrno));
515  } else {
516  /* Verify that the hostname given resolves properly */
517  struct addrinfo hints;
518  memset(&hints, 0, sizeof(addrinfo));
519  hints.ai_flags = AI_CANONNAME;
520 
521  if (getaddrinfo(host, nullptr, nullptr, &AI) == 0) {
522  /* DNS lookup successful */
523  /* use the official name from DNS lookup */
524  debugs(50, 6, "getMyHostname: '" << host << "' has DNS resolution.");
525  present = 1;
526 
527  /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
528  if (AI)
529  freeaddrinfo(AI);
530 
531  return host;
532  }
533  int xerrno = errno;
534 
535  if (AI)
536  freeaddrinfo(AI);
537  debugs(50, DBG_IMPORTANT, "WARNING: '" << host << "' rDNS test failed: " << xstrerr(xerrno));
538  }
539 
540  /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
541  debugs(50, DBG_CRITICAL, "WARNING: Could not determine this machines public hostname. " <<
542  "Please configure one or set 'visible_hostname'.");
543 
544  return ("localhost");
545 }
546 
547 const char *
549 {
550  debugs(21, 3, " Config: '" << Config.uniqueHostname << "'");
552 }
553 
559 void
561 {
562  debugs(21, 3, "leave_suid: PID " << getpid() << " called");
563 
564  if (Config.effectiveGroup) {
565 #if HAVE_SETGROUPS
566  setgroups(1, &Config2.effectiveGroupID);
567 #endif
568 
569  if (setgid(Config2.effectiveGroupID) < 0) {
570  int xerrno = errno;
571  debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
572  }
573  }
574 
575  if (geteuid() != 0)
576  return;
577 
578  /* Started as a root, check suid option */
579  if (Config.effectiveUser == nullptr)
580  return;
581 
582  debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
583 
584  if (!Config.effectiveGroup) {
585 
586  if (setgid(Config2.effectiveGroupID) < 0) {
587  int xerrno = errno;
588  debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
589  }
590 
592  debugs(50, DBG_CRITICAL, "ERROR: initgroups: unable to set groups for User " <<
593  Config.effectiveUser << " and Group " <<
594  (unsigned) Config2.effectiveGroupID << "");
595  }
596  }
597 
598 #if HAVE_SETRESUID
599  if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0) {
600  const auto xerrno = errno;
601  fatalf("FATAL: setresuid: %s", xstrerr(xerrno));
602  }
603 
604 #elif HAVE_SETEUID
605  if (seteuid(Config2.effectiveUserID) < 0) {
606  const auto xerrno = errno;
607  fatalf("FATAL: seteuid: %s", xstrerr(xerrno));
608  }
609 
610 #else
611  if (setuid(Config2.effectiveUserID) < 0) {
612  const auto xerrno = errno;
613  fatalf("FATAL: setuid: %s", xstrerr(xerrno));
614  }
615 
616 #endif
617 
618  restoreCapabilities(true);
619  setTraceability();
620 }
621 
622 /* Enter a privilegied section */
623 void
625 {
626  debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
627 #if HAVE_SETRESUID
628  if (setresuid((uid_t)-1, 0, (uid_t)-1) < 0) {
629  const auto xerrno = errno;
630  debugs (21, 3, "enter_suid: setresuid failed: " << xstrerr(xerrno));
631  }
632 #else
633 
634  if (setuid(0) < 0) {
635  const auto xerrno = errno;
636  debugs(21, 3, "setuid(0) failed: " << xstrerr(xerrno));
637  }
638 #endif
639 
640  setTraceability();
641 }
642 
643 /* Give up the possibility to gain privilegies.
644  * this should be used before starting a sub process
645  */
646 void
647 no_suid(void)
648 {
649  uid_t uid;
650  leave_suid();
651  uid = geteuid();
652  debugs(21, 3, "no_suid: PID " << getpid() << " giving up root privileges forever");
653 
654  if (setuid(0) < 0) {
655  int xerrno = errno;
656  debugs(50, DBG_IMPORTANT, "WARNING: no_suid: setuid(0): " << xstrerr(xerrno));
657  }
658 
659  if (setuid(uid) < 0) {
660  int xerrno = errno;
661  debugs(50, DBG_IMPORTANT, "ERROR: no_suid: setuid(" << uid << "): " << xstrerr(xerrno));
662  }
663 
664  restoreCapabilities(false);
665  setTraceability();
666 }
667 
668 bool
670 {
671  return KidIdentifier == 0;
672 }
673 
674 bool
676 {
677  // when there is only one process, it has to be the worker
678  if (opt_no_daemon || Config.workers == 0)
679  return true;
680 
681  return TheProcessKind == pkWorker;
682 }
683 
684 bool
686 {
687  return TheProcessKind == pkDisker;
688 }
689 
690 bool
692 {
693  return !opt_no_daemon && Config.workers > 0;
694 }
695 
696 bool
698 {
699  return InDaemonMode() && NumberOfKids() > 1;
700 }
701 
702 bool
704 {
705  return TheProcessKind == pkCoordinator;
706 }
707 
708 bool
710 {
711  // when there is only one process, it has to be primary
712  if (opt_no_daemon || Config.workers == 0)
713  return true;
714 
715  // when there is a master and worker process, the master delegates
716  // primary functions to its only kid
717  if (NumberOfKids() == 1)
718  return IamWorkerProcess();
719 
720  // in SMP mode, multiple kids delegate primary functions to the coordinator
721  return IamCoordinatorProcess();
722 }
723 
724 int
726 {
727  // no kids in no-daemon mode
728  if (!InDaemonMode())
729  return 0;
730 
731  // XXX: detect and abort when called before workers/cache_dirs are parsed
732 
733  const int rockDirs = Config.cacheSwap.n_strands;
734 
735  const bool needCoord = Config.workers > 1 || rockDirs > 0;
736  return (needCoord ? 1 : 0) + Config.workers + rockDirs;
737 }
738 
739 SBuf
741 {
742  SBuf roles;
743  if (IamMasterProcess())
744  roles.append(" master");
745  if (IamCoordinatorProcess())
746  roles.append(" coordinator");
747  if (IamWorkerProcess())
748  roles.append(" worker");
749  if (IamDiskProcess())
750  roles.append(" disker");
751  return roles;
752 }
753 
754 /* A little piece of glue for odd systems */
755 #ifndef RLIMIT_NOFILE
756 #ifdef RLIMIT_OFILE
757 #define RLIMIT_NOFILE RLIMIT_OFILE
758 #endif
759 #endif
760 
762 void
763 setMaxFD(void)
764 {
765 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
766 
767  /* On Linux with 64-bit file support the sys/resource.h header
768  * uses #define to change the function definition to require rlimit64
769  */
770 #if defined(getrlimit)
771  struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
772 #else
773  struct rlimit rl;
774 #endif
775 
776  if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
777  int xerrno = errno;
778  debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
779  } else if (Config.max_filedescriptors > 0) {
780 #if USE_SELECT
781  /* select() breaks if this gets set too big */
782  if (Config.max_filedescriptors > FD_SETSIZE) {
783  rl.rlim_cur = FD_SETSIZE;
784  debugs(50, DBG_CRITICAL, "WARNING: 'max_filedescriptors " << Config.max_filedescriptors << "' does not work with select()");
785  } else
786 #endif
787  rl.rlim_cur = Config.max_filedescriptors;
788  if (rl.rlim_cur > rl.rlim_max)
789  rl.rlim_max = rl.rlim_cur;
790  if (setrlimit(RLIMIT_NOFILE, &rl)) {
791  int xerrno = errno;
792  debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
793  getrlimit(RLIMIT_NOFILE, &rl);
794  rl.rlim_cur = rl.rlim_max;
795  if (setrlimit(RLIMIT_NOFILE, &rl)) {
796  xerrno = errno;
797  debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
798  }
799  }
800  }
801  if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
802  int xerrno = errno;
803  debugs(50, DBG_CRITICAL, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
804  } else {
805  Squid_MaxFD = rl.rlim_cur;
806  }
807 
808 #endif /* HAVE_SETRLIMIT */
809 }
810 
811 void
813 {
814 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
815  /* limit system filedescriptors to our own limit */
816 
817  /* On Linux with 64-bit file support the sys/resource.h header
818  * uses #define to change the function definition to require rlimit64
819  */
820 #if defined(getrlimit)
821  struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
822 #else
823  struct rlimit rl;
824 #endif
825 
826  if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
827  int xerrno = errno;
828  debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
829  } else {
830  rl.rlim_cur = Squid_MaxFD;
831  if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
832  int xerrno = errno;
833  snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_NOFILE: %s", xstrerr(xerrno));
835  }
836  }
837 #endif /* HAVE_SETRLIMIT */
838 
839 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA) && !_SQUID_CYGWIN_
840  if (getrlimit(RLIMIT_DATA, &rl) < 0) {
841  int xerrno = errno;
842  debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_DATA: " << xstrerr(xerrno));
843  } else if (rl.rlim_max > rl.rlim_cur) {
844  rl.rlim_cur = rl.rlim_max; /* set it to the max */
845 
846  if (setrlimit(RLIMIT_DATA, &rl) < 0) {
847  int xerrno = errno;
848  snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_DATA: %s", xstrerr(xerrno));
850  }
851  }
852 #endif /* RLIMIT_DATA */
854  debugs(50, DBG_IMPORTANT, "WARNING: Could not increase the number of filedescriptors");
855  }
856 
857 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM) && !_SQUID_CYGWIN_
858  if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
859  int xerrno = errno;
860  debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_VMEM: " << xstrerr(xerrno));
861  } else if (rl.rlim_max > rl.rlim_cur) {
862  rl.rlim_cur = rl.rlim_max; /* set it to the max */
863 
864  if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
865  int xerrno = errno;
866  snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_VMEM: %s", xstrerr(xerrno));
868  }
869  }
870 #endif /* RLIMIT_VMEM */
871 }
872 
873 void
874 squid_signal(int sig, SIGHDLR * func, int flags)
875 {
876 #if HAVE_SIGACTION
877 
878  struct sigaction sa;
879  sa.sa_handler = func;
880  sa.sa_flags = flags;
881  sigemptyset(&sa.sa_mask);
882 
883  if (sigaction(sig, &sa, nullptr) < 0) {
884  int xerrno = errno;
885  debugs(50, DBG_CRITICAL, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerr(xerrno));
886  }
887 #else
888 #if _SQUID_WINDOWS_
889  /*
890  On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
891  are supported, so we must care of don't call signal() for other value.
892  The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
893  for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
894  */
895  switch (sig) {
896 
897  case SIGINT:
898 
899  case SIGILL:
900 
901  case SIGFPE:
902 
903  case SIGTERM:
904 
905  case SIGBREAK:
906 
907  case SIGABRT:
908  break;
909 
910  case SIGSEGV:
911  WIN32_ExceptionHandlerInit();
912  break;
913 
914  case SIGBUS:
915  WIN32_ExceptionHandlerInit();
916  return;
917  break; /* Nor reached */
918 
919  default:
920  return;
921  break; /* Nor reached */
922  }
923 
924 #endif
925 
926  signal(sig, func);
927 
928 #endif
929 }
930 
931 void
933 {
934  if (DebugStream())
935  fflush(DebugStream());
936 }
937 
938 void
939 debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
940 {
941  assert(label && obj && pm);
942  MemBuf mb;
943  mb.init();
944  (*pm) (obj, &mb);
945  debugs(section, level, "" << label << "" << mb.buf << "");
946  mb.clean();
947 }
948 
949 void
951 {
952  char buf[1024];
953  char buf2[512];
954  char *nt = buf;
955  char *lt = buf;
956 
957  if (!Config.etcHostsPath)
958  return;
959 
960  if (0 == strcmp(Config.etcHostsPath, "none"))
961  return;
962 
963  FILE *fp = fopen(Config.etcHostsPath, "r");
964 
965  if (!fp) {
966  int xerrno = errno;
967  debugs(1, DBG_IMPORTANT, "parseEtcHosts: '" << Config.etcHostsPath << "' : " << xstrerr(xerrno));
968  return;
969  }
970 
971 #if _SQUID_WINDOWS_
972  setmode(fileno(fp), O_TEXT);
973 #endif
974 
975  while (fgets(buf, 1024, fp)) { /* for each line */
976 
977  if (buf[0] == '#') /* MS-windows likes to add comments */
978  continue;
979 
980  strtok(buf, "#"); /* chop everything following a comment marker */
981 
982  lt = buf;
983 
984  char *addr = buf;
985 
986  debugs(1, 5, "etc_hosts: line is '" << buf << "'");
987 
988  nt = strpbrk(lt, w_space);
989 
990  if (nt == nullptr) /* empty line */
991  continue;
992 
993  *nt = '\0'; /* null-terminate the address */
994 
995  debugs(1, 5, "etc_hosts: address is '" << addr << "'");
996 
997  lt = nt + 1;
998 
999  SBufList hosts;
1000 
1001  while ((nt = strpbrk(lt, w_space))) {
1002  char *host = nullptr;
1003 
1004  if (nt == lt) { /* multiple spaces */
1005  debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1006  lt = nt + 1;
1007  continue;
1008  }
1009 
1010  *nt = '\0';
1011  debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
1012 
1013  /* For IPV6 addresses also check for a colon */
1014  if (Config.appendDomain && !strchr(lt, '.') && !strchr(lt, ':')) {
1015  /* I know it's ugly, but it's only at reconfig */
1016  strncpy(buf2, lt, sizeof(buf2)-1);
1017  strncat(buf2, Config.appendDomain, sizeof(buf2) - strlen(lt) - 1);
1018  buf2[sizeof(buf2)-1] = '\0';
1019  host = buf2;
1020  } else {
1021  host = lt;
1022  }
1023 
1024  if (ipcacheAddEntryFromHosts(host, addr) != 0) {
1025  /* invalid address, continuing is useless */
1026  hosts.clear();
1027  break;
1028  }
1029  hosts.emplace_back(SBuf(host));
1030 
1031  lt = nt + 1;
1032  }
1033 
1034  if (!hosts.empty())
1035  fqdncacheAddEntryFromHosts(addr, hosts);
1036  }
1037 
1038  fclose (fp);
1039 }
1040 
1041 int
1043 {
1045  if ((p = HttpPortList) != nullptr) {
1046  // skip any special interception ports
1047  while (p != nullptr && p->flags.isIntercepted())
1048  p = p->next;
1049  if (p != nullptr)
1050  return p->s.port();
1051  }
1052 
1053  if ((p = FtpPortList) != nullptr) {
1054  // skip any special interception ports
1055  while (p != nullptr && p->flags.isIntercepted())
1056  p = p->next;
1057  if (p != nullptr)
1058  return p->s.port();
1059  }
1060 
1061  debugs(21, DBG_CRITICAL, "ERROR: No forward-proxy ports configured.");
1062  return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1063 }
1064 
1065 /*
1066  * Set the umask to at least the given mask. This is in addition
1067  * to the umask set at startup
1068  */
1069 void
1071 {
1072  // No way to get the current umask value without setting it.
1073  static const mode_t orig_umask = umask(mask); // once, to get
1074  umask(mask | orig_umask); // always, to set
1075 }
1076 
1077 /*
1078  * Inverse of strwordtok. Quotes a word if needed
1079  */
1080 void
1081 strwordquote(MemBuf * mb, const char *str)
1082 {
1083  int quoted = 0;
1084 
1085  if (strchr(str, ' ')) {
1086  quoted = 1;
1087  mb->append("\"", 1);
1088  }
1089 
1090  while (*str) {
1091  int l = strcspn(str, "\"\\\n\r");
1092  mb->append(str, l);
1093  str += l;
1094 
1095  switch (*str) {
1096 
1097  case '\n':
1098  mb->append("\\n", 2);
1099  ++str;
1100  break;
1101 
1102  case '\r':
1103  mb->append("\\r", 2);
1104  ++str;
1105  break;
1106 
1107  case '\0':
1108  break;
1109 
1110  default:
1111  mb->append("\\", 1);
1112  mb->append(str, 1);
1113  ++str;
1114  break;
1115  }
1116  }
1117 
1118  if (quoted)
1119  mb->append("\"", 1);
1120 }
1121 
1122 void
1124 {
1125 #if HAVE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1126  if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
1127  Ip::Interceptor.StopTransparency("capability setting has failed.");
1128  }
1129 #endif
1130 }
1131 
1132 static void
1134 {
1135 #if HAVE_LIBCAP
1136  cap_t caps;
1137  if (keep)
1138  caps = cap_get_proc();
1139  else
1140  caps = cap_init();
1141  if (!caps) {
1142  Ip::Interceptor.StopTransparency("Can't get current capabilities");
1143  } else {
1144  int ncaps = 0;
1145  int rc = 0;
1146  cap_value_t cap_list[10];
1147  cap_list[ncaps] = CAP_NET_BIND_SERVICE;
1148  ++ncaps;
1149  if (Ip::Interceptor.TransparentActive() ||
1150 #if USE_LIBNETFILTERCONNTRACK
1151  // netfilter_conntrack requires CAP_NET_ADMIN to get client's CONNMARK
1152  Ip::Interceptor.InterceptActive() ||
1153 #endif
1154  Ip::Qos::TheConfig.isHitNfmarkActive() ||
1155  Ip::Qos::TheConfig.isAclNfmarkActive() ||
1156  Ip::Qos::TheConfig.isAclTosActive()) {
1157  cap_list[ncaps] = CAP_NET_ADMIN;
1158  ++ncaps;
1159  }
1160 
1161  cap_clear_flag(caps, CAP_EFFECTIVE);
1162  rc |= cap_set_flag(caps, CAP_EFFECTIVE, ncaps, cap_list, CAP_SET);
1163  rc |= cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET);
1164 
1165  if (rc || cap_set_proc(caps) != 0) {
1166  Ip::Interceptor.StopTransparency("Error enabling needed capabilities.");
1167  }
1168  cap_free(caps);
1169  }
1170 #elif _SQUID_LINUX_
1171  /* Linux requires syscap support from libcap. */
1172  Ip::Interceptor.StopTransparency("Missing needed capability support.");
1173  (void)keep;
1174 #else
1175  /* Non-Linux transparent proxy works with or without libcap support. */
1176  (void)keep;
1177 #endif
1178 }
1179 
1180 pid_t
1181 WaitForOnePid(pid_t pid, PidStatus &status, int flags)
1182 {
1183 #if _SQUID_WINDOWS_
1184  return 0; // function not used on Windows
1185 #else
1186  return waitpid(pid, &status, flags);
1187 #endif
1188 }
1189 
1190 #if _SQUID_WINDOWS_ || _SQUID_MINGW_
1191 SBuf
1192 WindowsErrorMessage(DWORD errorId)
1193 {
1194  char *rawMessage = nullptr;
1195  const auto length = FormatMessage(
1196  FORMAT_MESSAGE_ALLOCATE_BUFFER |
1197  FORMAT_MESSAGE_FROM_SYSTEM |
1198  FORMAT_MESSAGE_IGNORE_INSERTS,
1199  nullptr,
1200  errorId,
1201  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1202  static_cast<LPTSTR>(&rawMessage),
1203  0,
1204  nullptr);
1205  if (!length) {
1206  Must(!rawMessage); // nothing to LocalFree()
1207  return ToSBuf("windows error ", errorId);
1208  }
1209  const auto result = SBuf(rawMessage, length);
1210  LocalFree(rawMessage);
1211  return result;
1212 }
1213 #endif // _SQUID_WINDOWS_ || _SQUID_MINGW_
1214 
static char * debugOptions
Definition: Stream.h:80
const char * xstrerr(int error)
Definition: xstrerror.cc:83
char * buf
Definition: MemBuf.h:134
void SIGHDLR(int sig)
callback type for signal handlers
Definition: tools.h:39
#define Here()
source code location of the caller
Definition: Here.h:15
int getMyPort(void)
Definition: tools.cc:1042
void dumpMallocStats(void)
Definition: tools.cc:167
static void mail_warranty(void)
Definition: tools.cc:116
#define DBG_CRITICAL
Definition: Stream.h:37
const char * uniqueHostname(void)
Definition: tools.cc:548
void StopTransparency(const char *str)
Definition: Intercept.cc:116
int intPercent(const int a, const int b)
Definition: SquidMath.cc:13
void clientConnectionsClose()
#define FALSE
Definition: std-includes.h:56
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:62
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:22
int TheProcessKind
ProcessKind for the current process.
Definition: Kid.cc:21
int KidIdentifier
static char * dead_msg(void)
Definition: tools.cc:108
bool isAnyAddr() const
Definition: Address.cc:190
#define O_TEXT
Definition: defines.h:131
SBuf ProcessRoles()
a string describing this process roles such as worker or coordinator
Definition: tools.cc:740
std::list< SBuf > SBufList
Definition: forward.h:22
char * coredump_dir
Definition: SquidConfig.h:472
void keepCapabilities(void)
Definition: tools.cc:1123
void init(mb_size_t szInit, mb_size_t szMax)
Definition: MemBuf.cc:93
#define DEAD_MSG
Definition: tools.cc:62
Definition: SBuf.h:93
std::ostream & ForceAlert(std::ostream &s)
Definition: debug.cc:1411
void death(int sig)
Definition: tools.cc:346
struct timeval ru_utime
Definition: compat_shared.h:88
bool IamDiskProcess()
whether the current process is dedicated to managing a cache_dir
Definition: tools.cc:685
static void FreeAddr(struct addrinfo *&ai)
Definition: Address.cc:706
char * EmailProgram
Definition: SquidConfig.h:195
int ipcacheAddEntryFromHosts(const char *name, const char *ipaddr)
Definition: ipcache.cc:1126
Store::DiskConfig cacheSwap
Definition: SquidConfig.h:423
static char tmp_error_buf[32768]
Definition: tools.cc:90
size_t count() const
returns the number of kids
Definition: Kids.cc:146
#define w_space
void releaseServerSockets(void)
Definition: tools.cc:93
int opt_no_daemon
int DebugSignal
Definition: tools.cc:74
Kid & get(size_t i)
returns the kid by index, useful for kids iteration
Definition: Kids.cc:60
int ru_maxrss
Definition: compat_shared.h:89
static pid_t pid
Definition: IcmpSquid.cc:35
#define APP_SHORTNAME
Definition: version.h:22
class SquidConfig2 Config2
Definition: SquidConfig.cc:14
const char * version_string
void fqdncacheAddEntryFromHosts(char *addr, SBufList &hostnames)
Definition: fqdncache.cc:636
void leave_suid(void)
Definition: tools.cc:560
char * tempnam(const char *dir, const char *pfx)
Definition: tempnam.c:119
void(* ObjPackMethod)(void *obj, Packable *p)
Definition: tools.h:33
void sigusr2_handle(int sig)
Definition: tools.cc:434
void append(const char *c, int sz) override
Definition: MemBuf.cc:209
uid_t effectiveUserID
Definition: SquidConfig.h:564
#define NULL
Definition: types.h:145
void PrintRusage(void)
Definition: tools.cc:330
int rusage_pagefaults(struct rusage *r)
Definition: tools.cc:275
char * uniqueHostname
Definition: SquidConfig.h:229
pid_t WaitForOnePid(pid_t pid, PidStatus &status, int flags)
Definition: tools.cc:1181
#define SQUIDCEXTERN
Definition: squid.h:21
Definition: MemBuf.h:23
void squid_signal(int sig, SIGHDLR *func, int flags)
Definition: tools.cc:874
Kids TheKids
All kids being maintained.
Definition: Kids.cc:18
int n_strands
number of disk processes required to support all cache_dirs
Definition: SquidConfig.h:72
void clean()
Definition: MemBuf.cc:110
char * adminEmail
Definition: SquidConfig.h:193
void debug_trap(const char *message)
Definition: tools.cc:459
AnyP::PortCfgPointer FtpPortList
list of Squid ftp_port configured
Definition: PortCfg.cc:23
char * etcHostsPath
Definition: SquidConfig.h:227
#define assert(EX)
Definition: assert.h:17
static void PrepareToDie()
Definition: debug.cc:563
static void parseOptions(char const *)
Definition: debug.cc:1095
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
char * EmailFrom
Definition: SquidConfig.h:194
void EVH void double
Definition: stub_event.cc:16
int initgroups(const char *name, gid_t basegid)
Definition: initgroups.c:28
std::ostream & CurrentException(std::ostream &os)
prints active (i.e., thrown but not yet handled) exception
FILE * DebugStream()
Definition: debug.cc:355
void squid_getrusage(struct rusage *r)
Definition: tools.cc:181
char * effectiveGroup
Definition: SquidConfig.h:198
void parseEtcHosts(void)
Definition: tools.cc:950
void fatal_dump(const char *message)
Definition: fatal.cc:78
static void makeTraceable()
Definition: tools.cc:289
time_t squid_curtime
Definition: stub_libtime.cc:20
char * effectiveUser
Definition: SquidConfig.h:196
static std::ostream & Extra(std::ostream &)
Definition: debug.cc:1316
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
int Squid_MaxFD
#define xfree
bool IamMasterProcess()
whether the current process is the parent of all other Squid processes
Definition: tools.cc:669
void strwordquote(MemBuf *mb, const char *str)
Definition: tools.cc:1081
void BroadcastSignalIfAny(int &sig)
Definition: tools.cc:419
#define SQUID_RELEASE_TIME
Definition: version.h:13
int rusage_maxrss(struct rusage *r)
Definition: tools.cc:254
int storeDirWriteCleanLogs(int reopen)
Definition: Disks.cc:695
Intercept Interceptor
Definition: Intercept.h:135
double rusage_cputime(struct rusage *r)
Definition: tools.cc:239
Config TheConfig
Globally available instance of Qos::Config.
Definition: QosConfig.cc:288
void setUmask(mode_t mask)
Definition: tools.cc:1070
void getAddrInfo(struct addrinfo *&ai, int force=AF_UNSPEC) const
Definition: Address.cc:619
@ pkWorker
general-purpose worker bee
Definition: Kid.h:105
an std::runtime_error with thrower location info
Definition: TextException.h:20
int PidStatus
Definition: tools.h:91
bool IamWorkerProcess()
whether the current process handles HTTP transactions and such
Definition: tools.cc:675
bool IamCoordinatorProcess()
whether the current process coordinates worker processes
Definition: tools.cc:703
const char * getMyHostname(void)
Definition: tools.cc:468
void icpClosePorts(void)
Definition: icp_v2.cc:785
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63
#define Must(condition)
Definition: TextException.h:75
unsigned short mode_t
Definition: types.h:129
void enter_suid(void)
Definition: tools.cc:624
#define DBG_IMPORTANT
Definition: Stream.h:38
void setSystemLimits(void)
Definition: tools.cc:812
char * visibleHostname
Definition: SquidConfig.h:228
void logsFlush(void)
Definition: tools.cc:932
struct timeval ru_stime
Definition: compat_shared.h:87
int shutting_down
void setMaxFD(void)
Definition: tools.cc:763
gid_t effectiveGroupID
Definition: SquidConfig.h:565
void no_suid(void)
Definition: tools.cc:647
void debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
Definition: tools.cc:939
int opt_catch_signals
int max_filedescriptors
Definition: SquidConfig.h:520
char * appendDomain
Definition: SquidConfig.h:222
bool UsingSmp()
Whether there should be more than one worker process running.
Definition: tools.cc:697
int NumberOfKids()
number of Kid processes as defined in src/ipc/Kid.h
Definition: tools.cc:725
@ pkCoordinator
manages all other kids
Definition: Kid.h:104
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
SBuf service_name(APP_SHORTNAME)
static void setTraceability()
Definition: tools.cc:315
#define SQUIDHOSTNAMELEN
Definition: rfc2181.h:30
int xgethostname(char *name, size_t nameLength)
POSIX gethostname(2) equivalent.
Definition: unistd.h:49
class SquidConfig Config
Definition: SquidConfig.cc:12
@ pkDisker
cache_dir manager
Definition: Kid.h:106
bool IamPrimaryProcess()
Definition: tools.cc:709
int ru_majflt
Definition: compat_shared.h:90
static void restoreCapabilities(bool keep)
Definition: tools.cc:1133
bool InDaemonMode()
Whether we are running in daemon mode.
Definition: tools.cc:691

 

Introduction

Documentation

Support

Miscellaneous