From ea35939be2141c7bb9fb96d6ee3a1e345b94428a Mon Sep 17 00:00:00 2001 From: Amish Date: Wed, 16 May 2018 19:09:52 +0000 Subject: [PATCH] New function to find Local listening IP and add new %A macro (#198) Implemented a new function to find local listening IP:Port in a consistent way and added support for %A macro in error pages and deny_info URL using the same function. --- src/HttpRequest.cc | 49 ++++++++++++++++++++++++++++++++++++++++++++ src/HttpRequest.h | 4 ++++ src/cf.data.pre | 1 + src/errorpage.cc | 8 ++++++++ src/errorpage.h | 1 + src/format/Format.cc | 25 ++++++---------------- 6 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/HttpRequest.cc b/src/HttpRequest.cc index 54e86bd671..5a2417385e 100644 --- a/src/HttpRequest.cc +++ b/src/HttpRequest.cc @@ -739,3 +739,52 @@ HttpRequest::manager(const CbcPointer &aMgr, const AccessLogEntry } } +/// a helper for validating FindListeningPortAddress()-found address candidates +static const Ip::Address * +FindListeningPortAddressInAddress(const Ip::Address *ip) +{ + // FindListeningPortAddress() callers do not want INADDR_ANY addresses + return (ip && !ip->isAnyAddr()) ? ip : nullptr; +} + +/// a helper for handling PortCfg cases of FindListeningPortAddress() +static const Ip::Address * +FindListeningPortAddressInPort(const AnyP::PortCfgPointer &port) +{ + return port ? FindListeningPortAddressInAddress(&port->s) : nullptr; +} + +/// a helper for handling Connection cases of FindListeningPortAddress() +static const Ip::Address * +FindListeningPortAddressInConn(const Comm::ConnectionPointer &conn) +{ + return conn ? FindListeningPortAddressInAddress(&conn->local) : nullptr; +} + +const Ip::Address * +FindListeningPortAddress(const HttpRequest *callerRequest, const AccessLogEntry *ale) +{ + // Check all sources of usable listening port information, giving + // HttpRequest and masterXaction a preference over ALE. + + const HttpRequest *request = callerRequest; + if (!request && ale) + request = ale->request; + if (!request) + return nullptr; // not enough information + + const Ip::Address *ip = FindListeningPortAddressInPort(request->masterXaction->squidPort); + if (!ip && ale) + ip = FindListeningPortAddressInPort(ale->cache.port); + + // XXX: also handle PROXY protocol here when we have a flag to identify such request + if (ip || request->flags.interceptTproxy || request->flags.intercepted) + return ip; + + /* handle non-intercepted cases that were not handled above */ + ip = FindListeningPortAddressInConn(request->masterXaction->tcpClient); + if (!ip && ale) + ip = FindListeningPortAddressInConn(ale->tcpClient); + return ip; // may still be nil +} + diff --git a/src/HttpRequest.h b/src/HttpRequest.h index 029ebeacfd..a963883885 100644 --- a/src/HttpRequest.h +++ b/src/HttpRequest.h @@ -254,5 +254,9 @@ class ConnStateData; */ void UpdateRequestNotes(ConnStateData *csd, HttpRequest &request, NotePairs const ¬es); +/// \returns listening/*_port address used by the client connection (or nil) +/// nil parameter(s) indicate missing caller information and are handled safely +const Ip::Address *FindListeningPortAddress(const HttpRequest *, const AccessLogEntry *); + #endif /* SQUID_HTTPREQUEST_H */ diff --git a/src/cf.data.pre b/src/cf.data.pre index 74747ad2d0..f13a7e2b9e 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -8451,6 +8451,7 @@ DOC_START URL FORMAT TAGS: %a - username (if available. Password NOT included) + %A - Local listening IP address the client connection was connected to %B - FTP path URL %e - Error number %E - Error description diff --git a/src/errorpage.cc b/src/errorpage.cc index 233e742066..5d9d6be9da 100644 --- a/src/errorpage.cc +++ b/src/errorpage.cc @@ -758,6 +758,14 @@ ErrorState::Convert(char token, bool building_deny_info_url, bool allowRecursion p = "-"; break; + case 'A': + // TODO: When/if we get ALE here, pass it as well + if (const auto addr = FindListeningPortAddress(request.getRaw(), nullptr)) + mb.appendf("%s", addr->toStr(ntoabuf, MAX_IPSTRLEN)); + else + p = "-"; + break; + case 'b': mb.appendf("%u", getMyPort()); break; diff --git a/src/errorpage.h b/src/errorpage.h index addc8e5c06..18c173bbf8 100644 --- a/src/errorpage.h +++ b/src/errorpage.h @@ -35,6 +35,7 @@ typedef void ERCB(int fd, void *, size_t); * \verbatim a - User identity x + A - Local listening IP address x B - URL with FTP %2f hack x c - Squid error code x d - seconds elapsed since request received x diff --git a/src/format/Format.cc b/src/format/Format.cc index cc2c577443..f1a8080086 100644 --- a/src/format/Format.cc +++ b/src/format/Format.cc @@ -470,20 +470,10 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS } break; - case LFT_LOCAL_LISTENING_IP: { - // avoid logging a dash if we have reliable info - const bool interceptedAtKnownPort = al->request ? - (al->request->flags.interceptTproxy || - al->request->flags.intercepted) && al->cache.port : - false; - if (interceptedAtKnownPort) { - const bool portAddressConfigured = !al->cache.port->s.isAnyAddr(); - if (portAddressConfigured) - out = al->cache.port->s.toStr(tmp, sizeof(tmp)); - } else if (al->tcpClient) - out = al->tcpClient->local.toStr(tmp, sizeof(tmp)); - } - break; + case LFT_LOCAL_LISTENING_IP: + if (const auto addr = FindListeningPortAddress(nullptr, al.getRaw())) + out = addr->toStr(tmp, sizeof(tmp)); + break; case LFT_CLIENT_LOCAL_IP: if (al->tcpClient) @@ -505,11 +495,8 @@ Format::Format::assemble(MemBuf &mb, const AccessLogEntry::Pointer &al, int logS break; case LFT_LOCAL_LISTENING_PORT: - if (al->cache.port) { - outint = al->cache.port->s.port(); - doint = 1; - } else if (al->request) { - outint = al->request->my_addr.port(); + if (const auto addr = FindListeningPortAddress(nullptr, al.getRaw())) { + outint = addr->port(); doint = 1; } break; -- 2.39.5