Version in base suite: 3.2-2 Base version: apt-cacher-ng_3.2-2 Target version: apt-cacher-ng_3.2.1-1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/a/apt-cacher-ng/apt-cacher-ng_3.2-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/a/apt-cacher-ng/apt-cacher-ng_3.2.1-1.dsc CMakeLists.txt | 4 ChangeLog | 35 ++ VERSION | 2 conf/acng.conf.in | 7 debian/changelog | 11 debian/patches/debian-changes | 38 --- include/acsyscap.h.in | 1 source/acfg_defaults.cc | 4 source/acngtool.cc | 476 +++++++++++++++++++++++---------------- source/dlcon.cc | 2 source/expiration.cc | 7 source/filereader.cc | 2 source/tcpconnect.cc | 2 systemd/apt-cacher-ng.service.in | 2 14 files changed, 363 insertions(+), 230 deletions(-) diff -Nru apt-cacher-ng-3.2/CMakeLists.txt apt-cacher-ng-3.2.1/CMakeLists.txt --- apt-cacher-ng-3.2/CMakeLists.txt 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/CMakeLists.txt 2020-02-03 18:54:57.000000000 +0000 @@ -58,6 +58,8 @@ if(NOT DEFINED(RUNDIR)) set(RUNDIR "/run") endif() +set(SOCKET_PATH "${RUNDIR}/${PACKAGE}/socket") + # carefully splicing of command line arguments, even from lists macro(_append varname) @@ -106,7 +108,7 @@ _append(ACNG_CXXFLAGS -fvisibility-inlines-hidden) endif() -foreach(linkarg -Wl,--as-needed -Wl,-O1 -Wl,--discard-all -Wl,--no-undefined -Wl,--build-id=sha1 -Wl,-fuse-ld=gold -Wl,--threads) +foreach(linkarg -Wl,--as-needed -Wl,-O1 -Wl,--discard-all -Wl,--no-undefined -Wl,--build-id=sha1 -Wl,-fuse-ld=gold) STRING(REGEX REPLACE "=|-|," "" optname "${linkarg}") set(CMAKE_REQUIRED_FLAGS "${linkarg}") CHECK_CXX_COMPILER_FLAG("" "LD_${optname}") diff -Nru apt-cacher-ng-3.2/ChangeLog apt-cacher-ng-3.2.1/ChangeLog --- apt-cacher-ng-3.2/ChangeLog 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/ChangeLog 2020-02-03 18:54:57.000000000 +0000 @@ -1,3 +1,38 @@ +apt-cacher-ng (3.2.1) SHAUN-OF-THE-LIVING; urgency=medium + + * POTENTIAL SECURITY ISSUE (CVE-2020-5202): + - in certain situations, the maint job run by acngtool could leak the + administrator credentials from apt-cacher-ng configuration. This is only + likely if the attacker is able to impersonate the daemon with an own + server listening on the same port. + - The mitigation path for this is: + - SocketPath option is configured by default + - By default, acngtool only attempts to run the maint job through the + Unix Domain Socket. If SocketPath is not set but admin credentials are + configured, the operation is denied. + - For non-standard cases where acngtool is used to run special arbitrary + commands (ACNG_REQ variable) and the operation through SocketPath is not + possible (i.e. missing permissions or the tool is run on a different + host), the operation through TCP can be enforced with ACNG_INSECURE + environment variable + + [ REALITY SYNC ] + * increased size of the decompression line buffer for config file reading + (Debian bug #942634) + * Support .zst compressed packages (reference: + https://www.archlinux.org/news/now-using-zstandard-instead-of-xz-for-package-compression/ ) + + [ Debian Stable Bugfix ] + * Fix of Debian bug #928957: overoptimistic guessing of the SHA256SUMS file location + Incorrect assumption of an existing SHA256SUMS file for Debian + repositories makes the expiration task fail without a proper way for the + end user to recover from it. Now ignore a download error in this case + (similar handling as for other guesses), assuming that permanent 404ing + for other reasons than removal of remote content can be considered + unlikely. + + -- Eduard Bloch Wed, 22 Jan 2020 20:53:50 +0100 + apt-cacher-ng (3.2) MY-NAME-IS-ANYBODY; urgency=medium * Maintenance release diff -Nru apt-cacher-ng-3.2/VERSION apt-cacher-ng-3.2.1/VERSION --- apt-cacher-ng-3.2/VERSION 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/VERSION 2020-02-03 18:54:57.000000000 +0000 @@ -1 +1 @@ -3.2 +3.2.1 diff -Nru apt-cacher-ng-3.2/conf/acng.conf.in apt-cacher-ng-3.2.1/conf/acng.conf.in --- apt-cacher-ng-3.2/conf/acng.conf.in 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/conf/acng.conf.in 2020-02-03 18:54:57.000000000 +0000 @@ -81,11 +81,12 @@ ReportPage: acng-report.html # Socket file for accessing through local UNIX socket instead of TCP/IP. Can be -# used with inetd (via bridge tool in.acng from apt-cacher-ng package). +# used with inetd (via bridge tool in.acng from apt-cacher-ng package), is also +# used internally for administrative purposes. # -# Default: not set, UNIX socket bridge is disabled. +# Default: @SOCKET_PATH@ # -# SocketPath:/var/run/apt-cacher-ng/socket +# SocketPath = /var/run/apt-cacher-ng/socket # If set to 1, makes log files be written to disk on every new line. Default # is 0, buffers are flushed after the client disconnects. Technically, diff -Nru apt-cacher-ng-3.2/debian/changelog apt-cacher-ng-3.2.1/debian/changelog --- apt-cacher-ng-3.2/debian/changelog 2019-05-17 20:59:21.000000000 +0000 +++ apt-cacher-ng-3.2.1/debian/changelog 2020-02-03 19:54:45.000000000 +0000 @@ -1,3 +1,14 @@ +apt-cacher-ng (3.2.1-1) buster; urgency=medium + + * Minor bugfix upstream release + + (CVE-2020-5202) Enforce secured call to the server in maint job triggering + + Allow .zst compression for tarballs (closes: Bug#948259, thanks + to Arnaud Rebillout) + + Upstreaming fix from #928957 and adding workaround of build failure on + mips(64)el (no multithreading with gold linker) + + -- Eduard Bloch Mon, 03 Feb 2020 20:54:45 +0100 + apt-cacher-ng (3.2-2) unstable; urgency=medium * Fix for incorrect assumption of some existing SHA256SUMS files in Debian diff -Nru apt-cacher-ng-3.2/debian/patches/debian-changes apt-cacher-ng-3.2.1/debian/patches/debian-changes --- apt-cacher-ng-3.2/debian/patches/debian-changes 2019-05-17 20:59:21.000000000 +0000 +++ apt-cacher-ng-3.2.1/debian/patches/debian-changes 2020-02-03 19:54:45.000000000 +0000 @@ -5,16 +5,16 @@ information below has been extracted from the changelog. Adjust it or drop it. . - apt-cacher-ng (3.2-2) unstable; urgency=medium + apt-cacher-ng (3.2.1-1) buster; urgency=medium . - * Fix for incorrect assumption of some existing SHA256SUMS files in Debian - repositories which makes the expiration task fail without a proper way - for the end user to recover from it. Now ignore a download error in this - case (similar handling as for other guesses), assuming that permanent - 404ing for other reasons than removal of remote content can be considered - unlikely (closes: #928957) + * Minor bugfix upstream release + + (CVE-2020-5202) Enforce secured call to the server in maint job triggering + + Allow .zst compression for tarballs (closes: Bug#948259, thanks + to Arnaud Rebillout) + + Upstreaming fix from #928957 and adding workaround of build failure on + mips(64)el (no multithreading with gold linker) Author: Eduard Bloch -Bug-Debian: https://bugs.debian.org/928957 +Bug-Debian: https://bugs.debian.org/948259 --- The information above should follow the Patch Tagging Guidelines, please @@ -27,26 +27,10 @@ Bug-Ubuntu: https://launchpad.net/bugs/ Forwarded: Reviewed-By: -Last-Update: 2019-05-21 +Last-Update: 2020-02-03 ---- apt-cacher-ng-3.2.orig/source/expiration.cc -+++ apt-cacher-ng-3.2/source/expiration.cc -@@ -806,6 +806,13 @@ bool expiration::ProcessRegular(const st - flags.eIdxType = EIDX_SHA256DILIST; - flags.vfile_ondisk = true; - flags.uptodate = false; -+ -+ // the original source context will probably provide a viable source for -+ // this URL - it might go 404 if the whole folder is missing but then the -+ // referenced content would also be outdated/gone and not worth keeping -+ // in the cache anyway -+ -+ flags.forgiveDlErrors = true; - } - // and last but not least - care only about the modern version of that index - m_metaFilesRel.erase(idir + "MD5SUMS"); ---- apt-cacher-ng-3.2.orig/systemd/apt-cacher-ng.service.in -+++ apt-cacher-ng-3.2/systemd/apt-cacher-ng.service.in +--- apt-cacher-ng-3.2.1.orig/systemd/apt-cacher-ng.service.in ++++ apt-cacher-ng-3.2.1/systemd/apt-cacher-ng.service.in @@ -1,6 +1,7 @@ [Unit] Description=Apt-Cacher NG software download proxy diff -Nru apt-cacher-ng-3.2/include/acsyscap.h.in apt-cacher-ng-3.2.1/include/acsyscap.h.in --- apt-cacher-ng-3.2/include/acsyscap.h.in 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/include/acsyscap.h.in 2020-02-03 18:54:57.000000000 +0000 @@ -31,3 +31,4 @@ #cmakedefine BINDIR "@BINDIR@" #cmakedefine SBINDIR "@SBINDIR@" #cmakedefine HAVE_CHECKSUM +#define UDSPATH "@SOCKET_PATH@" diff -Nru apt-cacher-ng-3.2/source/acfg_defaults.cc apt-cacher-ng-3.2.1/source/acfg_defaults.cc --- apt-cacher-ng-3.2/source/acfg_defaults.cc 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/source/acfg_defaults.cc 2020-02-03 18:54:57.000000000 +0000 @@ -16,12 +16,12 @@ namespace cfg { -string cachedir("/var/tmp"), logdir("/var/tmp"), fifopath, pidfile, reportpage, +string cachedir("/var/tmp"), logdir("/var/tmp"), fifopath(UDSPATH), pidfile, reportpage, confdir, adminauth, adminauthB64, bindaddr, mirrorsrcs, suppdir(LIBDIR), capath("/etc/ssl/certs"), cafile, badredmime("text/html"); #define INFOLDER "(^|.*/)" -#define COMPRLIST "(\\.gz|\\.bz2|\\.lzma|\\.xz)" +#define COMPRLIST "(\\.gz|\\.bz2|\\.lzma|\\.xz|\\.zst)" #define ALXPATTERN ".*\\.(db|files|abs)(\\.tar" COMPRLIST ")?" #define COMPOPT COMPRLIST"?" //#define COMPONENT_OPTIONAL "(-[a-z0-9-])" diff -Nru apt-cacher-ng-3.2/source/acngtool.cc apt-cacher-ng-3.2.1/source/acngtool.cc --- apt-cacher-ng-3.2/source/acngtool.cc 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/source/acngtool.cc 2020-02-03 18:54:57.000000000 +0000 @@ -27,7 +27,7 @@ #include #include #include - +#include #include #include #include @@ -38,7 +38,7 @@ #include "dlcon.h" #include "fileio.h" #include "fileitem.h" - +#include "sockio.h" #ifdef HAVE_SSL #include "openssl/bio.h" #include "openssl/ssl.h" @@ -57,6 +57,13 @@ bool g_bVerbose = false; +// from sockio.cc in more recent versions +bool isUdsAccessible(cmstring& path) +{ + Cstat s(path); + return s && S_ISSOCK(s.st_mode) && 0 == access(path.c_str(), W_OK); +} + // dummies to satisfy references namespace acng { @@ -117,6 +124,54 @@ } }; +// That is relevant to push the download agent logics correctly and are shown in logs; +// not relevant for the actual connection since it's rerouted through TUdsFactory +#define FAKE_UDS_HOSTNAME "UNIX-DOMAIN-SOCKET" + +SHARED_PTR CreateStdoutItem() +{ + class tPrintItem: public fileitem + { + public: + tPrintItem() + { + m_bAllowStoreData = false; + m_nSizeChecked = m_nSizeSeen = 0; + } + virtual FiStatus Setup(bool) override + { + m_nSizeChecked = m_nSizeSeen = 0; + return m_status = FIST_INITED; + } + virtual int GetFileFd() override + { + return 1; + } + ; // something, don't care for now + virtual bool DownloadStartedStoreHeader(const header &h, size_t, const char*, bool, bool&) + override + { + m_head = h; + auto opt_dbg = getenv("ACNGTOOL_DEBUG_DOWNLOAD"); + if (opt_dbg && *opt_dbg) + std::cerr << (std::string) h.ToString() << std::endl; + return true; + } + virtual bool StoreFileData(const char *data, unsigned int size) override + { + if (!size) + m_status = FIST_COMPLETE; + + return (size == fwrite(data, sizeof(char), size, stdout)); + } + ssize_t SendData(int, int, off_t&, size_t) override + { + return 0; + } + }; + return make_shared(); +} + struct verbprint { int cnt = 0; @@ -145,98 +200,115 @@ } } vprint; -struct CReportItemFactory : public IFitemFactory -{ - virtual SHARED_PTR Create() - { - class tRepItem : public fileitem - { - acbuf lineBuf; - string m_key = maark; - tStrVec m_errMsg; - - public: +/** + * Create a special processor which looks for error markers in the download stream and + * reports the result only then. + */ +SHARED_PTR CreateReportItem() +{ + class tRepItem: public fileitem + { + acbuf lineBuf; + string m_key = maark; + tStrVec m_errMsg; - tRepItem() - { - m_bAllowStoreData=false; - m_nSizeChecked = m_nSizeSeen = 0; - lineBuf.setsize(1<<16); - memset(lineBuf.wptr(), 0, 1<<16); - }; - virtual FiStatus Setup(bool) override - { - m_nSizeChecked = m_nSizeSeen = 0; - return m_status = FIST_INITED; - } - virtual int GetFileFd() override - { return 1;}; // something, don't care for now - virtual bool DownloadStartedStoreHeader(const header &h, size_t, const char *, - bool, bool&) override + public: + tRepItem() + { + m_bAllowStoreData = false; + m_nSizeChecked = m_nSizeSeen = 0; + lineBuf.setsize(1 << 16); + memset(lineBuf.wptr(), 0, 1 << 16); + } + ; + virtual FiStatus Setup(bool) override + { + m_nSizeChecked = m_nSizeSeen = 0; + return m_status = FIST_INITED; + } + virtual int GetFileFd() override + { + return 1; + } + ; // something, don't care for now + virtual bool DownloadStartedStoreHeader(const header &h, size_t, const char*, bool, bool&) + override + { + m_head = h; + return true; + } + virtual bool StoreFileData(const char *data, unsigned int size) override + { + if (!size) { - m_head = h; - return true; + m_status = FIST_COMPLETE; + vprint.fin(); } - virtual bool StoreFileData(const char *data, unsigned int size) override - { - if(!size) - { - m_status = FIST_COMPLETE; - vprint.fin(); - } - auto consumed = std::min(size, lineBuf.freecapa()); - memcpy(lineBuf.wptr(), data, consumed); - lineBuf.got(consumed); - for(;;) + auto consumed = std::min(size, lineBuf.freecapa()); + memcpy(lineBuf.wptr(), data, consumed); + lineBuf.got(consumed); + for (;;) + { + LPCSTR p = lineBuf.rptr(); + auto end = mempbrk(p, "\r\n", lineBuf.size()); + if (!end) + break; + string s(p, end - p); + lineBuf.drop(s.length() + 1); + vprint.dot(); + if (startsWith(s, m_key)) { - LPCSTR p = lineBuf.rptr(); - auto end = mempbrk(p, "\r\n", lineBuf.size()); - if(!end) + // that's for us... " content\n" + char *endchar = nullptr; + p = s.c_str(); + auto val = strtoul(p + m_key.length(), &endchar, 10); + if (!endchar || !*endchar) + continue; // heh? shall not finish here + switch (ControLineType(val)) + { + case ControLineType::BeforeError: + m_errMsg.emplace_back(endchar, s.size() - (endchar - p)); + vprint.msg(m_errMsg.back()); break; - string s(p, end-p); - lineBuf.drop(s.length()+1); - vprint.dot(); - if(startsWith(s, m_key)) + case ControLineType::Error: { - // that's for us... " content\n" - char *endchar = nullptr; - p = s.c_str(); - auto val = strtoul(p + m_key.length(), &endchar, 10); - if(!endchar || !*endchar) - continue; // heh? shall not finish here - switch(ControLineType(val)) - { - case ControLineType::BeforeError: - m_errMsg.emplace_back(endchar, s.size() - (endchar - p)); - vprint.msg(m_errMsg.back()); - break; - case ControLineType::Error: - { - if(!g_bVerbose) // printed before - for(auto l : m_errMsg) - cerr << l << endl; - m_errMsg.clear(); - string msg(endchar, s.size() - (endchar - p)); - vprint.fin(); - cerr << msg << endl; - break; - } - default: - continue; - } + if (!g_bVerbose) // printed before + for (auto l : m_errMsg) + cerr << l << endl; + m_errMsg.clear(); + string msg(endchar, s.size() - (endchar - p)); + vprint.fin(); + cerr << msg << endl; + break; + } + default: + continue; } } - return true; - } - ssize_t SendData(int , int, off_t &, size_t ) override - { - return 0; } - }; - return make_shared(); - } -}; + return true; + } + ssize_t SendData(int, int, off_t&, size_t) override + { + return 0; + } + }; + return make_shared(); +} +void DownloadItem(const tHttpUrl &url, IDlConFactory &pDlconFac, const SHARED_PTR &fi) +{ + dlcon dl("", nullptr, &pDlconFac); + std::thread dlThread([&]() {dl.WorkLoop();}); + dl.AddJob(fi, &url, nullptr, nullptr, 0, cfg::REDIRMAX_DEFAULT); + int st; + auto fistatus = fi->WaitForFinish(&st); + // just be sure to set a proper error code + if(fistatus != fileitem::FIST_COMPLETE && fi->GetHeader().getStatus() < 400) + fi->GetHeader().frontLine = "909 Incomplete download"; + dl.SignalStop(); + dlThread.join(); +} int wcat(LPCSTR url, LPCSTR proxy, IFitemFactory*, IDlConFactory *pdlconfa = &g_tcp_con_factory); static void usage(int retCode = 0, LPCSTR cmd = nullptr) @@ -488,127 +560,147 @@ return true; } -int maint_job() +/** + * Helper which implements a custom connection class that runs through a specified Unix Domain + * Socket (see base class for the name). + */ +struct TUdsFactory : public ::acng::IDlConFactory { - cfg::SetOption("proxy=", nullptr); - - tStrVec hostips; -#if 0 // FIXME, processing on UDS gets stuck somewhere - // prefer UDS if configured in a sane way - if (startsWithSz(cfg::fifopath, "/")) - hostips.emplace_back(cfg::fifopath); -#endif - auto nips = Tokenize(cfg::bindaddr, SPACECHARS, hostips, true); - if (!nips) - hostips.emplace_back("localhost"); - - for (const auto& hostaddr : hostips) - { - // use an own connection factory which does "the right thing" and leaks the - // internal connection result - struct maintfac: public IDlConFactory - { - bool m_bOK = false; - mstring m_hname; - maintfac(cmstring& s) : - m_hname(s) - { - } - - void RecycleIdleConnection(tDlStreamHandle & handle) override - { - // keep going, no recycling/restoring - } - virtual tDlStreamHandle CreateConnected(cmstring &, cmstring &, mstring &, bool *, - cfg::tRepoData::IHookHandler *, bool, int, bool) override + void RecycleIdleConnection(tDlStreamHandle &handle) override + { + // keep going, no recycling/restoring + } + tDlStreamHandle CreateConnected(cmstring&, cmstring&, mstring& sErrorOut, bool*, + cfg::tRepoData::IHookHandler*, bool, int, bool) override + { + struct udsconnection: public tcpconnect + { + bool failed = false; + udsconnection() : tcpconnect(nullptr) { - string serr; + // some static and dummy parameters, and invalidate SSL for sure + m_ssl = nullptr; + m_bio = nullptr; + m_sHostName = FAKE_UDS_HOSTNAME; + m_sPort = cfg::port; - if (m_hname[0] != '/') // not UDS + m_conFd = socket(PF_UNIX, SOCK_STREAM, 0); + if (m_conFd < 0) { - auto mhandle = g_tcp_con_factory.CreateConnected(m_hname, cfg::port, serr, 0, 0, - false, 30, true); - m_bOK = mhandle.get(); - return mhandle; + failed = true; + return; } - // otherwise build a fake connection on unix domain socket - struct udsconnection: public tcpconnect + struct sockaddr_un addr; + addr.sun_family = PF_UNIX; + strcpy(addr.sun_path, cfg::fifopath.c_str()); + socklen_t adlen = cfg::fifopath.length() + 1 + offsetof(struct sockaddr_un, sun_path); + if (connect(m_conFd, (struct sockaddr*) &addr, adlen)) { - udsconnection(cmstring& udspath, bool *ok) : - tcpconnect(nullptr) - { -#ifdef DEBUG - cerr << "Socket path: " << udspath << endl; -#endif - auto m_conFd = socket(PF_UNIX, SOCK_STREAM, 0); - if (m_conFd < 0) - return; - - struct sockaddr_un addr; - addr.sun_family = PF_UNIX; - strcpy(addr.sun_path, cfg::fifopath.c_str()); - socklen_t adlen = - cfg::fifopath.length() + 1 + offsetof(struct sockaddr_un, sun_path); - if (connect(m_conFd, (struct sockaddr*) &addr, adlen)) - { -#ifdef DEBUG - perror("connect"); -#endif - return; - } - // basic identification needed - tSS ids; - ids << "GET / HTTP/1.0\r\nX-Original-Source: localhost\r\n\r\n"; - if (!ids.send(m_conFd)) - return; - - m_ssl = nullptr; - m_bio = nullptr; - // better match the TCP socket parameters - m_sHostName = "localhost"; - m_sPort = sDefPortHTTP; - *ok = true; - } - }; - return make_shared(m_hname, &m_bOK); + DBGQLOG(tErrnoFmter("connect result: ")); + checkforceclose(m_conFd); + failed = true; + return; + } + // basic identification needed + tSS ids; + ids << "GET / HTTP/1.0\r\nX-Original-Source: localhost\r\n\r\n"; + if (!ids.send(m_conFd)) + { + failed = true; + return; + } } }; - maintfac factoryWrapper(hostaddr); - tSS urlPath; - urlPath << "http://"; - if (!cfg::adminauth.empty()) - urlPath << UserinfoEscape(cfg::adminauth) << "@"; - if (hostaddr[0] == '/') - urlPath << "localhost"; - else - urlPath << hostaddr << ":" << cfg::port; + auto ret = make_shared(); + // mimic regular processing of a bad result here! + if(ret && ret->failed) ret.reset(); + if(!ret) sErrorOut = "912 Cannot establish control connection"; + return ret; + } +}; + +int maint_job() +{ + if (cfg::reportpage.empty()) + { + cerr << "ReportPage is not configured in the server config, aborting..." < enforce it + bool have_cred = !url.sUserPass.empty(), + have_uds = !cfg::fifopath.empty(), + try_tcp = !have_cred; + bool uds_ok = have_uds && isUdsAccessible(cfg::fifopath); + + if(have_cred) + { + if(isInsecForced()) // so try TCP anyway + { + try_tcp = true; + } + else if(have_uds && !uds_ok) + { + cerr << "This operation transmits credentials but the socket (" << cfg::fifopath + << ") is currently not accessible!" << endl; + return EXIT_FAILURE; + } + else if(!have_uds) + { + cerr << "This operation transmits credentials but SocketPath is not configured to a safe location in the server configuration. " + "Please set SocketPath to a safe location, or set ACNG_INSECURE environment variable to override this check." + <GetHeader().getStatus() == 200; + DBGQLOG("UDS result: " << response_ok) + } + if(!response_ok && try_tcp) + { + DBGQLOG("Trying TCP path") + // never use a proxy here (insecure?), those are most likely local IPs + cfg::SetOption("Proxy=", nullptr); + cfg::nettimeout = 30; + vector hostips; + Tokenize(cfg::bindaddr, SPACECHARS, hostips, false); + if(hostips.empty()) + hostips.emplace_back("127.0.0.1"); + for (const auto &tgt : hostips) + { + url.sHost = tgt; + auto fi = CreateReportItem(); + DownloadItem(url, g_tcp_con_factory, fi); + response_ok = fi->GetHeader().getStatus() == 200; + if (response_ok) + break; } - else - return 0; } - // all attempts failed - return 3; + if(!response_ok) + { + cerr << "Could not make a valid request to the server. Please visit " + << url.ToURI(false) << " and check special conditions." <=0); diff -Nru apt-cacher-ng-3.2/systemd/apt-cacher-ng.service.in apt-cacher-ng-3.2.1/systemd/apt-cacher-ng.service.in --- apt-cacher-ng-3.2/systemd/apt-cacher-ng.service.in 2018-09-07 13:02:18.000000000 +0000 +++ apt-cacher-ng-3.2.1/systemd/apt-cacher-ng.service.in 2020-02-03 18:54:57.000000000 +0000 @@ -4,7 +4,7 @@ [Service] # the SocketPath option can be removed if the inetd bridge functionality is not needed -ExecStart=@SBINDIR@/apt-cacher-ng SocketPath=@RUNDIR@/apt-cacher-ng/socket -c @CFGDIR@ ForeGround=1 +ExecStart=@SBINDIR@/apt-cacher-ng -c @CFGDIR@ ForeGround=1 User=apt-cacher-ng Group=apt-cacher-ng # this can be changed to notify if the support was enabled at build time