Certain server certificates with a large chain and/or large certificates
(i.e. due to excessive amount of SAN entries) are producing helper requests and
replies which are larger than the 32KB limit set in src/helper.cc.
The major problem for squid is that the helper response should fit in the
helper read buffer. Currently squid starts with 4K request buffer and if
required may increase the buffer size up to 32K.
This patch:
- Uses a constant-size read buffer for helpers and accumulates the helper
response to Helper::Reply object.
- Changes the HelperServerBase::requests list to hold list of the new
Helper::Xaction class which holds pairs of Helper::Request and
Helper::Reply objects
- Modifies the Helper::Reply class to accumulate data and restricts the
required memory allocations
... also address Bug 4311 and partially address Bug 2833 and Bug 4471.
Extend collapsed_forwarding functionality to internal revalidation
requests. This implementation does not support Vary-controlled cache
objects and is limited to SMP-unaware caching environments, where each
Squid worker knows nothing about requests and caches handled by other
workers. However, it also lays critical groundwork for future SMP-aware
collapsed revalidation support.
Prior to these changes, multiple concurrent HTTP requests for the same
stale cached object always resulted in multiple internal revalidation
requests sent by Squid to the origin server. Those internal requests
were likely to result in multiple competing Squid cache updates, causing
cache misses and/or more internal revalidation requests, negating
collapsed forwarding savings.
Internal cache revalidation requests are collapsed if and only if
collapsed_forwarding is enabled. There is no option to control just
revalidation collapsing because there is no known use case for it.
* Public revalidation keys
Each Store entry has a unique key. Keys are used to find entries in the
Store (both already cached/swapped_out entries and not). Public keys are
normally tied to the request method and target URI. Same request
properties normally lead to the same public key, making cache hits
possible. If we were to calculate a public key for an internal
revalidation request, it would have been the same as the public key of
the stale cache entry being revalidated. Adding a revalidation response
to Store would have purged that being-revalidated cached entry, even if
the revalidation response itself was not cachable.
To avoid purging being-revalidated cached entries, the old code used
private keys for internal revalidation requests. Private keys are always
unique and cannot accidentally purge a public entry. On the other hand,
for concurrent [revalidation] requests to find the store entry to
collapse on, that store entry has to have a public key!
We resolved this conflict by adding "scope" to public keys:
* Regular/old public keys have default empty scope (that does not affect
key generation). The code not dealing with collapsed revalidation
continues to work as before. All entries stored in caches continue to
have the same keys (with an empty scope).
* When collapsed forwarding is enabled, collapsable internal
revalidation requests get public keys with a "revalidation" scope
(that is fed to the MD5 hash when the key is generated). Such a
revalidation request can find a matching store entry created by
another revalidation request (and collapse on it), but cannot clash
with the entry being revalidated (because that entry key is using a
different [empty] scope).
This change not only enables collapsing of internal revalidation
requests within one worker, but opens the way for SMP-aware workers to
share information about collapsed revalidation requests, similar to how
those workers already share information about being-swapped-out cache
entries.
After receiving the revalidation response, each collapsed revalidation
request may call updateOnNotModified() to update the stale entry [with
the same revalidation response!]. Concurrent entry updates would have
wasted many resources, especially for disk-cached entries that support
header updates, and may have purged being-revalidated entries due to
locking conflicts among updating transactions. To minimize these
problems, we adjusted header and entry metadata updating logic to skip
the update if nothing have changed since the last update.
Also fixed Bug 4311: Collapsed forwarding deadlocks for SMP Squids using
SMP-unaware caches. Collapsed transactions stalled without getting a
response because they were waiting for the shared "transients" table
updates. The table was created by Store::Controller but then abandoned (not
updated) by SMP-unaware caches. Now, the transients table is not created
at all unless SMP-aware caches are present. This fix should also address
complaints about shared memory being used for Squid instances without
SMP-aware caches.
A combination of SMP-aware and SMP-unaware caches is still not supported
and is likely to stall collapsed transactions if they are enabled. Note
that, by default, the memory cache is SMP-aware in SMP environments.
There are situations when Squid logs nothing to access.log after an
[abnormal] transaction termination. Such "stealthy" transactions may be
a security risk and an accounting problem.
ClientHttpRequest is responsible for logging most transactions but that
object is created only after the HTTP request headers are successfully
parsed. Request header parsing errors may be detected and logged
appropriately, but the job handling the incoming transaction may
terminate for reasons outside the parsing code control (e.g., a job-
killing exception thrown when there are no request headers to start
parsing yet or when the job waits for more request headers to finishing
parsing).
This change adds access logging for three cases:
1. accept(2) system call errors (before ConnStateData job is created).
2. Unexpected ConnStateData job termination, when there is no
ClientHttpRequest to log the failure.
3. Connections which send no bytes: these connections drain Squid
resources and, hence, should be logged.
TODO: make this behavior configurable because some browsers are known to
routinely create such connections(and, hence, logging them may create
too much noise in some environments).
* rename initializeSsl() method to initializeTls()
* use SessionPointer instead of SessionPtr
* return value is best used in boolean expressions, so make it bool
this also resolves some template issues with SessionPointer return type.
* rename the session parameter to serverSession which better documents what
it is than 'ssl', and distinguishes it from clientSession in child methods
which have to deal with both.
LockingPointer is now a stand-alone class that is understood (and
documented) as a typical shared pointer with OpenSSL-friendly object
importing methods. Replaced its TidyPointer::reset() abuse with an
explicit resetWithoutLocking() method after reviewing that all such
calls needed no locking indeed.
Patrick Welche [Wed, 29 Jun 2016 17:24:24 +0000 (11:24 -0600)]
Bug 4376: clang cannot build Squid eCAP code
This change is not needed for libecap v1.0 that uses tr1::shared_ptr.
However, libecap is being updated to use std::shared_ptr. Once that
update is complete, Squid eCAP code will no longer compile because the
implicit conversion of shared_ptr to bool in tr1 was deemed dangerous
and, hence, made "explicit" when shared_ptr became standard. Unlike "if"
statements, "return" statements do not trigger an explicit conversion.
HTTP/1.1: Update all stored headers on 304 revalidation.
According to RFC 7234 section 4.3.4. when a proxy receives 304 (Not Modified)
response, it should update every header, except Warning headers (which need
special processing). Also RFC 7232 section 4.1. does not prohibit origin servers
from sending any headers in 304 responses. That means that Squid now should not
ignore headers, which earlier were considered as malicious/faulty.
Nathan Hoad [Fri, 24 Jun 2016 05:29:44 +0000 (17:29 +1200)]
Convert Http::Stream::reqbuf to a MemBlob, making it configurable at runtime.
This also makes many other auxilary changes:
* Increases the size of Http::Stream::requestBuffer to match that of
read_ahead_gap. Previously this was a 4kb fixed size buffer. As a result,
the overhead for a single client connection has been increased by 12 KB in
the default configuration, but Squid will no longer artifically slow down
client responses in this situation by fragmenting the read(2)/write(2)
calls.
* Improves the performance of large uncacheable replies. This was achieved by
increasing the buffer size to 16 KB as mentioned above, but it is worth
mentioning separately. Specifically, for a server, client and proxy all
running on my local machine, this patch increases throughput on a 5 GB file
from ~110 MB/s to ~340 MB/s.
* Documents the influence that read_ahead_gap had on the size of read(2) calls
for HTTP, and now the size of write(2) calls.
* Prevent read_ahead_gap from being set to 0. Previously this would result in
hung requests.
This work is submitted on behalf of Bloomberg L.P.
The Ftp::Server::stopWaitingForOrigin() notification may come after
Ftp::Server (or an external force) has started closing the control
connection but before the Ftp::Server job became unreachable for
notifications. Writing a response in this state leads to assertions.
Other, currently unknown paths may lead to the same write-after-close
problems. This change protects all asynchronous notification methods
(except the connection closure handler itself) from exposing underlying
code to a closing control connection. This is very similar to checking
for ERR_CLOSING in Comm handlers.
Alex Rousskov [Wed, 15 Jun 2016 15:37:44 +0000 (09:37 -0600)]
Do not make bogus recvmsg(2) calls when closing UDS sockets.
comm_empty_os_read_buffers() assumes that all non-blocking
FD_READ_METHODs can read into an opaque buffer filled with random
characters. That assumption is wrong for UDS sockets that require an
initialized msghdr structure. Feeding random data to recvmsg(2) leads to
confusing errors, at best. Squid does not log those errors, but they
are visible in, for example, strace:
recvmsg(17, 0x7fffbb, MSG_DONTWAIT) = -1 EMSGSIZE (Message too long)
comm_empty_os_read_buffers() is meant to prevent TCP RST packets. The
function now ignores UDS sockets that are not used for TCP.
TODO: Useless reads may also exist for UDP and some TCP sockets.
Alex Rousskov [Tue, 14 Jun 2016 16:54:23 +0000 (04:54 +1200)]
Fixed Server::maybeMakeSpaceAvailable() logic.
This change fixes logic bugs that mostly affect performance: In micro-
tests, this change gives 10% performance improvement for intercepted
"fast peek at SNI and splice" SslBump configurations. Similar
improvement is expected for future plain HTTP/2 parsers.
maybeMakeSpaceAvailable() is called with an essentially random inBuf.
The method must prepare inBuf for the next network read. The old code
was not doing that [well enough], leading to performance problems.
In some environments, inBuf often ends up having tiny space exceeding 2
bytes (e.g., 6 bytes). This happens, for example, when Squid creates and
parses a fake CONNECT request. The old code often left such tiny inBufs
"as is" because we tried to ensure that we have at least 2 bytes to read
instead of trying to provide a reasonable number of buffer space for the
next network read. Tiny buffers naturally result in tiny network reads,
which are very inefficient, especially for non-incremental parsers.
I have removed the explicit "2 byte" space checks: Both the new and the
old code do not _guarantee_ that at least 2 bytes of buffer space are
always available, and the caller does not check that condition either.
If some other code relies on it, more fixes will be needed (but this
change is not breaking that guarantee -- either it was broken earlier or
was never fully enforced). In practice, only buffers approaching
Config.maxRequestBufferSize limit may violate this guarantee AFAICT, and
those buffers ought to be rare, so the bug, if any, remains unnoticed.
Another subtle maybeMakeSpaceAvailable() problem was that the code
contained its own buffer capacity increase algorithm (n^2 growth).
However, increasing buffer capacity exponentially does not make much
sense because network read sizes are not going to increase
exponentially. Also, memAllocStringmemAllocate() overwrites n^2 growth
with its own logic. Besides, it is buffer _space_, not the total
capacity that should be increased. More work is needed to better match
Squid buffer size for from-user network reads with the TCP stack buffers
and traffic patterns.
Both the old and the new code reallocate inBuf MemBlobs. However, the
new code leaves "reallocate or memmove" decision to the new
SBuf::reserve(), opening the possibility for future memmove
optimizations that SBuf/MemBlob do not currently support.
It is probably wrong that inBuf points to an essentially random MemBlob
outside Server control but this change does not attempt to fix that.
This patch add support for mimicking TLS Authority Key Identifier certificate
extension in Squid generated TLS certificates: If the origin server certificate
has that extension, the generated certificate (via the ssl_crtd daemon or
internally) should have the same extension, with the same set of fields if
possible.
Amos Jeffries [Tue, 14 Jun 2016 06:22:55 +0000 (18:22 +1200)]
Cleanup cppunit detection and use
The cppunit-config tool has apparently been replaced by pkg-config .pc
file years ago and is now in the process of being removed from some OS.
Notably Fedora.
Which means our present way of detecting it for use by "make check" will
increasingly fail.
This converts configure.ac to using the pkg-config method of detection
and updates the --with-cppunit-basedir parameter to --without-cppunit
matching our naming and usage scheme for other similar options. If a
=PATH is explicitly provided cppunit is assumed to exist at that
location without configure-time checking.
During start-up, Valgrind reported many errors with a similar
message: "Use of uninitialised value of size 8...". These errors
were caused by HttpRequestMethod& parameter during private
key generation: it was used as a raw void* memory there. HttpRequestMethod
is a non-POD type and has some "padding" bytes, which are not initialized
by the constructor.
The patch simplifies private key generation by using a simple counter for this,
which is sufficient to create a unique key within a single Squid process.
Except fixing Valgrind errors, this solution saves many CPU cycles wasted on
generating MD5 hashes just to "guarantee" uniqueness within a single process.
Amos Jeffries [Sat, 11 Jun 2016 05:28:18 +0000 (17:28 +1200)]
Fix GCC 4.8 eCAP builds after rev.14701
It seems GCC 4.8 at least does not reorder lnker flags so we can't use
the particular LDADD approach there. Use explicit setting of LIBS and
CXXFLAGS instead.
Amos Jeffries [Fri, 10 Jun 2016 04:53:56 +0000 (16:53 +1200)]
Bug 4446: undefined reference to 'libecap::Name::Name'
Add autoconf link check for -lecap if it is going to be used.
Also, cleanup adaptation dependency situation. Automake *_DEPENDENCIES should
no longer be used and there is no need for both AC_SUBST component lists and
ENABLE_FOO conditionals to be defined. This allows simpler configure.ac logic
for both eCAP and ICAP.
The libsecurity ServerOptions and PeerOptions class methods are now
supposed to be the API for creating SSL contexts for https_port,
cache_peer and outgoing connections.
Continue the API transition by making the callers of sslCreate*Context()
functions use the libsecurity API instead and repurpose the now obsolete
functions into the Ssl:: namespace to initialize the keying material and
other not-yet-converted OpenSSL state details of an existing context.
A side effect of this is that GnuTLS contexts are now actually created
and initialized as far as they can be.
SSL-Bump context initialization is not altered by this.
Before this change, transactions initiating a refresh were still marked
as TCP_HIT*. If such a transaction was terminated (for any reason)
before receiving an IMS reply, it was logged with that misleading tag.
Now, such transactions are logged using TCP_REFRESH[_ABORTED].
After the refresh (successful or otherwise), the tag changes to one of
the other TCP_REFRESH_* values, as before.
Amos Jeffries [Mon, 30 May 2016 01:55:32 +0000 (13:55 +1200)]
Deprecating SMB LanMan helpers
Bring the SMB LanMan helpers one step closer to removal by dropping them
from the set of helpers which are auto-detected and built by default
with Squid.
They are still available for the minority using them. But need to be
explicitly listed in the ./configure options to be built.
Amos Jeffries [Fri, 27 May 2016 12:58:15 +0000 (00:58 +1200)]
Remove ie_refresh configuration option
This option was provided as a hack to workaround problems in MSIE 5.01
and older.
Since those MSIE versions are long deprecated and no longer even
registering on the popularity charts for more than 5 years I think its
time we removed this hack.
Alex Rousskov [Fri, 27 May 2016 12:46:02 +0000 (00:46 +1200)]
Replace new/delete operators using modern C++ rules.
This change was motivated by "Mismatched free()/delete/delete[]" errors
reported by valgrind and mused about in Squid source code.
I speculate that the old new/delete replacement code was the result of
slow accumulation of working hacks to accomodate various environments,
as compiler support for the feature evolved. The cumulative result does
not actually work well (see the above paragraph), and the replacement
functions had the following visible coding problems according to [1,2]:
a) Declared with non-standard profiles that included throw specifiers.
b) Declared inline. C++ says that the results of inline declarations
have unspecified effects. In Squid, they probably necessitated
complex compiler-specific "extern inline" workarounds.
c) Defined in the header file. C++ says that defining replacements "in
any source file" is enough and that multiple replacements per
program (which is what a header file definition produces) result in
"undefined behavior".
d) Declared inconsistently (only 2 out of 4 flavors). Declaring one base
flavor should be sufficient, but if we declare more, we should
declare all of them.
The replacements were not provided to clang (trunk r13219), but there
was no explanation why. This patch does not change that exclusion.
I have no idea whether any of the old hacks are still necessary in some
cases. However, I suspect that either we do not care much if the
replacements are not enabled on some poorly supported platforms OR we
can disable them (or make them work) using much simpler hacks for the
platforms we do care about.
Alex Rousskov [Mon, 23 May 2016 23:20:27 +0000 (17:20 -0600)]
Bug 4517 error: comparison between signed and unsigned integer
The old cast is required when size_t is unsigned (as it should be).
The new cast is required when size_t is signed (as it may be).
We could cast just the left-hand side to be signed instead, but it feels
slightly wrong to do that here because all values we are casting are
meant to be unsigned and, hence, in theory, might overflow in some
future version of the code if we cast them to a signed value now and
forget to fix that cast later while adding support for larger values.
Alex Rousskov [Fri, 20 May 2016 18:16:19 +0000 (12:16 -0600)]
Fixed icons loading speed.
Since trunk r14100 (Bug 3875: bad mimeLoadIconFile error handling), each
icon was read from disk and written to Store one character at a time. I
did not measure startup delays in production, but in debugging runs,
fixing this bug sped up icons loading from 1 minute to 4 seconds.
Alex Rousskov [Fri, 20 May 2016 17:19:44 +0000 (11:19 -0600)]
Never enable OPENSSL_HELLO_OVERWRITE_HACK automatically.
OPENSSL_HELLO_OVERWRITE_HACK, a.k.a adjustSSL(), a.k.a. "splice after
stare and bump after peek" hack requires updating internal/private
OpenSSL structures. The hack also relies on SSL client making SSL
negotiation decisions that are similar to our OpenSSL version decisions.
Squid used to enable this hack if it could compile the sources, but:
* The hack works well in fewer and fewer cases.
* Making its behavior reliable is virtually impossible.
* Maintaining this hack is increasingly difficult, especially after
OpenSSL has changed its internal structures in v1.1.
* The combination of other bugs (fixed in r14670) and TLS extensions in
popular browsers effectively disabled this hack for a while, and
nobody (that we know of) noticed.
This temporary change disables the hack even if it can be compiled. If
an admin is willing to take the risks, they may enable it manually by
setting SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK macro value to 1 during
the build.
If, after this experimental change, we get no complaints (that we can
address), the hack will be completely removed from Squid sources.
Alex Rousskov [Fri, 20 May 2016 16:49:07 +0000 (10:49 -0600)]
Check for SSL_CIPHER_get_id() support required in adjustSSL().
Our adjustSSL() hack requires SSL_CIPHER_get_id() since trunk r14670,
but that OpenSSL function is not available in some environments, leading
to compilation failures.