tools/apparmor/Makefile
tools/helper-mux/Makefile
tools/purge/Makefile
- tools/squidclient/Makefile
tools/systemd/Makefile
tools/sysvinit/Makefile
])
<tag>cache_object URI</tag>
<p>Cache manager is no longer accessible by URIs with cache_object scheme.
+ <tag>cachemgr</tag>
+ <p>The 'cachemgr' tool is no longer supported and distributed with squid.
+ A plethora of tools, such as curl, wget, or any web browser,
+ can be used in its place
+
<tag>non_peers</tag>
<p>Removed the <em>mgr:non_peers</em> report. Squid still ignores
unexpected ICP responses but no longer remembers the details that comprised
if [ ! -d ${tmpdir}/doc/manuals ] ; then
mkdir -p ${tmpdir}/doc/manuals
fi
- for f in `ls -1 ${tmpdir}/helpers/*/*/*.8 ${tmpdir}/src/*.8 ${tmpdir}/src/*/*.8 ${tmpdir}/tools/squidclient/*.1 ${tmpdir}/tools/*.8 ./helpers/*/*/*.8 2>/dev/null` ; do
+ for f in `ls -1 ${tmpdir}/helpers/*/*/*.8 ${tmpdir}/src/*.8 ${tmpdir}/src/*/*.8 ${tmpdir}/tools/*.8 ./helpers/*/*/*.8 2>/dev/null` ; do
cp $f ${tmpdir}/doc/manuals/
done
for f in `ls -1 ${tmpdir}/doc/manuals/*.1 ${tmpdir}/doc/manuals/*.8 2>/dev/null` ; do
[type: man] tools/cachemgr.cgi.8.in $lang:doc/manuals/$lang/cachemgr.cgi.8.in
[type: man] tools/purge/purge.1 $lang:doc/manuals/$lang/purge.1
-
-[type: man] tools/squidclient/squidclient.1 $lang:doc/manuals/$lang/squidclient.1
.
.SH SEE ALSO
.if !'po4a'hide' .B cachemgr.cgi "(8), "
-.if !'po4a'hide' .B squidclient "(1), "
.if !'po4a'hide' .B basic_pam_auth "(8), "
.if !'po4a'hide' .B basic_ldap_auth "(8), "
.if !'po4a'hide' .B ext_ldap_group_acl "(8), "
## we need our local files too (but avoid -I. at all costs)
AM_CPPFLAGS += -I$(srcdir)
-SUBDIRS= apparmor helper-mux purge squidclient systemd sysvinit
+SUBDIRS= apparmor helper-mux purge systemd sysvinit
EXTRA_DIST=
man_MANS=
DISTCLEANFILES=
.
.SH SEE ALSO
.if !'po4a'hide' .BR squid "(8), "
-.if !'po4a'hide' .BR squidclient "(1)"
.
.SH SEE ALSO
.if !'po4a'hide' .BR squid "(8), "
-.if !'po4a'hide' .BR squidclient "(1)"
.if !'po4a'hide' .BR cachemgr.cgi "(8)"
+++ /dev/null
-## Copyright (C) 1996-2023 The Squid Software Foundation and contributors
-##
-## Squid software is distributed under GPLv2+ license and includes
-## contributions from numerous individuals and organizations.
-## Please see the COPYING and CONTRIBUTORS files for details.
-##
-
-include $(top_srcdir)/src/Common.am
-
-SUBDIRS =
-EXTRA_DIST = squidclient.1
-man_MANS = squidclient.1
-DISTCLEANFILES =
-
-LDADD = \
- $(top_builddir)/src/ip/libip.la \
- $(top_builddir)/src/mem/libminimal.la \
- $(top_builddir)/src/time/libtime.la \
- $(top_builddir)/src/base/libbase.la \
- $(top_builddir)/lib/libmiscencoding.la \
- $(top_builddir)/lib/libmiscutil.la \
- $(COMPAT_LIB) \
- $(LIBGNUTLS_LIBS) \
- $(LIBNETTLE_LIBS) \
- $(KRB5LIBS) \
- $(XTRA_LIBS)
-
-include $(top_srcdir)/doc/manuals/Substitute.am
-
-## Several files need to be shared but we cannot depend on the other
-## directories to be built.
-test_tools.cc: $(top_srcdir)/test-suite/test_tools.cc
- cp $(top_srcdir)/test-suite/test_tools.cc $@
-
-tests/stub_debug.cc: $(top_srcdir)/src/tests/stub_debug.cc | tests
- cp $(top_srcdir)/src/tests/stub_debug.cc $@
-
-tests/STUB.h: $(top_srcdir)/src/tests/STUB.h | tests
- cp $(top_srcdir)/src/tests/STUB.h $@
-
-tests:
- mkdir -p $@
-
-# stock tools for unit tests - library independent versions of dlink_list
-# etc.
-# globals.cc is needed by test_tools.cc.
-# Neither of these should be disted from here.
-TESTSOURCES= test_tools.cc
-CLEANFILES += test_tools.cc tests/stub_debug.cc tests/STUB.h
-
-## ##### squidclient #####
-
-bin_PROGRAMS = squidclient
-
-squidclient_SOURCES = \
- Parameters.h \
- Ping.cc \
- Ping.h \
- Transport.cc \
- Transport.h \
- gssapi_support.cc \
- gssapi_support.h \
- squidclient.cc \
- test_tools.cc
-
-nodist_squidclient_SOURCES = \
- tests/stub_debug.cc \
- tests/STUB.h
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#ifndef _SQUID_TOOLS_SQUIDCLIENT_PARAMETERS_H
-#define _SQUID_TOOLS_SQUIDCLIENT_PARAMETERS_H
-
-/**
- * squidclient command line parameters.
- */
-class Parameters
-{
-public:
- Parameters() : verbosityLevel(0) {}
-
- /**
- * What verbosity level to display.
- *
- * 0 : display no debug traces
- * 1 : display outgoing request message
- * 2+ : display all actions taken
- */
- int verbosityLevel;
-};
-
-/// display debug messages at varying verbosity levels
-#define debugVerbose(LEVEL, MESSAGE) \
- while ((LEVEL) <= scParams.verbosityLevel) {std::cerr << MESSAGE << std::endl; break;}
-
-/// global squidcleint parameters
-extern Parameters scParams;
-
-#endif /* _SQUID_TOOLS_SQUIDCLIENT_PARAMETERS_H */
-
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#include "squid.h"
-#include "time/gadgets.h"
-#include "tools/squidclient/Parameters.h"
-#include "tools/squidclient/Ping.h"
-
-#include <climits>
-#include <csignal>
-#include <iostream>
-
-#if HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-namespace Ping
-{
-Ping::TheConfig Config;
-
-/// measurements collected by the squidclient ping mode logics
-class pingStats_
-{
-public:
- pingStats_() {memset(this, 0, sizeof(pingStats_));}
-
- long counted; ///< number of transactions which have so far been measured
- long pMin; ///< shortest transaction time seen
- long pMax; ///< longest transaction time seen
- long sum; ///< total time so far spent waiting on transactions
-
-} stats;
-
-} // namespace Ping
-
-/**
- * Signal interrupt handler for squidclient ping.
- * Displays final statistics and disables further pings.
- */
-static void
-catchSignal(int sig)
-{
- Ping::DisplayStats();
- Ping::Config.enable = false;
- std::cerr << "SIGNAL " << sig << " Interrupted." << std::endl;
-}
-
-uint32_t
-Ping::Init()
-{
- if (Ping::Config.enable) {
-#if HAVE_SIGACTION
- struct sigaction sa, osa;
- if (sigaction(SIGINT, nullptr, &osa) == 0 && osa.sa_handler == SIG_DFL) {
- sa.sa_handler = catchSignal;
- sa.sa_flags = 0;
- sigemptyset(&sa.sa_mask);
- (void) sigaction(SIGINT, &sa, nullptr);
- }
-#else
- void (*osig) (int);
- if ((osig = signal(SIGINT, catchSignal)) != SIG_DFL)
- (void) signal(SIGINT, osig);
-#endif
- return Ping::Config.count;
- }
-
- return 1;
-}
-
-static struct timeval tv1, tv2;
-
-void
-Ping::TimerStart()
-{
- if (!Ping::Config.enable)
- return;
-
-#if GETTIMEOFDAY_NO_TZP
- (void)gettimeofday(&tv1);
-#else
- (void)gettimeofday(&tv1, nullptr);
-#endif
-}
-
-void
-Ping::TimerStop(size_t fsize)
-{
- if (!Ping::Config.enable)
- return;
-
- struct tm *tmp;
- time_t t2s;
- long elapsed_msec;
-
-#if GETTIMEOFDAY_NO_TZP
- (void)gettimeofday(&tv2);
-#else
- (void)gettimeofday(&tv2, nullptr);
-#endif
-
- elapsed_msec = tvSubMsec(tv1, tv2);
- t2s = tv2.tv_sec;
- tmp = localtime(&t2s);
- char tbuf[4096];
- snprintf(tbuf, sizeof(tbuf)-1, "%d-%02d-%02d %02d:%02d:%02d [%ld]: %ld.%03ld secs, %f KB/s",
- tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec, stats.counted + 1,
- elapsed_msec / 1000, elapsed_msec % 1000,
- elapsed_msec ? (double) fsize / elapsed_msec : -1.0);
- std::cerr << tbuf << std::endl;
-
- if (!stats.counted || elapsed_msec < stats.pMin)
- stats.pMin = elapsed_msec;
-
- if (!stats.counted || elapsed_msec > stats.pMax)
- stats.pMax = elapsed_msec;
-
- stats.sum += elapsed_msec;
-
- ++stats.counted;
-
- /* Delay until next "ping.interval" boundary */
- if (!LoopDone(stats.counted) && elapsed_msec < Ping::Config.interval) {
-
- struct timeval tvs;
- long msec_left = Ping::Config.interval - elapsed_msec;
-
- tvs.tv_sec = msec_left / 1000;
- tvs.tv_usec = (msec_left % 1000) * 1000;
- select(0, nullptr, nullptr, nullptr, &tvs);
- }
-}
-
-void
-Ping::DisplayStats()
-{
- if (Ping::Config.enable && stats.counted) {
- long mean = stats.sum / stats.counted;
- std::cerr << std::endl
- << stats.counted << " requests, round-trip (secs) min/avg/max = "
- << (stats.pMin/1000) << "." << (stats.pMin%1000)
- << "/" << (mean/1000) << "." << (mean%1000)
- << "/" << (stats.pMax/1000) << "." << (stats.pMax%1000)
- << std::endl;
- }
-}
-
-void
-Ping::TheConfig::usage()
-{
- std::cerr << "Ping Mode" << std::endl
- << " --ping [options] Enable ping mode." << std::endl
- << std::endl
- << " options:" << std::endl
- << " -g count Ping iteration count (default, loop until interrupted)." << std::endl
- << " -I interval Ping interval in seconds (default 1 second)." << std::endl
- << std::endl;
-}
-
-bool
-Ping::TheConfig::parseCommandOpts(int argc, char *argv[], int c, int &optIndex)
-{
- // to get here --ping was seen
- enable = true;
- count = 0; // default is infinite loop
- interval = 1 * 1000; // default is 1s intervals
-
- const char *shortOpStr = "g:I:?";
-
- // options for controlling squidclient ping mode
- static struct option pingOptions[] = {
- {"count", no_argument, nullptr, 'g'},
- {"interval", no_argument, nullptr, 'I'},
- {nullptr, 0, nullptr, 0}
- };
-
- int saved_opterr = opterr;
- opterr = 0; // suppress errors from getopt
- while ((c = getopt_long(argc, argv, shortOpStr, pingOptions, &optIndex)) != -1) {
- switch (c) {
- case 'g':
- if (optarg)
- count = atoi(optarg);
- else {
- std::cerr << "ERROR: -g ping count missing parameter." << std::endl;
- usage();
- }
- break;
-
- case 'I':
- if (!optarg) {
- std::cerr << "ERROR: -I ping interval missing parameter." << std::endl;
- usage();
- } else if ((interval = atoi(optarg) * 1000) <= 0) {
- std::cerr << "ERROR: -I ping interval out of range (0-" << (INT_MAX/1000) << ")." << std::endl;
- usage();
- }
- break;
-
- default:
- // rewind and let the caller handle unknown options
- --optind;
- opterr = saved_opterr;
- return true;
- }
- }
-
- opterr = saved_opterr;
- return false;
-}
-
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#ifndef _SQUID_TOOLS_CLIENT_PING_H
-#define _SQUID_TOOLS_CLIENT_PING_H
-
-/**
- * API for looping the squidclient request message
- * repeatedly.
- */
-namespace Ping
-{
-
-/// parameters controlling 'ping' mode message looping.
-class TheConfig
-{
-public:
- TheConfig() : enable(false), count(0), interval(1*1000) {}
-
- /// display Ping Options command line help to stderr
- void usage();
-
- /**
- * parse --ping command line options
- * \return true if there are other options still to parse
- */
- bool parseCommandOpts(int argc, char *argv[], int c, int &optIndex);
-
- bool enable;
- int count;
- int interval;
-};
-
-extern TheConfig Config;
-
-/// initialize the squidclient ping mode
-uint32_t Init();
-
-/// whether ping loop is completed at the given iteration.
-inline bool LoopDone(int i)
-{
- return !Ping::Config.enable || (Ping::Config.count && i >= Ping::Config.count);
-}
-
-/// start timing a new transaction
-void TimerStart();
-
-/// calculate and display the statistics for a complete transaction
-/// \param fsize number of bytes transferred during this transaction (for KB/s measure)
-void TimerStop(size_t fsize);
-
-/// display summary of ping data collected
-void DisplayStats();
-
-} // namespace Ping
-
-#endif /* _SQUID_TOOLS_CLIENT_PING_H */
-
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#include "squid.h"
-#include "ip/Address.h"
-#include "ip/tools.h"
-#include "tools/squidclient/Ping.h"
-#include "tools/squidclient/Transport.h"
-
-#if HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-#if HAVE_GNUTLS_X509_H
-#include <gnutls/x509.h>
-#endif
-#include <iostream>
-
-Transport::TheConfig Transport::Config;
-
-/// the current server connection FD
-int conn = -1;
-
-void
-Transport::TheConfig::usage()
-{
- std::cerr << "Connection Settings" << std::endl
- << " -h | --host host Send message to server on 'host'. Default is localhost." << std::endl
- << " -l | --local host Specify a local IP address to bind to. Default is none." << std::endl
- << " -p | --port port Port number on server to contact. Default is " << CACHE_HTTP_PORT << "." << std::endl
- << " -T timeout Timeout in seconds for read/write operations" << std::endl
-#if USE_GNUTLS
- << " --https Use TLS/SSL on the HTTP connection" << std::endl
- << std::endl
- << " TLS options:" << std::endl
- << " --anonymous-tls Use Anonymous TLS. Sets default parameters:" << std::endl
- << " \"PERFORMANCE:+ANON-ECDH:+ANON-DH\"" << std::endl
- << " --params=\"...\" Use the given parameters." << std::endl
- << " --cert=FILE Path to a PEM file holding the client X.509 certificate chain." << std::endl
- << " May be repeated if there are multiple certificates to use for the server." << std::endl
- << " --trusted-ca=PATH Path to a PEM file holding trusted CA certificate(s)." << std::endl
- << " May be repeated." << std::endl
- << " Example path: \"/etc/ssl/certs/ca-certificates.crt\"" << std::endl
-#endif
- << std::endl;
-}
-
-bool
-Transport::TheConfig::parseCommandOpts(int argc, char *argv[], int c, int &optIndex)
-{
- bool tls = false;
- const char *shortOpStr = "h:l:p:T:?";
-
- // options for controlling squidclient transport connection
- static struct option longOptions[] = {
- {"anonymous-tls",no_argument, nullptr, '\1'},
- {"https", no_argument, nullptr, '\3'},
- {"trusted-ca", required_argument, nullptr, 'A'},
- {"cert", required_argument, nullptr, 'C'},
- {"host", required_argument, nullptr, 'h'},
- {"local", required_argument, nullptr, 'l'},
- {"port", required_argument, nullptr, 'p'},
- {"params", required_argument, nullptr, 'P'},
- {nullptr, 0, nullptr, 0}
- };
-
- int saved_opterr = opterr;
- opterr = 0; // suppress errors from getopt
- do {
- switch (c) {
- case '\1':
- tls = true;
- tlsAnonymous = true;
- params = "PERFORMANCE:+ANON-ECDH:+ANON-DH";
- break;
-
- case '\3':
- tls = true;
- break;
-
- case 'A':
- tls = true;
- caFiles.push_back(std::string(optarg));
- break;
-
- case 'C':
- tls = true;
- certFiles.push_back(std::string(optarg));
- break;
-
- case 'h':
- hostname = optarg;
- break;
-
- case 'l':
- localHost = optarg;
- break;
-
- case 'p': /* port number */
- sscanf(optarg, "%hd", &port);
- if (port < 1)
- port = CACHE_HTTP_PORT; /* default */
- break;
-
- case 'P':
- tls = true;
- params = optarg;
- break;
-
- case 'T':
- ioTimeout = atoi(optarg);
- break;
-
- default:
- if (tls)
- Transport::InitTls();
-
- // rewind and let the caller handle unknown options
- --optind;
- opterr = saved_opterr;
- return true;
- }
- } while ((c = getopt_long(argc, argv, shortOpStr, longOptions, &optIndex)) != -1);
-
- if (tls)
- Transport::InitTls();
-
- opterr = saved_opterr;
- return false;
-}
-
-/// Set up the source socket address from which to send.
-static int
-client_comm_bind(int sock, const Ip::Address &addr)
-{
- static struct addrinfo *AI = nullptr;
- addr.getAddrInfo(AI);
- int res = bind(sock, AI->ai_addr, AI->ai_addrlen);
- Ip::Address::FreeAddr(AI);
- return res;
-}
-
-static void
-resolveDestination(Ip::Address &iaddr)
-{
- struct addrinfo *AI = nullptr;
-
- debugVerbose(2, "Transport detected: IPv4" <<
- ((Ip::EnableIpv6 & IPV6_SPECIAL_V4MAPPING) ? "-mapped " : "") <<
- (Ip::EnableIpv6 == IPV6_OFF ? "-only" : " and IPv6") <<
- ((Ip::EnableIpv6 & IPV6_SPECIAL_SPLITSTACK) ? " split-stack" : ""));
-
- if (Transport::Config.localHost) {
- debugVerbose(2, "Resolving " << Transport::Config.localHost << " ...");
-
- if ( !iaddr.GetHostByName(Transport::Config.localHost) ) {
- std::cerr << "ERROR: Cannot resolve " << Transport::Config.localHost << ": Host unknown." << std::endl;
- exit(1);
- }
- } else {
- debugVerbose(2, "Resolving " << Transport::Config.hostname << " ...");
- /* Process the remote host name to locate the Protocol required
- in case we are being asked to link to another version of squid */
- if ( !iaddr.GetHostByName(Transport::Config.hostname) ) {
- std::cerr << "ERROR: Cannot resolve " << Transport::Config.hostname << ": Host unknown." << std::endl;
- exit(1);
- }
- }
-
- iaddr.getAddrInfo(AI);
- if ((conn = socket(AI->ai_family, AI->ai_socktype, 0)) < 0) {
- std::cerr << "ERROR: could not open socket to " << iaddr << std::endl;
- Ip::Address::FreeAddr(AI);
- exit(1);
- }
- Ip::Address::FreeAddr(AI);
-
- if (Transport::Config.localHost) {
- if (client_comm_bind(conn, iaddr) < 0) {
- std::cerr << "ERROR: could not bind socket to " << iaddr << std::endl;
- exit(1);
- }
-
- iaddr.setEmpty();
-
- debugVerbose(2, "Resolving... " << Transport::Config.hostname);
-
- if ( !iaddr.GetHostByName(Transport::Config.hostname) ) {
- std::cerr << "ERROR: Cannot resolve " << Transport::Config.hostname << ": Host unknown." << std::endl;
- exit(1);
- }
- }
-
- iaddr.port(Transport::Config.port);
-}
-
-/// Set up the destination socket address for message to send to.
-static int
-client_comm_connect(int sock, const Ip::Address &addr)
-{
- static struct addrinfo *AI = nullptr;
- addr.getAddrInfo(AI);
- int res = connect(sock, AI->ai_addr, AI->ai_addrlen);
- Ip::Address::FreeAddr(AI);
- Ping::TimerStart();
- return res;
-}
-
-bool
-Transport::Connect()
-{
- Ip::Address iaddr;
- resolveDestination(iaddr);
-
- debugVerbose(2, "Connecting... " << Config.hostname << " (" << iaddr << ")");
-
- if (client_comm_connect(conn, iaddr) < 0) {
- char hostnameBuf[MAX_IPSTRLEN];
- iaddr.toUrl(hostnameBuf, MAX_IPSTRLEN);
- std::cerr << "ERROR: Cannot connect to " << hostnameBuf
- << (!errno ?": Host unknown." : "") << std::endl;
- exit(1);
- }
- debugVerbose(2, "Connected to: " << Config.hostname << " (" << iaddr << ")");
-
- // do any TLS setup that might be needed
- if (!Transport::MaybeStartTls(Config.hostname))
- return false;
-
- return true;
-}
-
-ssize_t
-Transport::Write(const void *buf, size_t len)
-{
- if (conn < 0)
- return -1;
-
- if (Config.tlsEnabled) {
-#if USE_GNUTLS
- gnutls_record_send(Config.session, buf, len);
- return len;
-#else
- return 0;
-#endif
- } else {
-
-#if _SQUID_WINDOWS_
- return send(conn, buf, len, 0);
-#else
- alarm(Config.ioTimeout);
- return write(conn, buf, len);
-#endif
- }
-}
-
-ssize_t
-Transport::Read(void *buf, size_t len)
-{
- if (conn < 0)
- return -1;
-
- if (Config.tlsEnabled) {
-#if USE_GNUTLS
- return gnutls_record_recv(Config.session, buf, len);
-#else
- return 0;
-#endif
- } else {
-
-#if _SQUID_WINDOWS_
- return recv(conn, buf, len, 0);
-#else
- alarm(Config.ioTimeout);
- return read(conn, buf, len);
-#endif
- }
-}
-
-void
-Transport::CloseConnection()
-{
- (void) close(conn);
- conn = -1;
-}
-
-#if USE_GNUTLS
-/* This function will verify the peer's certificate, and check
- * if the hostname matches, as well as the activation, expiration dates.
- */
-static int
-verifyByCA(gnutls_session_t session)
-{
- /* read hostname */
- const char *hostname = static_cast<const char*>(gnutls_session_get_ptr(session));
-
- /* This verification function uses the trusted CAs in the credentials
- * structure. So you must have installed one or more CA certificates.
- */
- unsigned int status;
- if (gnutls_certificate_verify_peers3(session, hostname, &status) < 0) {
- std::cerr << "VERIFY peers failure";
- return GNUTLS_E_CERTIFICATE_ERROR;
- }
-
- gnutls_certificate_type_t type = gnutls_certificate_type_get(session);
- gnutls_datum_t out;
- if (gnutls_certificate_verification_status_print(status, type, &out, 0) < 0) {
- std::cerr << "VERIFY status failure";
- return GNUTLS_E_CERTIFICATE_ERROR;
- }
-
- std::cerr << "VERIFY DATUM: " << out.data << std::endl;
- gnutls_free(out.data);
-
- if (status != 0) /* Certificate is not trusted */
- return GNUTLS_E_CERTIFICATE_ERROR;
-
- /* notify gnutls to continue handshake normally */
- return GNUTLS_E_SUCCESS;
-}
-
-static int
-verifyTlsCertificate(gnutls_session_t session)
-{
- // XXX: 1) try to verify using DANE -> Secure Authenticated Connection
-
- // 2) try to verify using CA
- if (verifyByCA(session) == GNUTLS_E_SUCCESS) {
- std::cerr << "SUCCESS: CA verified Encrypted Connection" << std::endl;
- return GNUTLS_E_SUCCESS;
- }
-
- // 3) fails both is insecure, but show the results anyway.
- std::cerr << "WARNING: Insecure Connection" << std::endl;
- return GNUTLS_E_SUCCESS;
-}
-#endif
-
-#if USE_GNUTLS
-static void
-gnutlsDebugHandler(int level, const char *msg)
-{
- debugVerbose(level, "GnuTLS: " << msg);
-}
-#endif
-
-void
-Transport::InitTls()
-{
-#if USE_GNUTLS
- debugVerbose(3, "Initializing TLS library...");
- // NP: gnutls init is re-entrant and lock-counted with deinit but not thread safe.
- if (gnutls_global_init() != GNUTLS_E_SUCCESS) {
- int xerrno = errno;
- std::cerr << "FATAL ERROR: TLS Initialize failed: " << xstrerr(xerrno) << std::endl;
- exit(1);
- }
-
- Config.tlsEnabled = true;
-
-#if USE_GNUTLS
- gnutls_global_set_log_function(&gnutlsDebugHandler);
- gnutls_global_set_log_level(scParams.verbosityLevel);
-#endif
-
- // Initialize for anonymous TLS
- gnutls_anon_allocate_client_credentials(&Config.anonCredentials);
-
- // Initialize for X.509 certificate exchange
- gnutls_certificate_allocate_credentials(&Config.certCredentials);
- for (std::list<std::string>::const_iterator i = Config.caFiles.begin(); i != Config.caFiles.end(); ++i) {
- int x = gnutls_certificate_set_x509_trust_file(Config.certCredentials, (*i).c_str(), GNUTLS_X509_FMT_PEM);
- if (x < 0) {
- debugVerbose(3, "WARNING: Failed to load Certificate Authorities from " << *i);
- } else {
- debugVerbose(3, "Loaded " << x << " Certificate Authorities from " << *i);
- }
- }
- gnutls_certificate_set_verify_function(Config.certCredentials, verifyTlsCertificate);
-
- for (std::list<std::string>::const_iterator i = Config.certFiles.begin(); i != Config.certFiles.end(); ++i) {
- if (gnutls_certificate_set_x509_key_file(Transport::Config.certCredentials, (*i).c_str(), (*i).c_str(), GNUTLS_X509_FMT_PEM) != GNUTLS_E_SUCCESS) {
- debugVerbose(3, "WARNING: Failed to load Certificate from " << *i);
- } else {
- debugVerbose(3, "Loaded Certificate from " << *i);
- }
- }
-
-#else
- std::cerr << "ERROR: TLS support not available." << std::endl;
-#endif
-}
-
-#if USE_GNUTLS
-
-// perform the actual handshake exchange with remote server
-static bool
-doTlsHandshake(const char *type)
-{
- // setup the connection for TLS
- gnutls_transport_set_int(Transport::Config.session, conn);
- gnutls_handshake_set_timeout(Transport::Config.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
-
- debugVerbose(2, type << " TLS handshake ... ");
-
- int ret = 0;
- do {
- ret = gnutls_handshake(Transport::Config.session);
- } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
-
- if (ret < 0) {
- std::cerr << "ERROR: " << type << " TLS Handshake failed (" << ret << ") "
- << gnutls_alert_get_name(gnutls_alert_get(Transport::Config.session))
- << std::endl;
- gnutls_perror(ret);
- gnutls_deinit(Transport::Config.session);
- return false;
- }
-
- char *desc = gnutls_session_get_desc(Transport::Config.session);
- debugVerbose(3, "TLS Session info: " << std::endl << desc << std::endl);
- gnutls_free(desc);
- return true;
-}
-
-static bool
-loadTlsParameters()
-{
- const char *err = nullptr;
- int x;
- if ((x = gnutls_priority_set_direct(Transport::Config.session, Transport::Config.params, &err)) != GNUTLS_E_SUCCESS) {
- if (x == GNUTLS_E_INVALID_REQUEST)
- std::cerr << "ERROR: Syntax error at: " << err << std::endl;
- gnutls_perror(x);
- return false;
- }
- return true;
-}
-
-// attempt an anonymous TLS handshake
-// this encrypts the connection but does not secure it
-// so many public servers do not support this handshake type.
-static bool
-tryTlsAnonymous()
-{
- if (!loadTlsParameters())
- return false;
-
- // put the anonymous credentials to the current session
- int x;
- if ((x = gnutls_credentials_set(Transport::Config.session, GNUTLS_CRD_ANON, Transport::Config.anonCredentials)) != GNUTLS_E_SUCCESS) {
- std::cerr << "ERROR: Anonymous TLS credentials setup failed (" << x << ") " << std::endl;
- gnutls_perror(x);
- return false;
- }
-
- return doTlsHandshake("Anonymous");
-}
-
-// attempt a X.509 certificate exchange
-// this both encrypts and authenticates the connection
-static bool
-tryTlsCertificate(const char *hostname)
-{
- gnutls_session_set_ptr(Transport::Config.session, (void *) hostname);
- gnutls_server_name_set(Transport::Config.session, GNUTLS_NAME_DNS, hostname, strlen(hostname));
-
- if (!loadTlsParameters())
- return false;
-
- // put the X.509 credentials to the current session
- gnutls_credentials_set(Transport::Config.session, GNUTLS_CRD_CERTIFICATE, Transport::Config.certCredentials);
-
- // setup the connection for TLS
- gnutls_transport_set_int(Transport::Config.session, conn);
- gnutls_handshake_set_timeout(Transport::Config.session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
-
- return doTlsHandshake("X.509");
-}
-#endif
-
-bool
-Transport::MaybeStartTls(const char *hostname)
-{
-#if USE_GNUTLS
- if (Config.tlsEnabled) {
-
- // Initialize TLS session
- gnutls_init(&Transport::Config.session, GNUTLS_CLIENT);
-
- if (Transport::Config.tlsAnonymous && !tryTlsAnonymous()) {
- gnutls_deinit(Config.session);
- return false;
- }
-
- if (!tryTlsCertificate(hostname)) {
- gnutls_deinit(Config.session);
- return false;
- }
- }
-#else
- (void)hostname;
-#endif
- return true;
-}
-
-void
-Transport::ShutdownTls()
-{
-#if USE_GNUTLS
- if (!Config.tlsEnabled)
- return;
-
- debugVerbose(3, "Shutting down TLS library...");
-
- // release any existing session and credentials
- gnutls_deinit(Config.session);
- gnutls_anon_free_client_credentials(Config.anonCredentials);
- gnutls_certificate_free_credentials(Config.certCredentials);
-
- // NP: gnutls init is re-entrant and lock-counted with deinit but not thread safe.
- gnutls_global_deinit();
- Config.tlsEnabled = false;
-#endif
-}
-
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#ifndef SQUID_TOOLS_SQUIDCLIENT_TRANSPORT_H
-#define SQUID_TOOLS_SQUIDCLIENT_TRANSPORT_H
-
-#include "tools/squidclient/Parameters.h"
-
-#if HAVE_GNUTLS_GNUTLS_H
-#include <gnutls/gnutls.h>
-#endif
-#include <list>
-#include <string>
-
-namespace Transport
-{
-
-/// parameters controlling outgoing connection
-class TheConfig
-{
-public:
- TheConfig() :
- ioTimeout(120),
- localHost(nullptr),
- port(CACHE_HTTP_PORT),
- tlsEnabled(false),
- tlsAnonymous(false) {
- params = "NORMAL";
- hostname = "localhost";
- }
-
-// TODO: implicit transport options depending on the protocol-specific options
-// ie --https enables TLS connection settings
-
- /// display Transport Options command line help to stderr
- void usage();
-
- /**
- * parse transport related command line options
- * \return true if there are other options still to parse
- */
- bool parseCommandOpts(int argc, char *argv[], int c, int &optIndex);
-
- /// I/O operation timeout
- int ioTimeout;
-
- /// the local hostname to bind as for outgoing IP
- const char *localHost;
-
- /// the destination server host name to contact
- const char *hostname;
-
- /// port on the server to contact
- uint16_t port;
-
- /// whether to enable TLS on the server connection
- bool tlsEnabled;
-
- /// whether to do anonymous TLS (non-authenticated)
- bool tlsAnonymous;
-
- /// The TLS parameters (list of ciphers, versions, flags)
- /// Default is "NORMAL" unless tlsAnonymous is used,
- /// in which case it becomes "PERFORMANCE:+ANON-ECDH:+ANON-DH".
- /// see http://gnutls.org/manual/html_node/Priority-Strings.html
- const char *params;
-
- // client certificate PEM file(s)
- std::list<std::string> certFiles;
-
- // client trusted x509 certificate authorities file
- std::list<std::string> caFiles;
-
-#if USE_GNUTLS
- /// anonymous client credentials
- gnutls_anon_client_credentials_t anonCredentials;
-
- // client x509 certificate credentials
- gnutls_certificate_credentials_t certCredentials;
-
- /// TLS session state
- gnutls_session_t session;
-#endif
-};
-
-extern TheConfig Config;
-
-/// locate and connect to the configured server
-bool Connect();
-
-/// close the current connection
-void CloseConnection();
-
-/// Initialize TLS library environment when necessary.
-void InitTls();
-
-/// perform TLS handshake on the currently open connection if
-/// TLS library has been initialized.
-/// return false on errors, true otherwise even if TLS not performed.
-bool MaybeStartTls(const char *hostname);
-
-/// De-initialize TLS library environment when necessary.
-void ShutdownTls();
-
-/// write len bytes to the currently open connection.
-/// \return the number of bytes written, or -1 on errors
-ssize_t Write(const void *buf, size_t len);
-
-/// read up to len bytes from the currently open connection.
-/// \return the number of bytes read, or -1 on errors
-ssize_t Read(void *buf, size_t len);
-
-} // namespace Transport
-
-#endif /* SQUID_TOOLS_SQUIDCLIENT_TRANSPORT_H */
-
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#include "squid.h"
-
-#if HAVE_GSSAPI
-
-#include "base64.h"
-#include "tools/squidclient/gssapi_support.h"
-
-#include <iostream>
-
-#if !defined(gss_mech_spnego)
-static gss_OID_desc _gss_mech_spnego = {6, (void *) "\x2b\x06\x01\x05\x05\x02"};
-gss_OID gss_mech_spnego = &_gss_mech_spnego;
-#endif
-
-#define BUFFER_SIZE 8192
-
-/**
- * Check return valuse major_status, minor_status for error and print error description
- * in case of an error.
- *
- * \retval true in case of gssapi error
- * \retval false in case of no gssapi error
- */
-bool
-check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char *function)
-{
- if (GSS_ERROR(major_status)) {
- OM_uint32 maj_stat, min_stat;
- OM_uint32 msg_ctx = 0;
- gss_buffer_desc status_string;
- char buf[BUFFER_SIZE];
- size_t len;
-
- len = 0;
- msg_ctx = 0;
- while (!msg_ctx) {
- /* convert major status code (GSS-API error) to text */
- maj_stat = gss_display_status(&min_stat, major_status,
- GSS_C_GSS_CODE,
- GSS_C_NULL_OID,
- &msg_ctx, &status_string);
- if (maj_stat == GSS_S_COMPLETE) {
- snprintf(buf + len, BUFFER_SIZE-len, "%s", (char *) status_string.value);
- len += status_string.length;
- gss_release_buffer(&min_stat, &status_string);
- break;
- }
- gss_release_buffer(&min_stat, &status_string);
- }
- snprintf(buf + len, BUFFER_SIZE-len, "%s", ". ");
- len += 2;
- msg_ctx = 0;
- while (!msg_ctx) {
- /* convert minor status code (underlying routine error) to text */
- maj_stat = gss_display_status(&min_stat, minor_status,
- GSS_C_MECH_CODE,
- GSS_C_NULL_OID,
- &msg_ctx, &status_string);
- if (maj_stat == GSS_S_COMPLETE) {
- snprintf(buf + len, BUFFER_SIZE-len,"%s", (char *) status_string.value);
- len += status_string.length;
- gss_release_buffer(&min_stat, &status_string);
- break;
- }
- gss_release_buffer(&min_stat, &status_string);
- }
- std::cerr << "ERROR: " << function << " failed: " << buf << std::endl;
- return true;
- }
- return false;
-}
-
-/**
- * Get gssapi token for service HTTP/<server>
- * User has to initiate a kinit user@DOMAIN on commandline first for the
- * function to be successful
- *
- * \return base64 encoded token if successful,
- * string "ERROR" if unsuccessful
- */
-char *
-GSSAPI_token(const char *server)
-{
- OM_uint32 major_status, minor_status;
- gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
- gss_name_t server_name = GSS_C_NO_NAME;
- gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
- gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
- gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
- char *token = nullptr;
-
- setbuf(stdout, nullptr);
- setbuf(stdin, nullptr);
-
- if (!server) {
- std::cerr << "ERROR: GSSAPI: No server name" << std::endl;
- token = new char[6];
- memcpy(token, "ERROR", 5);
- token[5] = '\0';
- return token;
- }
- service.value = xmalloc(strlen("HTTP") + strlen(server) + 2);
- snprintf((char *) service.value, strlen("HTTP") + strlen(server) + 2, "%s@%s", "HTTP", server);
- service.length = strlen((char *) service.value);
-
- major_status = gss_import_name(&minor_status, &service,
- gss_nt_service_name, &server_name);
-
- if (!check_gss_err(major_status, minor_status, "gss_import_name()")) {
-
- major_status = gss_init_sec_context(&minor_status,
- GSS_C_NO_CREDENTIAL,
- &gss_context,
- server_name,
- gss_mech_spnego,
- 0,
- 0,
- GSS_C_NO_CHANNEL_BINDINGS,
- &input_token,
- nullptr,
- &output_token,
- nullptr,
- nullptr);
-
- if (!check_gss_err(major_status, minor_status, "gss_init_sec_context()") && output_token.length) {
- token = new char[base64_encode_len(output_token.length)];
- struct base64_encode_ctx ctx;
- base64_encode_init(&ctx);
- size_t blen = base64_encode_update(&ctx, token, output_token.length, reinterpret_cast<const uint8_t*>(output_token.value));
- blen += base64_encode_final(&ctx, token+blen);
- token[blen] = '\0';
- }
- }
-
- if (!output_token.length) {
- token = new char[6];
- memcpy(token, "ERROR", 5);
- token[5] = '\0';
- }
-
- gss_delete_sec_context(&minor_status, &gss_context, nullptr);
- gss_release_buffer(&minor_status, &service);
- gss_release_buffer(&minor_status, &input_token);
- gss_release_buffer(&minor_status, &output_token);
- gss_release_name(&minor_status, &server_name);
-
- return token;
-}
-
-#endif /* HAVE_GSSAPI */
-
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#ifndef _SQUID_TOOLS_SQUIDCLIENT_GSSAPI_H
-#define _SQUID_TOOLS_SQUIDCLIENT_GSSAPI_H
-
-#if HAVE_GSSAPI
-#if USE_APPLE_KRB5
-#define GSSKRB_APPLE_DEPRECATED(x)
-#endif
-
-#if USE_HEIMDAL_KRB5
-#if HAVE_GSSAPI_GSSAPI_H
-#include <gssapi/gssapi.h>
-#elif HAVE_GSSAPI_H
-#include <gssapi.h>
-#endif /* HAVE_GSSAPI_GSSAPI_H/HAVE_GSSAPI_H */
-#elif USE_GNUGSS
-#if HAVE_GSS_H
-#include <gss.h>
-#endif
-#else
-#if HAVE_GSSAPI_GSSAPI_H
-#include <gssapi/gssapi.h>
-#elif HAVE_GSSAPI_H
-#include <gssapi.h>
-#endif /* HAVE_GSSAPI_GSSAPI_H/HAVE_GSSAPI_H */
-#if HAVE_GSSAPI_GSSAPI_KRB5_H
-#include <gssapi/gssapi_krb5.h>
-#endif
-#if HAVE_GSSAPI_GSSAPI_GENERIC_H
-#include <gssapi/gssapi_generic.h>
-#endif
-#if HAVE_GSSAPI_GSSAPI_EXT_H
-#include <gssapi/gssapi_ext.h>
-#endif
-#endif
-
-#ifndef gss_nt_service_name
-#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
-#endif
-
-bool check_gss_err(OM_uint32 major_status, OM_uint32 minor_status, const char *function);
-char *GSSAPI_token(const char *server);
-
-#endif /* HAVE_GSSAPI */
-#endif /* _SQUID_TOOLS_SQUIDCLIENT_GSSAPI_H */
-
+++ /dev/null
-.if !'po4a'hide' .TH squidclient 1
-.
-.SH NAME
-squidclient \- A simple HTTP web client tool
-.
-.SH SYNOPSIS
-.if !'po4a'hide' .B squidclient
-.if !'po4a'hide' .B "[ \-aknNrsv ] "
-.if !'po4a'hide' .B "[ \-\-ping [ping\-options] ] "
-.if !'po4a'hide' .B "[ \-\-https] [tls\-options] [ \-A"
-string
-.if !'po4a'hide' .B "] [ \-h | \-\-host"
-remote host
-.if !'po4a'hide' .B "] [ \-H '"
-string
-.if !'po4a'hide' .B "' ] [ \-i"
-IMS
-.if !'po4a'hide' .B "] [ \-j '"
-Host header
-.if !'po4a'hide' .B "' ] [ \-l | \-\-local"
-host
-.if !'po4a'hide' .B "] [ \-m"
-method
-.if !'po4a'hide' .B "] [ \-p | \-\-port"
-port
-.if !'po4a'hide' .B "] [ \-P"
-file
-.if !'po4a'hide' .B "] [ \-t"
-count
-.if !'po4a'hide' .B "] [ \-T"
-timeout
-.if !'po4a'hide' .B "] [ \-u"
-user
-.if !'po4a'hide' .B "] [ \-U"
-user
-.if !'po4a'hide' .B "] [ \-V"
-version
-.if !'po4a'hide' .B "] [ \-w"
-password
-.if !'po4a'hide' .B "] [ \-W"
-password
-.if !'po4a'hide' .B "] "
-url
-.
-.PP
-.if !'po4a'hide' .B "Ping options: [ \-g"
-count
-.if !'po4a'hide' .B "] [ \-I"
-interval
-.if !'po4a'hide' .B "] "
-.
-.PP
-.if !'po4a'hide' .B "TLS options: [ \-\-anonymous\-tls ] [ \-\-trusted\-ca"
-CA certificates file
-.if !'po4a'hide' .B "...] [ \-\-cert"
-client X.509 certificate file
-.if !'po4a'hide' .B "] [ \-\-params"
-TLS session parameters
-.if !'po4a'hide' .B "] "
-.
-.SH DESCRIPTION
-.B squidclient
-is a tool providing a command line interface for retrieving URLs.
-Designed for testing any HTTP 0.9, 1.0, or 1.1 web server or proxy.
-This tool can be combined with scripts to perform any basic HTTP operation.
-Some additional features for access to the
-.B squid
-proxy object cache and management information are provided.
-.
-.SH OPTIONS
-.if !'po4a'hide' .TP 12
-.if !'po4a'hide' .B "\-a"
-Do NOT include Accept: header.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-A 'string'"
-Send
-.B string
-as User-Agent: header. To omit the header completely set string to empty ('').
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-h | \-\-host host"
-Retrieve URL from server host. Default is
-.B localhost
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-H 'string'"
-Extra headers to send. Use
-.B '\en'
-for new lines.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-i time"
-If\-Modified\-Since time (in Epoch seconds).
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-j hosthdr"
-Host header content
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-k"
-Keep the connection active. Default is to do only one request then close.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-l | \-\-local host"
-Specify a local IP address to bind to. Default is none.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-m method"
-Request method, default is
-.I GET.
-Squid also supports a non-standard method called
-.I PURGE.
-You can use that to purge a specific URL from the cache.
-You need to have
-.I purge
-access setup in
-.B squid.conf
-similar to
-.I manager
-access. Here is an example:
-.if !'po4a'hide' .nf
-.if !'po4a'hide' acl purge method PURGE
-.if !'po4a'hide' http_access deny purge !localhost
-.if !'po4a'hide' .fi
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-n"
-Proxy Negotiate(Kerberos) authentication.
-.if !'po4a'hide' .nf
-Use kinit username@DOMAIN first to get initial TGS.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-N"
-WWW Negotiate(Kerberos) authentication.
-.if !'po4a'hide' .nf
-Use kinit username@DOMAIN first to get initial TGS.
-.if !'po4a'hide' .fi
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-p port"
-Port number of cache. Default is 3128.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-P file"
-Request body. Using the named file as data.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-r"
-Force cache to reload URL.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-s"
-Silent. Do not print data to stdout.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-t count"
-Trace
-.I count
-HTTP relay or proxy hops
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-T timeout"
-Timeout value (seconds) for read/write operations.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-u user"
-Proxy authentication username
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-U user"
-WWW authentication username
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-v"
-Verbose. Print outgoing message to stderr.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-V version"
-HTTP Version. Use '\-' for HTTP/0.9 omitted case
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-w password"
-Proxy authentication password
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-W password"
-WWW authentication password
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-\-https"
-Use Transport Layer Security on the HTTP connection.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-\-anonymous\-tls"
-Use TLS with unauthenticated (anonymous) certificate.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-\-cert file"
-File containing client X.509 certificate in PEM format.
-May be repeated to load several client certificates.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-\-trusted\-ca file"
-File containing trusted Certificate Authority (CA) certificates in PEM format.
-May be repeated to load any number of files.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-\-params values"
-TLS library specific parameters for the communication session.
-See the library documentation for details on valid parameters.
-.if !'po4a'hide' .I "GnuTLS: http://gnutls.org/manual/html_node/Priority\-Strings.html"
-If repeated only the last value will have effect.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-\-ping [options]"
-Enable ping mode. Optional \-g and \-I parameters must follow immediately if used.
-Repeated use resets to default ping settings.
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-g count"
-Ping mode, perform
-.I count
-iterations (default is to loop until interrupted).
-.
-.if !'po4a'hide' .TP
-.if !'po4a'hide' .B "\-I interval"
-Ping interval in seconds (default 1 second).
-.
-.SH AUTHOR
-This program and manual was written by
-.if !'po4a'hide' .I Amos Jeffries <amosjeffries@squid-cache.org>
-.PP
-Based on original code derived from Harvest and further developed by
-numerous individuals from the internet community.
-.
-.SH COPYRIGHT
-.PP
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
-.
-.SH QUESTIONS
-Questions on the usage of this program can be sent to the
-.I Squid Users mailing list
-.if !'po4a'hide' <squid-users@lists.squid-cache.org>
-.
-.SH REPORTING BUGS
-See https://wiki.squid-cache.org/SquidFaq/BugReporting for details of what you need to include with your bug report.
-.PP
-Report bugs or bug fixes using https://bugs.squid-cache.org/
-.PP
-Report serious security bugs to
-.I Squid Bugs <squid-bugs@lists.squid-cache.org>
-.PP
-Report ideas for new improvements to the
-.I Squid Developers mailing list
-.if !'po4a'hide' <squid-dev@lists.squid-cache.org>
-.
-.SH SEE ALSO
-.if !'po4a'hide' .BR squid "(8), "
-.if !'po4a'hide' .BR cachemgr.cgi "(8)"
+++ /dev/null
-/*
- * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#include "squid.h"
-#include "base64.h"
-#include "ip/Address.h"
-#include "ip/tools.h"
-#include "time/gadgets.h"
-#include "tools/squidclient/gssapi_support.h"
-#include "tools/squidclient/Parameters.h"
-#include "tools/squidclient/Ping.h"
-#include "tools/squidclient/Transport.h"
-
-#if _SQUID_WINDOWS_
-/** \cond AUTODOCS-IGNORE */
-using namespace Squid;
-/** \endcond */
-#endif
-
-#include <cassert>
-#include <cerrno>
-#include <csignal>
-#include <cstring>
-#include <iostream>
-#include <sstream>
-#if _SQUID_WINDOWS_
-#include <io.h>
-#endif
-#if HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#if HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#if HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#if HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#if HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#if HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#if HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
-#ifndef BUFSIZ
-#define BUFSIZ 8192
-#endif
-
-/* Local functions */
-static void usage(const char *progname);
-
-void pipe_handler(int sig);
-static void set_our_signal(void);
-
-Parameters scParams;
-
-static int put_fd;
-static char *put_file = nullptr;
-
-static struct stat sb;
-int total_bytes = 0;
-
-#if _SQUID_AIX_
-/* Bug 3854: AIX 6.1 tries to link in this fde.h global symbol
- * despite squidclient not using any of the fd_* code.
- */
-fde *fde::Table = nullptr;
-#endif
-
-#if _SQUID_WINDOWS_
-void
-Win32SockCleanup(void)
-{
- WSACleanup();
- return;
-}
-#endif
-
-static void
-usage(const char *progname)
-{
- std::cerr << "Version: " << VERSION << std::endl
- << "Usage: " << progname << " [Basic Options] [HTTP Options]" << std::endl
- << std::endl;
- std::cerr
- << " -s | --quiet Silent. Do not print response message to stdout." << std::endl
- << " -v | --verbose Verbose debugging. Repeat (-vv) to increase output level." << std::endl
- << " Levels:" << std::endl
- << " 1 - Print outgoing request message to stderr." << std::endl
- << " 2 - Print action trace to stderr." << std::endl
- << " --help Display this help text." << std::endl
- << std::endl;
- Transport::Config.usage();
- Ping::Config.usage();
- std::cerr
- << "HTTP Options:" << std::endl
- << " -a Do NOT include Accept: header." << std::endl
- << " -A User-Agent: header. Use \"\" to omit." << std::endl
- << " -H 'string' Extra headers to send. Supports '\\\\', '\\n', '\\r' and '\\t'." << std::endl
- << " -i IMS If-Modified-Since time (in Epoch seconds)." << std::endl
- << " -j hosthdr Host header content" << std::endl
- << " -k Keep the connection active. Default is to do only one request then close." << std::endl
- << " -m method Request method, default is GET." << std::endl
-#if HAVE_GSSAPI
- << " -n Proxy Negotiate(Kerberos) authentication" << std::endl
- << " -N WWW Negotiate(Kerberos) authentication" << std::endl
-#endif
- << " -P file Send content from the named file as request payload" << std::endl
- << " -r Force cache to reload URL" << std::endl
- << " -t count Trace count cache-hops" << std::endl
- << " -u user Proxy authentication username" << std::endl
- << " -U user WWW authentication username" << std::endl
- << " -V version HTTP Version. Use '-' for HTTP/0.9 omitted case" << std::endl
- << " -w password Proxy authentication password" << std::endl
- << " -W password WWW authentication password" << std::endl
- ;
- exit(EXIT_FAILURE);
-}
-
-static void
-shellUnescape(char *buf)
-{
- if (!buf)
- return;
-
- unsigned char *p, *d;
-
- d = p = reinterpret_cast<unsigned char *>(buf);
-
- while (auto ch = *p) {
-
- if (ch == '\\') {
- ++p;
-
- switch (*p) {
- case 'n':
- ch = '\n';
- break;
- case 'r':
- ch = '\r';
- break;
- case 't':
- ch = '\t';
- break;
- case '\\':
- ch = '\\';
- break;
- default:
- ch = *p;
- debugVerbose(1, "Warning: unsupported shell code '\\" << ch << "'");
- break;
- }
-
- *d = ch;
-
- if (!ch)
- continue;
-
- } else {
- *d = *p;
- }
-
- ++p;
- ++d;
- }
-
- *d = '\0';
-}
-
-/// [Proxy-]Authorization header producer
-class Authorization
-{
-public:
- Authorization(const char *aHeader, const char *aDestination):
- header(aHeader), destination(aDestination) {}
-
- /// finalizes and writes the right HTTP header to the given stream
- void commit(std::ostream &os);
-
- std::string header; ///< HTTP header name to send
- std::string destination; ///< used when describing password
- const char *user = nullptr; ///< user name to encode and send
- const char *password = nullptr; ///< user password to encode and send
-};
-
-void
-Authorization::commit(std::ostream &os)
-{
-#if HAVE_GETPASS
- if (!password)
- password = getpass((destination + " password: ").c_str());
-#endif
- if (!password) {
- std::cerr << "ERROR: " << destination << " password missing\n";
- exit(EXIT_FAILURE);
- }
-
- struct base64_encode_ctx ctx;
- base64_encode_init(&ctx);
- const auto bcapacity = base64_encode_len(strlen(user) + 1 + strlen(password));
- const auto buf = new char[bcapacity];
-
- size_t bsize = 0;
- bsize += base64_encode_update(&ctx, buf, strlen(user), reinterpret_cast<const uint8_t*>(user));
- bsize += base64_encode_update(&ctx, buf+bsize, 1, reinterpret_cast<const uint8_t*>(":"));
- bsize += base64_encode_update(&ctx, buf+bsize, strlen(password), reinterpret_cast<const uint8_t*>(password));
- bsize += base64_encode_final(&ctx, buf+bsize);
- assert(bsize <= bcapacity); // paranoid and late but better than nothing
-
- os << header << ": Basic ";
- os.write(buf, bsize);
- os << "\r\n";
-
- delete[] buf;
-}
-
-static Authorization ProxyAuthorization("Proxy-Authorization", "proxy");
-static Authorization OriginAuthorization("Authorization", "origin server");
-
-int
-main(int argc, char *argv[])
-{
- int len, bytesWritten;
- bool to_stdout, reload;
- int keep_alive = 0;
- int opt_noaccept = 0;
-#if HAVE_GSSAPI
- int www_neg = 0, proxy_neg = 0;
-#endif
- char url[BUFSIZ];
- char buf[BUFSIZ];
- char *extra_hdrs = nullptr;
- const char *method = "GET";
- extern char *optarg;
- time_t ims = 0;
- int max_forwards = -1;
-
- const char *host = nullptr;
- const char *version = "1.0";
- const char *useragent = nullptr;
-
- /* set the defaults */
- to_stdout = true;
- reload = false;
-
- Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
- if (argc < 2 || argv[argc-1][0] == '-') {
- usage(argv[0]); /* need URL */
- } else if (argc >= 2) {
- strncpy(url, argv[argc - 1], sizeof(url));
- url[sizeof(url) - 1] = '\0';
-
- int optIndex = 0;
- const char *shortOpStr = "aA:h:j:V:l:P:i:km:nNp:rsvt:H:T:u:U:w:W:?";
-
- // options for controlling squidclient
- static struct option basicOptions[] = {
- /* These are the generic options for squidclient itself */
- {"help", no_argument, nullptr, '?'},
- {"verbose", no_argument, nullptr, 'v'},
- {"quiet", no_argument, nullptr, 's'},
- {"host", required_argument, nullptr, 'h'},
- {"local", required_argument, nullptr, 'l'},
- {"port", required_argument, nullptr, 'p'},
- {"ping", no_argument, nullptr, '\1'},
- {"https", no_argument, nullptr, '\3'},
- {nullptr, 0, nullptr, 0}
- };
-
- int c;
- while ((c = getopt_long(argc, argv, shortOpStr, basicOptions, &optIndex)) != -1) {
-
- // modules parse their own specific options
- switch (c) {
- case '\1':
- to_stdout = 0;
- Ping::Config.parseCommandOpts(argc, argv, c, optIndex);
- continue;
-
- case 'h': /* remote host */
- case 'l': /* local host */
- case 'p': /* port number */
- // rewind and let the Transport::Config parser handle
- optind -= 2;
- Transport::Config.parseCommandOpts(argc, argv, c, optIndex);
- continue;
-
- case '\3': // request over a TLS connection
- Transport::Config.parseCommandOpts(argc, argv, c, optIndex);
- continue;
-
- default: // fall through to next switch
- break;
- }
-
- switch (c) {
-
- case '\0': // dummy value for end-of-options
- break;
-
- case 'a':
- opt_noaccept = 1;
- break;
-
- case 'A':
- useragent = optarg;
- break;
-
- case 'j':
- host = optarg;
- break;
-
- case 'V':
- version = optarg;
- break;
-
- case 's': /* silent */
- to_stdout = false;
- break;
-
- case 'k': /* backward compat */
- keep_alive = 1;
- break;
-
- case 'r': /* reload */
- reload = true;
- break;
-
- case 'P':
- put_file = xstrdup(optarg);
- break;
-
- case 'i': /* IMS */
- ims = (time_t) atoi(optarg);
- break;
-
- case 'm':
- method = xstrdup(optarg);
- break;
-
- case 't':
- method = xstrdup("TRACE");
- max_forwards = atoi(optarg);
- break;
-
- case 'H':
- if (strlen(optarg)) {
- if (extra_hdrs) {
- std::cerr << "ERROR: multiple -H options not supported. Discarding previous value." << std::endl;
- xfree(extra_hdrs);
- }
- extra_hdrs = xstrdup(optarg);
- shellUnescape(extra_hdrs);
- }
- break;
-
- case 'T':
- Transport::Config.ioTimeout = atoi(optarg);
- break;
-
- case 'u':
- ProxyAuthorization.user = optarg;
- break;
-
- case 'w':
- ProxyAuthorization.password = optarg;
- break;
-
- case 'U':
- OriginAuthorization.user = optarg;
- break;
-
- case 'W':
- OriginAuthorization.password = optarg;
- break;
-
- case 'n':
-#if HAVE_GSSAPI
- proxy_neg = 1;
-#else
- std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
- usage(argv[0]);
-#endif
- break;
-
- case 'N':
-#if HAVE_GSSAPI
- www_neg = 1;
-#else
- std::cerr << "ERROR: Negotiate authentication not supported." << std::endl;
- usage(argv[0]);
-#endif
- break;
-
- case 'v':
- /* undocumented: may increase verb-level by giving more -v's */
- ++scParams.verbosityLevel;
- debugVerbose(2, "verbosity level set to " << scParams.verbosityLevel);
- break;
-
- case '?': /* usage */
-
- default:
- usage(argv[0]);
- break;
- }
- }
- if (ProxyAuthorization.password && !ProxyAuthorization.user) {
- std::cerr << "ERROR: Proxy authentication password (-w) is given, but username (-u) is missing\n";
- exit(EXIT_FAILURE);
- }
- if (OriginAuthorization.password && !OriginAuthorization.user) {
- std::cerr << "ERROR: WWW authentication password (-W) is given, but username (-U) is missing\n";
- exit(EXIT_FAILURE);
- }
- }
-#if _SQUID_WINDOWS_
- {
- WSADATA wsaData;
- WSAStartup(2, &wsaData);
- atexit(Win32SockCleanup);
- }
-#endif
- /* Build the HTTP request */
- const char *pathPassword = nullptr;
- if (strncmp(url, "mgr:", 4) == 0) {
- char *t = xstrdup(url + 4);
- // XXX: Bail on snprintf() failures
- snprintf(url, sizeof(url), "http://%s:%hu/squid-internal-mgr/%s", Transport::Config.hostname, Transport::Config.port, t);
- if (const auto at = strrchr(url, '@')) {
- if (!OriginAuthorization.user) {
- std::cerr << "ERROR: Embedding a password in a cache manager command requires " <<
- "providing a username with -U: mgr:" << t << std::endl;
- exit(EXIT_FAILURE);
- }
- *at = 0; // send password in Authorization header, not URL
- pathPassword = at + 1; // the now-removed embedded @password overwrites OriginAuthorization.password further below
- }
- xfree(t);
- }
- if (put_file) {
- put_fd = open(put_file, O_RDONLY);
- set_our_signal();
-
- if (put_fd < 0) {
- int xerrno = errno;
- std::cerr << "ERROR: can't open file (" << xstrerr(xerrno) << ")" << std::endl;
- exit(EXIT_FAILURE);
- }
-#if _SQUID_WINDOWS_
- setmode(put_fd, O_BINARY);
-#endif
-
- if (fstat(put_fd, &sb) < 0) {
- int xerrno = errno;
- std::cerr << "ERROR: can't identify length of file (" << xstrerr(xerrno) << ")" << std::endl;
- }
- }
-
- if (!host) {
- char *newhost = strstr(url, "://");
- if (newhost) {
- char *t;
- newhost += 3;
- newhost = xstrdup(newhost);
- t = newhost + strcspn(newhost, "@/?");
- if (*t == '@') {
- newhost = t + 1;
- t = newhost + strcspn(newhost, "@/?");
- }
- *t = '\0';
- host = newhost;
- }
- }
-
- std::stringstream msg;
-
- if (version[0] == '-' || !version[0]) {
- /* HTTP/0.9, no headers, no version */
- msg << method << " " << url << "\r\n";
- } else {
- const auto versionImpliesHttp = xisdigit(version[0]); // is HTTP/n.n
- msg << method << " "
- << url << " "
- << (versionImpliesHttp ? "HTTP/" : "") << version
- << "\r\n";
-
- if (host) {
- msg << "Host: " << host << "\r\n";
- }
-
- if (!useragent) {
- msg << "User-Agent: squidclient/" << VERSION << "\r\n";
- } else if (useragent[0] != '\0') {
- msg << "User-Agent: " << useragent << "\r\n";
- } // else custom: no value U-A header
-
- if (reload) {
- msg << "Cache-Control: no-cache\r\n";
- }
- if (put_fd > 0) {
- msg << "Content-length: " << sb.st_size << "\r\n";
- }
- if (opt_noaccept == 0) {
- msg << "Accept: */*\r\n";
- }
- if (ims) {
- msg << "If-Modified-Since: " << Time::FormatRfc1123(ims) << "\r\n";
- }
- if (max_forwards > -1) {
- msg << "Max-Forwards: " << max_forwards << "\r\n";
- }
- if (ProxyAuthorization.user)
- ProxyAuthorization.commit(msg);
- if (OriginAuthorization.user) {
- const auto savedPassword = OriginAuthorization.password;
- if (pathPassword)
- OriginAuthorization.password = pathPassword;
- OriginAuthorization.commit(msg);
- OriginAuthorization.password = savedPassword; // restore the global password setting
- }
-#if HAVE_GSSAPI
- if (www_neg) {
- if (host) {
- const char *token = GSSAPI_token(host);
- msg << "Proxy-Authorization: Negotiate " << token << "\r\n";
- delete[] token;
- } else
- std::cerr << "ERROR: server host missing" << std::endl;
- }
- if (proxy_neg) {
- if (Transport::Config.hostname) {
- const char *token = GSSAPI_token(Transport::Config.hostname);
- msg << "Proxy-Authorization: Negotiate " << token << "\r\n";
- delete[] token;
- } else
- std::cerr << "ERROR: proxy server host missing" << std::endl;
- }
-#endif
-
- /* HTTP/1.0 may need keep-alive explicitly */
- if (strcmp(version, "1.0") == 0 && keep_alive)
- msg << "Connection: keep-alive\r\n";
-
- /* HTTP/1.1 may need close explicitly */
- if (!keep_alive)
- msg << "Connection: close\r\n";
-
- if (extra_hdrs) {
- msg << extra_hdrs;
- safe_free(extra_hdrs);
- }
- msg << "\r\n"; // empty line ends MIME header block
- }
-
- msg.flush();
- const auto messageHeader = msg.str();
- debugVerbose(1, "Request:" << std::endl << messageHeader << std::endl << ".");
-
- uint32_t loops = Ping::Init();
-
- for (uint32_t i = 0; loops == 0 || i < loops; ++i) {
- size_t fsize = 0;
-
- if (!Transport::Connect())
- continue;
-
- /* Send the HTTP request */
- debugVerbose(2, "Sending HTTP request ... ");
- bytesWritten = Transport::Write(messageHeader.data(), messageHeader.length());
-
- if (bytesWritten < 0) {
- std::cerr << "ERROR: write" << std::endl;
- exit(EXIT_FAILURE);
- } else if (static_cast<size_t>(bytesWritten) != messageHeader.length()) {
- std::cerr << "ERROR: Failed to send the following request: " << std::endl
- << messageHeader << std::endl;
- exit(EXIT_FAILURE);
- }
- debugVerbose(2, "done.");
-
- if (put_file) {
- debugVerbose(1, "Sending HTTP request payload ...");
- int x;
- if ((x = lseek(put_fd, 0, SEEK_SET)) < 0) {
- int xerrno = errno;
- std::cerr << "ERROR: lseek: " << xstrerr(xerrno) << std::endl;
-
- } else while ((x = read(put_fd, buf, sizeof(buf))) > 0) {
-
- x = Transport::Write(buf, x);
-
- total_bytes += x;
-
- if (x <= 0)
- break;
- }
-
- if (x != 0)
- std::cerr << "ERROR: Cannot send file." << std::endl;
- else
- debugVerbose(1, "done.");
- }
- /* Read the data */
-
-#if _SQUID_WINDOWS_
- setmode(1, O_BINARY);
-#endif
-
- while ((len = Transport::Read(buf, sizeof(buf))) > 0) {
- fsize += len;
-
- if (to_stdout && fwrite(buf, len, 1, stdout) != 1) {
- int xerrno = errno;
- std::cerr << "ERROR: writing to stdout: " << xstrerr(xerrno) << std::endl;
- }
- }
-
-#if USE_GNUTLS
- if (Transport::Config.tlsEnabled) {
- if (len == 0) {
- std::cerr << "- Peer has closed the TLS connection" << std::endl;
- } else if (!gnutls_error_is_fatal(len)) {
- std::cerr << "WARNING: " << gnutls_strerror(len) << std::endl;
- } else {
- std::cerr << "ERROR: " << gnutls_strerror(len) << std::endl;
- }
- }
-#endif
-
-#if _SQUID_WINDOWS_
- setmode(1, O_TEXT);
-#endif
-
- Transport::CloseConnection();
-
- if (Ping::LoopDone(i))
- break;
-
- Ping::TimerStop(fsize);
- }
-
- Ping::DisplayStats();
- Transport::ShutdownTls();
- return EXIT_SUCCESS;
-}
-
-void
-pipe_handler(int)
-{
- std::cerr << "SIGPIPE received." << std::endl;
-}
-
-static void
-set_our_signal(void)
-{
-#if HAVE_SIGACTION
- struct sigaction sa;
- sa.sa_handler = pipe_handler;
- sa.sa_flags = SA_RESTART;
- sigemptyset(&sa.sa_mask);
-
- if (sigaction(SIGPIPE, &sa, nullptr) < 0) {
- std::cerr << "ERROR: Cannot set PIPE signal." << std::endl;
- exit(EXIT_FAILURE);
- }
-#else
- signal(SIGPIPE, pipe_handler);
-#endif
-}
-