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