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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors