From 5fa25d6873e0e3f607a0b879f6fb964b41e9cd09 Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Tue, 3 Mar 2026 00:05:47 +1300 Subject: [PATCH 1/3] Update port modes Rename 'accel' to 'gateway' and fix documentation to match. Update documentation and code references to accel mode to gateway mode. Add explicit mode flag and accessor test for forward-proxy mode. Split option parsing to enforce [mode] parameter as first and treat mode names as invalid options when used late. This simplifies the validation that mode is only specified once and incompatible modes cannot be configured together on one port. --- src/anyp/TrafficMode.h | 21 +++++--- src/cache_cf.cc | 119 ++++++++++++++++++++--------------------- src/cf.data.pre | 75 +++++++++++++------------- src/client_side.cc | 14 ++--- 4 files changed, 118 insertions(+), 111 deletions(-) diff --git a/src/anyp/TrafficMode.h b/src/anyp/TrafficMode.h index 48ba4ce2659..405e2be48e0 100644 --- a/src/anyp/TrafficMode.h +++ b/src/anyp/TrafficMode.h @@ -21,13 +21,21 @@ namespace AnyP class TrafficMode { public: - /** marks HTTP accelerator (reverse/surrogate proxy) traffic + /** marks HTTP Proxy (forward proxy) traffic + * + * Indicating the following are required: + * - not gatewaySurrogate + * - not isIntercepted() + */ + bool forwardProxy = false; + + /** marks HTTP Gateway (accelerator/reverse/surrogate proxy) traffic * * Indicating the following are required: * - URL translation from relative to absolute form * - restriction to origin peer relay recommended */ - bool accelSurrogate = false; + bool gatewaySurrogate = false; /** marks ports receiving PROXY protocol traffic * @@ -73,10 +81,11 @@ class TrafficMode */ bool tunnelSslBumping = false; - /** true if the traffic is in any way intercepted - * - */ - bool isIntercepted() { return natIntercept||tproxyIntercept ;} + /// \returns true if the traffic is in any way intercepted + bool isIntercepted() const { return natIntercept||tproxyIntercept ;} + + /// \returns true if the traffic is in any way intercepted + bool isForwardProxy() const { return forwardProxy || (!gatewaySurrogate && !isIntercepted()); } }; } // namespace AnyP diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 4942f479bd2..ae87a4b26be 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -3479,47 +3479,7 @@ parse_port_option(AnyP::PortCfgPointer &s, char *token) { /* modes first */ - if (strcmp(token, "accel") == 0) { - if (s->flags.isIntercepted()) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Accelerator mode requires its own port. It cannot be shared with other modes."); - self_destruct(); - return; - } - s->flags.accelSurrogate = true; - s->vhost = true; - } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) { - if (s->flags.accelSurrogate || s->flags.tproxyIntercept) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Intercept mode requires its own interception port. It cannot be shared with other modes."); - self_destruct(); - return; - } - s->flags.natIntercept = true; - Ip::Interceptor.StartInterception(); - /* Log information regarding the port modes under interception. */ - debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s); - debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (interception enabled)"); - } else if (strcmp(token, "tproxy") == 0) { - if (s->flags.natIntercept || s->flags.accelSurrogate) { - debugs(3,DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY option requires its own interception port. It cannot be shared with other modes."); - self_destruct(); - return; - } - s->flags.tproxyIntercept = true; - Ip::Interceptor.StartTransparency(); - /* Log information regarding the port modes under transparency. */ - debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (TPROXY enabled)"); - - if (s->flags.proxySurrogate) { - debugs(3, DBG_IMPORTANT, "Disabling TPROXY Spoofing on port " << s->s << " (require-proxy-header enabled)"); - } - - if (!Ip::Interceptor.ProbeForTproxy(s->s)) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY support in the system does not work."); - self_destruct(); - return; - } - - } else if (strcmp(token, "require-proxy-header") == 0) { + if (strcmp(token, "require-proxy-header") == 0) { s->flags.proxySurrogate = true; if (s->flags.tproxyIntercept) { // receiving is still permitted, so we do not unset the TPROXY flag @@ -3528,61 +3488,61 @@ parse_port_option(AnyP::PortCfgPointer &s, char *token) } } else if (strncmp(token, "defaultsite=", 12) == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": defaultsite option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": defaultsite option requires 'gateway' mode flag."); self_destruct(); return; } safe_free(s->defaultsite); s->defaultsite = xstrdup(token + 12); } else if (strcmp(token, "vhost") == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_CRITICAL, "WARNING: " << cfg_directive << ": vhost option is deprecated. Use 'accel' mode flag instead."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_CRITICAL, "WARNING: " << cfg_directive << ": vhost option is deprecated. Use 'gateway' mode flag instead."); } - s->flags.accelSurrogate = true; + s->flags.gatewaySurrogate = true; s->vhost = true; } else if (strcmp(token, "no-vhost") == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": no-vhost option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": no-vhost option requires 'gateway' mode flag."); } s->vhost = false; } else if (strcmp(token, "vport") == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires 'gateway' mode flag."); self_destruct(); return; } s->vport = -1; } else if (strncmp(token, "vport=", 6) == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires 'gateway' mode flag."); self_destruct(); return; } s->vport = xatos(token + 6); } else if (strncmp(token, "protocol=", 9) == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": protocol option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": protocol option requires 'gateway' mode flag."); self_destruct(); return; } s->transport = parsePortProtocol(ToUpper(SBuf(token + 9))); } else if (strcmp(token, "allow-direct") == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": allow-direct option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": allow-direct option requires 'gateway' mode flag."); self_destruct(); return; } s->allow_direct = true; } else if (strcmp(token, "act-as-origin") == 0) { - if (!s->flags.accelSurrogate) { - debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": act-as-origin option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": act-as-origin option requires 'gateway' mode flag."); } else s->actAsOrigin = true; } else if (strcmp(token, "ignore-cc") == 0) { #if !USE_HTTP_VIOLATIONS - if (!s->flags.accelSurrogate) { - debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": ignore-cc option requires Acceleration mode flag."); + if (!s->flags.gatewaySurrogate) { + debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": ignore-cc option requires 'gateway' mode flag."); self_destruct(); return; } @@ -3694,6 +3654,37 @@ parse_port_option(AnyP::PortCfgPointer &s, char *token) } } +static void +parse_port_mode(AnyP::PortCfgPointer &s, char *token) +{ + if (strcmp(token, "proxy") == 0) { + s->flags.forwardProxy = true; + + } else if (strcmp(token, "gateway") == 0 || strcmp(token, "accel") == 0) { + s->flags.gatewaySurrogate = true; + s->vhost = true; + + } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) { + s->flags.natIntercept = true; + Ip::Interceptor.StartInterception(); + /* Log information regarding the port modes under interception. */ + debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s); + debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (interception enabled)"); + + } else if (strcmp(token, "tproxy") == 0) { + s->flags.tproxyIntercept = true; + Ip::Interceptor.StartTransparency(); + /* Log information regarding the port modes under transparency. */ + debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (TPROXY enabled)"); + + if (!Ip::Interceptor.ProbeForTproxy(s->s)) + throw TextException("TPROXY support in the system does not work.", Here()); + } else { + // not a mode, check as option. + parse_port_option(s, token); + } +} + void add_http_port(char *portspec) { @@ -3733,6 +3724,10 @@ parsePortCfg(AnyP::PortCfgPointer *head, const char *optionName) s->transport = parsePortProtocol(protoName); // default; protocol=... overwrites parsePortSpecification(s, token); + // port mode (or first option) + if ((token = ConfigParser::NextToken())) + parse_port_mode(s, token); + /* parse options ... */ while ((token = ConfigParser::NextToken())) { parse_port_option(s, token); @@ -3815,7 +3810,7 @@ dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfgPointer &s) else if (s->flags.proxySurrogate) storeAppendPrintf(e, " require-proxy-header"); - else if (s->flags.accelSurrogate) { + else if (s->flags.gatewaySurrogate) { storeAppendPrintf(e, " accel"); if (s->vhost) @@ -3847,7 +3842,7 @@ dump_generic_port(StoreEntry * e, const char *n, const AnyP::PortCfgPointer &s) storeAppendPrintf(e, " name=%s", s->name); #if USE_HTTP_VIOLATIONS - if (!s->flags.accelSurrogate && s->ignore_cc) + if (!s->flags.gatewaySurrogate && s->ignore_cc) storeAppendPrintf(e, " ignore-cc"); #endif diff --git a/src/cf.data.pre b/src/cf.data.pre index 51c90a376e8..f6a79349caf 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -1347,7 +1347,7 @@ ENDIF # -s Squid will just annoy the user by "randomly" denying requests. # (the counter is reset each time the limit is reached and a # request is denied) - # NOTE: in acceleration mode or where there is mesh of child proxies, + # NOTE: in gateway mode or where there is mesh of child proxies, # clients may appear to come from multiple addresses if they are # going through proxy farms, so a limit of 1 may cause user problems. @@ -2284,17 +2284,16 @@ LOC: HttpPortList DOC_START Usage: port [mode] [options] hostname:port [mode] [options] - 1.2.3.4:port [mode] [options] + IP:port [mode] [options] The socket addresses where Squid will listen for HTTP client - requests. You may specify multiple socket addresses. - There are three forms: port alone, hostname with port, and - IP address with port. If you specify a hostname or IP + requests. There are three forms: port alone, hostname with port, + and IP address with port. If you specify a hostname or IP address, Squid binds the socket to that specific address. Most likely, you do not need to bind to a specific address, so you can use the port number alone. - If you are running Squid in accelerator mode, you + If you are running Squid in gateway mode, you probably want to listen on port 80 also, or instead. The -a command line option may be used to specify additional @@ -2305,17 +2304,25 @@ DOC_START Modes: - intercept Support for IP-Layer NAT interception delivering + proxy The default. HTTP forward-proxy traffic syntax is + expected. SSL-Bump mode may be used in addition + to inspect CONNECT tunnels. + + gateway HTTP reverse-proxy traffic syntax is expected. + + intercept Support for IP-Layer NAT interception delivering traffic to this Squid port. - NP: disables authentication on the port. - tproxy Support Linux TPROXY (or BSD divert-to) with spoofing + SECURITY NOTE: disables authentication on the port. + + tproxy Support Linux TPROXY (or BSD divert-to) with spoofing of outgoing connections using the client IP address. - NP: disables authentication on the port. - accel Accelerator / reverse proxy mode + SECURITY NOTE: disables authentication on the port. - ssl-bump For each CONNECT request allowed by ssl_bump ACLs, + ssl-bump Support inspection of TLS traffic received on this port. + + For each CONNECT request allowed by ssl_bump ACLs, establish secure connection with the client and with the server, decrypt HTTPS messages as they pass through Squid, and treat them as unencrypted HTTP messages, @@ -2324,19 +2331,17 @@ DOC_START The ssl_bump option is required to fully enable bumping of CONNECT requests. - Omitting the mode flag causes default forward proxy mode to be used. - - Accelerator Mode Options: + Gateway Mode Options: defaultsite=domainname What to use for the Host: header if it is not present in a request. Determines what site (not origin server) - accelerators should consider the default. + gateway should consider the default. no-vhost Disable using HTTP/1.1 Host header for virtual domain support. - protocol= Protocol to reconstruct accelerated and intercepted + protocol= Protocol to reconstruct gateway and intercepted requests with. Defaults to HTTP/1.1 for http_port and HTTPS/1.1 for https_port. When an unsupported value is configured Squid will @@ -2357,19 +2362,18 @@ DOC_START ignore-cc Ignore request Cache-Control headers. WARNING: This option violates HTTP specifications if - used in non-accelerator setups. + used in non-gateway setups. - allow-direct Allow direct forwarding in accelerator mode. Normally - accelerated requests are denied direct forwarding as if + allow-direct Allow direct forwarding in gateway mode. Normally + gateway requests are denied direct forwarding as if never_direct was used. - WARNING: this option opens accelerator mode to security - vulnerabilities usually only affecting in interception + WARNING: this option opens gateway mode to security + vulnerabilities usually only affecting interception mode. Make sure to protect forwarding with suitable http_access rules when using this. - - SSL Bump Mode Options: + SSL-Bump Mode Options: In addition to these options ssl-bump requires TLS/SSL options. generate-host-certificates[=] @@ -2567,7 +2571,7 @@ DOC_START CONFIG_START # Squid normally listens to port 3128 -http_port @DEFAULT_HTTP_PORT@ +http_port @DEFAULT_HTTP_PORT@ proxy CONFIG_END DOC_END @@ -2583,8 +2587,7 @@ DOC_START over TLS or SSL connections. Commonly referred to as HTTPS. This is most useful for situations where you are running squid in - accelerator mode and you want to do the TLS work at the accelerator - level. + gateway mode and need to do TLS termination at the gateway. You may specify multiple socket addresses on multiple lines, each with their own certificate and/or options. @@ -2593,7 +2596,7 @@ DOC_START See http_port for a list of modes and options. Not all http_port options are available for https_port. - Among the unavalable options: + Among the unavailable options: - require-proxy-header DOC_END @@ -2634,7 +2637,7 @@ DOC_START tproxy Support Linux TPROXY for spoofing outgoing connections using the client IP address. - NP: disables authentication and maybe IPv6 on the port. + SECURITY NOTE: disables authentication and maybe IPv6 on the port. By default (i.e., without an explicit mode option), Squid extracts the FTP origin address from the login@origin parameter of the FTP USER @@ -2651,7 +2654,7 @@ DOC_START HTTP requests) to reflect the current FTP server directory. Tracking is disabled by default. - protocol=FTP Protocol to reconstruct accelerated and intercepted + protocol=FTP Protocol to reconstruct gateway and intercepted requests with. Defaults to FTP. No other accepted values have been tested with. An unsupported value results in a FATAL error. Accepted values are FTP, @@ -3751,15 +3754,15 @@ DOC_START scheme, host, port, path, params Order is not important. - ==== ACCELERATOR / REVERSE-PROXY OPTIONS ==== + ==== GATEWAY OPTIONS ==== originserver Causes this parent to be contacted as an origin server. - Meant to be used in accelerator setups when the peer + Meant to be used in gateway setups when the peer is a web server. forceddomain=name Set the Host header of requests forwarded to this peer. - Useful in accelerator setups where the server (peer) + Useful in gateway setups where the server (peer) expects a certain domain name but clients may request others. ie example.com or www.example.com @@ -6170,7 +6173,7 @@ DOC_START prevent Host: header forgery by redirectors Squid rewrites any Host: header in redirected requests. - If you are running an accelerator this may not be a wanted + If you are running a CDN gateway this may not be a wanted effect of a redirector. This directive enables you disable Host: alteration in reverse-proxy traffic. @@ -7660,7 +7663,7 @@ DOC_START DOC_END COMMENT_START - HTTPD-ACCELERATOR OPTIONS + CDN GATEWAY OPTIONS ----------------------------------------------------------------------------- COMMENT_END @@ -7675,7 +7678,7 @@ DOC_START a farm of surrogates may all perform the same tasks, they may share an identification token. - When the surrogate is a reverse-proxy, this ID is also + When the surrogate is another gateway (reverse-proxy), this ID is also used as cdn-id for CDN-Loop detection (RFC 8586). DOC_END diff --git a/src/client_side.cc b/src/client_side.cc index 3c78c62e5c2..fa5fde77446 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -1292,7 +1292,7 @@ ConnStateData::parseHttpRequest(const Http1::RequestParserPointer &hp) "\n----------"); /* deny CONNECT via accelerated ports */ - if (hp->method() == Http::METHOD_CONNECT && port != nullptr && port->flags.accelSurrogate) { + if (hp->method() == Http::METHOD_CONNECT && port != nullptr && port->flags.gatewaySurrogate) { debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << transferProtocol << " Accelerator port " << port->s.port()); debugs(33, DBG_IMPORTANT, "WARNING: for request: " << hp->method() << " " << hp->requestUri() << " " << hp->messageProtocol()); hp->parseStatusCode = Http::scMethodNotAllowed; @@ -1341,19 +1341,19 @@ ConnStateData::parseHttpRequest(const Http1::RequestParserPointer &hp) /* set url */ debugs(33,5, "Prepare absolute URL from " << - (transparent()?"intercept":(port->flags.accelSurrogate ? "accel":""))); + (transparent()?"intercept":(port->flags.gatewaySurrogate ? "gateway":""))); /* Rewrite the URL in transparent or accelerator mode */ /* NP: there are several cases to traverse here: - * - standard mode (forward proxy) + * - proxy mode (forward proxy) * - transparent mode (TPROXY) * - transparent mode with failures * - intercept mode (NAT) * - intercept mode with failures - * - accelerator mode (reverse proxy) + * - gateway mode (reverse proxy) * - internal relative-URL * - mixed combos of the above with internal URL * - remote interception with PROXY protocol - * - remote reverse-proxy with PROXY protocol + * - remote gateway (reverse-proxy) with PROXY protocol */ if (switchedToHttps()) { http->uri = prepareTlsSwitchingURL(hp); @@ -1367,7 +1367,7 @@ ConnStateData::parseHttpRequest(const Http1::RequestParserPointer &hp) // that may mismatch the (yet unparsed) Host header in the request. http->uri = xstrdup(internalLocalUri(nullptr, hp->requestUri())); - } else if (port->flags.accelSurrogate) { + } else if (port->flags.gatewaySurrogate) { /* accelerator mode */ http->uri = prepareAcceleratedURL(this, hp); http->flags.accel = true; @@ -3335,7 +3335,7 @@ clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId port (s->flags.natIntercept ? "NAT intercepted " : "") << (s->flags.tproxyIntercept ? "TPROXY intercepted " : "") << (s->flags.tunnelSslBumping ? "SSL bumped " : "") << - (s->flags.accelSurrogate ? "reverse-proxy " : "") + (s->flags.gatewaySurrogate ? "CDN gateway " : "") << FdNote(portTypeNote) << " connections at " << s->listenConn); From 2a869f5ee7d194a6f95f5863f12e1f939d8391ea Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Wed, 4 Mar 2026 01:04:08 +1300 Subject: [PATCH 2/3] Update src/anyp/TrafficMode.h Co-authored-by: Alex Rousskov --- src/anyp/TrafficMode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/anyp/TrafficMode.h b/src/anyp/TrafficMode.h index 405e2be48e0..2ecdfbcaa6a 100644 --- a/src/anyp/TrafficMode.h +++ b/src/anyp/TrafficMode.h @@ -81,7 +81,7 @@ class TrafficMode */ bool tunnelSslBumping = false; - /// \returns true if the traffic is in any way intercepted + /// whether the traffic is in any way intercepted bool isIntercepted() const { return natIntercept||tproxyIntercept ;} /// \returns true if the traffic is in any way intercepted From d79b44d7e06e1853a6df6e31d78a6fb5b379765b Mon Sep 17 00:00:00 2001 From: Amos Jeffries Date: Wed, 4 Mar 2026 01:23:58 +1300 Subject: [PATCH 3/3] updates after review --- src/anyp/TrafficMode.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/anyp/TrafficMode.h b/src/anyp/TrafficMode.h index 2ecdfbcaa6a..1ce4336a9d0 100644 --- a/src/anyp/TrafficMode.h +++ b/src/anyp/TrafficMode.h @@ -24,8 +24,9 @@ class TrafficMode /** marks HTTP Proxy (forward proxy) traffic * * Indicating the following are required: - * - not gatewaySurrogate - * - not isIntercepted() + * - URL in absolute form (exceptions for CONNECT and OPTIONS methods) + * - NAT is prohibited + * - WWW-Auth* is restricted to cache manager */ bool forwardProxy = false; @@ -84,7 +85,7 @@ class TrafficMode /// whether the traffic is in any way intercepted bool isIntercepted() const { return natIntercept||tproxyIntercept ;} - /// \returns true if the traffic is in any way intercepted + /// whether HTTP proxy (forward-proxy) traffic is expected bool isForwardProxy() const { return forwardProxy || (!gatewaySurrogate && !isIntercepted()); } };