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

 

Introduction

Documentation

Support

Miscellaneous