Squid Web Cache master
Loading...
Searching...
No Matches
tools.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2026 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_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
257 return r->ru_maxrss;
258#elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
259
260 return (r->ru_maxrss * getpagesize()) >> 10;
261#elif defined(PAGESIZE)
262
263 return (r->ru_maxrss * PAGESIZE) >> 10;
264#else
265
266 return r->ru_maxrss;
267#endif
268}
269
270int
271
273{
274 return r->ru_majflt;
275}
276
280static void
282{
283 const auto handleError = [](const char * const syscall, const int savedErrno) {
284 throw TextException(ToSBuf(syscall, " failure: ", xstrerr(savedErrno)), Here());
285 };
286#if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
287 if (prctl(PR_SET_DUMPABLE, 1) != 0)
288 handleError("prctl(PR_SET_DUMPABLE)", errno);
289#elif HAVE_PROCCTL && defined(PROC_TRACE_CTL)
290 // TODO: when FreeBSD 14 becomes the lowest version, we can
291 // possibly save one getpid syscall, for now still necessary.
292 int traceable = PROC_TRACE_CTL_ENABLE;
293 if (procctl(P_PID, getpid(), PROC_TRACE_CTL, &traceable) != 0)
294 handleError("procctl(PROC_TRACE_CTL_ENABLE)", errno);
295#elif HAVE_SETPFLAGS
296 if (setpflags(__PROC_PROTECT, 0) != 0)
297 handleError("setpflags(__PROC_PROTECT)", errno);
298#else
299 debugs(50, 2, "WARNING: Assuming this process is traceable");
300 (void)handleError; // just "use" the variable; there is no error here
301#endif
302}
303
306static void
308{
309 // for now, setting coredump_dir is required to make the process traceable
310 if (!Config.coredump_dir)
311 return;
312
313 try {
315 } catch (...) {
316 debugs(50, DBG_IMPORTANT, "ERROR: Cannot make the process traceable:" <<
317 Debug::Extra << "exception: " << CurrentException);
318 }
319}
320
321void
323{
324
325 struct rusage rusage;
327 fprintf(DebugStream(), "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
329 rusage.ru_utime.tv_sec + ((double) rusage.ru_utime.tv_usec / 1000000.0),
330 rusage.ru_stime.tv_sec + ((double) rusage.ru_stime.tv_usec / 1000000.0));
331 fprintf(DebugStream(), "Maximum Resident Size: %d KB\n",
333 fprintf(DebugStream(), "Page faults with physical i/o: %d\n",
335}
336
337void
338death(int sig)
339{
340 if (sig == SIGSEGV)
341 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Segment Violation...dying.");
342 else if (sig == SIGBUS)
343 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received Bus Error...dying.");
344 else
345 debugs(1, DBG_CRITICAL, ForceAlert << "FATAL: Received signal " << sig << "...dying.");
346
347#if PRINT_STACK_TRACE
348#if _SQUID_HPUX_
349 {
350 extern void U_STACK_TRACE(void); /* link with -lcl */
351 fflush(DebugStream());
352 dup2(fileno(DebugStream()), 2);
353 U_STACK_TRACE();
354 }
355
356#endif /* _SQUID_HPUX_ */
357#if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
358 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
359 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
360 fflush(DebugStream());
361 dup2(fileno(DebugStream()), fileno(stdout));
362 opcom_stack_trace();
363 fflush(stdout);
364 }
365
366#endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
367#if HAVE_BACKTRACE_SYMBOLS_FD
368 {
369 static void *callarray[8192];
370 int n;
371 n = backtrace(callarray, 8192);
372 backtrace_symbols_fd(callarray, n, fileno(DebugStream()));
373 }
374
375#endif
376#endif /* PRINT_STACK_TRACE */
377
378#if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
379 signal(SIGSEGV, SIG_DFL);
380
381 signal(SIGBUS, SIG_DFL);
382
383 signal(sig, SIG_DFL);
384
385#endif
386
388
390
391 if (!shutting_down) {
392 PrintRusage();
393
395 }
396
397 if (squid_curtime - SQUID_RELEASE_TIME < 864000) {
398 /* skip if more than 10 days old */
399
400 if (Config.adminEmail)
402
403 puts(dead_msg());
404 }
405
407 abort();
408}
409
410void
412{
413 if (sig > 0) {
414 if (IamMasterProcess()) {
415 for (int i = TheKids.count() - 1; i >= 0; --i) {
416 const auto &kid = TheKids.get(i);
417 if (kid.running())
418 kill(kid.getPid(), sig);
419 }
420 }
421 sig = -1;
422 }
423}
424
425void
427{
428 static int state = 0;
429 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
430
431 DebugSignal = sig;
432
433 if (state == 0) {
434 Debug::parseOptions("ALL,7");
435 state = 1;
436 } else {
438 state = 0;
439 }
440
441#if !HAVE_SIGACTION
442 /* reinstall */
443 if (signal(sig, sigusr2_handle) == SIG_ERR) {
444 int xerrno = errno;
445 debugs(50, DBG_CRITICAL, "signal: sig=" << sig << " func=sigusr2_handle: " << xstrerr(xerrno));
446 }
447#endif
448}
449
450void
451debug_trap(const char *message)
452{
454 fatal_dump(message);
455
456 debugs(50, DBG_CRITICAL, "WARNING: " << message);
457}
458
459const char *
461{
462 LOCAL_ARRAY(char, host, SQUIDHOSTNAMELEN + 1);
463 static int present = 0;
464 struct addrinfo *AI = nullptr;
465 Ip::Address sa;
466
467 if (Config.visibleHostname != nullptr)
468 return Config.visibleHostname;
469
470 if (present)
471 return host;
472
473 host[0] = '\0';
474
475 if (HttpPortList != nullptr && sa.isAnyAddr())
476 sa = HttpPortList->s;
477
478 /*
479 * If the first http_port address has a specific address, try a
480 * reverse DNS lookup on it.
481 */
482 if ( !sa.isAnyAddr() ) {
483
484 sa.getAddrInfo(AI);
485 /* we are looking for a name. */
486 if (getnameinfo(AI->ai_addr, AI->ai_addrlen, host, SQUIDHOSTNAMELEN, nullptr, 0, NI_NAMEREQD ) == 0) {
487 /* DNS lookup successful */
488 /* use the official name from DNS lookup */
489 debugs(50, 4, "getMyHostname: resolved " << sa << " to '" << host << "'");
490
491 present = 1;
492
494
495 if (strchr(host, '.'))
496 return host;
497 }
498
500 debugs(50, 2, "WARNING: failed to resolve " << sa << " to a fully qualified hostname");
501 }
502
503 // still no host. fallback to gethostname()
504 if (xgethostname(host, SQUIDHOSTNAMELEN) < 0) {
505 int xerrno = errno;
506 debugs(50, DBG_IMPORTANT, "WARNING: gethostname failed: " << xstrerr(xerrno));
507 } else {
508 /* Verify that the hostname given resolves properly */
509 struct addrinfo hints;
510 memset(&hints, 0, sizeof(addrinfo));
511 hints.ai_flags = AI_CANONNAME;
512
513 if (getaddrinfo(host, nullptr, nullptr, &AI) == 0) {
514 /* DNS lookup successful */
515 /* use the official name from DNS lookup */
516 debugs(50, 6, "getMyHostname: '" << host << "' has DNS resolution.");
517 present = 1;
518
519 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
520 if (AI)
521 freeaddrinfo(AI);
522
523 return host;
524 }
525 int xerrno = errno;
526
527 if (AI)
528 freeaddrinfo(AI);
529 debugs(50, DBG_IMPORTANT, "WARNING: '" << host << "' rDNS test failed: " << xstrerr(xerrno));
530 }
531
532 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
533 debugs(50, DBG_CRITICAL, "WARNING: Could not determine this machines public hostname. " <<
534 "Please configure one or set 'visible_hostname'.");
535
536 return ("localhost");
537}
538
539const char *
541{
542 debugs(21, 3, " Config: '" << Config.uniqueHostname << "'");
544}
545
551void
553{
554 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
555
557#if HAVE_SETGROUPS
558 setgroups(1, &Config2.effectiveGroupID);
559#endif
560
561 if (setgid(Config2.effectiveGroupID) < 0) {
562 int xerrno = errno;
563 debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
564 }
565 }
566
567 if (geteuid() != 0)
568 return;
569
570 /* Started as a root, check suid option */
571 if (Config.effectiveUser == nullptr)
572 return;
573
574 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config.effectiveUser << "'");
575
576 if (!Config.effectiveGroup) {
577
578 if (setgid(Config2.effectiveGroupID) < 0) {
579 int xerrno = errno;
580 debugs(50, DBG_CRITICAL, "ERROR: setgid: " << xstrerr(xerrno));
581 }
582
584 debugs(50, DBG_CRITICAL, "ERROR: initgroups: unable to set groups for User " <<
585 Config.effectiveUser << " and Group " <<
586 (unsigned) Config2.effectiveGroupID << "");
587 }
588 }
589
590#if HAVE_SETRESUID
591 if (setresuid(Config2.effectiveUserID, Config2.effectiveUserID, 0) < 0) {
592 const auto xerrno = errno;
593 fatalf("FATAL: setresuid: %s", xstrerr(xerrno));
594 }
595
596#elif HAVE_SETEUID
597 if (seteuid(Config2.effectiveUserID) < 0) {
598 const auto xerrno = errno;
599 fatalf("FATAL: seteuid: %s", xstrerr(xerrno));
600 }
601
602#else
603 if (setuid(Config2.effectiveUserID) < 0) {
604 const auto xerrno = errno;
605 fatalf("FATAL: setuid: %s", xstrerr(xerrno));
606 }
607
608#endif
609
612}
613
614/* Enter a privilegied section */
615void
617{
618 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
619#if HAVE_SETRESUID
620 if (setresuid((uid_t)-1, 0, (uid_t)-1) < 0) {
621 const auto xerrno = errno;
622 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerr(xerrno));
623 }
624#else
625
626 if (setuid(0) < 0) {
627 const auto xerrno = errno;
628 debugs(21, 3, "setuid(0) failed: " << xstrerr(xerrno));
629 }
630#endif
631
633}
634
635/* Give up the possibility to gain privilegies.
636 * this should be used before starting a sub process
637 */
638void
640{
641 uid_t uid;
642 leave_suid();
643 uid = geteuid();
644 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root privileges forever");
645
646 if (setuid(0) < 0) {
647 int xerrno = errno;
648 debugs(50, DBG_IMPORTANT, "WARNING: no_suid: setuid(0): " << xstrerr(xerrno));
649 }
650
651 if (setuid(uid) < 0) {
652 int xerrno = errno;
653 debugs(50, DBG_IMPORTANT, "ERROR: no_suid: setuid(" << uid << "): " << xstrerr(xerrno));
654 }
655
656 restoreCapabilities(false);
658}
659
660bool
662{
663 return KidIdentifier == 0;
664}
665
666bool
668{
669 // when there is only one process, it has to be the worker
670 if (opt_no_daemon || Config.workers == 0)
671 return true;
672
673 return TheProcessKind == pkWorker;
674}
675
676bool
678{
679 return TheProcessKind == pkDisker;
680}
681
682bool
684{
685 return !opt_no_daemon && Config.workers > 0;
686}
687
688bool
690{
691 return InDaemonMode() && NumberOfKids() > 1;
692}
693
694bool
699
700bool
702{
703 // when there is only one process, it has to be primary
704 if (opt_no_daemon || Config.workers == 0)
705 return true;
706
707 // when there is a master and worker process, the master delegates
708 // primary functions to its only kid
709 if (NumberOfKids() == 1)
710 return IamWorkerProcess();
711
712 // in SMP mode, multiple kids delegate primary functions to the coordinator
713 return IamCoordinatorProcess();
714}
715
716int
718{
719 // no kids in no-daemon mode
720 if (!InDaemonMode())
721 return 0;
722
723 // XXX: detect and abort when called before workers/cache_dirs are parsed
724
725 const int rockDirs = Config.cacheSwap.n_strands;
726
727 const bool needCoord = Config.workers > 1 || rockDirs > 0;
728 return (needCoord ? 1 : 0) + Config.workers + rockDirs;
729}
730
731SBuf
733{
734 SBuf roles;
735 if (IamMasterProcess())
736 roles.append(" master");
738 roles.append(" coordinator");
739 if (IamWorkerProcess())
740 roles.append(" worker");
741 if (IamDiskProcess())
742 roles.append(" disker");
743 return roles;
744}
745
746/* A little piece of glue for odd systems */
747#ifndef RLIMIT_NOFILE
748#ifdef RLIMIT_OFILE
749#define RLIMIT_NOFILE RLIMIT_OFILE
750#endif
751#endif
752
754void
756{
757#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
758
759 /* On Linux with 64-bit file support the sys/resource.h header
760 * uses #define to change the function definition to require rlimit64
761 */
762#if defined(getrlimit)
763 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
764#else
765 struct rlimit rl;
766#endif
767
768 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
769 int xerrno = errno;
770 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
771 } else if (Config.max_filedescriptors > 0) {
772#if USE_SELECT
773 /* select() breaks if this gets set too big */
774 if (Config.max_filedescriptors > FD_SETSIZE) {
775 rl.rlim_cur = FD_SETSIZE;
776 debugs(50, DBG_CRITICAL, "WARNING: 'max_filedescriptors " << Config.max_filedescriptors << "' does not work with select()");
777 } else
778#endif
779 rl.rlim_cur = Config.max_filedescriptors;
780 if (rl.rlim_cur > rl.rlim_max)
781 rl.rlim_max = rl.rlim_cur;
782 if (setrlimit(RLIMIT_NOFILE, &rl)) {
783 int xerrno = errno;
784 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
785 getrlimit(RLIMIT_NOFILE, &rl);
786 rl.rlim_cur = rl.rlim_max;
787 if (setrlimit(RLIMIT_NOFILE, &rl)) {
788 xerrno = errno;
789 debugs(50, DBG_CRITICAL, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
790 }
791 }
792 }
793 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
794 int xerrno = errno;
795 debugs(50, DBG_CRITICAL, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
796 } else {
797 Squid_MaxFD = rl.rlim_cur;
798 }
799
800#endif /* HAVE_SETRLIMIT */
801}
802
803void
805{
806#if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
807 /* limit system filedescriptors to our own limit */
808
809 /* On Linux with 64-bit file support the sys/resource.h header
810 * uses #define to change the function definition to require rlimit64
811 */
812#if defined(getrlimit)
813 struct rlimit64 rl; // Assume its a 64-bit redefine anyways.
814#else
815 struct rlimit rl;
816#endif
817
818 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
819 int xerrno = errno;
820 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno));
821 } else {
822 rl.rlim_cur = Squid_MaxFD;
823 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
824 int xerrno = errno;
825 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_NOFILE: %s", xstrerr(xerrno));
827 }
828 }
829#endif /* HAVE_SETRLIMIT */
830
831#if HAVE_SETRLIMIT && defined(RLIMIT_DATA) && !_SQUID_CYGWIN_
832 if (getrlimit(RLIMIT_DATA, &rl) < 0) {
833 int xerrno = errno;
834 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_DATA: " << xstrerr(xerrno));
835 } else if (rl.rlim_max > rl.rlim_cur) {
836 rl.rlim_cur = rl.rlim_max; /* set it to the max */
837
838 if (setrlimit(RLIMIT_DATA, &rl) < 0) {
839 int xerrno = errno;
840 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_DATA: %s", xstrerr(xerrno));
842 }
843 }
844#endif /* RLIMIT_DATA */
846 debugs(50, DBG_IMPORTANT, "WARNING: Could not increase the number of filedescriptors");
847 }
848
849#if HAVE_SETRLIMIT && defined(RLIMIT_VMEM) && !_SQUID_CYGWIN_
850 if (getrlimit(RLIMIT_VMEM, &rl) < 0) {
851 int xerrno = errno;
852 debugs(50, DBG_CRITICAL, "getrlimit: RLIMIT_VMEM: " << xstrerr(xerrno));
853 } else if (rl.rlim_max > rl.rlim_cur) {
854 rl.rlim_cur = rl.rlim_max; /* set it to the max */
855
856 if (setrlimit(RLIMIT_VMEM, &rl) < 0) {
857 int xerrno = errno;
858 snprintf(tmp_error_buf, sizeof(tmp_error_buf), "setrlimit: RLIMIT_VMEM: %s", xstrerr(xerrno));
860 }
861 }
862#endif /* RLIMIT_VMEM */
863}
864
865void
866squid_signal(int sig, SIGHDLR * func, int flags)
867{
868#if HAVE_SIGACTION
869
870 struct sigaction sa;
871 sa.sa_handler = func;
872 sa.sa_flags = flags;
873 sigemptyset(&sa.sa_mask);
874
875 if (sigaction(sig, &sa, nullptr) < 0) {
876 int xerrno = errno;
877 debugs(50, DBG_CRITICAL, "sigaction: sig=" << sig << " func=" << func << ": " << xstrerr(xerrno));
878 }
879#else
880#if _SQUID_WINDOWS_
881 /*
882 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
883 are supported, so we must care of don't call signal() for other value.
884 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
885 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
886 */
887 switch (sig) {
888
889 case SIGINT:
890
891 case SIGILL:
892
893 case SIGFPE:
894
895 case SIGTERM:
896
897 case SIGBREAK:
898
899 case SIGABRT:
900 break;
901
902 case SIGSEGV:
903 WIN32_ExceptionHandlerInit();
904 break;
905
906 case SIGBUS:
907 WIN32_ExceptionHandlerInit();
908 return;
909 break; /* Nor reached */
910
911 default:
912 return;
913 break; /* Nor reached */
914 }
915
916#endif
917
918 signal(sig, func);
919
920#endif
921}
922
923void
925{
926 if (DebugStream())
927 fflush(DebugStream());
928}
929
930void
931debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
932{
933 assert(label && obj && pm);
934 MemBuf mb;
935 mb.init();
936 (*pm) (obj, &mb);
937 debugs(section, level, "" << label << "" << mb.buf << "");
938 mb.clean();
939}
940
941void
943{
944 char buf[1024];
945 char buf2[512];
946 char *nt = buf;
947 char *lt = buf;
948
949 if (!Config.etcHostsPath)
950 return;
951
952 if (0 == strcmp(Config.etcHostsPath, "none"))
953 return;
954
955 FILE *fp = fopen(Config.etcHostsPath, "r");
956
957 if (!fp) {
958 int xerrno = errno;
959 debugs(1, DBG_IMPORTANT, "parseEtcHosts: '" << Config.etcHostsPath << "' : " << xstrerr(xerrno));
960 return;
961 }
962
963#if _SQUID_WINDOWS_
964 setmode(fileno(fp), O_TEXT);
965#endif
966
967 while (fgets(buf, 1024, fp)) { /* for each line */
968
969 if (buf[0] == '#') /* MS-windows likes to add comments */
970 continue;
971
972 strtok(buf, "#"); /* chop everything following a comment marker */
973
974 lt = buf;
975
976 char *addr = buf;
977
978 debugs(1, 5, "etc_hosts: line is '" << buf << "'");
979
980 nt = strpbrk(lt, w_space);
981
982 if (nt == nullptr) /* empty line */
983 continue;
984
985 *nt = '\0'; /* null-terminate the address */
986
987 debugs(1, 5, "etc_hosts: address is '" << addr << "'");
988
989 lt = nt + 1;
990
991 SBufList hosts;
992
993 while ((nt = strpbrk(lt, w_space))) {
994 char *host = nullptr;
995
996 if (nt == lt) { /* multiple spaces */
997 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
998 lt = nt + 1;
999 continue;
1000 }
1001
1002 *nt = '\0';
1003 debugs(1, 5, "etc_hosts: got hostname '" << lt << "'");
1004
1005 /* For IPV6 addresses also check for a colon */
1006 if (Config.appendDomain && !strchr(lt, '.') && !strchr(lt, ':')) {
1007 /* I know it's ugly, but it's only at reconfig */
1008 strncpy(buf2, lt, sizeof(buf2)-1);
1009 strncat(buf2, Config.appendDomain, sizeof(buf2) - strlen(lt) - 1);
1010 buf2[sizeof(buf2)-1] = '\0';
1011 host = buf2;
1012 } else {
1013 host = lt;
1014 }
1015
1016 if (ipcacheAddEntryFromHosts(host, addr) != 0) {
1017 /* invalid address, continuing is useless */
1018 hosts.clear();
1019 break;
1020 }
1021 hosts.emplace_back(SBuf(host));
1022
1023 lt = nt + 1;
1024 }
1025
1026 if (!hosts.empty())
1027 fqdncacheAddEntryFromHosts(addr, hosts);
1028 }
1029
1030 fclose (fp);
1031}
1032
1033int
1035{
1037 if ((p = HttpPortList) != nullptr) {
1038 // skip any special interception ports
1039 while (p != nullptr && p->flags.isIntercepted())
1040 p = p->next;
1041 if (p != nullptr)
1042 return p->s.port();
1043 }
1044
1045 if ((p = FtpPortList) != 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 debugs(21, DBG_CRITICAL, "ERROR: No forward-proxy ports configured.");
1054 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1055}
1056
1057/*
1058 * Set the umask to at least the given mask. This is in addition
1059 * to the umask set at startup
1060 */
1061void
1063{
1064 // No way to get the current umask value without setting it.
1065 static const mode_t orig_umask = umask(mask); // once, to get
1066 umask(mask | orig_umask); // always, to set
1067}
1068
1069/*
1070 * Inverse of strwordtok. Quotes a word if needed
1071 */
1072void
1073strwordquote(MemBuf * mb, const char *str)
1074{
1075 int quoted = 0;
1076
1077 if (strchr(str, ' ')) {
1078 quoted = 1;
1079 mb->append("\"", 1);
1080 }
1081
1082 while (*str) {
1083 const auto l = strcspn(str, "\"\\\n\r");
1084 mb->append(str, l);
1085 str += l;
1086
1087 switch (*str) {
1088
1089 case '\n':
1090 mb->append("\\n", 2);
1091 ++str;
1092 break;
1093
1094 case '\r':
1095 mb->append("\\r", 2);
1096 ++str;
1097 break;
1098
1099 case '\0':
1100 break;
1101
1102 default:
1103 mb->append("\\", 1);
1104 mb->append(str, 1);
1105 ++str;
1106 break;
1107 }
1108 }
1109
1110 if (quoted)
1111 mb->append("\"", 1);
1112}
1113
1114void
1116{
1117#if HAVE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1118 if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) {
1119 Ip::Interceptor.StopTransparency("capability setting has failed.");
1120 }
1121#endif
1122}
1123
1124static void
1126{
1127#if HAVE_LIBCAP
1128 cap_t caps;
1129 if (keep)
1130 caps = cap_get_proc();
1131 else
1132 caps = cap_init();
1133 if (!caps) {
1134 Ip::Interceptor.StopTransparency("Can't get current capabilities");
1135 } else {
1136 int ncaps = 0;
1137 int rc = 0;
1138 cap_value_t cap_list[10];
1139 cap_list[ncaps] = CAP_NET_BIND_SERVICE;
1140 ++ncaps;
1141 if (Ip::Interceptor.TransparentActive() ||
1143 // netfilter_conntrack requires CAP_NET_ADMIN to get client's CONNMARK
1144 Ip::Interceptor.InterceptActive() ||
1145#endif
1146 Ip::Qos::TheConfig.isHitNfmarkActive() ||
1147 Ip::Qos::TheConfig.isAclNfmarkActive() ||
1148 Ip::Qos::TheConfig.isAclTosActive()) {
1149 cap_list[ncaps] = CAP_NET_ADMIN;
1150 ++ncaps;
1151 }
1152
1153 cap_clear_flag(caps, CAP_EFFECTIVE);
1154 rc |= cap_set_flag(caps, CAP_EFFECTIVE, ncaps, cap_list, CAP_SET);
1155 rc |= cap_set_flag(caps, CAP_PERMITTED, ncaps, cap_list, CAP_SET);
1156
1157 if (rc || cap_set_proc(caps) != 0) {
1158 Ip::Interceptor.StopTransparency("Error enabling needed capabilities.");
1159 }
1160 cap_free(caps);
1161 }
1162#elif _SQUID_LINUX_
1163 /* Linux requires syscap support from libcap. */
1164 Ip::Interceptor.StopTransparency("Missing needed capability support.");
1165 (void)keep;
1166#else
1167 /* Non-Linux transparent proxy works with or without libcap support. */
1168 (void)keep;
1169#endif
1170}
1171
1172pid_t
1173WaitForOnePid(pid_t pid, PidStatus &status, int flags)
1174{
1175#if _SQUID_WINDOWS_
1176 return 0; // function not used on Windows
1177#else
1178 return waitpid(pid, &status, flags);
1179#endif
1180}
1181
1182#if _SQUID_WINDOWS_ || _SQUID_MINGW_
1183SBuf
1184WindowsErrorMessage(DWORD errorId)
1185{
1186 char *rawMessage = nullptr;
1187 const auto length = FormatMessage(
1188 FORMAT_MESSAGE_ALLOCATE_BUFFER |
1189 FORMAT_MESSAGE_FROM_SYSTEM |
1190 FORMAT_MESSAGE_IGNORE_INSERTS,
1191 nullptr,
1192 errorId,
1193 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1194 static_cast<LPTSTR>(&rawMessage),
1195 0,
1196 nullptr);
1197 if (!length) {
1198 Must(!rawMessage); // nothing to LocalFree()
1199 return ToSBuf("windows error ", errorId);
1200 }
1201 const auto result = SBuf(rawMessage, length);
1202 LocalFree(rawMessage);
1203 return result;
1204}
1205#endif // _SQUID_WINDOWS_ || _SQUID_MINGW_
1206
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:1532
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:824
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:552
bool IamMasterProcess()
whether the current process is the parent of all other Squid processes
Definition tools.cc:661
static void setTraceability()
Definition tools.cc:307
static void makeTraceable()
Definition tools.cc:281
bool InDaemonMode()
Whether we are running in daemon mode.
Definition tools.cc:683
void strwordquote(MemBuf *mb, const char *str)
Definition tools.cc:1073
void squid_signal(int sig, SIGHDLR *func, int flags)
Definition tools.cc:866
pid_t WaitForOnePid(pid_t pid, PidStatus &status, int flags)
Definition tools.cc:1173
bool IamWorkerProcess()
whether the current process handles HTTP transactions and such
Definition tools.cc:667
const char * getMyHostname(void)
Definition tools.cc:460
void setUmask(mode_t mask)
Definition tools.cc:1062
void death(int sig)
Definition tools.cc:338
void keepCapabilities(void)
Definition tools.cc:1115
void sigusr2_handle(int sig)
Definition tools.cc:426
void setMaxFD(void)
Definition tools.cc:755
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:701
void no_suid(void)
Definition tools.cc:639
int rusage_maxrss(struct rusage *r)
Definition tools.cc:254
void PrintRusage(void)
Definition tools.cc:322
SBuf service_name(APP_SHORTNAME)
int NumberOfKids()
number of Kid processes as defined in src/ipc/Kid.h
Definition tools.cc:717
#define DEAD_MSG
Definition tools.cc:62
void enter_suid(void)
Definition tools.cc:616
void logsFlush(void)
Definition tools.cc:924
int getMyPort(void)
Definition tools.cc:1034
static void mail_warranty(void)
Definition tools.cc:116
static void restoreCapabilities(bool keep)
Definition tools.cc:1125
void debugObj(int section, int level, const char *label, void *obj, ObjPackMethod pm)
Definition tools.cc:931
int DebugSignal
Definition tools.cc:74
void parseEtcHosts(void)
Definition tools.cc:942
void debug_trap(const char *message)
Definition tools.cc:451
int rusage_pagefaults(struct rusage *r)
Definition tools.cc:272
void BroadcastSignalIfAny(int &sig)
Definition tools.cc:411
bool IamCoordinatorProcess()
whether the current process coordinates worker processes
Definition tools.cc:695
const char * uniqueHostname(void)
Definition tools.cc:540
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:689
SBuf ProcessRoles()
a string describing this process roles such as worker or coordinator
Definition tools.cc:732
bool IamDiskProcess()
whether the current process is dedicated to managing a cache_dir
Definition tools.cc:677
void setSystemLimits(void)
Definition tools.cc:804
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