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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors