<p>Squid currently supports receiving HTTP traffic from a client proxy using this protocol.
An http_port which has been configured to receive this protocol may only be used to
receive traffic from client software sending in this protocol.
- Regular forward-proxy HTTP traffic is not accepted.
+ HTTP traffic without the PROXY header is not accepted on such a port.
<p>The <em>accel</em> and <em>intercept</em> options are still used to identify the
traffic syntax being delivered by the client proxy.
}
#endif
if (s->transport.protocol == AnyP::PROTO_HTTPS) {
- debugs(3,DBG_CRITICAL, "FATAL: https_port: proxy-surrogate option cannot be used on HTTPS ports.");
+ debugs(3,DBG_CRITICAL, "FATAL: https_port: proxy-surrogate option is not supported on HTTPS ports.");
self_destruct();
}
}
Determine which client proxies can be trusted to provide correct
information regarding real client IP address.
- The original source details can be relayed in:
- HTTP message Forwarded header, or
- HTTP message X-Forwarded-For header, or
- PROXY protocol connection header.
-
- Allowing or Denying the X-Forwarded-For or Forwarded headers to
- be followed to find the original source of a request. Or permitting
- a client proxy to connect using PROXY protocol.
-
Requests may pass through a chain of several other proxies
- before reaching us. The X-Forwarded-For header will contain a
- comma-separated list of the IP addresses in the chain, with the
- rightmost address being the most recent.
+ before reaching us. The original source details may by sent in:
+ * HTTP message Forwarded header, or
+ * HTTP message X-Forwarded-For header, or
+ * PROXY protocol connection header.
If a request reaches us from a source that is allowed by this
- configuration item, then we consult the X-Forwarded-For header
- to see where that host received the request from. If the
- X-Forwarded-For header contains multiple addresses, we continue
- backtracking until we reach an address for which we are not allowed
- to follow the X-Forwarded-For header, or until we reach the first
- address in the list. For the purpose of ACL used in the
- follow_x_forwarded_for directive the src ACL type always matches
- the address we are testing and srcdomain matches its rDNS.
+ directive, then we trust the information it provides regarding
+ the IP of the client it received from (if any).
+
+ For the purpose of ACLs used in this directive the src ACL type always
+ matches the address we are testing and srcdomain matches its rDNS.
+
+ For proxy-surrogate ports an allow match is required for Squid to
+ permit the corresponding TCP connection, before Squid even looks for
+ HTTP request headers. If there is an allow match, Squid starts using
+ PROXY header information to determine the source address of the
+ connection for all future ACL checks. A deny match results in TCP
+ connection closure. Evaluation described in this paragraph does not
+ happen on non proxy-surrogate ports.
+
+ On each HTTP request Squid checks for X-Forwarded-For header fields.
+ If found the header values are iterated in reverse order and an allow
+ match is required for Squid to continue on to the next value.
+ The verification ends when a value receives a deny match, cannot be
+ tested, or there are no more values to test.
+ NOTE: Squid does not yet follow the Forwarded HTTP header.
The end result of this process is an IP address that we will
refer to as the indirect client address. This address may
SECURITY CONSIDERATIONS:
- Any host for which we follow the X-Forwarded-For header
- can place incorrect information in the header, and Squid
+ Any host for which we accept client IP details can place
+ incorrect information in the relevant header, and Squid
will use the incorrect information as if it were the
source address of the request. This may enable remote
hosts to bypass any access control restrictions that are
ConnStateData::proxyProtocolError(const char *msg)
{
if (msg) {
- debugs(33, 2, msg << " from " << clientConnection);
+ // This is important to know, but maybe not so much that flooding the log is okay.
+#if QUIET_PROXY_PROTOCOL
+ // display the first of every 32 occurances at level 1, the others at level 2.
+ static uint8_t hide = 0;
+ debugs(33, (hide++ % 32 == 0 ? DBG_IMPORTANT : 2), msg << " from " << clientConnection);
+#else
+ debugs(33, DBG_IMPORTANT, msg << " from " << clientConnection);
+#endif
mustStop(msg);
}
return false;
}
/// magic octet prefix for PROXY protocol version 1
-static const SBuf Proxy10magic("PROXY ", 6);
+static const SBuf Proxy1p0magic("PROXY ", 6);
/// magic octet prefix for PROXY protocol version 2
-static const SBuf Proxy20magic("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
+static const SBuf Proxy2p0magic("\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
/**
* Test the connection read buffer for PROXY protocol header.
{
// http://www.haproxy.org/download/1.5/doc/proxy-protocol.txt
- // detect and parse PROXY protocol version 1 header
- if (in.buf.length() > Proxy10magic.length() && in.buf.startsWith(Proxy10magic)) {
- return parseProxy10();
+ // detect and parse PROXY/2.0 protocol header
+ if (in.buf.startsWith(Proxy2p0magic))
+ return parseProxy2p0();
- // detect and parse PROXY protocol version 2 header
- } else if (in.buf.length() > Proxy20magic.length() && in.buf.startsWith(Proxy20magic)) {
- return parseProxy20();
+ // detect and parse PROXY/1.0 protocol header
+ if (in.buf.startsWith(Proxy1p0magic))
+ return parseProxy1p0();
- // detect and terminate other protocols
- } else if (in.buf.length() >= Proxy20magic.length()) {
- // input other than the PROXY header is a protocol error
+ // detect and terminate other protocols
+ if (in.buf.length() >= Proxy2p0magic.length()) {
+ // PROXY/1.0 magic is shorter, so we know that
+ // the input does not start with any PROXY magic
return proxyProtocolError("PROXY protocol error: invalid header");
}
/// parse the PROXY/1.0 protocol header from the connection read buffer
bool
-ConnStateData::parseProxy10()
+ConnStateData::parseProxy1p0()
{
::Parser::Tokenizer tok(in.buf);
- tok.skip(Proxy10magic);
+ tok.skip(Proxy1p0magic);
SBuf tcpVersion;
if (!tok.prefix(tcpVersion, CharacterSet::ALPHA+CharacterSet::DIGIT))
/// parse the PROXY/2.0 protocol header from the connection read buffer
bool
-ConnStateData::parseProxy20()
+ConnStateData::parseProxy2p0()
{
if ((in.buf[0] & 0xF0) != 0x20) // version == 2 is mandatory
return proxyProtocolError("PROXY/2.0 error: invalid version");
if (proto > 0x2) // values other than 0x0-0x2 are invalid
return proxyProtocolError("PROXY/2.0 error: invalid protocol type");
- const char *clen = in.buf.rawContent() + Proxy20magic.length() + 2;
+ const char *clen = in.buf.rawContent() + Proxy2p0magic.length() + 2;
const uint16_t len = ntohs(*(reinterpret_cast<const uint16_t *>(clen)));
- if (in.buf.length() < Proxy20magic.length() + 4 + len)
+ if (in.buf.length() < Proxy2p0magic.length() + 4 + len)
return false; // need more bytes
- in.buf.consume(Proxy20magic.length() + 4); // 4 being the extra bytes
+ in.buf.consume(Proxy2p0magic.length() + 4); // 4 being the extra bytes
const SBuf extra = in.buf.consume(len);
needProxyProtocolHeader_ = false; // found successfully
/* PROXY protocol functionality */
bool proxyProtocolValidateClient();
bool parseProxyProtocolHeader();
- bool parseProxy10();
- bool parseProxy20();
+ bool parseProxy1p0();
+ bool parseProxy2p0();
bool proxyProtocolError(const char *reason = NULL);
/// whether PROXY protocol header is still expected