2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 21 Misc Functions */
12 #include "anyp/PortCfg.h"
13 #include "base/Subscription.h"
14 #include "client_side.h"
17 #include "fqdncache.h"
20 #include "http/Stream.h"
22 #include "ip/Intercept.h"
23 #include "ip/QosConfig.h"
24 #include "ipc/Coordinator.h"
28 #include "sbuf/Stream.h"
29 #include "SquidConfig.h"
30 #include "SquidMath.h"
31 #include "store/Disks.h"
36 #if HAVE_SYS_CAPABILITY_H
37 #include <sys/capability.h>
40 #include <sys/prctl.h>
42 #if HAVE_SYS_PROCCTL_H
43 #include <sys/procctl.h>
62 The Squid Cache (version %s) died.\n\
64 You've encountered a fatal error in the Squid Cache version %s.\n\
65 If a core file was created (possibly in the swap directory),\n\
66 please execute 'gdb squid core' or 'dbx squid core', then type 'where',\n\
67 and report the trace back to squid-bugs@lists.squid-cache.org.\n\
71 static void mail_warranty(void);
72 static void restoreCapabilities(bool keep
);
74 SBuf
service_name(APP_SHORTNAME
);
77 /* Workaround for crappy glic header files */
78 SQUIDCEXTERN
int backtrace(void *, int);
79 SQUIDCEXTERN
void backtrace_symbols_fd(void *, int, int);
80 SQUIDCEXTERN
int setresuid(uid_t
, uid_t
, uid_t
);
81 #else /* _SQUID_LINUX_ */
82 /* needed on Opensolaris for backtrace_symbols_fd */
85 #endif /* HAVE_EXECINFO_H */
87 #endif /* _SQUID_LINUX */
89 static char tmp_error_buf
[32768]; /* 32KB */
92 releaseServerSockets(void)
94 // Release the main ports as early as possible
96 // clear http_port, https_port, and ftp_port lists
97 clientConnectionsClose();
102 // XXX: Why not the HTCP, SNMP, DNS ports as well?
103 // XXX: why does this differ from main closeServerConnections() anyway ?
109 LOCAL_ARRAY(char, msg
, 1024);
110 snprintf(msg
, 1024, DEAD_MSG
, version_string
, version_string
);
118 static char command
[256];
121 * NP: umask() takes the mask of bits we DONT want set.
123 * We want the current user to have read/write access
124 * and since this file will be passed to mailsystem,
125 * the group and other must have read access.
127 const mode_t prev_umask
=umask(S_IXUSR
|S_IXGRP
|S_IWGRP
|S_IWOTH
|S_IXOTH
);
130 char filename
[] = "/tmp/squid-XXXXXX";
131 int tfd
= mkstemp(filename
);
132 if (tfd
< 0 || (fp
= fdopen(tfd
, "w")) == nullptr) {
138 // XXX tempnam is obsolete since POSIX.2008-1
139 // tmpfile is not an option, we want the created files to stick around
140 if ((filename
= tempnam(nullptr, APP_SHORTNAME
)) == NULL
||
141 (fp
= fopen(filename
, "w")) == NULL
) {
148 if (Config
.EmailFrom
)
149 fprintf(fp
, "From: %s\n", Config
.EmailFrom
);
151 fprintf(fp
, "From: %s@%s\n", APP_SHORTNAME
, uniqueHostname());
153 fprintf(fp
, "To: %s\n", Config
.adminEmail
);
154 fprintf(fp
, "Subject: %s\n", dead_msg());
157 snprintf(command
, 256, "%s %s < %s", Config
.EmailProgram
, Config
.adminEmail
, filename
);
158 if (system(command
)) {} /* XXX should avoid system(3) */
161 xfree(filename
); // tempnam() requires us to free its allocation
166 dumpMallocStats(void)
168 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
170 struct mstats ms
= mstats();
171 fprintf(DebugStream(), "\ttotal space in arena: %6d KB\n",
172 (int) (ms
.bytes_total
>> 10));
173 fprintf(DebugStream(), "\tTotal free: %6d KB %d%%\n",
174 (int) (ms
.bytes_free
>> 10),
175 Math::intPercent(ms
.bytes_free
, ms
.bytes_total
));
180 squid_getrusage(struct rusage
*r
)
182 memset(r
, '\0', sizeof(struct rusage
));
183 #if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
185 /* Solaris 2.5 has getrusage() permission bug -- Arjan de Vet */
189 getrusage(RUSAGE_SELF
, r
);
195 #elif defined(PSAPI_VERSION)
196 // Windows has an alternative method if there is no POSIX getrusage defined.
197 if (WIN32_OS_version
>= _WIN_OS_WINNT
) {
198 /* On Windows NT and later call PSAPI.DLL for process Memory */
199 /* information -- Guido Serassio */
201 PROCESS_MEMORY_COUNTERS pmc
;
202 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
|
204 FALSE
, GetCurrentProcessId());
206 /* Microsoft CRT doesn't have getrusage function, */
207 /* so we get process CPU time information from PSAPI.DLL. */
208 FILETIME ftCreate
, ftExit
, ftKernel
, ftUser
;
209 if (GetProcessTimes(hProcess
, &ftCreate
, &ftExit
, &ftKernel
, &ftUser
)) {
210 int64_t *ptUser
= (int64_t *)&ftUser
;
211 int64_t tUser64
= *ptUser
/ 10;
212 int64_t *ptKernel
= (int64_t *)&ftKernel
;
213 int64_t tKernel64
= *ptKernel
/ 10;
214 r
->ru_utime
.tv_sec
=(long)(tUser64
/ 1000000);
215 r
->ru_stime
.tv_sec
=(long)(tKernel64
/ 1000000);
216 r
->ru_utime
.tv_usec
=(long)(tUser64
% 1000000);
217 r
->ru_stime
.tv_usec
=(long)(tKernel64
% 1000000);
219 CloseHandle( hProcess
);
223 if (GetProcessMemoryInfo( hProcess
, &pmc
, sizeof(pmc
))) {
224 r
->ru_maxrss
=(DWORD
)(pmc
.WorkingSetSize
/ getpagesize());
225 r
->ru_majflt
=pmc
.PageFaultCount
;
227 CloseHandle( hProcess
);
231 CloseHandle( hProcess
);
238 rusage_cputime(struct rusage
*r
)
240 return (double) r
->ru_stime
.tv_sec
+
241 (double) r
->ru_utime
.tv_sec
+
242 (double) r
->ru_stime
.tv_usec
/ 1000000.0 +
243 (double) r
->ru_utime
.tv_usec
/ 1000000.0;
246 /* Hack for some HP-UX preprocessors */
247 #ifndef HAVE_GETPAGESIZE
248 #define HAVE_GETPAGESIZE 0
253 rusage_maxrss(struct rusage
*r
)
255 #if _SQUID_SGI_ && _ABIAPI
257 #elif _SQUID_SGI_|| _SQUID_OSF_ || _SQUID_AIX_ || defined(BSD4_4)
260 #elif defined(HAVE_GETPAGESIZE) && HAVE_GETPAGESIZE != 0
262 return (r
->ru_maxrss
* getpagesize()) >> 10;
263 #elif defined(PAGESIZE)
265 return (r
->ru_maxrss
* PAGESIZE
) >> 10;
274 rusage_pagefaults(struct rusage
*r
)
276 #if _SQUID_SGI_ && _ABIAPI
284 /// Make the process traceable if possible. Call setTraceability() instead!
285 /// Traceable processes may support attachment via ptrace(2) or ktrace(2),
286 /// debugging sysctls, hwpmc(4), dtrace(1) and core dumping.
290 const auto handleError
= [](const char * const syscall
, const int savedErrno
) {
291 throw TextException(ToSBuf(syscall
, " failure: ", xstrerr(savedErrno
)), Here());
293 #if HAVE_PRCTL && defined(PR_SET_DUMPABLE)
294 if (prctl(PR_SET_DUMPABLE
, 1) != 0)
295 handleError("prctl(PR_SET_DUMPABLE)", errno
);
296 #elif HAVE_PROCCTL && defined(PROC_TRACE_CTL)
297 // TODO: when FreeBSD 14 becomes the lowest version, we can
298 // possibly save one getpid syscall, for now still necessary.
299 int traceable
= PROC_TRACE_CTL_ENABLE
;
300 if (procctl(P_PID
, getpid(), PROC_TRACE_CTL
, &traceable
) != 0)
301 handleError("procctl(PROC_TRACE_CTL_ENABLE)", errno
);
303 if (setpflags(__PROC_PROTECT
, 0) != 0)
304 handleError("setpflags(__PROC_PROTECT)", errno
);
306 debugs(50, 2, "WARNING: Assuming this process is traceable");
307 (void)handleError
; // just "use" the variable; there is no error here
311 /// Make the process traceable if necessary.
312 /// \sa makeTraceable()
316 // for now, setting coredump_dir is required to make the process traceable
317 if (!Config
.coredump_dir
)
323 debugs(50, DBG_IMPORTANT
, "ERROR: Cannot make the process traceable:" <<
324 Debug::Extra
<< "exception: " << CurrentException
);
332 struct rusage rusage
;
333 squid_getrusage(&rusage
);
334 fprintf(DebugStream(), "CPU Usage: %.3f seconds = %.3f user + %.3f sys\n",
335 rusage_cputime(&rusage
),
336 rusage
.ru_utime
.tv_sec
+ ((double) rusage
.ru_utime
.tv_usec
/ 1000000.0),
337 rusage
.ru_stime
.tv_sec
+ ((double) rusage
.ru_stime
.tv_usec
/ 1000000.0));
338 fprintf(DebugStream(), "Maximum Resident Size: %d KB\n",
339 rusage_maxrss(&rusage
));
340 fprintf(DebugStream(), "Page faults with physical i/o: %d\n",
341 rusage_pagefaults(&rusage
));
348 debugs(1, DBG_CRITICAL
, ForceAlert
<< "FATAL: Received Segment Violation...dying.");
349 else if (sig
== SIGBUS
)
350 debugs(1, DBG_CRITICAL
, ForceAlert
<< "FATAL: Received Bus Error...dying.");
352 debugs(1, DBG_CRITICAL
, ForceAlert
<< "FATAL: Received signal " << sig
<< "...dying.");
354 #if PRINT_STACK_TRACE
357 extern void U_STACK_TRACE(void); /* link with -lcl */
358 fflush(DebugStream());
359 dup2(fileno(DebugStream()), 2);
363 #endif /* _SQUID_HPUX_ */
364 #if _SQUID_SOLARIS_ && HAVE_LIBOPCOM_STACK
365 { /* get ftp://opcom.sun.ca/pub/tars/opcom_stack.tar.gz and */
366 extern void opcom_stack_trace(void); /* link with -lopcom_stack */
367 fflush(DebugStream());
368 dup2(fileno(DebugStream()), fileno(stdout
));
373 #endif /* _SQUID_SOLARIS_and HAVE_LIBOPCOM_STACK */
374 #if HAVE_BACKTRACE_SYMBOLS_FD
376 static void *callarray
[8192];
378 n
= backtrace(callarray
, 8192);
379 backtrace_symbols_fd(callarray
, n
, fileno(DebugStream()));
383 #endif /* PRINT_STACK_TRACE */
385 #if SA_RESETHAND == 0 && !_SQUID_WINDOWS_
386 signal(SIGSEGV
, SIG_DFL
);
388 signal(SIGBUS
, SIG_DFL
);
390 signal(sig
, SIG_DFL
);
394 releaseServerSockets();
396 storeDirWriteCleanLogs(0);
398 if (!shutting_down
) {
404 if (squid_curtime
- SQUID_RELEASE_TIME
< 864000) {
405 /* skip if more than 10 days old */
407 if (Config
.adminEmail
)
413 Debug::PrepareToDie();
418 BroadcastSignalIfAny(int& sig
)
421 if (IamMasterProcess()) {
422 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
423 const auto &kid
= TheKids
.get(i
);
425 kill(kid
.getPid(), sig
);
433 sigusr2_handle(int sig
)
435 static int state
= 0;
436 /* no debugs() here; bad things happen if the signal is delivered during _db_print() */
441 Debug::parseOptions("ALL,7");
444 Debug::parseOptions(Debug::debugOptions
);
450 if (signal(sig
, sigusr2_handle
) == SIG_ERR
) {
452 debugs(50, DBG_CRITICAL
, "signal: sig=" << sig
<< " func=sigusr2_handle: " << xstrerr(xerrno
));
458 debug_trap(const char *message
)
460 if (!opt_catch_signals
)
463 debugs(50, DBG_CRITICAL
, "WARNING: " << message
);
469 LOCAL_ARRAY(char, host
, SQUIDHOSTNAMELEN
+ 1);
470 static int present
= 0;
471 struct addrinfo
*AI
= nullptr;
474 if (Config
.visibleHostname
!= nullptr)
475 return Config
.visibleHostname
;
482 if (HttpPortList
!= nullptr && sa
.isAnyAddr())
483 sa
= HttpPortList
->s
;
486 * If the first http_port address has a specific address, try a
487 * reverse DNS lookup on it.
489 if ( !sa
.isAnyAddr() ) {
492 /* we are looking for a name. */
493 if (getnameinfo(AI
->ai_addr
, AI
->ai_addrlen
, host
, SQUIDHOSTNAMELEN
, nullptr, 0, NI_NAMEREQD
) == 0) {
494 /* DNS lookup successful */
495 /* use the official name from DNS lookup */
496 debugs(50, 4, "getMyHostname: resolved " << sa
<< " to '" << host
<< "'");
500 Ip::Address::FreeAddr(AI
);
502 if (strchr(host
, '.'))
506 Ip::Address::FreeAddr(AI
);
507 debugs(50, 2, "WARNING: failed to resolve " << sa
<< " to a fully qualified hostname");
510 // still no host. fallback to gethostname()
511 if (gethostname(host
, SQUIDHOSTNAMELEN
) < 0) {
513 debugs(50, DBG_IMPORTANT
, "WARNING: gethostname failed: " << xstrerr(xerrno
));
515 /* Verify that the hostname given resolves properly */
516 struct addrinfo hints
;
517 memset(&hints
, 0, sizeof(addrinfo
));
518 hints
.ai_flags
= AI_CANONNAME
;
520 if (getaddrinfo(host
, nullptr, nullptr, &AI
) == 0) {
521 /* DNS lookup successful */
522 /* use the official name from DNS lookup */
523 debugs(50, 6, "getMyHostname: '" << host
<< "' has DNS resolution.");
526 /* AYJ: do we want to flag AI_ALL and cache the result anywhere. ie as our local host IPs? */
536 debugs(50, DBG_IMPORTANT
, "WARNING: '" << host
<< "' rDNS test failed: " << xstrerr(xerrno
));
539 /* throw a configuration error when the Host/IP given has bad DNS/rDNS. */
540 debugs(50, DBG_CRITICAL
, "WARNING: Could not determine this machines public hostname. " <<
541 "Please configure one or set 'visible_hostname'.");
543 return ("localhost");
549 debugs(21, 3, " Config: '" << Config
.uniqueHostname
<< "'");
550 return Config
.uniqueHostname
? Config
.uniqueHostname
: getMyHostname();
553 /** leave a privileged section. (Give up any privilegies)
554 * Routines that need privilegies can rap themselves in enter_suid()
556 * To give upp all posibilites to gain privilegies use no_suid()
561 debugs(21, 3, "leave_suid: PID " << getpid() << " called");
563 if (Config
.effectiveGroup
) {
565 setgroups(1, &Config2
.effectiveGroupID
);
568 if (setgid(Config2
.effectiveGroupID
) < 0) {
570 debugs(50, DBG_CRITICAL
, "ERROR: setgid: " << xstrerr(xerrno
));
577 /* Started as a root, check suid option */
578 if (Config
.effectiveUser
== nullptr)
581 debugs(21, 3, "leave_suid: PID " << getpid() << " giving up root, becoming '" << Config
.effectiveUser
<< "'");
583 if (!Config
.effectiveGroup
) {
585 if (setgid(Config2
.effectiveGroupID
) < 0) {
587 debugs(50, DBG_CRITICAL
, "ERROR: setgid: " << xstrerr(xerrno
));
590 if (initgroups(Config
.effectiveUser
, Config2
.effectiveGroupID
) < 0) {
591 debugs(50, DBG_CRITICAL
, "ERROR: initgroups: unable to set groups for User " <<
592 Config
.effectiveUser
<< " and Group " <<
593 (unsigned) Config2
.effectiveGroupID
<< "");
598 if (setresuid(Config2
.effectiveUserID
, Config2
.effectiveUserID
, 0) < 0) {
599 const auto xerrno
= errno
;
600 fatalf("FATAL: setresuid: %s", xstrerr(xerrno
));
604 if (seteuid(Config2
.effectiveUserID
) < 0) {
605 const auto xerrno
= errno
;
606 fatalf("FATAL: seteuid: %s", xstrerr(xerrno
));
610 if (setuid(Config2
.effectiveUserID
) < 0) {
611 const auto xerrno
= errno
;
612 fatalf("FATAL: setuid: %s", xstrerr(xerrno
));
617 restoreCapabilities(true);
621 /* Enter a privilegied section */
625 debugs(21, 3, "enter_suid: PID " << getpid() << " taking root privileges");
627 if (setresuid((uid_t
)-1, 0, (uid_t
)-1) < 0) {
628 const auto xerrno
= errno
;
629 debugs (21, 3, "enter_suid: setresuid failed: " << xstrerr(xerrno
));
634 const auto xerrno
= errno
;
635 debugs(21, 3, "setuid(0) failed: " << xstrerr(xerrno
));
642 /* Give up the possibility to gain privilegies.
643 * this should be used before starting a sub process
651 debugs(21, 3, "no_suid: PID " << getpid() << " giving up root privileges forever");
655 debugs(50, DBG_IMPORTANT
, "WARNING: no_suid: setuid(0): " << xstrerr(xerrno
));
658 if (setuid(uid
) < 0) {
660 debugs(50, DBG_IMPORTANT
, "ERROR: no_suid: setuid(" << uid
<< "): " << xstrerr(xerrno
));
663 restoreCapabilities(false);
670 return KidIdentifier
== 0;
676 // when there is only one process, it has to be the worker
677 if (opt_no_daemon
|| Config
.workers
== 0)
680 return TheProcessKind
== pkWorker
;
686 return TheProcessKind
== pkDisker
;
692 return !opt_no_daemon
&& Config
.workers
> 0;
698 return InDaemonMode() && NumberOfKids() > 1;
702 IamCoordinatorProcess()
704 return TheProcessKind
== pkCoordinator
;
710 // when there is only one process, it has to be primary
711 if (opt_no_daemon
|| Config
.workers
== 0)
714 // when there is a master and worker process, the master delegates
715 // primary functions to its only kid
716 if (NumberOfKids() == 1)
717 return IamWorkerProcess();
719 // in SMP mode, multiple kids delegate primary functions to the coordinator
720 return IamCoordinatorProcess();
726 // no kids in no-daemon mode
730 // XXX: detect and abort when called before workers/cache_dirs are parsed
732 const int rockDirs
= Config
.cacheSwap
.n_strands
;
734 const bool needCoord
= Config
.workers
> 1 || rockDirs
> 0;
735 return (needCoord
? 1 : 0) + Config
.workers
+ rockDirs
;
742 if (IamMasterProcess())
743 roles
.append(" master");
744 if (IamCoordinatorProcess())
745 roles
.append(" coordinator");
746 if (IamWorkerProcess())
747 roles
.append(" worker");
748 if (IamDiskProcess())
749 roles
.append(" disker");
753 /* A little piece of glue for odd systems */
754 #ifndef RLIMIT_NOFILE
756 #define RLIMIT_NOFILE RLIMIT_OFILE
760 /** Figure out the number of supported filedescriptors */
764 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE)
766 /* On Linux with 64-bit file support the sys/resource.h header
767 * uses #define to change the function definition to require rlimit64
769 #if defined(getrlimit)
770 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
775 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
777 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
778 } else if (Config
.max_filedescriptors
> 0) {
780 /* select() breaks if this gets set too big */
781 if (Config
.max_filedescriptors
> FD_SETSIZE
) {
782 rl
.rlim_cur
= FD_SETSIZE
;
783 debugs(50, DBG_CRITICAL
, "WARNING: 'max_filedescriptors " << Config
.max_filedescriptors
<< "' does not work with select()");
786 rl
.rlim_cur
= Config
.max_filedescriptors
;
787 if (rl
.rlim_cur
> rl
.rlim_max
)
788 rl
.rlim_max
= rl
.rlim_cur
;
789 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
791 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
792 getrlimit(RLIMIT_NOFILE
, &rl
);
793 rl
.rlim_cur
= rl
.rlim_max
;
794 if (setrlimit(RLIMIT_NOFILE
, &rl
)) {
796 debugs(50, DBG_CRITICAL
, "ERROR: setrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
800 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
802 debugs(50, DBG_CRITICAL
, "ERROR: getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
804 Squid_MaxFD
= rl
.rlim_cur
;
807 #endif /* HAVE_SETRLIMIT */
811 setSystemLimits(void)
813 #if HAVE_SETRLIMIT && defined(RLIMIT_NOFILE) && !_SQUID_CYGWIN_
814 /* limit system filedescriptors to our own limit */
816 /* On Linux with 64-bit file support the sys/resource.h header
817 * uses #define to change the function definition to require rlimit64
819 #if defined(getrlimit)
820 struct rlimit64 rl
; // Assume its a 64-bit redefine anyways.
825 if (getrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
827 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_NOFILE: " << xstrerr(xerrno
));
829 rl
.rlim_cur
= Squid_MaxFD
;
830 if (setrlimit(RLIMIT_NOFILE
, &rl
) < 0) {
832 snprintf(tmp_error_buf
, sizeof(tmp_error_buf
), "setrlimit: RLIMIT_NOFILE: %s", xstrerr(xerrno
));
833 fatal_dump(tmp_error_buf
);
836 #endif /* HAVE_SETRLIMIT */
838 #if HAVE_SETRLIMIT && defined(RLIMIT_DATA) && !_SQUID_CYGWIN_
839 if (getrlimit(RLIMIT_DATA
, &rl
) < 0) {
841 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_DATA: " << xstrerr(xerrno
));
842 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
843 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
845 if (setrlimit(RLIMIT_DATA
, &rl
) < 0) {
847 snprintf(tmp_error_buf
, sizeof(tmp_error_buf
), "setrlimit: RLIMIT_DATA: %s", xstrerr(xerrno
));
848 fatal_dump(tmp_error_buf
);
851 #endif /* RLIMIT_DATA */
852 if (Config
.max_filedescriptors
> Squid_MaxFD
) {
853 debugs(50, DBG_IMPORTANT
, "WARNING: Could not increase the number of filedescriptors");
856 #if HAVE_SETRLIMIT && defined(RLIMIT_VMEM) && !_SQUID_CYGWIN_
857 if (getrlimit(RLIMIT_VMEM
, &rl
) < 0) {
859 debugs(50, DBG_CRITICAL
, "getrlimit: RLIMIT_VMEM: " << xstrerr(xerrno
));
860 } else if (rl
.rlim_max
> rl
.rlim_cur
) {
861 rl
.rlim_cur
= rl
.rlim_max
; /* set it to the max */
863 if (setrlimit(RLIMIT_VMEM
, &rl
) < 0) {
865 snprintf(tmp_error_buf
, sizeof(tmp_error_buf
), "setrlimit: RLIMIT_VMEM: %s", xstrerr(xerrno
));
866 fatal_dump(tmp_error_buf
);
869 #endif /* RLIMIT_VMEM */
873 squid_signal(int sig
, SIGHDLR
* func
, int flags
)
878 sa
.sa_handler
= func
;
880 sigemptyset(&sa
.sa_mask
);
882 if (sigaction(sig
, &sa
, nullptr) < 0) {
884 debugs(50, DBG_CRITICAL
, "sigaction: sig=" << sig
<< " func=" << func
<< ": " << xstrerr(xerrno
));
889 On Windows, only SIGINT, SIGILL, SIGFPE, SIGTERM, SIGBREAK, SIGABRT and SIGSEGV signals
890 are supported, so we must care of don't call signal() for other value.
891 The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows. They are defined
892 for ANSI compatibility, so both SIGSEGV and SIGBUS are emulated with an Exception Handler.
910 WIN32_ExceptionHandlerInit();
914 WIN32_ExceptionHandlerInit();
916 break; /* Nor reached */
920 break; /* Nor reached */
934 fflush(DebugStream());
938 debugObj(int section
, int level
, const char *label
, void *obj
, ObjPackMethod pm
)
940 assert(label
&& obj
&& pm
);
944 debugs(section
, level
, "" << label
<< "" << mb
.buf
<< "");
956 if (!Config
.etcHostsPath
)
959 if (0 == strcmp(Config
.etcHostsPath
, "none"))
962 FILE *fp
= fopen(Config
.etcHostsPath
, "r");
966 debugs(1, DBG_IMPORTANT
, "parseEtcHosts: '" << Config
.etcHostsPath
<< "' : " << xstrerr(xerrno
));
971 setmode(fileno(fp
), O_TEXT
);
974 while (fgets(buf
, 1024, fp
)) { /* for each line */
976 if (buf
[0] == '#') /* MS-windows likes to add comments */
979 strtok(buf
, "#"); /* chop everything following a comment marker */
985 debugs(1, 5, "etc_hosts: line is '" << buf
<< "'");
987 nt
= strpbrk(lt
, w_space
);
989 if (nt
== nullptr) /* empty line */
992 *nt
= '\0'; /* null-terminate the address */
994 debugs(1, 5, "etc_hosts: address is '" << addr
<< "'");
1000 while ((nt
= strpbrk(lt
, w_space
))) {
1001 char *host
= nullptr;
1003 if (nt
== lt
) { /* multiple spaces */
1004 debugs(1, 5, "etc_hosts: multiple spaces, skipping");
1010 debugs(1, 5, "etc_hosts: got hostname '" << lt
<< "'");
1012 /* For IPV6 addresses also check for a colon */
1013 if (Config
.appendDomain
&& !strchr(lt
, '.') && !strchr(lt
, ':')) {
1014 /* I know it's ugly, but it's only at reconfig */
1015 strncpy(buf2
, lt
, sizeof(buf2
)-1);
1016 strncat(buf2
, Config
.appendDomain
, sizeof(buf2
) - strlen(lt
) - 1);
1017 buf2
[sizeof(buf2
)-1] = '\0';
1023 if (ipcacheAddEntryFromHosts(host
, addr
) != 0) {
1024 /* invalid address, continuing is useless */
1028 hosts
.emplace_back(SBuf(host
));
1034 fqdncacheAddEntryFromHosts(addr
, hosts
);
1043 AnyP::PortCfgPointer p
;
1044 if ((p
= HttpPortList
) != nullptr) {
1045 // skip any special interception ports
1046 while (p
!= nullptr && p
->flags
.isIntercepted())
1052 if ((p
= FtpPortList
) != nullptr) {
1053 // skip any special interception ports
1054 while (p
!= nullptr && p
->flags
.isIntercepted())
1060 debugs(21, DBG_CRITICAL
, "ERROR: No forward-proxy ports configured.");
1061 return 0; // Invalid port. This will result in invalid URLs on bad configurations.
1065 * Set the umask to at least the given mask. This is in addition
1066 * to the umask set at startup
1069 setUmask(mode_t mask
)
1071 // No way to get the current umask value without setting it.
1072 static const mode_t orig_umask
= umask(mask
); // once, to get
1073 umask(mask
| orig_umask
); // always, to set
1077 * Inverse of strwordtok. Quotes a word if needed
1080 strwordquote(MemBuf
* mb
, const char *str
)
1084 if (strchr(str
, ' ')) {
1086 mb
->append("\"", 1);
1090 int l
= strcspn(str
, "\"\\\n\r");
1097 mb
->append("\\n", 2);
1102 mb
->append("\\r", 2);
1110 mb
->append("\\", 1);
1118 mb
->append("\"", 1);
1122 keepCapabilities(void)
1124 #if HAVE_LIBCAP && HAVE_PRCTL && defined(PR_SET_KEEPCAPS)
1125 if (prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0)) {
1126 Ip::Interceptor
.StopTransparency("capability setting has failed.");
1132 restoreCapabilities(bool keep
)
1137 caps
= cap_get_proc();
1141 Ip::Interceptor
.StopTransparency("Can't get current capabilities");
1145 cap_value_t cap_list
[10];
1146 cap_list
[ncaps
] = CAP_NET_BIND_SERVICE
;
1148 if (Ip::Interceptor
.TransparentActive() ||
1149 #if USE_LIBNETFILTERCONNTRACK
1150 // netfilter_conntrack requires CAP_NET_ADMIN to get client's CONNMARK
1151 Ip::Interceptor
.InterceptActive() ||
1153 Ip::Qos::TheConfig
.isHitNfmarkActive() ||
1154 Ip::Qos::TheConfig
.isAclNfmarkActive() ||
1155 Ip::Qos::TheConfig
.isAclTosActive()) {
1156 cap_list
[ncaps
] = CAP_NET_ADMIN
;
1160 cap_clear_flag(caps
, CAP_EFFECTIVE
);
1161 rc
|= cap_set_flag(caps
, CAP_EFFECTIVE
, ncaps
, cap_list
, CAP_SET
);
1162 rc
|= cap_set_flag(caps
, CAP_PERMITTED
, ncaps
, cap_list
, CAP_SET
);
1164 if (rc
|| cap_set_proc(caps
) != 0) {
1165 Ip::Interceptor
.StopTransparency("Error enabling needed capabilities.");
1170 /* Linux requires syscap support from libcap. */
1171 Ip::Interceptor
.StopTransparency("Missing needed capability support.");
1174 /* Non-Linux transparent proxy works with or without libcap support. */
1180 WaitForOnePid(pid_t pid
, PidStatus
&status
, int flags
)
1183 return 0; // function not used on Windows
1185 return waitpid(pid
, &status
, flags
);
1189 #if _SQUID_WINDOWS_ || _SQUID_MINGW_
1191 WindowsErrorMessage(DWORD errorId
)
1193 char *rawMessage
= nullptr;
1194 const auto length
= FormatMessage(
1195 FORMAT_MESSAGE_ALLOCATE_BUFFER
|
1196 FORMAT_MESSAGE_FROM_SYSTEM
|
1197 FORMAT_MESSAGE_IGNORE_INSERTS
,
1200 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), // Default language
1201 static_cast<LPTSTR
>(&rawMessage
),
1205 Must(!rawMessage
); // nothing to LocalFree()
1206 return ToSBuf("windows error ", errorId
);
1208 const auto result
= SBuf(rawMessage
, length
);
1209 LocalFree(rawMessage
);
1212 #endif // _SQUID_WINDOWS_ || _SQUID_MINGW_