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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors