Auto-detection of SMP related modules has been fixed to
diff -u -r -N squid-4.0.10/include/autoconf.h.in squid-4.0.11/include/autoconf.h.in
--- squid-4.0.10/include/autoconf.h.in 2016-05-06 23:35:46.000000000 +1200
+++ squid-4.0.11/include/autoconf.h.in 2016-06-10 08:33:50.000000000 +1200
@@ -1367,7 +1367,7 @@
/* DiskIO modules are expected to be available. */
#undef USE_DISKIO
-/* Disable eCAP support */
+/* Whether to use eCAP support */
#undef USE_ECAP
/* Use epoll() for the IO loop */
diff -u -r -N squid-4.0.10/include/SquidNew.h squid-4.0.11/include/SquidNew.h
--- squid-4.0.10/include/SquidNew.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/include/SquidNew.h 1970-01-01 12:00:00.000000000 +1200
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
- *
- * Squid software is distributed under GPLv2+ license and includes
- * contributions from numerous individuals and organizations.
- * Please see the COPYING and CONTRIBUTORS files for details.
- */
-
-#ifndef SQUID_NEW_H
-#define SQUID_NEW_H
-
-#if !defined(__SUNPRO_CC) && !defined(__clang__)
-/* Any code using libstdc++ must have externally resolvable overloads
- * for void * operator new - which means in the .o for the binary,
- * or in a shared library. static libs don't propogate the symbol
- * so, look in the translation unit containing main() in squid
- * for the extern version in squid
- */
-#include
-
-_SQUID_EXTERNNEW_ void *operator new(size_t size) throw (std::bad_alloc)
-{
- return xmalloc(size);
-}
-_SQUID_EXTERNNEW_ void operator delete (void *address) throw()
-{
- xfree(address);
-}
-_SQUID_EXTERNNEW_ void *operator new[] (size_t size) throw (std::bad_alloc)
-{
- return xmalloc(size);
-}
-_SQUID_EXTERNNEW_ void operator delete[] (void *address) throw()
-{
- xfree(address);
-}
-
-#endif /* !__SUNPRO_CC && !__clang__*/
-
-#endif /* SQUID_NEW_H */
-
diff -u -r -N squid-4.0.10/include/util.h squid-4.0.11/include/util.h
--- squid-4.0.10/include/util.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/include/util.h 2016-06-10 08:32:57.000000000 +1200
@@ -19,23 +19,6 @@
SQUIDCEXTERN int tvSubUsec(struct timeval, struct timeval);
SQUIDCEXTERN double tvSubDsec(struct timeval, struct timeval);
SQUIDCEXTERN void Tolower(char *);
-#if defined(__cplusplus)
-/*
- * Any code using libstdc++ must have externally resolvable overloads
- * for void * operator new - which means in the .o for the binary,
- * or in a shared library. static libs don't propogate the symbol
- * so, look in the translation unit containing main() in squid
- * for the extern version in squid
- */
-#if !defined(_SQUID_EXTERNNEW_)
-#if defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__)
-#define _SQUID_EXTERNNEW_ extern inline __attribute__((gnu_inline))
-#else
-#define _SQUID_EXTERNNEW_ extern inline
-#endif
-#endif
-#include "SquidNew.h"
-#endif
SQUIDCEXTERN time_t parse_iso3307_time(const char *buf);
diff -u -r -N squid-4.0.10/include/version.h squid-4.0.11/include/version.h
--- squid-4.0.10/include/version.h 2016-05-06 23:37:24.000000000 +1200
+++ squid-4.0.11/include/version.h 2016-06-10 08:35:21.000000000 +1200
@@ -7,7 +7,7 @@
*/
#ifndef SQUID_RELEASE_TIME
-#define SQUID_RELEASE_TIME 1462534506
+#define SQUID_RELEASE_TIME 1465504370
#endif
/*
diff -u -r -N squid-4.0.10/lib/Makefile.am squid-4.0.11/lib/Makefile.am
--- squid-4.0.10/lib/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/lib/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -11,7 +11,7 @@
SUBDIRS=
EXTRA_DIST=
-if USE_ESI
+if ENABLE_ESI
SUBDIRS += libTrie
endif
if ENABLE_SNMP
@@ -37,9 +37,12 @@
noinst_LTLIBRARIES += libsspwin32.la
libsspwin32_la_SOURCES = sspwin32.cc
else
-SUBDIRS += rfcnb smblib
EXTRA_DIST += sspwin32.cc
endif
+if ENABLE_SMBLIB
+# smblib is the only user of the rfcnb library
+SUBDIRS += rfcnb smblib
+endif
if ENABLE_AUTH_NTLM
SUBDIRS += ntlmauth
endif
diff -u -r -N squid-4.0.10/lib/Makefile.in squid-4.0.11/lib/Makefile.in
--- squid-4.0.10/lib/Makefile.in 2016-05-06 23:36:23.000000000 +1200
+++ squid-4.0.11/lib/Makefile.in 2016-06-10 08:34:22.000000000 +1200
@@ -91,7 +91,7 @@
check_PROGRAMS = tests/testRFC1738$(EXEEXT)
TESTS = tests/testRFC1738$(EXEEXT) testHeaders
@ENABLE_LOADABLE_MODULES_TRUE@am__append_1 = $(INCLTDL)
-@USE_ESI_TRUE@am__append_2 = libTrie
+@ENABLE_ESI_TRUE@am__append_2 = libTrie
@ENABLE_SNMP_TRUE@am__append_3 = snmplib
@ENABLE_XPROF_STATS_TRUE@am__append_4 = profiler
@@ -100,8 +100,9 @@
# and others are unable to be built.
#
@ENABLE_WIN32SPECIFIC_TRUE@am__append_5 = libsspwin32.la
-@ENABLE_WIN32SPECIFIC_FALSE@am__append_6 = rfcnb smblib
-@ENABLE_WIN32SPECIFIC_FALSE@am__append_7 = sspwin32.cc
+@ENABLE_WIN32SPECIFIC_FALSE@am__append_6 = sspwin32.cc
+# smblib is the only user of the rfcnb library
+@ENABLE_SMBLIB_TRUE@am__append_7 = rfcnb smblib
@ENABLE_AUTH_NTLM_TRUE@am__append_8 = ntlmauth
subdir = lib
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -804,8 +805,8 @@
subst_perlshell = sed -e 's,[@]PERL[@],$(PERL),g' <$(srcdir)/$@.pl.in >$@ || ($(RM) -f $@ ; exit 1)
DIST_SUBDIRS = ntlmauth profiler rfcnb smblib libTrie snmplib
SUBDIRS = $(am__append_2) $(am__append_3) $(am__append_4) \
- $(am__append_6) $(am__append_8)
-EXTRA_DIST = $(am__append_7)
+ $(am__append_7) $(am__append_8)
+EXTRA_DIST = $(am__append_6)
noinst_LTLIBRARIES = libmiscencoding.la libmisccontainers.la \
libmiscutil.la $(am__append_5)
@ENABLE_WIN32SPECIFIC_TRUE@libsspwin32_la_SOURCES = sspwin32.cc
diff -u -r -N squid-4.0.10/RELEASENOTES.html squid-4.0.11/RELEASENOTES.html
--- squid-4.0.10/RELEASENOTES.html 2016-05-07 00:29:29.000000000 +1200
+++ squid-4.0.11/RELEASENOTES.html 2016-06-10 09:27:51.000000000 +1200
@@ -1,11 +1,11 @@
-
- Squid 4.0.10 release notes
+
+ Squid 4.0.11 release notes
-Squid 4.0.10 release notes
+Squid 4.0.11 release notes
Squid Developers
@@ -61,7 +61,7 @@
-The Squid Team are pleased to announce the release of Squid-4.0.10 for testing.
+The Squid Team are pleased to announce the release of Squid-4.0.11 for testing.
This new release is available for download from
http://www.squid-cache.org/Versions/v4/ or the
mirrors.
@@ -425,6 +425,9 @@
Superceded by cache_peer_access. Use dstdomain ACL
in the access control list to restrict domains requested.
+ie_refresh
+Removed. MSIE 3.x, 4.x, 5.0 and 5.01 are no longer popular browsers.
+
sslproxy_cafile
Replaced by tls_outgoing_options cafile=.
Which now takes multiple entries.
@@ -482,8 +485,8 @@
--enable-security-cert-generators
New option to control which TLS/SSL dynamic certificate generator
helpers are built and installed.
-Helper ssl_crtd has been renamed to security_file_certgen
-and built with module name file. Requires --with-openssl.
+Helper ssl_crtd has been renamed to security_file_certgen
+and built with module name file. Requires --with-openssl.
--enable-security-cert-validators
New option to control which TLS/SSL certificate validation
@@ -502,10 +505,14 @@
- --enable-auth-basic
-
The MSNT-multi-domain helper has been removed.
+The SMB LanMan helper SMB_LM is no longer built by default.
+It needs to be explicitly listed to be built.
- --enable-auth-ntlm
-
The SMB LanMan helper is now built using SMB_LM
(was lower case smb_lm).
+The SMB LanMan helper SMB_LM is no longer built by default.
+It needs to be explicitly listed to be built.
- --enable-diskio
-
Auto-detection of SMP related modules has been fixed to
diff -u -r -N squid-4.0.10/scripts/find-alive.pl squid-4.0.11/scripts/find-alive.pl
--- squid-4.0.10/scripts/find-alive.pl 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/scripts/find-alive.pl 2016-06-10 08:32:57.000000000 +1200
@@ -55,8 +55,8 @@
'HttpStateData (\S+) destroyed',
],
cbdata => [
- 'cbdataAlloc: (\S+)',
- '(?:cbdataFree|cbdataUnlock): Freeing (\S+)',
+ 'cbdataInternalAlloc: Allocating (\S+)',
+ 'cbdataRealFree: Freeing (\S+)',
],
FD => [
'fd_open.*\sFD (\d+)',
diff -u -r -N squid-4.0.10/SPONSORS squid-4.0.11/SPONSORS
--- squid-4.0.10/SPONSORS 2016-05-06 23:37:22.000000000 +1200
+++ squid-4.0.11/SPONSORS 2016-06-10 08:35:20.000000000 +1200
@@ -24,6 +24,11 @@
testing infrastructure, and since late 2014 to host many of the
Squid Project services.
+RM Education - http://www.rm.com/
+
+ RM Education has sponsored Squid performance optimizations and
+ stability improvements.
+
Squid Software Foundation - http://foundation.squid-cache.org/
The Foundation governs and facilitates Squid project activities,
@@ -32,7 +37,7 @@
The Measurement Factory - http://www.measurement-factory.com/
- Measurement Factory has constributed significant resources
+ Measurement Factory has contributed significant resources
toward Squid-3+ development and server maintenance.
Treehouse Networks, NZ - http://treenet.co.nz/
@@ -90,7 +95,7 @@
BBC (UK) and Siemens IT Solutions and Services (UK)
- Provided developement and testing resources for Solaris /dev/poll
+ Provided development and testing resources for Solaris /dev/poll
support in Squid-3.1.
webwasher AG - http://www.webwasher.com/
@@ -131,7 +136,7 @@
Yahoo! Inc. - http://www.yahoo.com/
Yahoo! Inc. supported the development of improved refresh
- logics. Many thanks to Yahoo! Inc. for supporting the development
+ logic. Many thanks to Yahoo! Inc. for supporting the development
of these features.
diff -u -r -N squid-4.0.10/src/acl/external/delayer/ext_delayer_acl.8 squid-4.0.11/src/acl/external/delayer/ext_delayer_acl.8
--- squid-4.0.10/src/acl/external/delayer/ext_delayer_acl.8 2016-05-07 00:30:34.000000000 +1200
+++ squid-4.0.11/src/acl/external/delayer/ext_delayer_acl.8 2016-06-10 09:28:37.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "EXT_DELAYER_ACL 8"
-.TH EXT_DELAYER_ACL 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH EXT_DELAYER_ACL 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.0.11/src/acl/external/SQL_session/ext_sql_session_acl.8
--- squid-4.0.10/src/acl/external/SQL_session/ext_sql_session_acl.8 2016-05-07 00:30:46.000000000 +1200
+++ squid-4.0.11/src/acl/external/SQL_session/ext_sql_session_acl.8 2016-06-10 09:28:45.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "EXT_SQL_SESSION_ACL 8"
-.TH EXT_SQL_SESSION_ACL 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH EXT_SQL_SESSION_ACL 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.0.11/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8
--- squid-4.0.10/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2016-05-07 00:30:51.000000000 +1200
+++ squid-4.0.11/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2016-06-10 09:28:48.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "EXT_WBINFO_GROUP_ACL 8"
-.TH EXT_WBINFO_GROUP_ACL 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH EXT_WBINFO_GROUP_ACL 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/acl/Makefile.am squid-4.0.11/src/acl/Makefile.am
--- squid-4.0.10/src/acl/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/acl/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -177,14 +177,14 @@
AdaptationServiceData.h \
AdaptationServiceData.cc
-if USE_ADAPTATION
+if ENABLE_ADAPTATION
libacls_la_SOURCES += $(ADAPT_ACLS)
endif
EXTRA_libacls_la_SOURCES += $(ADAPT_ACLS)
ARP_ACLS = Arp.cc Arp.h Eui64.cc Eui64.h
-if USE_SQUID_EUI
+if ENABLE_EUI
libacls_la_SOURCES += $(ARP_ACLS)
endif
EXTRA_libacls_la_SOURCES += $(ARP_ACLS)
diff -u -r -N squid-4.0.10/src/acl/Makefile.in squid-4.0.11/src/acl/Makefile.in
--- squid-4.0.10/src/acl/Makefile.in 2016-05-06 23:36:32.000000000 +1200
+++ squid-4.0.11/src/acl/Makefile.in 2016-06-10 08:34:31.000000000 +1200
@@ -91,8 +91,8 @@
check_PROGRAMS =
@ENABLE_LOADABLE_MODULES_TRUE@am__append_1 = $(INCLTDL)
@ENABLE_SSL_TRUE@am__append_2 = $(SSL_ACLS)
-@USE_ADAPTATION_TRUE@am__append_3 = $(ADAPT_ACLS)
-@USE_SQUID_EUI_TRUE@am__append_4 = $(ARP_ACLS)
+@ENABLE_ADAPTATION_TRUE@am__append_3 = $(ADAPT_ACLS)
+@ENABLE_EUI_TRUE@am__append_4 = $(ARP_ACLS)
subdir = src/acl
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude/ax_with_prog.m4 \
@@ -202,9 +202,9 @@
SslErrorData.lo
@ENABLE_SSL_TRUE@am__objects_2 = $(am__objects_1)
am__objects_3 = AdaptationService.lo AdaptationServiceData.lo
-@USE_ADAPTATION_TRUE@am__objects_4 = $(am__objects_3)
+@ENABLE_ADAPTATION_TRUE@am__objects_4 = $(am__objects_3)
am__objects_5 = Arp.lo Eui64.lo
-@USE_SQUID_EUI_TRUE@am__objects_6 = $(am__objects_5)
+@ENABLE_EUI_TRUE@am__objects_6 = $(am__objects_5)
am_libacls_la_OBJECTS = IntRange.lo RegexData.lo StringData.lo Time.lo \
TimeData.lo AllOf.lo AnyOf.lo Asn.lo Browser.lo \
ConnectionsEncrypted.lo DestinationDomain.lo DestinationIp.lo \
diff -u -r -N squid-4.0.10/src/adaptation/ecap/Host.cc squid-4.0.11/src/adaptation/ecap/Host.cc
--- squid-4.0.10/src/adaptation/ecap/Host.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/adaptation/ecap/Host.cc 2016-06-10 08:32:57.000000000 +1200
@@ -147,18 +147,16 @@
{
const int squidLevel = SquidLogLevel(lv);
const int squidSection = 93; // XXX: this should be a global constant
- // XXX: Debug.h should provide this to us
- if ((Debug::level = squidLevel) <= Debug::Levels[squidSection])
- return &Debug::getDebugOut();
- else
- return NULL;
+ return Debug::Enabled(squidSection, squidLevel) ?
+ &Debug::Start(squidSection, squidLevel) :
+ nullptr;
}
void
Adaptation::Ecap::Host::closeDebug(std::ostream *debug)
{
if (debug)
- Debug::finishDebug();
+ Debug::Finish();
}
Adaptation::Ecap::Host::MessagePtr
diff -u -r -N squid-4.0.10/src/adaptation/Makefile.am squid-4.0.11/src/adaptation/Makefile.am
--- squid-4.0.10/src/adaptation/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/adaptation/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -11,11 +11,11 @@
## make a list of directories for configured adaptation schemes
SUBDIRS =
-if USE_ICAP_CLIENT
+if ENABLE_ICAP_CLIENT
SUBDIRS += icap
endif
-if USE_ECAP
+if ENABLE_ECAP
SUBDIRS += ecap
endif
@@ -53,7 +53,7 @@
ServiceFilter.cc \
ServiceFilter.h \
History.cc \
- History.h
+ History.h
# add libraries for specific adaptation schemes
libadaptation_la_LIBADD = $(ECAP_LIBS) $(ICAP_LIBS)
diff -u -r -N squid-4.0.10/src/adaptation/Makefile.in squid-4.0.11/src/adaptation/Makefile.in
--- squid-4.0.10/src/adaptation/Makefile.in 2016-05-06 23:36:38.000000000 +1200
+++ squid-4.0.11/src/adaptation/Makefile.in 2016-06-10 08:34:37.000000000 +1200
@@ -90,8 +90,8 @@
host_triplet = @host@
check_PROGRAMS =
@ENABLE_LOADABLE_MODULES_TRUE@am__append_1 = $(INCLTDL)
-@USE_ICAP_CLIENT_TRUE@am__append_2 = icap
-@USE_ECAP_TRUE@am__append_3 = ecap
+@ENABLE_ICAP_CLIENT_TRUE@am__append_2 = icap
+@ENABLE_ECAP_TRUE@am__append_3 = ecap
subdir = src/adaptation
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude/ax_with_prog.m4 \
@@ -795,7 +795,7 @@
ServiceFilter.cc \
ServiceFilter.h \
History.cc \
- History.h
+ History.h
# add libraries for specific adaptation schemes
diff -u -r -N squid-4.0.10/src/anyp/PortCfg.cc squid-4.0.11/src/anyp/PortCfg.cc
--- squid-4.0.10/src/anyp/PortCfg.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/anyp/PortCfg.cc 2016-06-10 08:32:57.000000000 +1200
@@ -143,9 +143,7 @@
}
}
- secure.updateTlsVersionLimits();
- secure.staticContext.reset(sslCreateServerContext(*this));
-
+ secure.staticContext.reset(secure.createStaticServerContext(*this));
if (!secure.staticContext) {
char buf[128];
fatalf("%s_port %s initialization error", AnyP::ProtocolType_str[transport.protocol], s.toUrl(buf, sizeof(buf)));
diff -u -r -N squid-4.0.10/src/anyp/ProtocolType.cc squid-4.0.11/src/anyp/ProtocolType.cc
--- squid-4.0.10/src/anyp/ProtocolType.cc 2016-05-07 00:30:08.000000000 +1200
+++ squid-4.0.11/src/anyp/ProtocolType.cc 2016-06-10 09:28:14.000000000 +1200
@@ -23,6 +23,8 @@
"URN",
"WHOIS",
"ICY",
+ "TLS",
+ "SSL",
"UNKNOWN",
"MAX"
};
diff -u -r -N squid-4.0.10/src/anyp/ProtocolType.h squid-4.0.11/src/anyp/ProtocolType.h
--- squid-4.0.10/src/anyp/ProtocolType.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/anyp/ProtocolType.h 2016-06-10 08:32:57.000000000 +1200
@@ -36,6 +36,8 @@
PROTO_URN,
PROTO_WHOIS,
PROTO_ICY,
+ PROTO_TLS,
+ PROTO_SSL,
PROTO_UNKNOWN,
PROTO_MAX
} ProtocolType;
diff -u -r -N squid-4.0.10/src/auth/basic/DB/basic_db_auth.8 squid-4.0.11/src/auth/basic/DB/basic_db_auth.8
--- squid-4.0.10/src/auth/basic/DB/basic_db_auth.8 2016-05-07 00:31:30.000000000 +1200
+++ squid-4.0.11/src/auth/basic/DB/basic_db_auth.8 2016-06-10 09:29:13.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "BASIC_DB_AUTH 8"
-.TH BASIC_DB_AUTH 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH BASIC_DB_AUTH 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.0.11/src/auth/basic/POP3/basic_pop3_auth.8
--- squid-4.0.10/src/auth/basic/POP3/basic_pop3_auth.8 2016-05-07 00:31:41.000000000 +1200
+++ squid-4.0.11/src/auth/basic/POP3/basic_pop3_auth.8 2016-06-10 09:29:20.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "BASIC_POP3_AUTH 8"
-.TH BASIC_POP3_AUTH 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH BASIC_POP3_AUTH 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/auth/basic/SMB_LM/required.m4 squid-4.0.11/src/auth/basic/SMB_LM/required.m4
--- squid-4.0.10/src/auth/basic/SMB_LM/required.m4 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/auth/basic/SMB_LM/required.m4 2016-06-10 08:32:57.000000000 +1200
@@ -5,7 +5,10 @@
## Please see the COPYING and CONTRIBUTORS files for details.
##
-BUILD_HELPER="SMB_LM"
-
# DONT build this helper on Windows
-AC_CHECK_HEADERS([w32api/windows.h windows.h],[BUILD_HELPER=""])
+# DONT build this helper by default
+if test "x$auto_auth_basic_modules" != "xyes";then
+ BUILD_HELPER="SMB_LM"
+ AC_CHECK_HEADERS([w32api/windows.h windows.h],[BUILD_HELPER=""])
+ require_smblib=`test "x$BUILD_HELPER" = "xSMB_LM"`
+fi
diff -u -r -N squid-4.0.10/src/auth/ntlm/SMB_LM/required.m4 squid-4.0.11/src/auth/ntlm/SMB_LM/required.m4
--- squid-4.0.10/src/auth/ntlm/SMB_LM/required.m4 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/auth/ntlm/SMB_LM/required.m4 2016-06-10 08:32:57.000000000 +1200
@@ -7,9 +7,11 @@
#
# DONT build this helper on Windows
+# DONT build this helper by default
#
# XXX: do we really need the mingw check?
-if test "$squid_host_os" != "mingw"; then
+if test "$squid_host_os" != "mingw" -a "x$auto_auth_ntlm_modules" != "xyes"; then
BUILD_HELPER="SMB_LM"
AC_CHECK_HEADERS([w32api/windows.h windows.h],[BUILD_HELPER=""])
+ require_smblib=`test "x$BUILD_HELPER" = "xSMB_LM"`
fi
diff -u -r -N squid-4.0.10/src/base/Lock.h squid-4.0.11/src/base/Lock.h
--- squid-4.0.10/src/base/Lock.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/base/Lock.h 2016-06-10 08:32:57.000000000 +1200
@@ -33,7 +33,7 @@
/// All locks must be cleared before it may be destroyed.
void lock() const {
#if defined(LOCKCOUNT_DEBUG)
- old_debug(0,1)("Incrementing this %p from count %u\n",this,count_);
+ debugs(0,1, "Incrementing this " << static_cast(this) << " from count " << count_);
#endif
assert(count_ < UINT32_MAX);
++count_;
@@ -43,7 +43,7 @@
/// All locks must be cleared before it may be destroyed.
uint32_t unlock() const {
#if defined(LOCKCOUNT_DEBUG)
- old_debug(0,1)("Decrementing this %p from count %u\n",this,count_);
+ debugs(0,1, "Decrementing this " << static_cast(this) << " from count " << count_);
#endif
assert(count_ > 0);
return --count_;
diff -u -r -N squid-4.0.10/src/cbdata.cc squid-4.0.11/src/cbdata.cc
--- squid-4.0.10/src/cbdata.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/cbdata.cc 2016-06-10 08:32:57.000000000 +1200
@@ -162,6 +162,13 @@
}
#endif
+
+#if WITH_VALGRIND
+ void *p = data;
+#else
+ void *p = this;
+#endif
+ cbdata_index[type].pool->freeOne(p);
}
static void
@@ -255,25 +262,24 @@
void
cbdataRealFree(cbdata *c, const char *file, const int line)
{
- void *p = c;
+#if WITH_VALGRIND
+ void *p = c->data;
+#else
+ void *p = (void *)&c->data;
+#endif
--cbdataCount;
- debugs(45, 9, "Freeing " << p);
#if USE_CBDATA_DEBUG
+ debugs(45, 3, "Freeing " << p << ' ' << file << ':' << line);
dlinkDelete(&c->link, &cbdataEntries);
+#else
+ debugs(45, 9, "Freeing " << p);
#endif
#if WITH_VALGRIND
- cbdata_htable.erase(c->data);
-#if USE_CBDATA_DEBUG
- debugs(45, 3, "Call delete " << p << " " << file << ":" << line);
-#endif
+ cbdata_htable.erase(p);
delete c;
#else
-#if USE_CBDATA_DEBUG
- debugs(45, 3, "Call cbdata::~cbdata() " << p << " " << file << ":" << line);
-#endif
-
/* This is ugly. But: operator delete doesn't get
* the type parameter, so we can't use that
* to free the memory.
@@ -284,9 +290,7 @@
* we could use the normal delete operator
* and it would Just Work. RBC 20030902
*/
- cbdata_type theType = c->type;
c->cbdata::~cbdata();
- cbdata_index[theType].pool->freeOne(p);
#endif
}
diff -u -r -N squid-4.0.10/src/cf.data.pre squid-4.0.11/src/cf.data.pre
--- squid-4.0.10/src/cf.data.pre 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/cf.data.pre 2016-06-10 08:32:57.000000000 +1200
@@ -163,13 +163,19 @@
This option is not yet supported by Squid-3.
DOC_END
-# Options removed in 3.6
+# Options removed in 4.x
NAME: cache_peer_domain cache_host_domain
TYPE: obsolete
DOC_START
Replace with dstdomain ACLs and cache_peer_access.
DOC_END
+NAME: ie_refresh
+TYPE: obsolete
+DOC_START
+ Remove this line. The behaviour enabled by this is no longer needed.
+DOC_END
+
NAME: sslproxy_cafile
TYPE: obsolete
DOC_START
@@ -5889,30 +5895,6 @@
replies as required by RFC2616.
DOC_END
-NAME: ie_refresh
-COMMENT: on|off
-TYPE: onoff
-LOC: Config.onoff.ie_refresh
-DEFAULT: off
-DOC_START
- Microsoft Internet Explorer up until version 5.5 Service
- Pack 1 has an issue with transparent proxies, wherein it
- is impossible to force a refresh. Turning this on provides
- a partial fix to the problem, by causing all IMS-REFRESH
- requests from older IE versions to check the origin server
- for fresh content. This reduces hit ratio by some amount
- (~10% in my experience), but allows users to actually get
- fresh content when they want it. Note because Squid
- cannot tell if the user is using 5.5 or 5.5SP1, the behavior
- of 5.5 is unchanged from old versions of Squid (i.e. a
- forced refresh is impossible). Newer versions of IE will,
- hopefully, continue to have the new behavior and will be
- handled based on that assumption. This option defaults to
- the old Squid behavior, which is better for hit ratios but
- worse for clients using IE, if they need to be able to
- force fresh content.
-DOC_END
-
NAME: vary_ignore_expire
COMMENT: on|off
TYPE: onoff
diff -u -r -N squid-4.0.10/src/client_side.cc squid-4.0.11/src/client_side.cc
--- squid-4.0.10/src/client_side.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/client_side.cc 2016-06-10 08:32:57.000000000 +1200
@@ -2185,6 +2185,13 @@
void
ConnStateData::afterClientRead()
{
+#if USE_OPENSSL
+ if (parsingTlsHandshake) {
+ parseTlsHandshake();
+ return;
+ }
+#endif
+
/* Process next request */
if (pipeline.empty())
fd_note(clientConnection->fd, "Reading next request");
@@ -2417,6 +2424,7 @@
needProxyProtocolHeader_(false),
#if USE_OPENSSL
switchedToHttps_(false),
+ parsingTlsHandshake(false),
sslServerBump(NULL),
signAlgorithm(Ssl::algSignTrusted),
#endif
@@ -2602,11 +2610,11 @@
switch (ssl_error) {
case SSL_ERROR_WANT_READ:
- Comm::SetSelect(fd, COMM_SELECT_READ, callback, conn, 0);
+ Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback != NULL ? conn : NULL), 0);
return 0;
case SSL_ERROR_WANT_WRITE:
- Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, conn, 0);
+ Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback != NULL ? conn : NULL), 0);
return 0;
case SSL_ERROR_SYSCALL:
@@ -2653,7 +2661,7 @@
debugs(83, 2, "clientNegotiateSSL: Session " << SSL_get_session(ssl) <<
" reused on FD " << fd << " (" << fd_table[fd].ipaddr << ":" << (int)fd_table[fd].remote_port << ")");
} else {
- if (do_debug(83, 4)) {
+ if (Debug::Enabled(83, 4)) {
/* Write out the SSL session details.. actually the call below, but
* OpenSSL headers do strange typecasts confusing GCC.. */
/* PEM_write_SSL_SESSION(debug_log, SSL_get_session(ssl)); */
@@ -2687,7 +2695,7 @@
}
// Connection established. Retrieve TLS connection parameters for logging.
- conn->clientConnection->tlsNegotiations()->fillWith(ssl);
+ conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(ssl);
client_cert = SSL_get_peer_certificate(ssl);
@@ -3089,10 +3097,14 @@
this, ConnStateData::requestTimeout);
commSetConnTimeout(clientConnection, Config.Timeout.request, timeoutCall);
- // Disable the client read handler until CachePeer selection is complete
- Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0);
- Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, clientNegotiateSSL, this, 0);
switchedToHttps_ = true;
+
+ auto ssl = fd_table[clientConnection->fd].ssl.get();
+ BIO *b = SSL_get_rbio(ssl);
+ Ssl::ClientBio *bio = static_cast(b->ptr);
+ bio->setReadBufData(inBuf);
+ inBuf.clear();
+ clientNegotiateSSL(clientConnection->fd, this);
}
void
@@ -3117,19 +3129,67 @@
if (bumpServerMode == Ssl::bumpServerFirst && !sslServerBump) {
request->flags.sslPeek = true;
sslServerBump = new Ssl::ServerBump(request);
-
- // will call httpsPeeked() with certificate and connection, eventually
- FwdState::fwdStart(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw());
- return;
} else if (bumpServerMode == Ssl::bumpPeek || bumpServerMode == Ssl::bumpStare) {
request->flags.sslPeek = true;
sslServerBump = new Ssl::ServerBump(request, NULL, bumpServerMode);
- startPeekAndSplice();
- return;
}
- // otherwise, use sslConnectHostOrIp
- getSslContextStart();
+ // commSetConnTimeout() was called for this request before we switched.
+ // Fix timeout to request_start_timeout
+ typedef CommCbMemFunT TimeoutDialer;
+ AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
+ TimeoutDialer, this, ConnStateData::requestTimeout);
+ commSetConnTimeout(clientConnection, Config.Timeout.request_start_timeout, timeoutCall);
+ // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
+ // a bumbed "connect" request on non transparent port.
+ receivedFirstByte_ = false;
+ // Get more data to peek at Tls
+ parsingTlsHandshake = true;
+ readSomeData();
+}
+
+void
+ConnStateData::parseTlsHandshake()
+{
+ Must(parsingTlsHandshake);
+
+ assert(!inBuf.isEmpty());
+ receivedFirstByte();
+ fd_note(clientConnection->fd, "Parsing TLS handshake");
+
+ bool unsupportedProtocol = false;
+ try {
+ if (!tlsParser.parseHello(inBuf)) {
+ // need more data to finish parsing
+ readSomeData();
+ return;
+ }
+ }
+ catch (const std::exception &ex) {
+ debugs(83, 2, "error on FD " << clientConnection->fd << ": " << ex.what());
+ unsupportedProtocol = true;
+ }
+
+ parsingTlsHandshake = false;
+
+ // Even if the parser failed, each TLS detail should either be set
+ // correctly or still be "unknown"; copying unknown detail is a no-op.
+ clientConnection->tlsNegotiations()->retrieveParsedInfo(tlsParser.details);
+
+ // We should disable read/write handlers
+ Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0);
+ Comm::SetSelect(clientConnection->fd, COMM_SELECT_WRITE, NULL, NULL, 0);
+
+ if (!sslServerBump) { // BumpClientFirst mode does not use this member
+ getSslContextStart();
+ return;
+ } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) {
+ // will call httpsPeeked() with certificate and connection, eventually
+ FwdState::fwdStart(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw());
+ } else {
+ Must(sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare);
+ startPeekAndSplice(unsupportedProtocol);
+ }
}
bool
@@ -3148,77 +3208,24 @@
return false;
}
-/** negotiate an SSL connection */
-static void
-clientPeekAndSpliceSSL(int fd, void *data)
+void
+ConnStateData::startPeekAndSplice(const bool unsupportedProtocol)
{
- ConnStateData *conn = (ConnStateData *)data;
- auto ssl = fd_table[fd].ssl.get();
-
- debugs(83, 5, "Start peek and splice on FD " << fd);
-
- int ret = 0;
- if ((ret = Squid_SSL_accept(conn, clientPeekAndSpliceSSL)) < 0)
- debugs(83, 2, "SSL_accept failed.");
-
- BIO *b = SSL_get_rbio(ssl);
- assert(b);
- Ssl::ClientBio *bio = static_cast(b->ptr);
- if (ret < 0) {
- const err_type err = bio->noSslClient() ? ERR_PROTOCOL_UNKNOWN : ERR_SECURE_ACCEPT_FAIL;
- if (!conn->spliceOnError(err))
- conn->clientConnection->close();
+ if (unsupportedProtocol) {
+ if (!spliceOnError(ERR_PROTOCOL_UNKNOWN))
+ clientConnection->close();
return;
}
- if (bio->rBufData().contentSize() > 0)
- conn->receivedFirstByte();
-
- if (bio->gotHello()) {
- if (conn->serverBump()) {
- Ssl::Bio::sslFeatures const &features = bio->receivedHelloFeatures();
- if (!features.serverName.isEmpty()) {
- conn->serverBump()->clientSni = features.serverName;
- conn->resetSslCommonName(features.serverName.c_str());
- }
+ if (serverBump()) {
+ Security::TlsDetails::Pointer const &details = tlsParser.details;
+ if (details && !details->serverName.isEmpty()) {
+ serverBump()->clientSni = details->serverName;
+ resetSslCommonName(details->serverName.c_str());
}
-
- debugs(83, 5, "I got hello. Start forwarding the request!!! ");
- Comm::SetSelect(fd, COMM_SELECT_READ, NULL, NULL, 0);
- Comm::SetSelect(fd, COMM_SELECT_WRITE, NULL, NULL, 0);
- conn->startPeekAndSpliceDone();
- return;
}
-}
-
-void ConnStateData::startPeekAndSplice()
-{
- // will call httpsPeeked() with certificate and connection, eventually
- auto unConfiguredCTX = Ssl::createSSLContext(port->signingCert, port->signPkey, *port);
- fd_table[clientConnection->fd].dynamicSslContext = unConfiguredCTX;
-
- if (!httpsCreate(clientConnection, unConfiguredCTX))
- return;
-
- // commSetConnTimeout() was called for this request before we switched.
- // Fix timeout to request_start_timeout
- typedef CommCbMemFunT TimeoutDialer;
- AsyncCall::Pointer timeoutCall = JobCallback(33, 5,
- TimeoutDialer, this, ConnStateData::requestTimeout);
- commSetConnTimeout(clientConnection, Config.Timeout.request_start_timeout, timeoutCall);
- // Also reset receivedFirstByte_ flag to allow this timeout work in the case we have
- // a bumbed "connect" request on non transparent port.
- receivedFirstByte_ = false;
- // Disable the client read handler until CachePeer selection is complete
- Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0);
- Comm::SetSelect(clientConnection->fd, COMM_SELECT_READ, clientPeekAndSpliceSSL, this, 0);
- switchedToHttps_ = true;
-
- auto ssl = fd_table[clientConnection->fd].ssl.get();
- BIO *b = SSL_get_rbio(ssl);
- Ssl::ClientBio *bio = static_cast(b->ptr);
- bio->hold(true);
+ startPeekAndSpliceDone();
}
void httpsSslBumpStep2AccessCheckDone(allow_t answer, void *data)
@@ -3252,34 +3259,23 @@
ConnStateData::splice()
{
// normally we can splice here, because we just got client hello message
- auto ssl = fd_table[clientConnection->fd].ssl.get();
-
- //retrieve received TLS client information
- clientConnection->tlsNegotiations()->fillWith(ssl);
- BIO *b = SSL_get_rbio(ssl);
- Ssl::ClientBio *bio = static_cast(b->ptr);
- MemBuf const &rbuf = bio->rBufData();
- debugs(83,5, "Bio for " << clientConnection << " read " << rbuf.contentSize() << " helo bytes");
- // Do splice:
- fd_table[clientConnection->fd].read_method = &default_read_method;
- fd_table[clientConnection->fd].write_method = &default_write_method;
+ if (fd_table[clientConnection->fd].ssl.get()) {
+ // Restore default read methods
+ fd_table[clientConnection->fd].read_method = &default_read_method;
+ fd_table[clientConnection->fd].write_method = &default_write_method;
+ }
if (transparent()) {
// set the current protocol to something sensible (was "HTTPS" for the bumping process)
// we are sending a faked-up HTTP/1.1 message wrapper, so go with that.
transferProtocol = Http::ProtocolVersion();
- // XXX: copy from MemBuf reallocates, not a regression since old code did too
- SBuf temp;
- temp.append(rbuf.content(), rbuf.contentSize());
- return fakeAConnectRequest("intercepted TLS spliced", temp);
+ return fakeAConnectRequest("intercepted TLS spliced", inBuf);
} else {
// XXX: assuming that there was an HTTP/1.1 CONNECT to begin with...
// reset the current protocol to HTTP/1.1 (was "HTTPS" for the bumping process)
transferProtocol = Http::ProtocolVersion();
- // inBuf still has the "CONNECT ..." request data, reset it to SSL hello message
- inBuf.append(rbuf.content(), rbuf.contentSize());
Http::StreamPointer context = pipeline.front();
ClientHttpRequest *http = context->http;
tunnelStart(http);
@@ -3310,6 +3306,39 @@
return;
}
+ // will call httpsPeeked() with certificate and connection, eventually
+ auto unConfiguredCTX = Ssl::createSSLContext(port->signingCert, port->signPkey, *port);
+ fd_table[clientConnection->fd].dynamicSslContext = unConfiguredCTX;
+
+ if (!httpsCreate(clientConnection, unConfiguredCTX))
+ return;
+
+ switchedToHttps_ = true;
+
+ auto ssl = fd_table[clientConnection->fd].ssl.get();
+ BIO *b = SSL_get_rbio(ssl);
+ Ssl::ClientBio *bio = static_cast(b->ptr);
+ bio->setReadBufData(inBuf);
+ bio->hold(true);
+
+ // Here squid should have all of the client hello message so the
+ // Squid_SSL_accept should return 0;
+ // This block exist only to force openSSL parse client hello and detect
+ // ERR_SECURE_ACCEPT_FAIL error, which should be checked and splice if required.
+ int ret = 0;
+ if ((ret = Squid_SSL_accept(this, NULL)) < 0) {
+ debugs(83, 2, "SSL_accept failed.");
+ const err_type err = ERR_SECURE_ACCEPT_FAIL;
+ if (!spliceOnError(err))
+ clientConnection->close();
+ return;
+ }
+
+ // We need to reset inBuf here, to be used by incoming requests in the case
+ // of SSL bump
+ inBuf.clear();
+
+ debugs(83, 5, "Peek and splice at step2 done. Start forwarding the request!!! ");
FwdState::Start(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw(), http ? http->al : NULL);
}
diff -u -r -N squid-4.0.10/src/client_side.h squid-4.0.11/src/client_side.h
--- squid-4.0.10/src/client_side.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/client_side.h 2016-06-10 08:32:57.000000000 +1200
@@ -24,6 +24,7 @@
#include "auth/UserRequest.h"
#endif
#if USE_OPENSSL
+#include "security/Handshake.h"
#include "ssl/support.h"
#endif
@@ -202,7 +203,7 @@
void postHttpsAccept();
/// Initializes and starts a peek-and-splice negotiation with the SSL client
- void startPeekAndSplice();
+ void startPeekAndSplice(const bool unknownProtocol);
/// Called when the initialization of peek-and-splice negotiation finidhed
void startPeekAndSpliceDone();
/// Called when a peek-and-splice step finished. For example after
@@ -234,6 +235,7 @@
void sslCrtdHandleReply(const Helper::Reply &reply);
void switchToHttps(HttpRequest *request, Ssl::BumpMode bumpServerMode);
+ void parseTlsHandshake();
bool switchedToHttps() const { return switchedToHttps_; }
Ssl::ServerBump *serverBump() {return sslServerBump;}
inline void setServerBump(Ssl::ServerBump *srvBump) {
@@ -255,6 +257,9 @@
Ssl::BumpMode sslBumpMode; ///< ssl_bump decision (Ssl::bumpEnd if n/a).
+ /// Tls parser to use for client HELLO messages parsing on bumped
+ /// connections.
+ Security::HandshakeParser tlsParser;
#else
bool switchedToHttps() const { return false; }
#endif
@@ -350,6 +355,8 @@
#if USE_OPENSSL
bool switchedToHttps_;
+ bool parsingTlsHandshake; ///< whether we are getting/parsing TLS Hello bytes
+
/// The SSL server host name appears in CONNECT request or the server ip address for the intercepted requests
String sslConnectHostOrIp; ///< The SSL server host name as passed in the CONNECT request
SBuf sslCommonName_; ///< CN name for SSL certificate generation
diff -u -r -N squid-4.0.10/src/client_side_reply.cc squid-4.0.11/src/client_side_reply.cc
--- squid-4.0.10/src/client_side_reply.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/client_side_reply.cc 2016-06-10 08:32:57.000000000 +1200
@@ -278,6 +278,7 @@
return;
}
+ http->logType = LOG_TCP_REFRESH;
http->request->flags.refresh = true;
#if STORE_CLIENT_LIST_DEBUG
/* Prevent a race with the store client memory free routines
@@ -1532,9 +1533,7 @@
}
// Decide if we send chunked reply
- if (maySendChunkedReply &&
- request->flags.proxyKeepalive &&
- reply->bodySize(request->method) < 0) {
+ if (maySendChunkedReply && reply->bodySize(request->method) < 0) {
debugs(88, 3, "clientBuildReplyHeader: chunked reply");
request->flags.chunkedReply = true;
hdr->putStr(Http::HdrType::TRANSFER_ENCODING, "chunked");
diff -u -r -N squid-4.0.10/src/client_side_request.cc squid-4.0.11/src/client_side_request.cc
--- squid-4.0.10/src/client_side_request.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/client_side_request.cc 2016-06-10 08:32:57.000000000 +1200
@@ -1056,7 +1056,6 @@
HttpRequest *request = http->request;
HttpHeader *req_hdr = &request->header;
bool no_cache = false;
- const char *str;
request->imslen = -1;
request->ims = req_hdr->getTime(Http::HdrType::IF_MODIFIED_SINCE);
@@ -1072,28 +1071,6 @@
// RFC 2616: treat Pragma:no-cache as if it was Cache-Control:no-cache when Cache-Control is missing
} else if (req_hdr->has(Http::HdrType::PRAGMA))
no_cache = req_hdr->hasListMember(Http::HdrType::PRAGMA,"no-cache",',');
-
- /*
- * Work around for supporting the Reload button in IE browsers when Squid
- * is used as an accelerator or transparent proxy, by turning accelerated
- * IMS request to no-cache requests. Now knows about IE 5.5 fix (is
- * actually only fixed in SP1, but we can't tell whether we are talking to
- * SP1 or not so all 5.5 versions are treated 'normally').
- */
- if (Config.onoff.ie_refresh) {
- if (http->flags.accel && request->flags.ims) {
- if ((str = req_hdr->getStr(Http::HdrType::USER_AGENT))) {
- if (strstr(str, "MSIE 5.01") != NULL)
- no_cache=true;
- else if (strstr(str, "MSIE 5.0") != NULL)
- no_cache=true;
- else if (strstr(str, "MSIE 4.") != NULL)
- no_cache=true;
- else if (strstr(str, "MSIE 3.") != NULL)
- no_cache=true;
- }
- }
- }
}
if (request->method == Http::METHOD_OTHER) {
diff -u -r -N squid-4.0.10/src/debug.cc squid-4.0.11/src/debug.cc
--- squid-4.0.10/src/debug.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/debug.cc 2016-06-10 08:32:57.000000000 +1200
@@ -14,6 +14,8 @@
#include "SquidTime.h"
#include "util.h"
+#include
+
/* for shutting_down flag in xassert() */
#include "globals.h"
@@ -22,8 +24,6 @@
int Debug::log_stderr = -1;
bool Debug::log_syslog = false;
int Debug::Levels[MAX_DEBUG_SECTIONS];
-int Debug::level;
-int Debug::sectionLevel;
char *Debug::cache_log = NULL;
int Debug::rotateNumber = -1;
FILE *debug_log = NULL;
@@ -134,7 +134,7 @@
static void
_db_print_stderr(const char *format, va_list args)
{
- if (Debug::log_stderr < Debug::level)
+ if (Debug::log_stderr < Debug::Level())
return;
if (debug_log == stderr)
@@ -149,7 +149,7 @@
{
/* level 0,1 go to syslog */
- if (Debug::level > 1)
+ if (Debug::Level() > 1)
return;
if (!Debug::log_syslog)
@@ -162,7 +162,7 @@
tmpbuf[BUFSIZ - 1] = '\0';
- syslog(Debug::level == 0 ? LOG_WARNING : LOG_NOTICE, "%s", tmpbuf);
+ syslog(Debug::Level() == 0 ? LOG_WARNING : LOG_NOTICE, "%s", tmpbuf);
}
#endif /* HAVE_SYSLOG */
@@ -524,7 +524,7 @@
static char buf[128];
static time_t last_t = 0;
- if (Debug::level > 1) {
+ if (Debug::Level() > 1) {
char buf2[128];
tm = localtime(&t);
strftime(buf2, 127, "%Y/%m/%d %H:%M:%S", tm);
@@ -726,55 +726,75 @@
return Ctx_Descrs[ctx] ? Ctx_Descrs[ctx] : "";
}
-int Debug::TheDepth = 0;
+Debug::Context *Debug::Current = nullptr;
-Debug::OutStream *Debug::CurrentDebug(NULL);
+Debug::Context::Context(const int aSection, const int aLevel):
+ level(aLevel),
+ sectionLevel(Levels[aSection]),
+ upper(Current)
+{
+ formatStream();
+}
-std::ostream &
-Debug::getDebugOut()
+/// Optimization: avoids new Context creation for every debugs().
+void
+Debug::Context::rewind(const int aSection, const int aLevel)
{
- assert(TheDepth >= 0);
- ++TheDepth;
- if (TheDepth > 1) {
- assert(CurrentDebug);
- *CurrentDebug << std::endl << "reentrant debuging " << TheDepth << "-{";
- } else {
- assert(!CurrentDebug);
- CurrentDebug = new Debug::OutStream;
- // set default formatting flags
- CurrentDebug->setf(std::ios::fixed);
- CurrentDebug->precision(2);
- }
- return *CurrentDebug;
+ level = aLevel;
+ sectionLevel = Levels[aSection];
+ assert(upper == Current);
+
+ buf.str(std::string());
+ buf.clear();
+ // debugs() users are supposed to preserve format, but
+ // some do not, so we have to waste cycles resetting it for all.
+ formatStream();
}
+/// configures default formatting for the debugging stream
void
-Debug::finishDebug()
+Debug::Context::formatStream()
+{
+ const static std::ostringstream cleanStream;
+ buf.flags(cleanStream.flags() | std::ios::fixed);
+ buf.width(cleanStream.width());
+ buf.precision(2);
+ buf.fill(' ');
+ // If this is not enough, use copyfmt(cleanStream) which is ~10% slower.
+}
+
+std::ostringstream &
+Debug::Start(const int section, const int level)
{
- assert(TheDepth >= 0);
- assert(CurrentDebug);
- if (TheDepth > 1) {
- *CurrentDebug << "}-" << TheDepth << std::endl;
+ Context *future = nullptr;
+
+ // prepare future context
+ if (Current) {
+ // all reentrant debugs() calls get here; create a dedicated context
+ future = new Context(section, level);
} else {
- assert(TheDepth == 1);
- _db_print("%s\n", CurrentDebug->str().c_str());
- delete CurrentDebug;
- CurrentDebug = NULL;
+ // Optimization: Nearly all debugs() calls get here; avoid allocations
+ static Context *topContext = new Context(1, 1);
+ topContext->rewind(section, level);
+ future = topContext;
}
- --TheDepth;
+
+ Current = future;
+
+ return future->buf;
}
-// Hack: replaces global ::xassert() to debug debugging assertions
-// Relies on assert macro calling xassert() without a specific scope.
void
-Debug::xassert(const char *msg, const char *file, int line)
+Debug::Finish()
{
+ // TODO: Optimize to remove at least one extra copy.
+ _db_print("%s\n", Current->buf.str().c_str());
- if (CurrentDebug) {
- *CurrentDebug << "assertion failed: " << file << ":" << line <<
- ": \"" << msg << "\"";
- }
- abort();
+ Context *past = Current;
+ Current = past->upper;
+ if (Current)
+ delete past;
+ // else it was a static topContext from Debug::Start()
}
size_t
@@ -800,6 +820,19 @@
return path+BuildPrefixLength;
}
+/// print data bytes using hex notation
+void
+Raw::printHex(std::ostream &os) const
+{
+ const auto savedFill = os.fill('0');
+ const auto savedFlags = os.flags(); // std::ios_base::fmtflags
+ os << std::hex;
+ std::for_each(data_, data_ + size_,
+ [&os](const char &c) { os << std::setw(2) << static_cast(c); });
+ os.flags(savedFlags);
+ os.fill(savedFill);
+}
+
std::ostream &
Raw::print(std::ostream &os) const
{
@@ -811,13 +844,17 @@
// finalize debugging level if no level was set explicitly via minLevel()
const int finalLevel = (level >= 0) ? level :
- (size_ > 40 ? DBG_DATA : Debug::sectionLevel);
- if (finalLevel <= Debug::sectionLevel) {
+ (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
+ if (finalLevel <= Debug::SectionLevel()) {
os << (label_ ? '=' : ' ');
- if (data_)
- os.write(data_, size_);
- else
+ if (data_) {
+ if (useHex_)
+ printHex(os);
+ else
+ os.write(data_, size_);
+ } else {
os << "[null]";
+ }
}
return os;
diff -u -r -N squid-4.0.10/src/Debug.h squid-4.0.11/src/Debug.h
--- squid-4.0.10/src/Debug.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/Debug.h 2016-06-10 08:32:57.000000000 +1200
@@ -52,36 +52,51 @@
{
public:
+ /// meta-information for debugs() or a similar debugging call
+ class Context
+ {
+ public:
+ Context(const int aSectionLevel, const int aLevel);
+
+ int level; ///< minimum debugging level required by the debugs() call
+ int sectionLevel; ///< maximum debugging level allowed during the call
+
+ private:
+ friend class Debug;
+ void rewind(const int aSection, const int aLevel);
+ void formatStream();
+ Context *upper; ///< previous or parent record in nested debugging calls
+ std::ostringstream buf; ///< debugs() output sink
+ };
+
+ /// whether debugging the given section and the given level produces output
+ static bool Enabled(const int section, const int level)
+ {
+ return level <= Debug::Levels[section];
+ }
+
static char *debugOptions;
static char *cache_log;
static int rotateNumber;
static int Levels[MAX_DEBUG_SECTIONS];
- static int level; ///< minimum debugging level required by debugs() call
- static int sectionLevel; ///< maximum debugging level allowed now
static int override_X;
static int log_stderr;
static bool log_syslog;
- static std::ostream &getDebugOut();
- static void finishDebug();
static void parseOptions(char const *);
-private:
- // Hack: replaces global ::xassert() to debug debugging assertions
- static void xassert(const char *msg, const char *file, int line);
+ /// minimum level required by the current debugs() call
+ static int Level() { return Current ? Current->level : 1; }
+ /// maximum level currently allowed
+ static int SectionLevel() { return Current ? Current->sectionLevel : 1; }
+
+ /// opens debugging context and returns output buffer
+ static std::ostringstream &Start(const int section, const int level);
+ /// logs output buffer created in Start() and closes debugging context
+ static void Finish();
- /// Wrapper class to prevent SquidNew.h overrides getting confused
- /// with the libc++6 std::ostringstream definitions
- class OutStream : public std::ostringstream
- {
- MEMPROXY_CLASS(OutStream);
- public:
- void *operator new[] (size_t size) throw(std::bad_alloc) = delete; //{return xmalloc(size);}
- void operator delete[] (void *address) throw() = delete; // {xfree(address);}
- };
-
- static OutStream *CurrentDebug;
- static int TheDepth; // level of nested debugging calls
+private:
+ static Context *Current; ///< deepest active context; nil outside debugs()
};
extern FILE *debug_log;
@@ -97,15 +112,15 @@
*/
#define debugs(SECTION, LEVEL, CONTENT) \
do { \
- if ((Debug::level = (LEVEL)) <= Debug::Levels[SECTION]) { \
- Debug::sectionLevel = Debug::Levels[SECTION]; \
- std::ostream &_dbo=Debug::getDebugOut(); \
- if (Debug::level > DBG_IMPORTANT) { \
- _dbo << (SECTION) << ',' << (LEVEL) << "| " \
+ const int _dbg_level = (LEVEL); \
+ if (Debug::Enabled((SECTION), _dbg_level)) { \
+ std::ostream &_dbo = Debug::Start((SECTION), _dbg_level); \
+ if (_dbg_level > DBG_IMPORTANT) { \
+ _dbo << (SECTION) << ',' << _dbg_level << "| " \
<< SkipBuildPrefix(__FILE__)<<"("<<__LINE__<<") "<<__FUNCTION__<<": "; \
} \
_dbo << CONTENT; \
- Debug::finishDebug(); \
+ Debug::Finish(); \
} \
} while (/*CONSTCOND*/ 0)
@@ -141,10 +156,6 @@
return (os << (int)d);
}
-/* Legacy debug style. Still used in some places. needs to die... */
-#define do_debug(SECTION, LEVEL) ((Debug::level = (LEVEL)) <= Debug::Levels[SECTION])
-#define old_debug(SECTION, LEVEL) if do_debug((SECTION), (LEVEL)) _db_print
-
/* Legacy debug function definitions */
void _db_init(const char *logfile, const char *options);
void _db_print(const char *,...) PRINTF_FORMAT_ARG1;
@@ -159,11 +170,14 @@
{
public:
Raw(const char *label, const char *data, const size_t size):
- level(-1), label_(label), data_(data), size_(size) {}
+ level(-1), label_(label), data_(data), size_(size), useHex_(false) {}
/// limit data printing to at least the given debugging level
Raw &minLevel(const int aLevel) { level = aLevel; return *this; }
+ /// print data using two hex digits per byte (decoder: xxd -r -p)
+ Raw &hex() { useHex_ = true; return *this; }
+
/// If debugging is prohibited by the current debugs() or section level,
/// prints nothing. Otherwise, dumps data using one of these formats:
/// " label[size]=data" if label was set and data size is positive
@@ -178,9 +192,12 @@
int level;
private:
+ void printHex(std::ostream &os) const;
+
const char *label_; ///< optional data name or ID; triggers size printing
const char *data_; ///< raw data to be printed
size_t size_; ///< data length
+ bool useHex_; ///< whether hex() has been called
};
inline
diff -u -r -N squid-4.0.10/src/esi/Expression.cc squid-4.0.11/src/esi/Expression.cc
--- squid-4.0.10/src/esi/Expression.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/esi/Expression.cc 2016-06-10 08:32:57.000000000 +1200
@@ -116,8 +116,6 @@
static int membercompare(stackmember a, stackmember b);
static char const *trim(char const *s);
static stackmember getsymbol(const char *s, char const **endptr);
-static void printliteral(stackmember s);
-static void printmember(stackmember s);
/* -2 = failed to compate
* -1 = a less than b
@@ -846,105 +844,106 @@
return rv;
}
-void
-printliteral(stackmember s)
+static void
+printLiteral(std::ostream &os, const stackmember &s)
{
switch (s.valuestored) {
case ESI_LITERAL_INVALID:
- old_debug(86, 1)( " Invalid " );
+ os << " Invalid ";
break;
case ESI_LITERAL_FLOAT:
- old_debug(86,1)("%f", s.value.floating);
+ os << s.value.floating;
break;
case ESI_LITERAL_STRING:
- old_debug(86,1)("'%s'", s.value.string);
+ os << '\'' << s.value.string << '\'';
break;
case ESI_LITERAL_INT:
- old_debug(86,1)("%d", s.value.integral);
+ os << s.value.integral;
break;
case ESI_LITERAL_BOOL:
- old_debug(86,1)("%s",s.value.integral ? "true" : "false");
+ os << (s.value.integral ? "true" : "false");
}
}
-void
-printmember(stackmember s)
+static std::ostream &
+operator <<(std::ostream &os, const stackmember &s)
{
switch (s.valuetype) {
case ESI_EXPR_INVALID:
- old_debug(86,1)(" Invalid ");
+ os << " Invalid ";
break;
case ESI_EXPR_LITERAL:
- printliteral(s);
+ printLiteral(os, s);
break;
case ESI_EXPR_EXPR:
- old_debug(86,1)("%s", s.value.integral ? "true" : "false");
+ os << (s.value.integral ? "true" : "false");
break;
case ESI_EXPR_OR:
- old_debug(86,1)("|");
+ os << "|";
break;
case ESI_EXPR_AND:
- old_debug(86,1)("&");
+ os << "&";
break;
case ESI_EXPR_NOT:
- old_debug(86,1)("!");
+ os << "!";
break;
case ESI_EXPR_START:
- old_debug(86,1)("(");
+ os << "(";
break;
case ESI_EXPR_END:
- old_debug(86,1)(")");
+ os << ")";
break;
case ESI_EXPR_EQ:
- old_debug(86,1)("==");
+ os << "==";
break;
case ESI_EXPR_NOTEQ:
- old_debug(86,1)("!=");
+ os << "!=";
break;
case ESI_EXPR_LESS:
- old_debug(86,1)("<");
+ os << "<";
break;
case ESI_EXPR_LESSEQ:
- old_debug(86,1)("<=");
+ os << "<=";
break;
case ESI_EXPR_MORE:
- old_debug(86,1)(">");
+ os << ">";
break;
case ESI_EXPR_MOREEQ:
- old_debug(86,1)(">=");
+ os << ">=";
break;
}
+
+ return os;
}
void
dumpstack(stackmember * stack, int depth)
{
- int i;
-
- for (i = 0; i < depth; ++i)
- printmember(stack[i]);
-
- if (depth)
- old_debug(86,1)("\n");
+ if (depth) {
+ std::ostringstream buf;
+ for (int i = 0; i < depth; ++i)
+ buf << stack[i];
+ debugs(86,1, buf.str());
+ }
}
int
diff -u -r -N squid-4.0.10/src/esi/Makefile.am squid-4.0.11/src/esi/Makefile.am
--- squid-4.0.10/src/esi/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/esi/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -14,13 +14,13 @@
CustomParser.cc \
CustomParser.h
-if HAVE_LIBEXPAT
+if ENABLE_LIBEXPAT
ESI_PARSER_SOURCES += \
ExpatParser.cc \
ExpatParser.h
endif
-if HAVE_LIBXML2
+if ENABLE_LIBXML2
ESI_PARSER_SOURCES += \
Libxml2Parser.cc \
Libxml2Parser.h
diff -u -r -N squid-4.0.10/src/esi/Makefile.in squid-4.0.11/src/esi/Makefile.in
--- squid-4.0.10/src/esi/Makefile.in 2016-05-06 23:36:54.000000000 +1200
+++ squid-4.0.11/src/esi/Makefile.in 2016-06-10 08:34:53.000000000 +1200
@@ -90,13 +90,13 @@
host_triplet = @host@
check_PROGRAMS =
@ENABLE_LOADABLE_MODULES_TRUE@am__append_1 = $(INCLTDL)
-@HAVE_LIBEXPAT_TRUE@am__append_2 = \
-@HAVE_LIBEXPAT_TRUE@ ExpatParser.cc \
-@HAVE_LIBEXPAT_TRUE@ ExpatParser.h
+@ENABLE_LIBEXPAT_TRUE@am__append_2 = \
+@ENABLE_LIBEXPAT_TRUE@ ExpatParser.cc \
+@ENABLE_LIBEXPAT_TRUE@ ExpatParser.h
-@HAVE_LIBXML2_TRUE@am__append_3 = \
-@HAVE_LIBXML2_TRUE@ Libxml2Parser.cc \
-@HAVE_LIBXML2_TRUE@ Libxml2Parser.h
+@ENABLE_LIBXML2_TRUE@am__append_3 = \
+@ENABLE_LIBXML2_TRUE@ Libxml2Parser.cc \
+@ENABLE_LIBXML2_TRUE@ Libxml2Parser.h
subdir = src/esi
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -178,8 +178,8 @@
Include.cc Include.h Literal.h Module.cc Module.h Parser.cc \
Parser.h Segment.cc Segment.h Sequence.cc Sequence.h Var.h \
VarState.cc VarState.h
-@HAVE_LIBEXPAT_TRUE@am__objects_1 = ExpatParser.lo
-@HAVE_LIBXML2_TRUE@am__objects_2 = Libxml2Parser.lo
+@ENABLE_LIBEXPAT_TRUE@am__objects_1 = ExpatParser.lo
+@ENABLE_LIBXML2_TRUE@am__objects_2 = Libxml2Parser.lo
am__objects_3 = CustomParser.lo $(am__objects_1) $(am__objects_2)
am_libesi_la_OBJECTS = Assign.lo Context.lo $(am__objects_3) Esi.lo \
Expression.lo Include.lo Module.lo Parser.lo Segment.lo \
diff -u -r -N squid-4.0.10/src/fs/rock/RockIoState.cc squid-4.0.11/src/fs/rock/RockIoState.cc
--- squid-4.0.10/src/fs/rock/RockIoState.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/fs/rock/RockIoState.cc 2016-06-10 08:32:57.000000000 +1200
@@ -185,7 +185,7 @@
assert(!coreOff || coreOff == -1);
// throw if an accepted unknown-size entry grew too big or max-size changed
- Must(offset_ + size <= static_cast(dir->maxObjectSize()));
+ Must(static_cast(offset_ + size) <= static_cast(dir->maxObjectSize()));
// allocate the first slice during the first write
if (!coreOff) {
diff -u -r -N squid-4.0.10/src/fs/ufs/UFSStoreState.cc squid-4.0.11/src/fs/ufs/UFSStoreState.cc
--- squid-4.0.10/src/fs/ufs/UFSStoreState.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/fs/ufs/UFSStoreState.cc 2016-06-10 08:32:57.000000000 +1200
@@ -169,7 +169,7 @@
}
const Store::Disk &dir = *INDEXSD(swap_dirn);
- if (offset_ + size > static_cast(dir.maxObjectSize())) {
+ if (static_cast(offset_ + size) > static_cast(dir.maxObjectSize())) {
debugs(79, 2, "accepted unknown-size entry grew too big: " <<
(offset_ + size) << " > " << dir.maxObjectSize());
free_func((void*)buf);
diff -u -r -N squid-4.0.10/src/http/one/forward.h squid-4.0.11/src/http/one/forward.h
--- squid-4.0.10/src/http/one/forward.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/http/one/forward.h 2016-06-10 08:32:57.000000000 +1200
@@ -10,6 +10,7 @@
#define SQUID_SRC_HTTP_ONE_FORWARD_H
#include "base/RefCount.h"
+#include "sbuf/forward.h"
namespace Http {
namespace One {
@@ -27,6 +28,9 @@
class ResponseParser;
typedef RefCount ResponseParserPointer;
+/// CRLF textual representation
+const SBuf &CrLf();
+
} // namespace One
} // namespace Http
diff -u -r -N squid-4.0.10/src/http/one/Parser.cc squid-4.0.11/src/http/one/Parser.cc
--- squid-4.0.10/src/http/one/Parser.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/http/one/Parser.cc 2016-06-10 08:32:57.000000000 +1200
@@ -16,6 +16,12 @@
/// RFC 7230 section 2.6 - 7 magic octets
const SBuf Http::One::Parser::Http1magic("HTTP/1.");
+const SBuf &Http::One::CrLf()
+{
+ static const SBuf crlf("\r\n");
+ return crlf;
+}
+
void
Http::One::Parser::clear()
{
@@ -25,11 +31,34 @@
mimeHeaderBlock_.clear();
}
+/// characters HTTP permits tolerant parsers to accept as delimiters
+static const CharacterSet &
+RelaxedDelimiterCharacters()
+{
+ // RFC 7230 section 3.5
+ // tolerant parser MAY accept any of SP, HTAB, VT (%x0B), FF (%x0C),
+ // or bare CR as whitespace between request-line fields
+ static const CharacterSet RelaxedDels =
+ (CharacterSet::SP +
+ CharacterSet::HTAB +
+ CharacterSet("VT,FF","\x0B\x0C") +
+ CharacterSet::CR).rename("relaxed-WSP");
+
+ return RelaxedDels;
+}
+
+/// characters used to separate HTTP fields
+const CharacterSet &
+Http::One::Parser::DelimiterCharacters()
+{
+ return Config.onoff.relaxed_header_parser ?
+ RelaxedDelimiterCharacters() : CharacterSet::SP;
+}
+
bool
Http::One::Parser::skipLineTerminator(Http1::Tokenizer &tok) const
{
- static const SBuf crlf("\r\n");
- if (tok.skip(crlf))
+ if (tok.skip(Http1::CrLf()))
return true;
if (Config.onoff.relaxed_header_parser && tok.skipOne(CharacterSet::LF))
@@ -38,6 +67,88 @@
return false;
}
+/// all characters except the LF line terminator
+static const CharacterSet &
+LineCharacters()
+{
+ static const CharacterSet line = CharacterSet::LF.complement("non-LF");
+ return line;
+}
+
+/**
+ * Remove invalid lines (if any) from the mime prefix
+ *
+ * RFC 7230 section 3:
+ * "A recipient that receives whitespace between the start-line and
+ * the first header field MUST ... consume each whitespace-preceded
+ * line without further processing of it."
+ *
+ * We need to always use the relaxed delimiters here to prevent
+ * line smuggling through strict parsers.
+ *
+ * Note that 'whitespace' in RFC 7230 includes CR. So that means
+ * sequences of CRLF will be pruned, but not sequences of bare-LF.
+ */
+void
+Http::One::Parser::cleanMimePrefix()
+{
+ Http1::Tokenizer tok(mimeHeaderBlock_);
+ while (tok.skipOne(RelaxedDelimiterCharacters())) {
+ (void)tok.skipAll(LineCharacters()); // optional line content
+ // LF terminator is required.
+ // trust headersEnd() to ensure that we have at least one LF
+ (void)tok.skipOne(CharacterSet::LF);
+ }
+
+ // If mimeHeaderBlock_ had just whitespace line(s) followed by CRLF,
+ // then we skipped everything, including that terminating LF.
+ // Restore the terminating CRLF if needed.
+ if (tok.atEnd())
+ mimeHeaderBlock_ = Http1::CrLf();
+ else
+ mimeHeaderBlock_ = tok.remaining();
+ // now mimeHeaderBlock_ has 0+ fields followed by the LF terminator
+}
+
+/**
+ * Replace obs-fold with a single SP,
+ *
+ * RFC 7230 section 3.2.4
+ * "A server that receives an obs-fold in a request message that is not
+ * within a message/http container MUST ... replace
+ * each received obs-fold with one or more SP octets prior to
+ * interpreting the field value or forwarding the message downstream."
+ *
+ * "A proxy or gateway that receives an obs-fold in a response message
+ * that is not within a message/http container MUST ... replace each
+ * received obs-fold with one or more SP octets prior to interpreting
+ * the field value or forwarding the message downstream."
+ */
+void
+Http::One::Parser::unfoldMime()
+{
+ Http1::Tokenizer tok(mimeHeaderBlock_);
+ const auto szLimit = mimeHeaderBlock_.length();
+ mimeHeaderBlock_.clear();
+ // prevent the mime sender being able to make append() realloc/grow multiple times.
+ mimeHeaderBlock_.reserveSpace(szLimit);
+
+ static const CharacterSet nonCRLF = (CharacterSet::CR + CharacterSet::LF).complement().rename("non-CRLF");
+
+ while (!tok.atEnd()) {
+ const SBuf all(tok.remaining());
+ const auto blobLen = tok.skipAll(nonCRLF); // may not be there
+ const auto crLen = tok.skipAll(CharacterSet::CR); // may not be there
+ const auto lfLen = tok.skipOne(CharacterSet::LF); // may not be there
+
+ if (lfLen && tok.skipAll(CharacterSet::WSP)) { // obs-fold!
+ mimeHeaderBlock_.append(all.substr(0, blobLen));
+ mimeHeaderBlock_.append(' '); // replace one obs-fold with one SP
+ } else
+ mimeHeaderBlock_.append(all.substr(0, blobLen + crLen + lfLen));
+ }
+}
+
bool
Http::One::Parser::grabMimeBlock(const char *which, const size_t limit)
{
@@ -51,8 +162,8 @@
* So the rest of the code will need to deal with '0'-byte headers
* (ie, none, so don't try parsing em)
*/
- // XXX: c_str() reallocates. performance regression.
- if (SBuf::size_type mimeHeaderBytes = headersEnd(buf_.c_str(), buf_.length())) {
+ bool containsObsFold;
+ if (SBuf::size_type mimeHeaderBytes = headersEnd(buf_, containsObsFold)) {
// Squid could handle these headers, but admin does not want to
if (firstLineSize() + mimeHeaderBytes >= limit) {
@@ -64,6 +175,10 @@
}
mimeHeaderBlock_ = buf_.consume(mimeHeaderBytes);
+ cleanMimePrefix();
+ if (containsObsFold)
+ unfoldMime();
+
debugs(74, 5, "mime header (0-" << mimeHeaderBytes << ") {" << mimeHeaderBlock_ << "}");
} else { // headersEnd() == 0
@@ -102,12 +217,10 @@
debugs(25, 5, "looking for " << name);
// while we can find more LF in the SBuf
- static CharacterSet iso8859Line = CharacterSet("non-LF",'\0','\n'-1) + CharacterSet(NULL, '\n'+1, (unsigned char)0xFF);
Http1::Tokenizer tok(mimeHeaderBlock_);
SBuf p;
- static const SBuf crlf("\r\n");
- while (tok.prefix(p, iso8859Line)) {
+ while (tok.prefix(p, LineCharacters())) {
if (!tok.skipOne(CharacterSet::LF)) // move tokenizer past the LF
break; // error. reached invalid octet or end of buffer insted of an LF ??
@@ -120,7 +233,7 @@
continue;
// drop any trailing *CR sequence
- p.trim(crlf, false, true);
+ p.trim(Http1::CrLf(), false, true);
debugs(25, 5, "checking " << p);
p.consume(namelen + 1);
diff -u -r -N squid-4.0.10/src/http/one/Parser.h squid-4.0.11/src/http/one/Parser.h
--- squid-4.0.10/src/http/one/Parser.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/http/one/Parser.h 2016-06-10 08:32:57.000000000 +1200
@@ -111,6 +111,10 @@
/// consume from the tokenizer and return true only if found
bool skipLineTerminator(Http1::Tokenizer &tok) const;
+ /// the characters which are to be considered valid whitespace
+ /// (WSP / BSP / OWS)
+ static const CharacterSet &DelimiterCharacters();
+
/**
* Scan to find the mime headers block for current message.
*
@@ -139,6 +143,10 @@
/// Whether the invalid HTTP as HTTP/0.9 hack expects a mime header block
bool hackExpectsMime_;
+
+private:
+ void cleanMimePrefix();
+ void unfoldMime();
};
} // namespace One
diff -u -r -N squid-4.0.10/src/http/one/RequestParser.cc squid-4.0.11/src/http/one/RequestParser.cc
--- squid-4.0.10/src/http/one/RequestParser.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/http/one/RequestParser.cc 2016-06-10 08:32:57.000000000 +1200
@@ -114,30 +114,6 @@
return UriChars;
}
-/// characters HTTP permits tolerant parsers to accept as delimiters
-static const CharacterSet &
-RelaxedDelimiterCharacters()
-{
- // RFC 7230 section 3.5
- // tolerant parser MAY accept any of SP, HTAB, VT (%x0B), FF (%x0C),
- // or bare CR as whitespace between request-line fields
- static const CharacterSet RelaxedDels =
- CharacterSet::SP +
- CharacterSet::HTAB +
- CharacterSet("VT,FF","\x0B\x0C") +
- CharacterSet::CR;
-
- return RelaxedDels;
-}
-
-/// characters used to separate HTTP fields
-const CharacterSet &
-Http::One::RequestParser::DelimiterCharacters()
-{
- return Config.onoff.relaxed_header_parser ?
- RelaxedDelimiterCharacters() : CharacterSet::SP;
-}
-
/// characters which Squid will accept in the HTTP request-target (URI)
const CharacterSet &
Http::One::RequestParser::RequestTargetCharacters()
diff -u -r -N squid-4.0.10/src/http/one/RequestParser.h squid-4.0.11/src/http/one/RequestParser.h
--- squid-4.0.10/src/http/one/RequestParser.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/http/one/RequestParser.h 2016-06-10 08:32:57.000000000 +1200
@@ -56,7 +56,6 @@
bool skipTrailingCrs(Http1::Tokenizer &tok);
bool http0() const {return !msgProtocol_.major;}
- static const CharacterSet &DelimiterCharacters();
static const CharacterSet &RequestTargetCharacters();
/// what request method has been found on the first line
diff -u -r -N squid-4.0.10/src/http/one/TeChunkedParser.cc squid-4.0.11/src/http/one/TeChunkedParser.cc
--- squid-4.0.10/src/http/one/TeChunkedParser.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/http/one/TeChunkedParser.cc 2016-06-10 08:32:57.000000000 +1200
@@ -117,6 +117,11 @@
bool
Http::One::TeChunkedParser::parseChunkExtension(Http1::Tokenizer &tok, bool skipKnown)
{
+ // Bug 4492: IBM_HTTP_Server sends SP padding
+ if (auto n = tok.skipAll(CharacterSet::SP)) {
+ debugs(94, 3, "skipping " << n << " spurious whitespace at start of chunk extension");
+ }
+
SBuf ext;
SBuf value;
while (tok.skip(';') && tok.prefix(ext, CharacterSet::TCHAR)) {
diff -u -r -N squid-4.0.10/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.0.11/src/http/url_rewriters/LFS/url_lfs_rewrite.8
--- squid-4.0.10/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2016-05-07 00:32:14.000000000 +1200
+++ squid-4.0.11/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2016-06-10 09:29:43.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "URL_LFS_REWRITE 8"
-.TH URL_LFS_REWRITE 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH URL_LFS_REWRITE 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/HttpHeader.cc squid-4.0.11/src/HttpHeader.cc
--- squid-4.0.10/src/HttpHeader.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/HttpHeader.cc 2016-06-10 08:32:57.000000000 +1200
@@ -595,21 +595,17 @@
{
debugs(55, 8, this << " del-by-id " << id);
assert(any_registered_header(id));
- int count=0;
if (!CBIT_TEST(mask, id))
return 0;
- //replace matching items with nil and count them
- std::replace_if(entries.begin(), entries.end(),
- [&](const HttpHeaderEntry *e) {
- if (e && e->id == id) {
- ++count;
- return true;
- }
- return false;
- },
- nullptr);
+ int count = 0;
+
+ HttpHeaderPos pos = HttpHeaderInitPos;
+ while (HttpHeaderEntry *e = getEntry(&pos)) {
+ if (e->id == id)
+ delAt(pos, count); // deletes e
+ }
CBIT_CLR(mask, id);
assert(count);
diff -u -r -N squid-4.0.10/src/log/DB/log_db_daemon.8 squid-4.0.11/src/log/DB/log_db_daemon.8
--- squid-4.0.10/src/log/DB/log_db_daemon.8 2016-05-07 00:32:23.000000000 +1200
+++ squid-4.0.11/src/log/DB/log_db_daemon.8 2016-06-10 09:29:50.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "LOG_DB_DAEMON 8"
-.TH LOG_DB_DAEMON 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH LOG_DB_DAEMON 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/LogTags.cc squid-4.0.11/src/LogTags.cc
--- squid-4.0.10/src/LogTags.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/LogTags.cc 2016-06-10 08:32:57.000000000 +1200
@@ -18,6 +18,7 @@
"TCP_REFRESH_FAIL_OLD",
"TCP_REFRESH_FAIL_ERR",
"TCP_REFRESH_MODIFIED",
+ "TCP_REFRESH",
"TCP_CLIENT_REFRESH_MISS",
"TCP_IMS_HIT",
"TCP_SWAPFAIL_MISS",
diff -u -r -N squid-4.0.10/src/LogTags.h squid-4.0.11/src/LogTags.h
--- squid-4.0.10/src/LogTags.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/LogTags.h 2016-06-10 08:32:57.000000000 +1200
@@ -25,6 +25,7 @@
LOG_TCP_REFRESH_FAIL_OLD, // refresh from origin failed, stale reply sent
LOG_TCP_REFRESH_FAIL_ERR, // refresh from origin failed, error forwarded
LOG_TCP_REFRESH_MODIFIED, // refresh from origin replaced existing entry
+ LOG_TCP_REFRESH, // refresh from origin started, but still pending
LOG_TCP_CLIENT_REFRESH_MISS,
LOG_TCP_IMS_HIT,
LOG_TCP_SWAPFAIL_MISS,
diff -u -r -N squid-4.0.10/src/Makefile.am squid-4.0.11/src/Makefile.am
--- squid-4.0.10/src/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -66,16 +66,16 @@
SUBDIRS += snmp
SNMP_LIBS = snmp/libsnmp.la $(SNMPLIB)
else
-SNMP_SOURCE =
+SNMP_SOURCE =
endif
DIST_SUBDIRS += snmp
-if USE_ADAPTATION
+if ENABLE_ADAPTATION
SUBDIRS += adaptation
endif
DIST_SUBDIRS += adaptation
-if USE_ESI
+if ENABLE_ESI
SUBDIRS += esi
ESI_LIBS = \
esi/libesi.la \
@@ -113,27 +113,27 @@
NullDelayId.h \
ClientDelayConfig.cc \
ClientDelayConfig.h
-
+
if ENABLE_DELAY_POOLS
DELAY_POOL_SOURCE = $(DELAY_POOL_ALL_SOURCE)
else
-DELAY_POOL_SOURCE =
+DELAY_POOL_SOURCE =
endif
if ENABLE_XPROF_STATS
XPROF_STATS_SOURCE = ProfStats.cc
else
-XPROF_STATS_SOURCE =
+XPROF_STATS_SOURCE =
endif
if ENABLE_HTCP
HTCPSOURCE = htcp.cc htcp.h
endif
-if MAKE_LEAKFINDER
+if ENABLE_LEAKFINDER
LEAKFINDERSOURCE = LeakFinder.cc
else
-LEAKFINDERSOURCE =
+LEAKFINDERSOURCE =
endif
if ENABLE_UNLINKD
@@ -141,7 +141,7 @@
UNLINKD = unlinkd
else
UNLINKDSOURCE = unlinkd.h
-UNLINKD =
+UNLINKD =
endif
WIN32_ALL_SOURCE = \
@@ -181,8 +181,7 @@
sbin_PROGRAMS = \
squid
-bin_PROGRAMS =
-
+bin_PROGRAMS =
libexec_PROGRAMS = \
$(UNLINKD)
@@ -539,7 +538,6 @@
ftp/libftp.la \
helper/libhelper.la \
http/libhttp.la \
- parser/libparser.la \
dns/libdns.la \
base/libbase.la \
libsquid.la \
@@ -552,6 +550,7 @@
anyp/libanyp.la \
comm/libcomm.la \
security/libsecurity.la \
+ parser/libparser.la \
eui/libeui.la \
icmp/libicmp.la \
log/liblog.la \
@@ -888,10 +887,10 @@
tests/testLookupTable \
tests/testYesNoNone
-if HAVE_FS_ROCK
+if ENABLE_FS_ROCK
check_PROGRAMS += tests/testRock
endif
-if HAVE_FS_UFS
+if ENABLE_FS_UFS
check_PROGRAMS += tests/testUfs
endif
diff -u -r -N squid-4.0.10/src/Makefile.in squid-4.0.11/src/Makefile.in
--- squid-4.0.10/src/Makefile.in 2016-05-06 23:36:31.000000000 +1200
+++ squid-4.0.11/src/Makefile.in 2016-06-10 08:34:30.000000000 +1200
@@ -114,8 +114,8 @@
@ENABLE_SSL_TRUE@ ssl/libsslutil.la
@ENABLE_SNMP_TRUE@am__append_6 = snmp
-@USE_ADAPTATION_TRUE@am__append_7 = adaptation
-@USE_ESI_TRUE@am__append_8 = esi
+@ENABLE_ADAPTATION_TRUE@am__append_7 = adaptation
+@ENABLE_ESI_TRUE@am__append_8 = esi
EXTRA_PROGRAMS = unlinkd$(EXEEXT) recv-announce$(EXEEXT) \
tests/testUfs$(EXEEXT) tests/testRock$(EXEEXT) \
ufsdump$(EXEEXT)
@@ -126,8 +126,8 @@
@ENABLE_LOADABLE_MODULES_TRUE@am__append_9 = $(LOADABLE_MODULES_SOURCES)
@ENABLE_LOADABLE_MODULES_TRUE@am__append_10 = -L$(top_builddir) $(LIBLTDL)
@ENABLE_LOADABLE_MODULES_TRUE@am__append_11 = $(INCLTDL)
-@HAVE_FS_ROCK_TRUE@am__append_12 = tests/testRock
-@HAVE_FS_UFS_TRUE@am__append_13 = tests/testUfs
+@ENABLE_FS_ROCK_TRUE@am__append_12 = tests/testRock
+@ENABLE_FS_UFS_TRUE@am__append_13 = tests/testUfs
subdir = src
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude/ax_with_prog.m4 \
@@ -213,8 +213,8 @@
"$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man8dir)" \
"$(DESTDIR)$(datadir)" "$(DESTDIR)$(sysconfdir)"
@ENABLE_AUTH_TRUE@am__EXEEXT_1 = tests/testACLMaxUserIP$(EXEEXT)
-@HAVE_FS_ROCK_TRUE@am__EXEEXT_2 = tests/testRock$(EXEEXT)
-@HAVE_FS_UFS_TRUE@am__EXEEXT_3 = tests/testUfs$(EXEEXT)
+@ENABLE_FS_ROCK_TRUE@am__EXEEXT_2 = tests/testRock$(EXEEXT)
+@ENABLE_FS_UFS_TRUE@am__EXEEXT_3 = tests/testUfs$(EXEEXT)
@ENABLE_UNLINKD_TRUE@am__EXEEXT_4 = unlinkd$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(noinst_PROGRAMS) \
$(sbin_PROGRAMS)
@@ -322,7 +322,7 @@
@ENABLE_HTCP_TRUE@am__objects_5 = htcp.$(OBJEXT)
@ENABLE_WIN32_IPC_FALSE@am__objects_6 = ipc.$(OBJEXT)
@ENABLE_WIN32_IPC_TRUE@am__objects_6 = ipc_win32.$(OBJEXT)
-@MAKE_LEAKFINDER_TRUE@am__objects_7 = LeakFinder.$(OBJEXT)
+@ENABLE_LEAKFINDER_TRUE@am__objects_7 = LeakFinder.$(OBJEXT)
@ENABLE_XPROF_STATS_TRUE@am__objects_8 = ProfStats.$(OBJEXT)
am__objects_9 = snmp_core.$(OBJEXT) snmp_agent.$(OBJEXT)
@ENABLE_SNMP_TRUE@am__objects_10 = $(am__objects_9)
@@ -404,9 +404,9 @@
swap_log_op.$(OBJEXT)
nodist_squid_OBJECTS = $(am__objects_17)
squid_OBJECTS = $(am_squid_OBJECTS) $(nodist_squid_OBJECTS)
-@USE_ESI_TRUE@am__DEPENDENCIES_4 = esi/libesi.la \
-@USE_ESI_TRUE@ $(top_builddir)/lib/libTrie/libTrie.a \
-@USE_ESI_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+@ENABLE_ESI_TRUE@am__DEPENDENCIES_4 = esi/libesi.la \
+@ENABLE_ESI_TRUE@ $(top_builddir)/lib/libTrie/libTrie.a \
+@ENABLE_ESI_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
@ENABLE_SNMP_TRUE@am__DEPENDENCIES_5 = snmp/libsnmp.la \
@ENABLE_SNMP_TRUE@ $(am__DEPENDENCIES_1)
@ENABLE_LOADABLE_MODULES_TRUE@am__DEPENDENCIES_6 = \
@@ -414,11 +414,11 @@
squid_DEPENDENCIES = $(AUTH_ACL_LIBS) ident/libident.la acl/libacls.la \
acl/libstate.la $(AUTH_LIBS) acl/libapi.la \
clients/libclients.la servers/libservers.la ftp/libftp.la \
- helper/libhelper.la http/libhttp.la parser/libparser.la \
- dns/libdns.la base/libbase.la libsquid.la ip/libip.la \
- fs/libfs.la DiskIO/libdiskio.la $(SSL_LIBS) ipc/libipc.la \
- mgr/libmgr.la anyp/libanyp.la comm/libcomm.la \
- security/libsecurity.la eui/libeui.la icmp/libicmp.la \
+ helper/libhelper.la http/libhttp.la dns/libdns.la \
+ base/libbase.la libsquid.la ip/libip.la fs/libfs.la \
+ DiskIO/libdiskio.la $(SSL_LIBS) ipc/libipc.la mgr/libmgr.la \
+ anyp/libanyp.la comm/libcomm.la security/libsecurity.la \
+ parser/libparser.la eui/libeui.la icmp/libicmp.la \
log/liblog.la format/libformat.la sbuf/libsbuf.la \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
@@ -2766,12 +2766,12 @@
@ENABLE_SNMP_FALSE@SNMP_SOURCE =
@ENABLE_SNMP_TRUE@SNMP_SOURCE = $(SNMP_ALL_SOURCE)
@ENABLE_SNMP_TRUE@SNMP_LIBS = snmp/libsnmp.la $(SNMPLIB)
-@USE_ESI_FALSE@ESI_LIBS =
-@USE_ESI_TRUE@ESI_LIBS = \
-@USE_ESI_TRUE@ esi/libesi.la \
-@USE_ESI_TRUE@ $(top_builddir)/lib/libTrie/libTrie.a \
-@USE_ESI_TRUE@ $(XMLLIB) \
-@USE_ESI_TRUE@ $(EXPATLIB)
+@ENABLE_ESI_FALSE@ESI_LIBS =
+@ENABLE_ESI_TRUE@ESI_LIBS = \
+@ENABLE_ESI_TRUE@ esi/libesi.la \
+@ENABLE_ESI_TRUE@ $(top_builddir)/lib/libTrie/libTrie.a \
+@ENABLE_ESI_TRUE@ $(XMLLIB) \
+@ENABLE_ESI_TRUE@ $(EXPATLIB)
DELAY_POOL_ALL_SOURCE = \
CommonPool.h \
@@ -2805,8 +2805,8 @@
@ENABLE_XPROF_STATS_FALSE@XPROF_STATS_SOURCE =
@ENABLE_XPROF_STATS_TRUE@XPROF_STATS_SOURCE = ProfStats.cc
@ENABLE_HTCP_TRUE@HTCPSOURCE = htcp.cc htcp.h
-@MAKE_LEAKFINDER_FALSE@LEAKFINDERSOURCE =
-@MAKE_LEAKFINDER_TRUE@LEAKFINDERSOURCE = LeakFinder.cc
+@ENABLE_LEAKFINDER_FALSE@LEAKFINDERSOURCE =
+@ENABLE_LEAKFINDER_TRUE@LEAKFINDERSOURCE = LeakFinder.cc
@ENABLE_UNLINKD_FALSE@UNLINKDSOURCE = unlinkd.h
@ENABLE_UNLINKD_TRUE@UNLINKDSOURCE = unlinkd.h unlinkd.cc
@ENABLE_UNLINKD_FALSE@UNLINKD =
@@ -2950,11 +2950,11 @@
squid_LDADD = $(AUTH_ACL_LIBS) ident/libident.la acl/libacls.la \
acl/libstate.la $(AUTH_LIBS) acl/libapi.la \
clients/libclients.la servers/libservers.la ftp/libftp.la \
- helper/libhelper.la http/libhttp.la parser/libparser.la \
- dns/libdns.la base/libbase.la libsquid.la ip/libip.la \
- fs/libfs.la DiskIO/libdiskio.la $(SSL_LIBS) ipc/libipc.la \
- mgr/libmgr.la anyp/libanyp.la comm/libcomm.la \
- security/libsecurity.la eui/libeui.la icmp/libicmp.la \
+ helper/libhelper.la http/libhttp.la dns/libdns.la \
+ base/libbase.la libsquid.la ip/libip.la fs/libfs.la \
+ DiskIO/libdiskio.la $(SSL_LIBS) ipc/libipc.la mgr/libmgr.la \
+ anyp/libanyp.la comm/libcomm.la security/libsecurity.la \
+ parser/libparser.la eui/libeui.la icmp/libicmp.la \
log/liblog.la format/libformat.la sbuf/libsbuf.la $(XTRA_OBJS) \
$(REPL_OBJS) $(NETTLELIB) $(CRYPTLIB) $(REGEXLIB) \
$(ADAPTATION_LIBS) $(ESI_LIBS) $(SNMP_LIBS) mem/libmem.la \
diff -u -r -N squid-4.0.10/src/mime.cc squid-4.0.11/src/mime.cc
--- squid-4.0.10/src/mime.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/mime.cc 2016-06-10 08:32:57.000000000 +1200
@@ -24,6 +24,8 @@
#include "Store.h"
#include "StoreClient.h"
+#include
+
#if HAVE_SYS_STAT_H
#include
#endif
@@ -422,12 +424,11 @@
if (status == Http::scOkay) {
/* read the file into the buffer and append it to store */
int n;
- char *buf = (char *)memAllocate(MEM_4K_BUF);
- while ((n = FD_READ_METHOD(fd, buf, sizeof(*buf))) > 0)
- e->append(buf, n);
+ std::array buf;
+ while ((n = FD_READ_METHOD(fd, buf.data(), buf.size())) > 0)
+ e->append(buf.data(), n);
file_close(fd);
- memFree(buf, MEM_4K_BUF);
}
e->flush();
diff -u -r -N squid-4.0.10/src/mime_header.cc squid-4.0.11/src/mime_header.cc
--- squid-4.0.10/src/mime_header.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/mime_header.cc 2016-06-10 08:32:57.000000000 +1200
@@ -13,10 +13,11 @@
#include "profiler/Profiler.h"
size_t
-headersEnd(const char *mime, size_t l)
+headersEnd(const char *mime, size_t l, bool &containsObsFold)
{
size_t e = 0;
int state = 1;
+ containsObsFold = false;
PROF_start(headersEnd);
@@ -35,7 +36,10 @@
state = 2;
else if ('\n' == mime[e])
state = 3;
- else
+ else if (' ' == mime[e] || '\t' == mime[e]) {
+ containsObsFold = true;
+ state = 0;
+ } else
state = 0;
break;
diff -u -r -N squid-4.0.10/src/mime_header.h squid-4.0.11/src/mime_header.h
--- squid-4.0.10/src/mime_header.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/mime_header.h 2016-06-10 08:32:57.000000000 +1200
@@ -11,7 +11,35 @@
#ifndef SQUID_MIME_HEADER_H_
#define SQUID_MIME_HEADER_H_
-size_t headersEnd(const char *, size_t);
+/**
+ * Scan for the end of mime header block.
+ *
+ * Which is one of the following octet patterns:
+ * - CRLF CRLF, or
+ * - CRLF LF, or
+ * - LF CRLF, or
+ * - LF LF
+ *
+ * Also detects whether a obf-fold pattern exists within the mime block
+ * - CR*LF (SP / HTAB)
+ *
+ * \param containsObsFold will be set to true if obs-fold pattern is found.
+ */
+size_t headersEnd(const char *, size_t, bool &containsObsFold);
+
+inline size_t
+headersEnd(const SBuf &buf, bool &containsObsFold)
+{
+ return headersEnd(buf.rawContent(), buf.length(), containsObsFold);
+}
+
+/// \deprecated caller needs to be fixed to handle obs-fold
+inline size_t
+headersEnd(const char *buf, size_t sz)
+{
+ bool ignored;
+ return headersEnd(buf, sz, ignored);
+}
#endif /* SQUID_MIME_HEADER_H_ */
diff -u -r -N squid-4.0.10/src/parser/BinaryTokenizer.cc squid-4.0.11/src/parser/BinaryTokenizer.cc
--- squid-4.0.10/src/parser/BinaryTokenizer.cc 1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.11/src/parser/BinaryTokenizer.cc 2016-06-10 08:32:57.000000000 +1200
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+/* DEBUG: section 24 SBuf */
+
+#include "squid.h"
+#include "parser/BinaryTokenizer.h"
+
+Parser::BinaryTokenizer::BinaryTokenizer(): BinaryTokenizer(SBuf())
+{
+}
+
+Parser::BinaryTokenizer::BinaryTokenizer(const SBuf &data, const bool expectMore):
+ context(nullptr),
+ data_(data),
+ parsed_(0),
+ syncPoint_(0),
+ expectMore_(expectMore)
+{
+}
+
+static inline
+std::ostream &
+operator <<(std::ostream &os, const Parser::BinaryTokenizerContext *context)
+{
+ if (context)
+ os << context->parent << context->name;
+ return os;
+}
+
+/// debugging helper that prints a "standard" debugs() trailer
+#define BinaryTokenizer_tail(size, start) \
+ " occupying " << (size) << " bytes @" << (start) << " in " << this << \
+ (expectMore_ ? ';' : '.');
+
+/// logs and throws if fewer than size octets remain; no other side effects
+void
+Parser::BinaryTokenizer::want(uint64_t size, const char *description) const
+{
+ if (parsed_ + size > data_.length()) {
+ debugs(24, 5, (parsed_ + size - data_.length()) << " more bytes for " <<
+ context << description << BinaryTokenizer_tail(size, parsed_));
+ Must(expectMore_); // throw an error on premature input termination
+ throw InsufficientInput();
+ }
+}
+
+void
+Parser::BinaryTokenizer::got(uint64_t size, const char *description) const
+{
+ debugs(24, 7, context << description <<
+ BinaryTokenizer_tail(size, parsed_ - size));
+}
+
+/// debugging helper for parsed number fields
+void
+Parser::BinaryTokenizer::got(uint32_t value, uint64_t size, const char *description) const
+{
+ debugs(24, 7, context << description << '=' << value <<
+ BinaryTokenizer_tail(size, parsed_ - size));
+}
+
+/// debugging helper for parsed areas/blobs
+void
+Parser::BinaryTokenizer::got(const SBuf &value, uint64_t size, const char *description) const
+{
+ debugs(24, 7, context << description << '=' <<
+ Raw(nullptr, value.rawContent(), value.length()).hex() <<
+ BinaryTokenizer_tail(size, parsed_ - size));
+
+}
+
+/// debugging helper for skipped fields
+void
+Parser::BinaryTokenizer::skipped(uint64_t size, const char *description) const
+{
+ debugs(24, 7, context << description << BinaryTokenizer_tail(size, parsed_ - size));
+
+}
+
+/// Returns the next ready-for-shift byte, adjusting the number of parsed bytes.
+/// The larger 32-bit return type helps callers shift/merge octets into numbers.
+/// This internal method does not perform out-of-bounds checks.
+uint32_t
+Parser::BinaryTokenizer::octet()
+{
+ // While char may be signed, we view data characters as unsigned,
+ // which helps to arrive at the right 32-bit return value.
+ return static_cast(data_[parsed_++]);
+}
+
+void
+Parser::BinaryTokenizer::reset(const SBuf &data, const bool expectMore)
+{
+ *this = BinaryTokenizer(data, expectMore);
+}
+
+void
+Parser::BinaryTokenizer::rollback()
+{
+ parsed_ = syncPoint_;
+}
+
+void
+Parser::BinaryTokenizer::commit()
+{
+ syncPoint_ = parsed_;
+}
+
+bool
+Parser::BinaryTokenizer::atEnd() const
+{
+ return parsed_ >= data_.length();
+}
+
+uint8_t
+Parser::BinaryTokenizer::uint8(const char *description)
+{
+ want(1, description);
+ const uint8_t result = octet();
+ got(result, 1, description);
+ return result;
+}
+
+uint16_t
+Parser::BinaryTokenizer::uint16(const char *description)
+{
+ want(2, description);
+ const uint16_t result = (octet() << 8) | octet();
+ got(result, 2, description);
+ return result;
+}
+
+uint32_t
+Parser::BinaryTokenizer::uint24(const char *description)
+{
+ want(3, description);
+ const uint32_t result = (octet() << 16) | (octet() << 8) | octet();
+ got(result, 3, description);
+ return result;
+}
+
+uint32_t
+Parser::BinaryTokenizer::uint32(const char *description)
+{
+ want(4, description);
+ const uint32_t result = (octet() << 24) | (octet() << 16) | (octet() << 8) | octet();
+ got(result, 4, description);
+ return result;
+}
+
+SBuf
+Parser::BinaryTokenizer::area(uint64_t size, const char *description)
+{
+ want(size, description);
+ const SBuf result = data_.substr(parsed_, size);
+ parsed_ += size;
+ got(result, size, description);
+ return result;
+}
+
+void
+Parser::BinaryTokenizer::skip(uint64_t size, const char *description)
+{
+ want(size, description);
+ parsed_ += size;
+ skipped(size, description);
+}
+
+/*
+ * BinaryTokenizer::pstringN() implementations below reduce debugging noise by
+ * not parsing empty areas and not summarizing parsing context.success().
+ */
+
+SBuf
+Parser::BinaryTokenizer::pstring8(const char *description)
+{
+ BinaryTokenizerContext pstring(*this, description);
+ if (const uint8_t length = uint8(".length"))
+ return area(length, ".octets");
+ return SBuf();
+}
+
+SBuf
+Parser::BinaryTokenizer::pstring16(const char *description)
+{
+ BinaryTokenizerContext pstring(*this, description);
+ if (const uint16_t length = uint16(".length"))
+ return area(length, ".octets");
+ return SBuf();
+}
+
+SBuf
+Parser::BinaryTokenizer::pstring24(const char *description)
+{
+ BinaryTokenizerContext pstring(*this, description);
+ if (const uint32_t length = uint24(".length"))
+ return area(length, ".octets");
+ return SBuf();
+}
+
diff -u -r -N squid-4.0.10/src/parser/BinaryTokenizer.h squid-4.0.11/src/parser/BinaryTokenizer.h
--- squid-4.0.10/src/parser/BinaryTokenizer.h 1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.11/src/parser/BinaryTokenizer.h 2016-06-10 08:32:57.000000000 +1200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SRC_PARSER_BINARYTOKENIZER_H
+#define SQUID_SRC_PARSER_BINARYTOKENIZER_H
+
+#include "sbuf/SBuf.h"
+
+namespace Parser
+{
+
+class BinaryTokenizer;
+
+/// enables efficient debugging with concise field names: Hello.version.major
+class BinaryTokenizerContext
+{
+public:
+ /// starts parsing named object
+ explicit BinaryTokenizerContext(BinaryTokenizer &tk, const char *aName);
+ ~BinaryTokenizerContext() { close(); }
+
+ /// ends parsing named object; repeated calls OK
+ inline void close();
+
+ /// reports successful parsing of a named object and calls close()
+ inline void success();
+
+ BinaryTokenizer &tokenizer; ///< tokenizer being used for parsing
+ const BinaryTokenizerContext * const parent; ///< enclosing context or nullptr
+ const char *const name; ///< this context description or nullptr
+ uint64_t start; ///< context parsing begins at this tokenizer position
+};
+
+/// Safely extracts byte-oriented (i.e., non-textual) fields from raw input.
+/// Assume that the integers are stored in network byte order.
+/// Supports commit points for atomic incremental parsing of multi-part fields.
+/// Throws InsufficientInput when more input is needed to parse the next field.
+/// Throws on errors.
+class BinaryTokenizer
+{
+public:
+ class InsufficientInput {}; // thrown when a method runs out of data
+ typedef uint64_t size_type; // enough for the largest supported offset
+
+ BinaryTokenizer();
+ explicit BinaryTokenizer(const SBuf &data, const bool expectMore = false);
+
+ /// restart parsing from the very beginning
+ /// this method is for using one BinaryTokenizer to parse independent inputs
+ void reset(const SBuf &data, const bool expectMore);
+
+ /// change input state without changing parsing state
+ /// this method avoids append overheads during incremental parsing
+ void reinput(const SBuf &data, const bool expectMore) { data_ = data; expectMore_ = expectMore; }
+
+ /// make progress: future parsing failures will not rollback beyond this point
+ void commit();
+
+ /// resume [incremental] parsing from the last commit point
+ void rollback();
+
+ /// no more bytes to parse or skip
+ bool atEnd() const;
+
+ /// parse a single-byte unsigned integer
+ uint8_t uint8(const char *description);
+
+ /// parse a two-byte unsigned integer
+ uint16_t uint16(const char *description);
+
+ /// parse a three-byte unsigned integer (returned as uint32_t)
+ uint32_t uint24(const char *description);
+
+ /// parse a four-byte unsigned integer
+ uint32_t uint32(const char *description);
+
+ /// parse size consecutive bytes as an opaque blob
+ SBuf area(uint64_t size, const char *description);
+
+ /*
+ * Variable-length arrays (a.k.a. Pascal or prefix strings).
+ * pstringN() extracts and returns N-bit length followed by length bytes
+ */
+ SBuf pstring8(const char *description); ///< up to 255 byte-long p-string
+ SBuf pstring16(const char *description); ///< up to 64 KiB-long p-string
+ SBuf pstring24(const char *description); ///< up to 16 MiB-long p-string!
+
+ /// ignore the next size bytes
+ void skip(uint64_t size, const char *description);
+
+ /// the number of already parsed bytes
+ uint64_t parsed() const { return parsed_; }
+
+ /// yet unparsed bytes
+ SBuf leftovers() const { return data_.substr(parsed_); }
+
+ /// debugging helper for parsed multi-field structures
+ void got(uint64_t size, const char *description) const;
+
+ const BinaryTokenizerContext *context; ///< debugging: thing being parsed
+
+protected:
+ uint32_t octet();
+ void want(uint64_t size, const char *description) const;
+ void got(uint32_t value, uint64_t size, const char *description) const;
+ void got(const SBuf &value, uint64_t size, const char *description) const;
+ void skipped(uint64_t size, const char *description) const;
+
+private:
+ SBuf data_;
+ uint64_t parsed_; ///< number of data bytes parsed or skipped
+ uint64_t syncPoint_; ///< where to re-start the next parsing attempt
+ bool expectMore_; ///< whether more data bytes may arrive in the future
+};
+
+/* BinaryTokenizerContext */
+
+inline
+BinaryTokenizerContext::BinaryTokenizerContext(BinaryTokenizer &tk, const char *aName):
+ tokenizer(tk),
+ parent(tk.context),
+ name(aName),
+ start(tk.parsed())
+{
+ tk.context = this;
+}
+
+inline
+void
+BinaryTokenizerContext::close() {
+ tokenizer.context = parent;
+}
+
+inline
+void
+BinaryTokenizerContext::success() {
+ tokenizer.got(tokenizer.parsed() - start, "");
+ close();
+}
+
+} /* namespace Parser */
+
+#endif // SQUID_SRC_PARSER_BINARYTOKENIZER_H
+
diff -u -r -N squid-4.0.10/src/parser/Makefile.am squid-4.0.11/src/parser/Makefile.am
--- squid-4.0.10/src/parser/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/parser/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -11,6 +11,8 @@
noinst_LTLIBRARIES = libparser.la
libparser_la_SOURCES = \
+ BinaryTokenizer.h \
+ BinaryTokenizer.cc \
Tokenizer.h \
Tokenizer.cc
diff -u -r -N squid-4.0.10/src/parser/Makefile.in squid-4.0.11/src/parser/Makefile.in
--- squid-4.0.10/src/parser/Makefile.in 2016-05-06 23:37:05.000000000 +1200
+++ squid-4.0.11/src/parser/Makefile.in 2016-06-10 08:35:03.000000000 +1200
@@ -163,7 +163,7 @@
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libparser_la_LIBADD =
-am_libparser_la_OBJECTS = Tokenizer.lo
+am_libparser_la_OBJECTS = BinaryTokenizer.lo Tokenizer.lo
libparser_la_OBJECTS = $(am_libparser_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -718,6 +718,8 @@
subst_perlshell = sed -e 's,[@]PERL[@],$(PERL),g' <$(srcdir)/$@.pl.in >$@ || ($(RM) -f $@ ; exit 1)
noinst_LTLIBRARIES = libparser.la
libparser_la_SOURCES = \
+ BinaryTokenizer.h \
+ BinaryTokenizer.cc \
Tokenizer.h \
Tokenizer.cc
@@ -785,6 +787,7 @@
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BinaryTokenizer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Tokenizer.Plo@am__quote@
.cc.o:
diff -u -r -N squid-4.0.10/src/parser/Tokenizer.cc squid-4.0.11/src/parser/Tokenizer.cc
--- squid-4.0.10/src/parser/Tokenizer.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/parser/Tokenizer.cc 2016-06-10 08:32:57.000000000 +1200
@@ -227,7 +227,7 @@
}
if (s >= end) return false;
}
- if (( base == 0 || base == 16) && *s == '0' && (s+1 <= end ) &&
+ if (( base == 0 || base == 16) && *s == '0' && (s+1 < end ) &&
tolower(*(s+1)) == 'x') {
s += 2;
base = 16;
@@ -250,7 +250,8 @@
int any = 0, c;
int64_t acc = 0;
- for (c = *s++; s <= end; c = *s++) {
+ do {
+ c = *s;
if (xisdigit(c)) {
c -= '0';
} else if (xisalpha(c)) {
@@ -267,7 +268,7 @@
acc *= base;
acc += c;
}
- }
+ } while (++s < end);
if (any == 0) // nothing was parsed
return false;
@@ -279,6 +280,6 @@
acc = -acc;
result = acc;
- return success(s - range.rawContent() - 1);
+ return success(s - range.rawContent());
}
diff -u -r -N squid-4.0.10/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.0.11/src/security/cert_validators/fake/security_fake_certverify.8
--- squid-4.0.10/src/security/cert_validators/fake/security_fake_certverify.8 2016-05-07 00:32:44.000000000 +1200
+++ squid-4.0.11/src/security/cert_validators/fake/security_fake_certverify.8 2016-06-10 09:30:03.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "SECURITY_FAKE_CERTVERIFY 8"
-.TH SECURITY_FAKE_CERTVERIFY 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH SECURITY_FAKE_CERTVERIFY 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/security/Handshake.cc squid-4.0.11/src/security/Handshake.cc
--- squid-4.0.10/src/security/Handshake.cc 1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.11/src/security/Handshake.cc 2016-06-10 08:32:57.000000000 +1200
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+/* DEBUG: section 83 SSL-Bump Server/Peer negotiation */
+
+#include "squid.h"
+#include "security/Handshake.h"
+#if USE_OPENSSL
+#include "ssl/support.h"
+#endif
+
+#include
+
+namespace Security {
+/*
+ * The types below represent various SSL and TLS protocol elements. Most names
+ * are based on RFC 5264 and RFC 6066 terminology. Objects of these explicit
+ * types are stored or passed around. Other protocol elements are simply parsed
+ * in-place, without declaring a corresponding explicit class.
+ */
+
+/// TLS Record Layer's content types from RFC 5246 Section 6.2.1
+enum ContentType {
+ ctChangeCipherSpec = 20,
+ ctAlert = 21,
+ ctHandshake = 22,
+ ctApplicationData = 23
+};
+
+/// TLS Record Layer's frame from RFC 5246 Section 6.2.1.
+class TLSPlaintext
+{
+public:
+ explicit TLSPlaintext(Parser::BinaryTokenizer &tk);
+
+ uint8_t type; ///< see ContentType
+ AnyP::ProtocolVersion version; ///< Record Layer, not necessarily the negotiated TLS version;
+ SBuf fragment; ///< possibly partial content
+};
+
+/// draft-hickman-netscape-ssl-00. Section 4.1. SSL Record Header Format
+class Sslv2Record
+{
+public:
+ explicit Sslv2Record(Parser::BinaryTokenizer &tk);
+
+ SBuf fragment;
+};
+
+/// TLS Handshake protocol's handshake types from RFC 5246 Section 7.4
+enum HandshakeType {
+ hskClientHello = 1,
+ hskServerHello = 2,
+ hskCertificate = 11,
+ hskServerHelloDone = 14
+};
+
+/// TLS Handshake Protocol frame from RFC 5246 Section 7.4.
+class Handshake
+{
+public:
+ explicit Handshake(Parser::BinaryTokenizer &tk);
+
+ uint8_t msg_type; ///< see HandshakeType
+ SBuf msg_body; ///< Handshake Protocol message
+};
+
+/// TLS Alert protocol frame from RFC 5246 Section 7.2.
+class Alert
+{
+public:
+ explicit Alert(Parser::BinaryTokenizer &tk);
+
+ bool fatal() const { return level == 2; }
+
+ uint8_t level; ///< warning or fatal
+ uint8_t description; ///< close_notify, unexpected_message, etc.
+};
+
+/// The size of the TLS Random structure from RFC 5246 Section 7.4.1.2.
+static const uint64_t HelloRandomSize = 32;
+
+/// TLS Hello Extension from RFC 5246 Section 7.4.1.4.
+class Extension
+{
+public:
+ typedef uint16_t Type;
+ explicit Extension(Parser::BinaryTokenizer &tk);
+
+ /// whether this extension is supported by Squid and, hence, may be bumped
+ /// after peeking or spliced after staring (subject to other restrictions)
+ bool supported() const;
+
+ Type type;
+ SBuf data;
+};
+
+/// Extension types optimized for fast lookups.
+typedef std::unordered_set Extensions;
+static Extensions SupportedExtensions();
+
+} // namespace Security
+
+/// Convenience helper: We parse ProtocolVersion but store "int".
+static AnyP::ProtocolVersion
+ParseProtocolVersion(Parser::BinaryTokenizer &tk)
+{
+ Parser::BinaryTokenizerContext context(tk, ".version");
+ uint8_t vMajor = tk.uint8(".major");
+ uint8_t vMinor = tk.uint8(".minor");
+ if (vMajor == 0 && vMinor == 2)
+ return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0);
+
+ Must(vMajor == 3);
+ if (vMinor == 0)
+ return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0);
+
+ return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, (vMinor - 1));
+}
+
+Security::TLSPlaintext::TLSPlaintext(Parser::BinaryTokenizer &tk)
+{
+ Parser::BinaryTokenizerContext context(tk, "TLSPlaintext");
+ type = tk.uint8(".type");
+ Must(type >= ctChangeCipherSpec && type <= ctApplicationData);
+ version = ParseProtocolVersion(tk);
+ // TODO: Must(version.major == 3);
+ fragment = tk.pstring16(".fragment");
+ context.success();
+}
+
+Security::Handshake::Handshake(Parser::BinaryTokenizer &tk)
+{
+ Parser::BinaryTokenizerContext context(tk, "Handshake");
+ msg_type = tk.uint8(".msg_type");
+ msg_body = tk.pstring24(".msg_body");
+ context.success();
+}
+
+Security::Alert::Alert(Parser::BinaryTokenizer &tk)
+{
+ Parser::BinaryTokenizerContext context(tk, "Alert");
+ level = tk.uint8(".level");
+ description = tk.uint8(".description");
+ context.success();
+}
+
+Security::Extension::Extension(Parser::BinaryTokenizer &tk)
+{
+ Parser::BinaryTokenizerContext context(tk, "Extension");
+ type = tk.uint16(".type");
+ data = tk.pstring16(".data");
+ context.success();
+}
+
+bool
+Security::Extension::supported() const
+{
+ static const Extensions supportedExtensions = SupportedExtensions();
+ return supportedExtensions.find(type) != supportedExtensions.end();
+}
+
+Security::Sslv2Record::Sslv2Record(Parser::BinaryTokenizer &tk)
+{
+ Parser::BinaryTokenizerContext context(tk, "Sslv2Record");
+ const uint16_t head = tk.uint16(".head");
+ const uint16_t length = head & 0x7FFF;
+ Must((head & 0x8000) && length); // SSLv2 message [without padding]
+ fragment = tk.area(length, ".fragment");
+ context.success();
+}
+
+Security::TlsDetails::TlsDetails():
+ compressionSupported(false),
+ doHeartBeats(false),
+ tlsTicketsExtension(false),
+ hasTlsTicket(false),
+ tlsStatusRequest(false),
+ unsupportedExtensions(false)
+{
+}
+
+/* Security::HandshakeParser */
+
+Security::HandshakeParser::HandshakeParser():
+ details(new TlsDetails),
+ state(atHelloNone),
+ resumingSession(false),
+ currentContentType(0),
+ done(nullptr),
+ expectingModernRecords(false)
+{
+}
+
+void
+Security::HandshakeParser::parseVersion2Record()
+{
+ const Sslv2Record record(tkRecords);
+ tkRecords.commit();
+ details->tlsVersion = AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0);
+ parseVersion2HandshakeMessage(record.fragment);
+ state = atHelloReceived;
+ done = "SSLv2";
+}
+
+/// RFC 5246. Appendix E.2. Compatibility with SSL 2.0
+/// And draft-hickman-netscape-ssl-00. Section 4.1. SSL Record Header Format
+bool
+Security::HandshakeParser::isSslv2Record(const SBuf &raw) const
+{
+ Parser::BinaryTokenizer tk(raw, true);
+ const uint16_t head = tk.uint16("?v2Hello.msg_head");
+ const uint8_t type = tk.uint8("?v2Hello.msg_type");
+ const uint16_t length = head & 0x7FFF;
+ return (head & 0x8000) && length && type == 1;
+}
+
+void
+Security::HandshakeParser::parseRecord()
+{
+ if (expectingModernRecords)
+ parseModernRecord();
+ else
+ parseVersion2Record();
+}
+
+/// parses a single TLS Record Layer frame
+void
+Security::HandshakeParser::parseModernRecord()
+{
+ const TLSPlaintext record(tkRecords);
+ tkRecords.commit();
+
+ details->tlsVersion = record.version;
+
+ // RFC 5246: length MUST NOT exceed 2^14
+ Must(record.fragment.length() <= (1 << 14));
+ // RFC 5246: MUST NOT send zero-length [non-application] fragments
+ Must(record.fragment.length() || record.type == ContentType::ctApplicationData);
+
+ if (currentContentType != record.type) {
+ Must(tkMessages.atEnd()); // no currentContentType leftovers
+ fragments = record.fragment;
+ tkMessages.reset(fragments, true); // true because more fragments may come
+ currentContentType = record.type;
+ } else {
+ fragments.append(record.fragment);
+ tkMessages.reinput(fragments, true); // true because more fragments may come
+ tkMessages.rollback();
+ }
+ parseMessages();
+}
+
+/// parses one or more "higher-level protocol" frames of currentContentType
+void
+Security::HandshakeParser::parseMessages()
+{
+ for (; !tkMessages.atEnd(); tkMessages.commit()) {
+ switch (currentContentType) {
+ case ContentType::ctChangeCipherSpec:
+ parseChangeCipherCpecMessage();
+ continue;
+ case ContentType::ctAlert:
+ parseAlertMessage();
+ continue;
+ case ContentType::ctHandshake:
+ parseHandshakeMessage();
+ continue;
+ case ContentType::ctApplicationData:
+ parseApplicationDataMessage();
+ continue;
+ }
+ skipMessage("unknown ContentType msg [fragment]");
+ }
+}
+
+void
+Security::HandshakeParser::parseChangeCipherCpecMessage()
+{
+ Must(currentContentType == ContentType::ctChangeCipherSpec);
+ // We are currently ignoring Change Cipher Spec Protocol messages.
+ skipMessage("ChangeCipherCpec msg [fragment]");
+
+ // Everything after the ChangeCipherCpec message may be encrypted.
+ // Continuing parsing is pointless. Stop here.
+ resumingSession = true;
+ done = "ChangeCipherCpec";
+}
+
+void
+Security::HandshakeParser::parseAlertMessage()
+{
+ Must(currentContentType == ContentType::ctAlert);
+ const Alert alert(tkMessages);
+ debugs(83, (alert.fatal() ? 2:3),
+ "level " << static_cast(alert.level) <<
+ " description " << static_cast(alert.description));
+ if (alert.fatal())
+ done = "fatal Alert";
+ // else ignore the warning (at least for now)
+}
+
+void
+Security::HandshakeParser::parseHandshakeMessage()
+{
+ Must(currentContentType == ContentType::ctHandshake);
+
+ const Handshake message(tkMessages);
+
+ switch (message.msg_type) {
+ case HandshakeType::hskClientHello:
+ Must(state < atHelloReceived);
+ Security::HandshakeParser::parseClientHelloHandshakeMessage(message.msg_body);
+ state = atHelloReceived;
+ done = "ClientHello";
+ return;
+ case HandshakeType::hskServerHello:
+ Must(state < atHelloReceived);
+ parseServerHelloHandshakeMessage(message.msg_body);
+ state = atHelloReceived;
+ return;
+ case HandshakeType::hskCertificate:
+ Must(state < atCertificatesReceived);
+ state = atCertificatesReceived;
+ return;
+ case HandshakeType::hskServerHelloDone:
+ Must(state < atHelloDoneReceived);
+ // zero-length
+ state = atHelloDoneReceived;
+ done = "ServerHelloDone";
+ return;
+ }
+ debugs(83, 5, "ignoring " << message.msg_body.length() << "-byte type-" <<
+ message.msg_type << " handshake message");
+}
+
+void
+Security::HandshakeParser::parseApplicationDataMessage()
+{
+ Must(currentContentType == ContentType::ctApplicationData);
+ skipMessage("app data [fragment]");
+}
+
+void
+Security::HandshakeParser::parseVersion2HandshakeMessage(const SBuf &raw)
+{
+ Parser::BinaryTokenizer tk(raw);
+ Parser::BinaryTokenizerContext hello(tk, "V2ClientHello");
+ Must(tk.uint8(".type") == hskClientHello); // Only client hello supported.
+ details->tlsSupportedVersion = ParseProtocolVersion(tk);
+ const uint16_t ciphersLen = tk.uint16(".cipher_specs.length");
+ const uint16_t sessionIdLen = tk.uint16(".session_id.length");
+ const uint16_t challengeLen = tk.uint16(".challenge.length");
+ parseV23Ciphers(tk.area(ciphersLen, ".cipher_specs.body"));
+ details->sessionId = tk.area(sessionIdLen, ".session_id.body");
+ tk.skip(challengeLen, ".challenge.body");
+ hello.success();
+}
+
+void
+Security::HandshakeParser::parseClientHelloHandshakeMessage(const SBuf &raw)
+{
+ Parser::BinaryTokenizer tk(raw);
+ Parser::BinaryTokenizerContext hello(tk, "ClientHello");
+ details->tlsSupportedVersion = ParseProtocolVersion(tk);
+ details->clientRandom = tk.area(HelloRandomSize, ".random");
+ details->sessionId = tk.pstring8(".session_id");
+ parseCiphers(tk.pstring16(".cipher_suites"));
+ details->compressionSupported = parseCompressionMethods(tk.pstring8(".compression_methods"));
+ if (!tk.atEnd()) // extension-free message ends here
+ parseExtensions(tk.pstring16(".extensions"));
+ hello.success();
+}
+
+bool
+Security::HandshakeParser::parseCompressionMethods(const SBuf &raw)
+{
+ if (raw.length() == 0)
+ return false;
+ Parser::BinaryTokenizer tk(raw);
+ while (!tk.atEnd()) {
+ // Probably here we should check for DEFLATE(1) compression method
+ // which is the only supported by openSSL subsystem.
+ if (tk.uint8("compression_method") != 0)
+ return true;
+ }
+ return false;
+}
+
+void
+Security::HandshakeParser::parseExtensions(const SBuf &raw)
+{
+ Parser::BinaryTokenizer tk(raw);
+ while (!tk.atEnd()) {
+ Extension extension(tk);
+
+ if (!details->unsupportedExtensions && !extension.supported()) {
+ debugs(83, 5, "first unsupported extension: " << extension.type);
+ details->unsupportedExtensions = true;
+ }
+
+ switch(extension.type) {
+ case 0: // The SNI extension; RFC 6066, Section 3
+ details->serverName = parseSniExtension(extension.data);
+ break;
+ case 5: // Certificate Status Request; RFC 6066, Section 8
+ details->tlsStatusRequest = true;
+ break;
+ case 15: // The heartBeats, RFC 6520
+ details->doHeartBeats = true;
+ break;
+ case 16: { // Application-Layer Protocol Negotiation Extension, RFC 7301
+ Parser::BinaryTokenizer tkAPN(extension.data);
+ details->tlsAppLayerProtoNeg = tkAPN.pstring16("APN");
+ break;
+ }
+ case 35: // SessionTicket TLS Extension; RFC 5077
+ details->tlsTicketsExtension = true;
+ details->hasTlsTicket = !extension.data.isEmpty();
+ case 13172: // Next Protocol Negotiation Extension (expired draft?)
+ default:
+ break;
+ }
+ }
+}
+
+void
+Security::HandshakeParser::parseCiphers(const SBuf &raw)
+{
+ details->ciphers.reserve(raw.length() / sizeof(uint16_t));
+ Parser::BinaryTokenizer tk(raw);
+ while (!tk.atEnd()) {
+ const uint16_t cipher = tk.uint16("cipher");
+ details->ciphers.insert(cipher);
+ }
+}
+
+void
+Security::HandshakeParser::parseV23Ciphers(const SBuf &raw)
+{
+ Parser::BinaryTokenizer tk(raw);
+ while (!tk.atEnd()) {
+ // RFC 6101 Appendix E, RFC 5246 Appendix E2
+ // Unlike TLS, ciphers in SSLv23 Hellos are 3 bytes long and come in
+ // two versions: v2 and v3. The two versions may co-exist in a single
+ // SSLv23 Hello. Only v3 ciphers have a first byte value of zero.
+ // The ciphers are needed for our peeking/staring code that
+ // does not support SSLv2, so we ignore v2 ciphers.
+ const uint8_t prefix = tk.uint8("prefix");
+ const uint16_t cipher = tk.uint16("cipher");
+ if (prefix == 0)
+ details->ciphers.insert(cipher);
+ }
+}
+
+/// RFC 5246 Section 7.4.1.3. Server Hello
+void
+Security::HandshakeParser::parseServerHelloHandshakeMessage(const SBuf &raw)
+{
+ Parser::BinaryTokenizer tk(raw);
+ Parser::BinaryTokenizerContext hello(tk, "ServerHello");
+ details->tlsSupportedVersion = ParseProtocolVersion(tk);
+ tk.skip(HelloRandomSize, ".random");
+ details->sessionId = tk.pstring8(".session_id");
+ details->ciphers.insert(tk.uint16(".cipher_suite"));
+ details->compressionSupported = tk.uint8(".compression_method") != 0; // not null
+ if (!tk.atEnd()) // extensions present
+ parseExtensions(tk.pstring16(".extensions"));
+ hello.success();
+}
+
+// RFC 6066 Section 3: ServerNameList (may be sent by both clients and servers)
+SBuf
+Security::HandshakeParser::parseSniExtension(const SBuf &extensionData) const
+{
+ // Servers SHOULD send an empty SNI extension, not an empty ServerNameList!
+ if (extensionData.isEmpty())
+ return SBuf();
+
+ // SNI MUST NOT contain more than one name of the same name_type but
+ // we ignore violations and simply return the first host name found.
+ Parser::BinaryTokenizer tkList(extensionData);
+ Parser::BinaryTokenizer tkNames(tkList.pstring16("ServerNameList"));
+ while (!tkNames.atEnd()) {
+ Parser::BinaryTokenizerContext serverName(tkNames, "ServerName");
+ const uint8_t nameType = tkNames.uint8(".name_type");
+ const SBuf name = tkNames.pstring16(".name");
+ serverName.success();
+
+ if (nameType == 0) {
+ debugs(83, 3, "host_name=" << name);
+ return name; // it may be empty
+ }
+ // else we just parsed a new/unsupported NameType which,
+ // according to RFC 6066, MUST begin with a 16-bit length field
+ }
+ return SBuf(); // SNI extension lacks host_name
+}
+
+void
+Security::HandshakeParser::skipMessage(const char *description)
+{
+ // tkMessages/fragments can only contain messages of the same ContentType.
+ // To skip a message, we can and should skip everything we have [left]. If
+ // we have partial messages, debugging will mislead about their boundaries.
+ tkMessages.skip(tkMessages.leftovers().length(), description);
+}
+
+bool
+Security::HandshakeParser::parseHello(const SBuf &data)
+{
+ try {
+ if (!expectingModernRecords.configured())
+ expectingModernRecords.configure(!isSslv2Record(data));
+
+ // data contains everything read so far, but we may read more later
+ tkRecords.reinput(data, true);
+ tkRecords.rollback();
+ while (!done)
+ parseRecord();
+ debugs(83, 7, "success; got: " << done);
+ // we are done; tkRecords may have leftovers we are not interested in
+ return true;
+ }
+ catch (const Parser::BinaryTokenizer::InsufficientInput &) {
+ debugs(83, 5, "need more data");
+ return false;
+ }
+ return false; // unreached
+}
+
+#if USE_OPENSSL
+
+/// A helper function to create a set of all supported TLS extensions
+static
+Security::Extensions
+Security::SupportedExtensions()
+{
+ // optimize lookup speed by reserving the number of values x3, approximately
+ Security::Extensions extensions(64);
+
+ // Keep this list ordered and up to date by running something like
+ // egrep '# *define TLSEXT_TYPE_' /usr/include/openssl/tls1.h
+ // TODO: Teach OpenSSL to return the list of extensions it supports.
+#if defined(TLSEXT_TYPE_server_name) // 0
+ extensions.insert(TLSEXT_TYPE_server_name);
+#endif
+#if defined(TLSEXT_TYPE_max_fragment_length) // 1
+ extensions.insert(TLSEXT_TYPE_max_fragment_length);
+#endif
+#if defined(TLSEXT_TYPE_client_certificate_url) // 2
+ extensions.insert(TLSEXT_TYPE_client_certificate_url);
+#endif
+#if defined(TLSEXT_TYPE_trusted_ca_keys) // 3
+ extensions.insert(TLSEXT_TYPE_trusted_ca_keys);
+#endif
+#if defined(TLSEXT_TYPE_truncated_hmac) // 4
+ extensions.insert(TLSEXT_TYPE_truncated_hmac);
+#endif
+#if defined(TLSEXT_TYPE_status_request) // 5
+ extensions.insert(TLSEXT_TYPE_status_request);
+#endif
+#if defined(TLSEXT_TYPE_user_mapping) // 6
+ extensions.insert(TLSEXT_TYPE_user_mapping);
+#endif
+#if defined(TLSEXT_TYPE_client_authz) // 7
+ extensions.insert(TLSEXT_TYPE_client_authz);
+#endif
+#if defined(TLSEXT_TYPE_server_authz) // 8
+ extensions.insert(TLSEXT_TYPE_server_authz);
+#endif
+#if defined(TLSEXT_TYPE_cert_type) // 9
+ extensions.insert(TLSEXT_TYPE_cert_type);
+#endif
+#if defined(TLSEXT_TYPE_elliptic_curves) // 10
+ extensions.insert(TLSEXT_TYPE_elliptic_curves);
+#endif
+#if defined(TLSEXT_TYPE_ec_point_formats) // 11
+ extensions.insert(TLSEXT_TYPE_ec_point_formats);
+#endif
+#if defined(TLSEXT_TYPE_srp) // 12
+ extensions.insert(TLSEXT_TYPE_srp);
+#endif
+#if defined(TLSEXT_TYPE_signature_algorithms) // 13
+ extensions.insert(TLSEXT_TYPE_signature_algorithms);
+#endif
+#if defined(TLSEXT_TYPE_use_srtp) // 14
+ extensions.insert(TLSEXT_TYPE_use_srtp);
+#endif
+#if defined(TLSEXT_TYPE_heartbeat) // 15
+ extensions.insert(TLSEXT_TYPE_heartbeat);
+#endif
+#if defined(TLSEXT_TYPE_session_ticket) // 35
+ extensions.insert(TLSEXT_TYPE_session_ticket);
+#endif
+#if defined(TLSEXT_TYPE_renegotiate) // 0xff01
+ extensions.insert(TLSEXT_TYPE_renegotiate);
+#endif
+#if defined(TLSEXT_TYPE_next_proto_neg) // 13172
+ extensions.insert(TLSEXT_TYPE_next_proto_neg);
+#endif
+
+ /*
+ * OpenSSL does not support these last extensions by default, but those
+ * building the OpenSSL libraries and/or Squid might define them.
+ */
+
+ // OpenSSL may be built to support draft-rescorla-tls-opaque-prf-input-00,
+ // with the extension type value configured at build time. OpenSSL, Squid,
+ // and TLS agents must all be built with the same extension type value.
+#if defined(TLSEXT_TYPE_opaque_prf_input)
+ extensions.insert(TLSEXT_TYPE_opaque_prf_input);
+#endif
+
+ // Define this to add extensions supported by your OpenSSL but unknown to
+ // your Squid version. Use {list-initialization} to add multiple extensions.
+#if defined(TLSEXT_TYPE_SUPPORTED_BY_MY_SQUID)
+ extensions.insert(TLSEXT_TYPE_SUPPORTED_BY_MY_SQUID);
+#endif
+
+ return extensions; // might be empty
+}
+
+#else
+
+static
+Security::Extensions
+Security::SupportedExtensions()
+{
+ return Extensions(); // no extensions are supported without OpenSSL
+}
+#endif
+
diff -u -r -N squid-4.0.10/src/security/Handshake.h squid-4.0.11/src/security/Handshake.h
--- squid-4.0.10/src/security/Handshake.h 1970-01-01 12:00:00.000000000 +1200
+++ squid-4.0.11/src/security/Handshake.h 2016-06-10 08:32:57.000000000 +1200
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
+ *
+ * Squid software is distributed under GPLv2+ license and includes
+ * contributions from numerous individuals and organizations.
+ * Please see the COPYING and CONTRIBUTORS files for details.
+ */
+
+#ifndef SQUID_SECURITY_HANDSHAKE_H
+#define SQUID_SECURITY_HANDSHAKE_H
+
+#include "anyp/ProtocolVersion.h"
+#include "base/YesNoNone.h"
+#include "parser/BinaryTokenizer.h"
+
+#include
+
+namespace Security
+{
+
+class TlsDetails: public RefCountable
+{
+public:
+ typedef RefCount Pointer;
+
+ TlsDetails();
+ /// Prints to os stream a human readable form of TlsDetails object
+ std::ostream & print(std::ostream &os) const;
+
+ AnyP::ProtocolVersion tlsVersion; ///< The TLS hello message version
+ AnyP::ProtocolVersion tlsSupportedVersion; ///< The requested/used TLS version
+ bool compressionSupported; ///< The requested/used compressed method
+ SBuf serverName; ///< The SNI hostname, if any
+ bool doHeartBeats;
+ bool tlsTicketsExtension; ///< whether TLS tickets extension is enabled
+ bool hasTlsTicket; ///< whether a TLS ticket is included
+ bool tlsStatusRequest; ///< whether the TLS status request extension is set
+ bool unsupportedExtensions; ///< whether any unsupported by Squid extensions are used
+ SBuf tlsAppLayerProtoNeg; ///< The value of the TLS application layer protocol extension if it is enabled
+ /// The client random number
+ SBuf clientRandom;
+ SBuf sessionId;
+
+ typedef std::unordered_set Ciphers;
+ Ciphers ciphers;
+};
+
+inline
+std::ostream &operator <<(std::ostream &os, Security::TlsDetails const &details)
+{
+ return details.print(os);
+}
+
+/// Incremental TLS/SSL Handshake parser.
+class HandshakeParser
+{
+public:
+ /// The parsing states
+ typedef enum {atHelloNone = 0, atHelloStarted, atHelloReceived, atCertificatesReceived, atHelloDoneReceived, atNstReceived, atCcsReceived, atFinishReceived} ParserState;
+
+ HandshakeParser();
+
+ /// Parses the initial sequence of raw bytes sent by the TLS/SSL agent.
+ /// Returns true upon successful completion (e.g., got HelloDone).
+ /// Returns false if more data is needed.
+ /// Throws on errors.
+ bool parseHello(const SBuf &data);
+
+ TlsDetails::Pointer details; ///< TLS handshake meta info or nil.
+
+ ParserState state; ///< current parsing state.
+
+ bool resumingSession; ///< True if this is a resuming session
+
+private:
+ bool isSslv2Record(const SBuf &raw) const;
+ void parseRecord();
+ void parseModernRecord();
+ void parseVersion2Record();
+ void parseMessages();
+
+ void parseChangeCipherCpecMessage();
+ void parseAlertMessage();
+ void parseHandshakeMessage();
+ void parseApplicationDataMessage();
+ void skipMessage(const char *msgType);
+
+ bool parseRecordVersion2Try();
+ void parseVersion2HandshakeMessage(const SBuf &raw);
+ void parseClientHelloHandshakeMessage(const SBuf &raw);
+ void parseServerHelloHandshakeMessage(const SBuf &raw);
+
+ bool parseCompressionMethods(const SBuf &raw);
+ void parseExtensions(const SBuf &raw);
+ SBuf parseSniExtension(const SBuf &extensionData) const;
+
+ void parseCiphers(const SBuf &raw);
+ void parseV23Ciphers(const SBuf &raw);
+
+ unsigned int currentContentType; ///< The current TLS/SSL record content type
+
+ const char *done; ///< not nil if we got what we were looking for
+
+ /// concatenated TLSPlaintext.fragments of TLSPlaintext.type
+ SBuf fragments;
+
+ /// TLS record layer (parsing uninterpreted data)
+ Parser::BinaryTokenizer tkRecords;
+
+ /// TLS message layer (parsing fragments)
+ Parser::BinaryTokenizer tkMessages;
+
+ /// Whether to use TLS parser or a V2 compatible parser
+ YesNoNone expectingModernRecords;
+};
+
+}
+
+#endif // SQUID_SECURITY_HANDSHAKE_H
+
diff -u -r -N squid-4.0.10/src/security/Makefile.am squid-4.0.11/src/security/Makefile.am
--- squid-4.0.10/src/security/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/security/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -16,6 +16,8 @@
Context.h \
EncryptorAnswer.cc \
EncryptorAnswer.h \
+ Handshake.cc \
+ Handshake.h \
forward.h \
KeyData.h \
LockingPointer.h \
diff -u -r -N squid-4.0.10/src/security/Makefile.in squid-4.0.11/src/security/Makefile.in
--- squid-4.0.10/src/security/Makefile.in 2016-05-06 23:37:07.000000000 +1200
+++ squid-4.0.11/src/security/Makefile.in 2016-06-10 08:35:05.000000000 +1200
@@ -163,8 +163,9 @@
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libsecurity_la_LIBADD =
-am_libsecurity_la_OBJECTS = EncryptorAnswer.lo NegotiationHistory.lo \
- PeerOptions.lo ServerOptions.lo Session.lo
+am_libsecurity_la_OBJECTS = EncryptorAnswer.lo Handshake.lo \
+ NegotiationHistory.lo PeerOptions.lo ServerOptions.lo \
+ Session.lo
libsecurity_la_OBJECTS = $(am_libsecurity_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@@ -764,6 +765,8 @@
Context.h \
EncryptorAnswer.cc \
EncryptorAnswer.h \
+ Handshake.cc \
+ Handshake.h \
forward.h \
KeyData.h \
LockingPointer.h \
@@ -841,6 +844,7 @@
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/EncryptorAnswer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Handshake.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NegotiationHistory.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerOptions.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerOptions.Plo@am__quote@
diff -u -r -N squid-4.0.10/src/security/NegotiationHistory.cc squid-4.0.11/src/security/NegotiationHistory.cc
--- squid-4.0.10/src/security/NegotiationHistory.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/security/NegotiationHistory.cc 2016-06-10 08:32:57.000000000 +1200
@@ -15,70 +15,85 @@
#include "ssl/support.h"
#endif
-Security::NegotiationHistory::NegotiationHistory():
- helloVersion_(-1),
- supportedVersion_(-1),
- version_(-1)
+Security::NegotiationHistory::NegotiationHistory()
#if USE_OPENSSL
- , cipher(NULL)
+ : cipher(nullptr)
#endif
{
}
const char *
-Security::NegotiationHistory::printTlsVersion(int v) const
+Security::NegotiationHistory::printTlsVersion(AnyP::ProtocolVersion const &v) const
{
+ if (v.protocol != AnyP::PROTO_SSL && v.protocol != AnyP::PROTO_TLS)
+ return nullptr;
+
+ static char buf[512];
+ snprintf(buf, sizeof(buf), "%s/%d.%d", AnyP::ProtocolType_str[v.protocol], v.major, v.minor);
+ return buf;
+}
+
#if USE_OPENSSL
+static AnyP::ProtocolVersion
+toProtocolVersion(const int v)
+{
switch(v) {
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+#if defined(TLS1_2_VERSION)
case TLS1_2_VERSION:
- return "TLS/1.2";
+ return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 2);
+#endif
+#if defined(TLS1_1_VERSION)
case TLS1_1_VERSION:
- return "TLS/1.1";
+ return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 1);
#endif
+#if defined(TLS1_VERSION)
case TLS1_VERSION:
- return "TLS/1.0";
+ return AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 0);
+#endif
+#if defined(SSL3_VERSION)
case SSL3_VERSION:
- return "SSL/3.0";
+ return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0);
+#endif
+#if defined(SSL2_VERSION)
case SSL2_VERSION:
- return "SSL/2.0";
+ return AnyP::ProtocolVersion(AnyP::PROTO_SSL, 2, 0);
+#endif
default:
- return nullptr;
+ return AnyP::ProtocolVersion();
}
-#else
- return nullptr;
-#endif
}
+#endif
void
-Security::NegotiationHistory::fillWith(Security::SessionPtr ssl)
+Security::NegotiationHistory::retrieveNegotiatedInfo(Security::SessionPtr ssl)
{
#if USE_OPENSSL
if ((cipher = SSL_get_current_cipher(ssl)) != NULL) {
// Set the negotiated version only if the cipher negotiated
// else probably the negotiation is not completed and version
// is not the final negotiated version
- version_ = ssl->version;
+ version_ = toProtocolVersion(ssl->version);
}
- BIO *b = SSL_get_rbio(ssl);
- Ssl::Bio *bio = static_cast(b->ptr);
-
- if (::Config.onoff.logTlsServerHelloDetails) {
- if (Ssl::ServerBio *srvBio = dynamic_cast(bio))
- srvBio->extractHelloFeatures();
+ if (Debug::Enabled(83, 5)) {
+ BIO *b = SSL_get_rbio(ssl);
+ Ssl::Bio *bio = static_cast(b->ptr);
+ debugs(83, 5, "SSL connection info on FD " << bio->fd() <<
+ " SSL version " << version_ <<
+ " negotiated cipher " << cipherName());
}
-
- const Ssl::Bio::sslFeatures &features = bio->receivedHelloFeatures();
- helloVersion_ = features.sslHelloVersion;
- supportedVersion_ = features.sslVersion;
-
- debugs(83, 5, "SSL connection info on FD " << bio->fd() <<
- " SSL version " << version_ <<
- " negotiated cipher " << cipherName());
#endif
}
+void
+Security::NegotiationHistory::retrieveParsedInfo(Security::TlsDetails::Pointer const &details)
+{
+ if (details) {
+ helloVersion_ = details->tlsVersion;
+ supportedVersion_ = details->tlsSupportedVersion;
+ }
+}
+
const char *
Security::NegotiationHistory::cipherName() const
{
diff -u -r -N squid-4.0.10/src/security/NegotiationHistory.h squid-4.0.11/src/security/NegotiationHistory.h
--- squid-4.0.10/src/security/NegotiationHistory.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/security/NegotiationHistory.h 2016-06-10 08:32:57.000000000 +1200
@@ -9,6 +9,8 @@
#ifndef SQUID_SRC_SECURITY_NEGOTIATIONHISTORY_H
#define SQUID_SRC_SECURITY_NEGOTIATIONHISTORY_H
+#include "anyp/ProtocolVersion.h"
+#include "security/Handshake.h"
#include "security/Session.h"
namespace Security {
@@ -17,7 +19,13 @@
{
public:
NegotiationHistory();
- void fillWith(Security::SessionPtr); ///< Extract negotiation information from TLS object
+
+ /// Extract negotiation information from TLS object
+ void retrieveNegotiatedInfo(Security::SessionPtr);
+
+ /// Extract information from parser stored in TlsDetails object
+ void retrieveParsedInfo(Security::TlsDetails::Pointer const &details);
+
const char *cipherName() const; ///< The name of negotiated cipher
/// String representation of TLS negotiated version
const char *negotiatedVersion() const {return printTlsVersion(version_);}
@@ -28,10 +36,10 @@
const char *supportedVersion() const {return printTlsVersion(supportedVersion_);}
private:
/// String representation of the TLS version 'v'
- const char *printTlsVersion(int v) const;
- int helloVersion_; ///< The TLL version of the hello message
- int supportedVersion_; ///< The maximum supported TLS version
- int version_; ///< The negotiated TLL version
+ const char *printTlsVersion(AnyP::ProtocolVersion const &v) const;
+ AnyP::ProtocolVersion helloVersion_; ///< The TLS version of the hello message
+ AnyP::ProtocolVersion supportedVersion_; ///< The maximum supported TLS version
+ AnyP::ProtocolVersion version_; ///< The negotiated TLS version
#if USE_OPENSSL
const SSL_CIPHER *cipher; ///< The negotiated cipher
#endif
diff -u -r -N squid-4.0.10/src/security/PeerOptions.cc squid-4.0.11/src/security/PeerOptions.cc
--- squid-4.0.10/src/security/PeerOptions.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/security/PeerOptions.cc 2016-06-10 08:32:57.000000000 +1200
@@ -240,7 +240,7 @@
}
#else
- fatal("Failed to allocate TLS client context: No TLS library\n");
+ debugs(83, 1, "WARNING: Failed to allocate TLS client context: No TLS library");
#endif
@@ -250,20 +250,14 @@
Security::ContextPtr
Security::PeerOptions::createClientContext(bool setOptions)
{
- Security::ContextPtr t = nullptr;
-
updateTlsVersionLimits();
+ Security::ContextPtr t = createBlankContext();
+ if (t) {
#if USE_OPENSSL
- // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
- t = sslCreateClientContext(*this, (setOptions ? parsedOptions : 0), parsedFlags);
-
-#elif USE_GNUTLS && WHEN_READY_FOR_GNUTLS
- t = createBlankContext();
-
+ // XXX: temporary performance regression. c_str() data copies and prevents this being a const method
+ Ssl::InitClientContext(t, *this, (setOptions ? parsedOptions : 0), parsedFlags);
#endif
-
- if (t) {
updateContextNpn(t);
updateContextCa(t);
updateContextCrl(t);
@@ -573,6 +567,22 @@
// it does support ALPN per-session, not per-context.
}
+static const char *
+loadSystemTrustedCa(Security::ContextPtr &ctx)
+{
+#if USE_OPENSSL
+ if (SSL_CTX_set_default_verify_paths(ctx) == 0)
+ return ERR_error_string(ERR_get_error(), nullptr);
+
+#elif USE_GNUTLS
+ auto x = gnutls_certificate_set_x509_system_trust(ctx);
+ if (x < 0)
+ return gnutls_strerror(x);
+
+#endif
+ return nullptr;
+}
+
void
Security::PeerOptions::updateContextCa(Security::ContextPtr &ctx)
{
@@ -594,17 +604,9 @@
if (!flags.tlsDefaultCa)
return;
-#if USE_OPENSSL
- if (!SSL_CTX_set_default_verify_paths(ctx)) {
- const int ssl_error = ERR_get_error();
- debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA : "
- << ERR_error_string(ssl_error, NULL));
- }
-#elif USE_GNUTLS
- if (gnutls_certificate_set_x509_system_trust(ctx) != GNUTLS_E_SUCCESS) {
- debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA.");
+ if (const char *err = loadSystemTrustedCa(ctx)) {
+ debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default trusted CA : " << err);
}
-#endif
}
void
diff -u -r -N squid-4.0.10/src/security/ServerOptions.cc squid-4.0.11/src/security/ServerOptions.cc
--- squid-4.0.10/src/security/ServerOptions.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/security/ServerOptions.cc 2016-06-10 08:32:57.000000000 +1200
@@ -117,6 +117,21 @@
return t;
}
+Security::ContextPtr
+Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &port)
+{
+ updateTlsVersionLimits();
+
+ Security::ContextPtr t = createBlankContext();
+ if (t) {
+#if USE_OPENSSL
+ Ssl::InitServerContext(t, port);
+#endif
+ }
+
+ return t;
+}
+
void
Security::ServerOptions::loadDhParams()
{
diff -u -r -N squid-4.0.10/src/security/ServerOptions.h squid-4.0.11/src/security/ServerOptions.h
--- squid-4.0.10/src/security/ServerOptions.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/security/ServerOptions.h 2016-06-10 08:32:57.000000000 +1200
@@ -9,6 +9,7 @@
#ifndef SQUID_SRC_SECURITY_SERVEROPTIONS_H
#define SQUID_SRC_SECURITY_SERVEROPTIONS_H
+#include "anyp/forward.h"
#include "security/PeerOptions.h"
namespace Security
@@ -31,6 +32,9 @@
virtual Security::ContextPtr createBlankContext() const;
virtual void dumpCfg(Packable *, const char *pfx) const;
+ /// generate a security server-context from these configured options
+ Security::ContextPtr createStaticServerContext(AnyP::PortCfg &);
+
/// update the context with DH, EDH, EECDH settings
void updateContextEecdh(Security::ContextPtr &);
diff -u -r -N squid-4.0.10/src/servers/FtpServer.cc squid-4.0.11/src/servers/FtpServer.cc
--- squid-4.0.10/src/servers/FtpServer.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/servers/FtpServer.cc 2016-06-10 08:32:57.000000000 +1200
@@ -1305,7 +1305,7 @@
Must(header.has(Http::HdrType::FTP_ARGUMENTS));
String ¶ms = header.findEntry(Http::HdrType::FTP_ARGUMENTS)->value;
- if (do_debug(9, 2)) {
+ if (Debug::Enabled(9, 2)) {
MemBuf mb;
mb.init();
request->pack(&mb);
diff -u -r -N squid-4.0.10/src/SquidConfig.h squid-4.0.11/src/SquidConfig.h
--- squid-4.0.10/src/SquidConfig.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/SquidConfig.h 2016-06-10 08:32:57.000000000 +1200
@@ -305,7 +305,6 @@
int digest_generation;
#endif
- int ie_refresh;
int vary_ignore_expire;
int surrogate_is_remote;
int request_entities;
diff -u -r -N squid-4.0.10/src/SquidNew.cc squid-4.0.11/src/SquidNew.cc
--- squid-4.0.10/src/SquidNew.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/SquidNew.cc 2016-06-10 08:32:57.000000000 +1200
@@ -8,29 +8,45 @@
/* DEBUG: none Memory Allocation */
-#define _SQUID_EXTERNNEW_
-
#include "squid.h"
-#ifdef __SUNPRO_CC
+#if !defined(__clang__)
#include
-void *operator new(size_t size) throw (std::bad_alloc)
+
+void *operator new(size_t size)
+{
+ return xmalloc(size);
+}
+void operator delete(void *address)
+{
+ xfree(address);
+}
+void *operator new[](size_t size)
+{
+ return xmalloc(size);
+}
+void operator delete[](void *address)
+{
+ xfree(address);
+}
+
+void *operator new(size_t size, const std::nothrow_t &tag)
{
return xmalloc(size);
}
-void operator delete (void *address) throw()
+void operator delete(void *address, const std::nothrow_t &tag)
{
- xfree (address);
+ xfree(address);
}
-void *operator new[] (size_t size) throw (std::bad_alloc)
+void *operator new[](size_t size, const std::nothrow_t &tag)
{
return xmalloc(size);
}
-void operator delete[] (void *address) throw()
+void operator delete[](void *address, const std::nothrow_t &tag)
{
- xfree (address);
+ xfree(address);
}
-#endif /* __SUNPRO_CC */
+#endif /* !defined(__clang__) */
diff -u -r -N squid-4.0.10/src/ssl/bio.cc squid-4.0.11/src/ssl/bio.cc
--- squid-4.0.10/src/ssl/bio.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/ssl/bio.cc 2016-06-10 08:32:57.000000000 +1200
@@ -15,9 +15,11 @@
#if USE_OPENSSL
#include "comm.h"
+#include "fd.h"
#include "fde.h"
#include "globals.h"
#include "ip/Address.h"
+#include "parser/BinaryTokenizer.h"
#include "ssl/bio.h"
#if HAVE_OPENSSL_SSL_H
@@ -127,28 +129,6 @@
return result;
}
-int
-Ssl::Bio::readAndBuffer(char *buf, int size, BIO *table, const char *description)
-{
- prepReadBuf();
-
- size = min((int)rbuf.potentialSpaceSize(), size);
- if (size <= 0) {
- debugs(83, DBG_IMPORTANT, "Not enough space to hold " <<
- rbuf.contentSize() << "+ byte " << description);
- return -1;
- }
-
- const int bytes = Ssl::Bio::read(buf, size, table);
- debugs(83, 5, "read " << bytes << " out of " << size << " bytes"); // move to Ssl::Bio::read()
-
- if (bytes > 0) {
- rbuf.append(buf, bytes);
- debugs(83, 5, "recorded " << bytes << " bytes of " << description);
- }
- return bytes;
-}
-
/// Called whenever the SSL connection state changes, an alert appears, or an
/// error occurs. See SSL_set_info_callback().
void
@@ -167,13 +147,6 @@
SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")");
}
-void
-Ssl::Bio::prepReadBuf()
-{
- if (rbuf.isNull())
- rbuf.init(4096, 65536);
-}
-
bool
Ssl::ClientBio::isClientHello(int state)
{
@@ -203,73 +176,40 @@
return Ssl::Bio::write(buf, size, table);
}
-const char *objToString(unsigned char const *bytes, int len)
-{
- static std::string buf;
- buf.clear();
- for (int i = 0; i < len; i++ ) {
- char tmp[3];
- snprintf(tmp, sizeof(tmp), "%.2x", bytes[i]);
- buf.append(tmp);
- }
- return buf.c_str();
-}
-
int
Ssl::ClientBio::read(char *buf, int size, BIO *table)
{
- if (helloState < atHelloReceived) {
- int bytes = readAndBuffer(buf, size, table, "TLS client Hello");
- if (bytes <= 0)
- return bytes;
- }
-
- if (helloState == atHelloNone) {
- helloSize = receivedHelloFeatures_.parseMsgHead(rbuf);
- if (helloSize == 0) {
- // Not enough bytes to get hello message size
- BIO_set_retry_read(table);
- return -1;
- } else if (helloSize < 0) {
- wrongProtocol = true;
- return -1;
- }
-
- helloState = atHelloStarted; //Next state
- }
-
- if (helloState == atHelloStarted) {
- const unsigned char *head = (const unsigned char *)rbuf.content();
- const char *s = objToString(head, rbuf.contentSize());
- debugs(83, 7, "SSL Header: " << s);
-
- if (helloSize > rbuf.contentSize()) {
- BIO_set_retry_read(table);
- return -1;
- }
- receivedHelloFeatures_.get(rbuf);
- helloState = atHelloReceived;
- }
-
if (holdRead_) {
debugs(83, 7, "Hold flag is set, retry latter. (Hold " << size << "bytes)");
BIO_set_retry_read(table);
return -1;
}
- if (helloState == atHelloReceived) {
- if (rbuf.hasContent()) {
- int bytes = (size <= rbuf.contentSize() ? size : rbuf.contentSize());
- memcpy(buf, rbuf.content(), bytes);
- rbuf.consume(bytes);
- return bytes;
- } else
- return Ssl::Bio::read(buf, size, table);
- }
+ if (!rbuf.isEmpty()) {
+ int bytes = (size <= (int)rbuf.length() ? size : rbuf.length());
+ memcpy(buf, rbuf.rawContent(), bytes);
+ rbuf.consume(bytes);
+ return bytes;
+ } else
+ return Ssl::Bio::read(buf, size, table);
return -1;
}
+Ssl::ServerBio::ServerBio(const int anFd):
+ Bio(anFd),
+ helloMsgSize(0),
+ helloBuild(false),
+ allowSplice(false),
+ allowBump(false),
+ holdWrite_(false),
+ record_(false),
+ parsedHandshake(false),
+ bumpMode_(bumpNone),
+ rbufConsumePos(0)
+{
+}
+
void
Ssl::ServerBio::stateChanged(const SSL *ssl, int where, int ret)
{
@@ -277,16 +217,93 @@
}
void
-Ssl::ServerBio::setClientFeatures(const Ssl::Bio::sslFeatures &features)
+Ssl::ServerBio::setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &aHello)
{
- clientFeatures = features;
+ clientTlsDetails = details;
+ clientHelloMessage = aHello;
};
int
Ssl::ServerBio::read(char *buf, int size, BIO *table)
{
- return record_ ?
- readAndBuffer(buf, size, table, "TLS server Hello") : Ssl::Bio::read(buf, size, table);
+ if (parsedHandshake) // done parsing TLS Hello
+ return readAndGive(buf, size, table);
+ else
+ return readAndParse(buf, size, table);
+}
+
+/// Read and give everything to OpenSSL.
+int
+Ssl::ServerBio::readAndGive(char *buf, const int size, BIO *table)
+{
+ // If we have unused buffered bytes, give those bytes to OpenSSL now,
+ // before reading more. TODO: Read if we have buffered less than size?
+ if (rbufConsumePos < rbuf.length())
+ return giveBuffered(buf, size);
+
+ if (record_) {
+ const int result = readAndBuffer(table);
+ if (result <= 0)
+ return result;
+ return giveBuffered(buf, size);
+ }
+
+ return Ssl::Bio::read(buf, size, table);
+}
+
+/// Read and give everything to our parser.
+/// When/if parsing is finished (successfully or not), start giving to OpenSSL.
+int
+Ssl::ServerBio::readAndParse(char *buf, const int size, BIO *table)
+{
+ const int result = readAndBuffer(table);
+ if (result <= 0)
+ return result;
+
+ try {
+ if (!parser_.parseHello(rbuf)) {
+ // need more data to finish parsing
+ BIO_set_retry_read(table);
+ return -1;
+ }
+ parsedHandshake = true; // done parsing (successfully)
+ }
+ catch (const std::exception &ex) {
+ debugs(83, 2, "parsing error on FD " << fd_ << ": " << ex.what());
+ parsedHandshake = true; // done parsing (due to an error)
+ }
+
+ return giveBuffered(buf, size);
+}
+
+/// Reads more data into the read buffer. Returns either the number of bytes
+/// read or, on errors (including "try again" errors), a negative number.
+int
+Ssl::ServerBio::readAndBuffer(BIO *table)
+{
+ char *space = rbuf.rawSpace(SQUID_TCP_SO_RCVBUF);
+ const int result = Ssl::Bio::read(space, rbuf.spaceSize(), table);
+ if (result <= 0)
+ return result;
+
+ rbuf.forceSize(rbuf.length() + result);
+ return result;
+}
+
+/// give previously buffered bytes to OpenSSL
+/// returns the number of bytes given
+int
+Ssl::ServerBio::giveBuffered(char *buf, const int size)
+{
+ if (rbuf.length() <= rbufConsumePos)
+ return -1; // buffered nothing yet
+
+ const int unsent = rbuf.length() - rbufConsumePos;
+ const int bytes = (size <= unsent ? size : unsent);
+ memcpy(buf, rbuf.rawContent() + rbufConsumePos, bytes);
+ rbufConsumePos += bytes;
+ debugs(83, 7, bytes << "<=" << size << " bytes to OpenSSL");
+ return bytes;
}
// This function makes the required checks to examine if the client hello
@@ -297,7 +314,7 @@
// This is mostly possible in the cases where the web client uses openSSL
// library similar with this one used by squid.
static bool
-adjustSSL(SSL *ssl, Ssl::Bio::sslFeatures &features)
+adjustSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, SBuf &helloMessage)
{
#if SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK
if (!ssl->s3) {
@@ -308,107 +325,78 @@
// If the client supports compression but our context does not support
// we can not adjust.
#if !defined(OPENSSL_NO_COMP)
- const bool requireCompression = (features.compressMethod && ssl->ctx->comp_methods == NULL);
+ const bool requireCompression = (details->compressionSupported && ssl->ctx->comp_methods == nullptr);
#else
- const bool requireCompression = features.compressMethod;
+ const bool requireCompression = details->compressionSupported;
#endif
if (requireCompression) {
debugs(83, 5, "Client Hello Data supports compression, but we do not!");
return false;
}
- // Check ciphers list
- size_t token = 0;
- size_t end = 0;
- while (token != std::string::npos) {
- end = features.clientRequestedCiphers.find(':',token);
- std::string cipher;
- cipher.assign(features.clientRequestedCiphers, token, end - token);
- token = (end != std::string::npos ? end + 1 : std::string::npos);
- bool found = false;
- STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
- for (int i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
- SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);
- const char *cname = SSL_CIPHER_get_name(c);
- if (cipher.compare(cname)) {
- found = true;
- break;
- }
- }
- if (!found) {
- debugs(83, 5, "Client Hello Data supports cipher '"<< cipher <<"' but we do not support it!");
- return false;
- }
- }
-
#if !defined(SSL_TLSEXT_HB_ENABLED)
- if (features.doHeartBeats) {
+ if (details->doHeartBeats) {
debugs(83, 5, "Client Hello Data supports HeartBeats but we do not support!");
return false;
}
#endif
- for (std::list::iterator it = features.extensions.begin(); it != features.extensions.end(); ++it) {
- static int supportedExtensions[] = {
-#if defined(TLSEXT_TYPE_server_name)
- TLSEXT_TYPE_server_name,
-#endif
-#if defined(TLSEXT_TYPE_opaque_prf_input)
- TLSEXT_TYPE_opaque_prf_input,
-#endif
-#if defined(TLSEXT_TYPE_heartbeat)
- TLSEXT_TYPE_heartbeat,
-#endif
+ if (details->unsupportedExtensions) {
+ debugs(83, 5, "Client Hello contains extensions that we do not support!");
+ return false;
+ }
+
+ SSL3_BUFFER *wb=&(ssl->s3->wbuf);
+ if (wb->len < (size_t)helloMessage.length()) {
+ debugs(83, 5, "Client Hello exceeds OpenSSL buffer: " << helloMessage.length() << " >= " << wb->len);
+ return false;
+ }
+
+ /* Check whether all on-the-wire ciphers are supported by OpenSSL. */
+
+ const auto &wireCiphers = details->ciphers;
+ Security::TlsDetails::Ciphers::size_type ciphersToFind = wireCiphers.size();
+
+ // RFC 5746: "TLS_EMPTY_RENEGOTIATION_INFO_SCSV is not a true cipher suite".
+ // It is commonly seen on the wire, including in from-OpenSSL traffic, but
+ // SSL_get_ciphers() does not return this _pseudo_ cipher suite in my tests.
+ // If OpenSSL supports scsvCipher, we count it (at most once) further below.
#if defined(TLSEXT_TYPE_renegotiate)
- TLSEXT_TYPE_renegotiate,
-#endif
-#if defined(TLSEXT_TYPE_ec_point_formats)
- TLSEXT_TYPE_ec_point_formats,
-#endif
-#if defined(TLSEXT_TYPE_elliptic_curves)
- TLSEXT_TYPE_elliptic_curves,
-#endif
-#if defined(TLSEXT_TYPE_session_ticket)
- TLSEXT_TYPE_session_ticket,
-#endif
-#if defined(TLSEXT_TYPE_status_request)
- TLSEXT_TYPE_status_request,
-#endif
-#if defined(TLSEXT_TYPE_use_srtp)
- TLSEXT_TYPE_use_srtp,
-#endif
-#if 0 //Allow 13172 Firefox supported extension for testing purposes
- 13172,
+ // the 0x00FFFF mask converts 3-byte OpenSSL cipher to our 2-byte cipher
+ const uint16_t scsvCipher = SSL3_CK_SCSV & 0x00FFFF;
+#else
+ const uint16_t scsvCipher = 0;
#endif
- -1
- };
- bool found = false;
- for (int i = 0; supportedExtensions[i] != -1; i++) {
- if (*it == supportedExtensions[i]) {
- found = true;
- break;
- }
- }
- if (!found) {
- debugs(83, 5, "Extension " << *it << " does not supported!");
- return false;
- }
+
+ STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
+ const int supportedCipherCount = sk_SSL_CIPHER_num(cipher_stack);
+ for (int idx = 0; idx < supportedCipherCount && ciphersToFind > 0; ++idx) {
+ const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, idx);
+ const auto id = SSL_CIPHER_get_id(cipher) & 0x00FFFF;
+ if (wireCiphers.find(id) != wireCiphers.end() && (!scsvCipher || id != scsvCipher))
+ --ciphersToFind;
}
- SSL3_BUFFER *wb=&(ssl->s3->wbuf);
- if (wb->len < (size_t)features.helloMessage.length())
+ if (ciphersToFind > 0 && scsvCipher && wireCiphers.find(scsvCipher) != wireCiphers.end())
+ --ciphersToFind;
+
+ if (ciphersToFind > 0) {
+ // TODO: Add slowlyReportUnsupportedCiphers() to slowly find and report each of them
+ debugs(83, 5, "Client Hello Data has " << ciphersToFind << " ciphers that we do not support!");
return false;
+ }
debugs(83, 5, "OpenSSL SSL struct will be adjusted to mimic client hello data!");
//Adjust ssl structure data.
// We need to fix the random in SSL struct:
- memcpy(ssl->s3->client_random, features.client_random, SSL3_RANDOM_SIZE);
- memcpy(wb->buf, features.helloMessage.rawContent(), features.helloMessage.length());
- wb->left = features.helloMessage.length();
+ if (details->clientRandom.length() == SSL3_RANDOM_SIZE)
+ memcpy(ssl->s3->client_random, details->clientRandom.c_str(), SSL3_RANDOM_SIZE);
+ memcpy(wb->buf, helloMessage.rawContent(), helloMessage.length());
+ wb->left = helloMessage.length();
- size_t mainHelloSize = features.helloMessage.length() - 5;
- const char *mainHello = features.helloMessage.rawContent() + 5;
+ size_t mainHelloSize = helloMessage.length() - 5;
+ const char *mainHello = helloMessage.rawContent() + 5;
assert((size_t)ssl->init_buf->max > mainHelloSize);
memcpy(ssl->init_buf->data, mainHello, mainHelloSize);
debugs(83, 5, "Hello Data init and adjustd sizes :" << ssl->init_num << " = "<< mainHelloSize);
@@ -426,7 +414,7 @@
{
if (holdWrite_) {
- debugs(83, 7, "Hold write, for SSL connection on " << fd_ << "will not write bytes of size " << size);
+ debugs(83, 7, "postpone writing " << size << " bytes to SSL FD " << fd_);
BIO_set_retry_write(table);
return -1;
}
@@ -441,18 +429,18 @@
assert(helloMsg.isEmpty());
auto ssl = fd_table[fd_].ssl.get();
- if (clientFeatures.initialized_ && ssl) {
+ if (ssl) {
if (bumpMode_ == Ssl::bumpPeek) {
- if (adjustSSL(ssl, clientFeatures))
+ if (adjustSSL(ssl, clientTlsDetails, clientHelloMessage))
allowBump = true;
allowSplice = true;
- helloMsg.append(clientFeatures.helloMessage);
+ helloMsg.append(clientHelloMessage);
debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for peek mode");
} else { /*Ssl::bumpStare*/
allowBump = true;
- if (adjustSSL(ssl, clientFeatures)) {
+ if (adjustSSL(ssl, clientTlsDetails, clientHelloMessage)) {
allowSplice = true;
- helloMsg.append(clientFeatures.helloMessage);
+ helloMsg.append(clientHelloMessage);
debugs(83, 7, "SSL HELLO message for FD " << fd_ << ": Random number is adjusted for stare mode");
}
}
@@ -502,26 +490,10 @@
}
}
-void
-Ssl::ServerBio::extractHelloFeatures()
-{
- if (!receivedHelloFeatures_.initialized_)
- receivedHelloFeatures_.get(rbuf, false);
-}
-
bool
Ssl::ServerBio::resumingSession()
{
- extractHelloFeatures();
-
- if (!clientFeatures.sessionId.isEmpty() && !receivedHelloFeatures_.sessionId.isEmpty())
- return clientFeatures.sessionId == receivedHelloFeatures_.sessionId;
-
- // is this a session resuming attempt using TLS tickets?
- if (clientFeatures.hasTlsTicket && receivedHelloFeatures_.hasCcsOrNst)
- return true;
-
- return false;
+ return parser_.resumingSession;
}
/// initializes BIO table after allocation
@@ -643,556 +615,60 @@
}
}
-Ssl::Bio::sslFeatures::sslFeatures():
- sslHelloVersion(-1),
- sslVersion(-1),
- compressMethod(-1),
- helloMsgSize(0),
- unknownCiphers(false),
- doHeartBeats(true),
- tlsTicketsExtension(false),
- hasTlsTicket(false),
- tlsStatusRequest(false),
- hasCcsOrNst(false),
- initialized_(false)
-{
- memset(client_random, 0, SSL3_RANDOM_SIZE);
-}
-
-int Ssl::Bio::sslFeatures::toSquidSSLVersion() const
-{
- if (sslVersion == SSL2_VERSION)
- return 2;
- else if (sslVersion == SSL3_VERSION)
- return 3;
- else if (sslVersion == TLS1_VERSION)
- return 4;
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
- else if (sslVersion == TLS1_1_VERSION)
- return 5;
- else if (sslVersion == TLS1_2_VERSION)
- return 6;
-#endif
- else
- return 1;
-}
-
-bool
-Ssl::Bio::sslFeatures::get(const SSL *ssl)
+void
+applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode)
{
- sslVersion = SSL_version(ssl);
- debugs(83, 7, "SSL version: " << SSL_get_version(ssl) << " (" << sslVersion << ")");
-
+ // To increase the possibility for bumping after peek mode selection or
+ // splicing after stare mode selection it is good to set the
+ // SSL protocol version.
+ // The SSL_set_ssl_method is wrong here because it will restrict the
+ // permitted transport version to be identical to the version used in the
+ // ClientHello message.
+ // For example will prevent comunnicating with a tls1.0 server if the
+ // client sent and tlsv1.2 Hello message.
#if defined(TLSEXT_NAMETYPE_host_name)
- if (const char *server = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))
- serverName = server;
- debugs(83, 7, "SNI server name: " << serverName);
-#endif
-
-#if !defined(OPENSSL_NO_COMP)
- if (ssl->session->compress_meth)
- compressMethod = ssl->session->compress_meth;
- else if (sslVersion >= 3) //if it is 3 or newer version then compression is disabled
-#endif
- compressMethod = 0;
- debugs(83, 7, "SSL compression: " << compressMethod);
-
- STACK_OF(SSL_CIPHER) * ciphers = NULL;
- if (ssl->server)
- ciphers = ssl->session->ciphers;
- else
- ciphers = ssl->cipher_list;
- if (ciphers) {
- for (int i = 0; i < sk_SSL_CIPHER_num(ciphers); ++i) {
- SSL_CIPHER *c = sk_SSL_CIPHER_value(ciphers, i);
- if (c != NULL) {
- if (!clientRequestedCiphers.empty())
- clientRequestedCiphers.append(":");
- clientRequestedCiphers.append(c->name);
- }
- }
- }
- debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
-
- if (sslVersion >=3 && ssl->s3 && ssl->s3->client_random[0]) {
- memcpy(client_random, ssl->s3->client_random, SSL3_RANDOM_SIZE);
- }
-
-#if 0 /* XXX: OpenSSL 0.9.8k lacks at least some of these tlsext_* fields */
- //The following extracted for logging purpuses:
- // TLSEXT_TYPE_ec_point_formats
- unsigned char *p;
- int len;
- if (ssl->server) {
- p = ssl->session->tlsext_ecpointformatlist;
- len = ssl->session->tlsext_ecpointformatlist_length;
- } else {
- p = ssl->tlsext_ecpointformatlist;
- len = ssl->tlsext_ecpointformatlist_length;
- }
- if (p) {
- ecPointFormatList = objToString(p, len);
- debugs(83, 7, "tlsExtension ecPointFormatList of length " << len << " :" << ecPointFormatList);
- }
-
- // TLSEXT_TYPE_elliptic_curves
- if (ssl->server) {
- p = ssl->session->tlsext_ellipticcurvelist;
- len = ssl->session->tlsext_ellipticcurvelist_length;
- } else {
- p = ssl->tlsext_ellipticcurvelist;
- len = ssl->tlsext_ellipticcurvelist_length;
- }
- if (p) {
- ellipticCurves = objToString(p, len);
- debugs(83, 7, "tlsExtension ellipticCurveList of length " << len <<" :" << ellipticCurves);
- }
- // TLSEXT_TYPE_opaque_prf_input
- p = NULL;
- if (ssl->server) {
- if (ssl->s3 && ssl->s3->client_opaque_prf_input) {
- p = (unsigned char *)ssl->s3->client_opaque_prf_input;
- len = ssl->s3->client_opaque_prf_input_len;
- }
- } else {
- p = (unsigned char *)ssl->tlsext_opaque_prf_input;
- len = ssl->tlsext_opaque_prf_input_len;
- }
- if (p) {
- debugs(83, 7, "tlsExtension client-opaque-prf-input of length " << len);
- opaquePrf = objToString(p, len);
+ if (!details->serverName.isEmpty()) {
+ SSL_set_tlsext_host_name(ssl, details->serverName.c_str());
}
#endif
- initialized_ = true;
- return true;
-}
-
-int
-Ssl::Bio::sslFeatures::parseMsgHead(const MemBuf &buf)
-{
- const unsigned char *head = (const unsigned char *)buf.content();
- const char *s = objToString(head, buf.contentSize());
- debugs(83, 7, "SSL Header: " << s);
- if (buf.contentSize() < 5)
- return 0;
-
- if (helloMsgSize > 0)
- return helloMsgSize;
-
- // Check for SSLPlaintext/TLSPlaintext record
- // RFC6101 section 5.2.1
- // RFC5246 section 6.2.1
- if (head[0] == 0x16) {
- debugs(83, 7, "SSL version 3 handshake message");
- // The SSL version exist in the 2nd and 3rd bytes
- sslHelloVersion = (head[1] << 8) | head[2];
- debugs(83, 7, "SSL Version :" << std::hex << std::setw(8) << std::setfill('0') << sslVersion);
- // The hello message size exist in 4th and 5th bytes
- helloMsgSize = (head[3] << 8) + head[4];
- debugs(83, 7, "SSL Header Size: " << helloMsgSize);
- helloMsgSize +=5;
- } else if ((head[0] & 0x80) && head[2] == 0x01 && head[3] == 0x03) {
- debugs(83, 7, "SSL version 2 handshake message with v3 support");
- sslHelloVersion = 0x0002;
- debugs(83, 7, "SSL Version :" << std::hex << std::setw(8) << std::setfill('0') << sslVersion);
- // The hello message size exist in 2nd byte
- helloMsgSize = head[1];
- helloMsgSize +=2;
- } else {
- debugs(83, 7, "Not an SSL acceptable handshake message (SSLv2 message?)");
- return (helloMsgSize = -1);
- }
-
- // Set object as initialized. Even if we did not full parsing yet
- // The basic features, like the SSL version is set
- initialized_ = true;
- return helloMsgSize;
-}
-
-bool
-Ssl::Bio::sslFeatures::checkForCcsOrNst(const unsigned char *msg, size_t size)
-{
- while (size > 5) {
- const int msgType = msg[0];
- const int msgSslVersion = (msg[1] << 8) | msg[2];
- debugs(83, 7, "SSL Message Version :" << std::hex << std::setw(8) << std::setfill('0') << msgSslVersion);
- // Check for Change Cipher Spec message
- // RFC5246 section 6.2.1
- if (msgType == 0x14) {// Change Cipher Spec message found
- debugs(83, 7, "SSL Change Cipher Spec message found");
- return true;
- }
- // Check for New Session Ticket message
- // RFC5077 section 3.3
- if (msgType == 0x04) {// New Session Ticket message found
- debugs(83, 7, "TLS New Session Ticket message found");
- return true;
- }
- // The hello message size exist in 4th and 5th bytes
- size_t msgLength = (msg[3] << 8) + msg[4];
- debugs(83, 7, "SSL Message Size: " << msgLength);
- msgLength += 5;
-
- if (msgLength <= size) {
- msg += msgLength;
- size -= msgLength;
- } else
- size = 0;
- }
- return false;
-}
-
-bool
-Ssl::Bio::sslFeatures::get(const MemBuf &buf, bool record)
-{
- int msgSize;
- if ((msgSize = parseMsgHead(buf)) <= 0) {
- debugs(83, 7, "Not a known SSL handshake message");
- return false;
- }
-
- if (msgSize > buf.contentSize()) {
- debugs(83, 2, "Partial SSL handshake message, can not parse!");
- return false;
- }
-
- if (record) {
- helloMessage.clear();
- helloMessage.append(buf.content(), buf.contentSize());
- }
-
- const unsigned char *msg = (const unsigned char *)buf.content();
- if (msg[0] & 0x80)
- return parseV23Hello(msg, (size_t)msgSize);
- else {
- // Hello messages require 5 bytes header + 1 byte Msg type + 3 bytes for Msg size
- if (buf.contentSize() < 9)
- return false;
-
- // Check for the Handshake/Message type
- // The type 2 is a ServerHello, the type 1 is a ClientHello
- // RFC5246 section 7.4
- if (msg[5] == 0x2) { // ServerHello message
- if (parseV3ServerHello(msg, (size_t)msgSize)) {
- hasCcsOrNst = checkForCcsOrNst(msg + msgSize, buf.contentSize() - msgSize);
- return true;
- }
- } else if (msg[5] == 0x1) // ClientHello message,
- return parseV3Hello(msg, (size_t)msgSize);
- }
-
- return false;
-}
-bool
-Ssl::Bio::sslFeatures::parseV3ServerHello(const unsigned char *messageContainer, size_t messageContainerSize)
-{
- // Parse a ServerHello Handshake message
- // RFC5246 section 7.4, 7.4.1.3
- // The ServerHello starts at messageContainer + 5
- const unsigned char *serverHello = messageContainer + 5;
-
- // The Length field (bytes 1-3) plus 4 bytes of the serverHello message header (1 handshake type + 3 hello length)
- const size_t helloSize = ((serverHello[1] << 16) | (serverHello[2] << 8) | serverHello[3]) + 4;
- debugs(83, 7, "ServerHello message size: " << helloSize);
- if (helloSize > messageContainerSize) {
- debugs(83, 2, "ServerHello parse error");
- return false;
- }
-
- // helloSize should be at least 38 bytes long:
- // (SSL Version + Random + SessionId Length + Cipher Suite + Compression Method)
- if (helloSize < 38) {
- debugs(83, 2, "Too short ServerHello message");
- return false;
- }
-
- debugs(83, 7, "Get fake features from v3 ServerHello message.");
- // Get the correct version of the sub-hello message
- sslVersion = (serverHello[4] << 8) | serverHello[5];
- // At the position 38 (HelloHeader (6bytes) + SSL3_RANDOM_SIZE (32bytes))
- const size_t sessIdLen = static_cast(serverHello[38]);
- debugs(83, 7, "Session ID Length: " << sessIdLen);
-
- // The size should be enough to hold at least the following
- // 4 (hello header)
- // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
- // + sessIdLength + 2 (cipher suite) + 1 (compression method)
- // = 42 + sessIdLength
- if (42 + sessIdLen > helloSize) {
- debugs(83, 2, "ciphers length parse error");
- return false;
- }
-
- // The sessionID stored at 39 position, after sessionID length field
- sessionId.assign(reinterpret_cast(serverHello + 39), sessIdLen);
-
- // Check if there are extensions in hello message
- // RFC5246 section 7.4.1.4
- if (helloSize > 42 + sessIdLen + 2) {
- // 42 + sessIdLen
- const unsigned char *pToExtensions = serverHello + 42 + sessIdLen;
- const size_t extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
- // Check if the hello size can hold extensions
- if (42 + 2 + sessIdLen + extensionsLen > helloSize ) {
- debugs(83, 2, "Extensions length parse error");
- return false;
- }
-
- pToExtensions += 2;
- const unsigned char *ext = pToExtensions;
- while (ext + 4 <= pToExtensions + extensionsLen) {
- const size_t extType = (ext[0] << 8) | ext[1];
- ext += 2;
- const size_t extLen = (ext[0] << 8) | ext[1];
- ext += 2;
- debugs(83, 7, "TLS Extension: " << std::hex << extType << " of size:" << extLen);
- // SessionTicket TLS Extension, RFC5077 section 3.2
- if (extType == 0x23) {
- tlsTicketsExtension = true;
- }
- ext += extLen;
- }
- }
- return true;
-}
-
-bool
-Ssl::Bio::sslFeatures::parseV3Hello(const unsigned char *messageContainer, size_t messageContainerSize)
-{
- // Parse a ClientHello Handshake message
- // RFC5246 section 7.4, 7.4.1.2
- // The ClientHello starts at messageContainer + 5
- const unsigned char * clientHello = messageContainer + 5;
-
- debugs(83, 7, "Get fake features from v3 ClientHello message.");
- // The Length field (bytes 1-3) plus 4 bytes of the clientHello message header (1 handshake type + 3 hello length)
- const size_t helloSize = ((clientHello[1] << 16) | (clientHello[2] << 8) | clientHello[3]) + 4;
- debugs(83, 7, "ClientHello message size: " << helloSize);
- if (helloSize > messageContainerSize) {
- debugs(83, 2, "ClientHello parse error");
- return false;
- }
-
- // helloSize should be at least 38 bytes long:
- // (SSL Version(2) + Random(32) + SessionId Length(1) + Cipher Suite Length(2) + Compression Method Length(1))
- if (helloSize < 38) {
- debugs(83, 2, "Too short ClientHello message");
- return false;
- }
-
- //For SSLv3 or TLSv1.* protocols we can get some more informations
- if (messageContainer[1] != 0x3 || clientHello[0] != 0x1 /*HELLO A message*/) {
- debugs(83, 2, "Not an SSLv3/TLSv1.x client hello message, stop parsing here");
- return true;
- }
-
- // Get the correct version of the sub-hello message
- sslVersion = (clientHello[4] << 8) | clientHello[5];
- //Get Client Random number. It starts on the position 6 of clientHello message
- memcpy(client_random, clientHello + 6, SSL3_RANDOM_SIZE);
- debugs(83, 7, "Client random: " << objToString(client_random, SSL3_RANDOM_SIZE));
-
- // At the position 38 (6+SSL3_RANDOM_SIZE)
- const size_t sessIDLen = static_cast(clientHello[38]);
- debugs(83, 7, "Session ID Length: " << sessIDLen);
-
- // The helloSize should be enough to hold at least the following
- // 1 handshake type + 3 hello Length
- // + 2 (SSL Version) + 32 (random) + 1 (sessionId length)
- // + sessIdLength + 2 (cipher suite length) + 1 (compression method length)
- // = 42 + sessIdLength
- if (42 + sessIDLen > helloSize) {
- debugs(83, 2, "Session ID length parse error");
- return false;
- }
-
- // The sessionID stored art 39 position, after sessionID length field
- sessionId.assign(reinterpret_cast(clientHello + 39), sessIDLen);
-
- //Ciphers list. It is stored after the Session ID.
- // It is a variable-length vector(RFC5246 section 4.3)
- const unsigned char *ciphers = clientHello + 39 + sessIDLen;
- const size_t ciphersLen = (ciphers[0] << 8) | ciphers[1];
- if (42 + sessIDLen + ciphersLen > helloSize) {
- debugs(83, 2, "ciphers length parse error");
- return false;
- }
-
- ciphers += 2;
- if (ciphersLen) {
+ if (!details->ciphers.empty()) {
+ SBuf strCiphers;
+ for (auto cipherId: details->ciphers) {
+ unsigned char cbytes[3];
+ cbytes[0] = (cipherId >> 8) & 0xFF;
+ cbytes[1] = cipherId & 0xFF;
+ cbytes[2] = 0;
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- const SSL_METHOD *method = TLS_method();
+ const SSL_METHOD *method = TLS_method();
#else
- const SSL_METHOD *method = SSLv23_method();
+ const SSL_METHOD *method = SSLv23_method();
#endif
- for (size_t i = 0; i < ciphersLen; i += 2) {
- // each cipher in v3/tls HELLO message is of size 2
- const SSL_CIPHER *c = method->get_cipher_by_char((ciphers + i));
+ const SSL_CIPHER *c = method->get_cipher_by_char(cbytes);
if (c != NULL) {
- if (!clientRequestedCiphers.empty())
- clientRequestedCiphers.append(":");
- clientRequestedCiphers.append(c->name);
- } else
- unknownCiphers = true;
- }
- }
- debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
-
- // Compression field: 1 bytes the number of compression methods and
- // 1 byte for each compression method
- const unsigned char *compression = ciphers + ciphersLen;
- if (compression[0] > 1)
- compressMethod = 1;
- else
- compressMethod = 0;
- debugs(83, 7, "SSL compression methods number: " << static_cast(compression[0]));
-
- // Parse Extensions, RFC5246 section 7.4.1.4
- const unsigned char *pToExtensions = compression + 1 + static_cast(compression[0]);
- if ((size_t)((pToExtensions - clientHello) + 2) < helloSize) {
- const size_t extensionsLen = (pToExtensions[0] << 8) | pToExtensions[1];
- if ((pToExtensions - clientHello) + 2 + extensionsLen > helloSize) {
- debugs(83, 2, "Extensions length parse error");
- return false;
- }
-
- pToExtensions += 2;
- const unsigned char *ext = pToExtensions;
- while (ext + 4 <= pToExtensions + extensionsLen) {
- const size_t extType = (ext[0] << 8) | ext[1];
- ext += 2;
- const size_t extLen = (ext[0] << 8) | ext[1];
- ext += 2;
- debugs(83, 7, "TLS Extension: " << std::hex << extType << " of size:" << extLen);
-
- if (ext + extLen > pToExtensions + extensionsLen) {
- debugs(83, 2, "Extension " << std::hex << extType << " length parser error");
- return false;
+ if (!strCiphers.isEmpty())
+ strCiphers.append(":");
+ strCiphers.append(c->name);
}
-
- //The SNI extension has the type 0 (extType == 0)
- // RFC6066 sections 3, 10.2
- // The two first bytes indicates the length of the SNI data (should be extLen-2)
- // The next byte is the hostname type, it should be '0' for normal hostname (ext[2] == 0)
- // The 3rd and 4th bytes are the length of the hostname
- if (extType == 0 && ext[2] == 0) {
- const size_t hostLen = (ext[3] << 8) | ext[4];
- if (hostLen < extLen)
- serverName.assign(reinterpret_cast(ext+5), hostLen);
- debugs(83, 7, "Found server name: " << serverName);
- } else if (extType == 15 && ext[0] != 0) {
- // The heartBeats are the type 15, RFC6520
- doHeartBeats = true;
- } else if (extType == 0x23) {
- //SessionTicket TLS Extension RFC5077
- tlsTicketsExtension = true;
- if (extLen != 0)
- hasTlsTicket = true;
- } else if (extType == 0x05) {
- // RFC6066 sections 8, 10.2
- tlsStatusRequest = true;
- } else if (extType == 0x3374) {
- // detected TLS next protocol negotiate extension
- } else if (extType == 0x10) {
- // Application-Layer Protocol Negotiation Extension, RFC7301
- const size_t listLen = (ext[0] << 8) | ext[1];
- if (listLen < extLen)
- tlsAppLayerProtoNeg.assign(reinterpret_cast(ext+5), listLen);
- } else
- extensions.push_back(extType);
-
- ext += extLen;
}
+ if (!strCiphers.isEmpty())
+ SSL_set_cipher_list(ssl, strCiphers.c_str());
}
- return true;
-}
-bool
-Ssl::Bio::sslFeatures::parseV23Hello(const unsigned char *hello, size_t size)
-{
- debugs(83, 7, "Get fake features from v23 ClientHello message.");
- if (size < 7)
- return false;
-
- // Get the SSL/TLS version supported by client
- sslVersion = (hello[3] << 8) | hello[4];
-
- //Ciphers list. It is stored after the Session ID.
- const unsigned int ciphersLen = (hello[5] << 8) | hello[6];
- const unsigned char *ciphers = hello + 11;
-
- if (size < ciphersLen + 11)
- return false;
-
- if (ciphersLen) {
-#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- const SSL_METHOD *method = TLS_method();
-#else
- const SSL_METHOD *method = SSLv23_method();
-#endif
- for (unsigned int i = 0; i < ciphersLen; i += 3) {
- // The v2 hello messages cipher has 3 bytes.
- // The v2 cipher has the first byte not null
- // Because we are going to sent only v3 message we
- // are ignoring these ciphers
- if (ciphers[i] != 0)
- continue;
- const SSL_CIPHER *c = method->get_cipher_by_char((ciphers + i + 1));
- if (c != NULL) {
- if (!clientRequestedCiphers.empty())
- clientRequestedCiphers.append(":");
- clientRequestedCiphers.append(c->name);
- }
- }
- }
- debugs(83, 7, "Ciphers requested by client: " << clientRequestedCiphers);
-
- const unsigned int sessionIdLength = (hello[7] << 8) | hello[8];
- debugs(83, 7, "SessionID length: " << sessionIdLength);
- // SessionID starts at: hello+11+ciphersLen
- if (sessionIdLength)
- sessionId.assign((const char *)(hello + 11 + ciphersLen), sessionIdLength);
-
- const unsigned int challengeLength = (hello[5] << 9) | hello[10];
- debugs(83, 7, "Challenge Length: " << challengeLength);
- //challenge starts at: hello+11+ciphersLen+sessionIdLength
-
- compressMethod = 0;
- return true;
-}
-
-void
-Ssl::Bio::sslFeatures::applyToSSL(SSL *ssl, Ssl::BumpMode bumpMode) const
-{
- // To increase the possibility for bumping after peek mode selection or
- // splicing after stare mode selection it is good to set the
- // SSL protocol version.
- // The SSL_set_ssl_method is not the correct method because it will strict
- // SSL version which can be used to the SSL version used for client hello message.
- // For example will prevent comunnicating with a tls1.0 server if the
- // client sent and tlsv1.2 Hello message.
-#if defined(TLSEXT_NAMETYPE_host_name)
- if (!serverName.isEmpty()) {
- SSL_set_tlsext_host_name(ssl, serverName.c_str());
- }
-#endif
- if (!clientRequestedCiphers.empty())
- SSL_set_cipher_list(ssl, clientRequestedCiphers.c_str());
#if defined(SSL_OP_NO_COMPRESSION) /* XXX: OpenSSL 0.9.8k lacks SSL_OP_NO_COMPRESSION */
- if (compressMethod == 0)
+ if (!details->compressionSupported)
SSL_set_options(ssl, SSL_OP_NO_COMPRESSION);
#endif
#if defined(TLSEXT_STATUSTYPE_ocsp)
- if (tlsStatusRequest)
+ if (details->tlsStatusRequest)
SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
#endif
#if defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
- if (!tlsAppLayerProtoNeg.isEmpty()) {
+ if (!details->tlsAppLayerProtoNeg.isEmpty()) {
if (bumpMode == Ssl::bumpPeek)
- SSL_set_alpn_protos(ssl, (const unsigned char*)tlsAppLayerProtoNeg.rawContent(), tlsAppLayerProtoNeg.length());
+ SSL_set_alpn_protos(ssl, (const unsigned char*)details->tlsAppLayerProtoNeg.rawContent(), details->tlsAppLayerProtoNeg.length());
else {
static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
SSL_set_alpn_protos(ssl, supported_protos, sizeof(supported_protos));
@@ -1201,20 +677,5 @@
#endif
}
-std::ostream &
-Ssl::Bio::sslFeatures::print(std::ostream &os) const
-{
- static std::string buf;
- // TODO: Also print missing features like the HeartBeats and AppLayerProtoNeg
- return os << "v" << sslVersion <<
- " SNI:" << (serverName.isEmpty() ? SBuf("-") : serverName) <<
- " comp:" << compressMethod <<
- " Ciphers:" << clientRequestedCiphers <<
- " Random:" << objToString(client_random, SSL3_RANDOM_SIZE) <<
- " ecPointFormats:" << ecPointFormatList <<
- " ec:" << ellipticCurves <<
- " opaquePrf:" << opaquePrf;
-}
-
-#endif /* USE_SSL */
+#endif // USE_OPENSSL
diff -u -r -N squid-4.0.10/src/ssl/bio.h squid-4.0.11/src/ssl/bio.h
--- squid-4.0.10/src/ssl/bio.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/ssl/bio.h 2016-06-10 08:32:57.000000000 +1200
@@ -10,7 +10,7 @@
#define SQUID_SSL_BIO_H
#include "fd.h"
-#include "sbuf/SBuf.h"
+#include "security/Handshake.h"
#include
#include
@@ -18,6 +18,7 @@
#include
#endif
#include
+#include
namespace Ssl
{
@@ -31,61 +32,6 @@
BIO_TO_SERVER
};
- /// Class to store SSL connection features
- class sslFeatures
- {
- public:
- sslFeatures();
- bool get(const SSL *ssl); ///< Retrieves the features from SSL object
- /// Retrieves features from raw SSL Hello message.
- /// \param record whether to store Message to the helloMessage member
- bool get(const MemBuf &, bool record = true);
- /// Parses a v3 ClientHello message
- bool parseV3Hello(const unsigned char *hello, size_t helloSize);
- /// Parses a v23 ClientHello message
- bool parseV23Hello(const unsigned char *hello, size_t helloSize);
- /// Parses a v3 ServerHello message.
- bool parseV3ServerHello(const unsigned char *hello, size_t helloSize);
- /// Prints to os stream a human readable form of sslFeatures object
- std::ostream & print(std::ostream &os) const;
- /// Converts to the internal squid SSL version form the sslVersion
- int toSquidSSLVersion() const;
- /// Configure the SSL object with the SSL features of the sslFeatures object
- void applyToSSL(SSL *ssl, Ssl::BumpMode bumpMode) const;
- /// Parses an SSL Message header. It returns the ssl Message size.
- /// \retval >0 if the hello size is retrieved
- /// \retval 0 if the contents of the buffer are not enough
- /// \retval <0 if the contents of buf are not SSLv3 or TLS hello message
- int parseMsgHead(const MemBuf &);
- /// Parses msg buffer and return true if one of the Change Cipher Spec
- /// or New Session Ticket messages found
- bool checkForCcsOrNst(const unsigned char *msg, size_t size);
- public:
- int sslHelloVersion; ///< The SSL hello message version
- int sslVersion; ///< The requested/used SSL version
- int compressMethod; ///< The requested/used compressed method
- int helloMsgSize; ///< the hello message size
- mutable SBuf serverName; ///< The SNI hostname, if any
- std::string clientRequestedCiphers; ///< The client requested ciphers
- bool unknownCiphers; ///< True if one or more ciphers are unknown
- std::string ecPointFormatList;///< tlsExtension ecPointFormatList
- std::string ellipticCurves; ///< tlsExtension ellipticCurveList
- std::string opaquePrf; ///< tlsExtension opaquePrf
- bool doHeartBeats;
- bool tlsTicketsExtension; ///< whether TLS tickets extension is enabled
- bool hasTlsTicket; ///< whether a TLS ticket is included
- bool tlsStatusRequest; ///< whether the TLS status request extension is set
- SBuf tlsAppLayerProtoNeg; ///< The value of the TLS application layer protocol extension if it is enabled
- /// whether Change Cipher Spec message included in ServerHello
- /// handshake message
- bool hasCcsOrNst;
- /// The client random number
- unsigned char client_random[SSL3_RANDOM_SIZE];
- SBuf sessionId;
- std::list extensions;
- SBuf helloMessage;
- bool initialized_;
- };
explicit Bio(const int anFd);
virtual ~Bio();
@@ -111,21 +57,10 @@
/// Tells ssl connection to use BIO and monitor state via stateChanged()
static void Link(SSL *ssl, BIO *bio);
- /// Prepare the rbuf buffer to accept hello data
- void prepReadBuf();
-
- /// Reads data from socket and record them to a buffer
- int readAndBuffer(char *buf, int size, BIO *table, const char *description);
-
- /// Return the TLS features requested by TLS client
- const Bio::sslFeatures &receivedHelloFeatures() const {return receivedHelloFeatures_;}
-
- const MemBuf &rBufData() {return rbuf;}
+ const SBuf &rBufData() {return rbuf;} ///< The buffered input data
protected:
const int fd_; ///< the SSL socket we are reading and writing
- MemBuf rbuf; ///< Used to buffer input data.
- /// The features retrieved from client or Server TLS hello message
- Bio::sslFeatures receivedHelloFeatures_;
+ SBuf rbuf; ///< Used to buffer input data.
};
/// BIO node to handle socket IO for squid client side
@@ -134,9 +69,7 @@
class ClientBio: public Bio
{
public:
- /// The ssl hello message read states
- typedef enum {atHelloNone = 0, atHelloStarted, atHelloReceived} HelloReadState;
- explicit ClientBio(const int anFd): Bio(anFd), holdRead_(false), holdWrite_(false), helloState(atHelloNone), helloSize(0), wrongProtocol(false) {}
+ explicit ClientBio(const int anFd): Bio(anFd), holdRead_(false), holdWrite_(false), helloSize(0) {}
/// The ClientBio version of the Ssl::Bio::stateChanged method
/// When the client hello message retrieved, fill the
@@ -148,20 +81,19 @@
/// If the holdRead flag is true then it does not write any data
/// to socket and sets the "read retry" flag of the BIO to true
virtual int read(char *buf, int size, BIO *table);
- /// Return true if the client hello message received and analized
- bool gotHello() { return (helloState == atHelloReceived); }
/// Prevents or allow writting on socket.
void hold(bool h) {holdRead_ = holdWrite_ = h;}
- /// True if client does not looks like an SSL client
- bool noSslClient() {return wrongProtocol;}
+
+ /// Sets the buffered input data (Bio::rbuf).
+ /// Used to pass payload data (normally client HELLO data) retrieved
+ /// by the caller.
+ void setReadBufData(SBuf &data) {rbuf = data;}
private:
/// True if the SSL state corresponds to a hello message
bool isClientHello(int state);
bool holdRead_; ///< The read hold state of the bio.
bool holdWrite_; ///< The write hold state of the bio.
- HelloReadState helloState; ///< The SSL hello read state
int helloSize; ///< The SSL hello message sent by client size
- bool wrongProtocol; ///< true if client SSL hello parsing failed
};
/// BIO node to handle socket IO for squid server side
@@ -182,7 +114,8 @@
class ServerBio: public Bio
{
public:
- explicit ServerBio(const int anFd): Bio(anFd), helloMsgSize(0), helloBuild(false), allowSplice(false), allowBump(false), holdWrite_(false), record_(false), bumpMode_(bumpNone) {}
+ explicit ServerBio(const int anFd);
+
/// The ServerBio version of the Ssl::Bio::stateChanged method
virtual void stateChanged(const SSL *ssl, int where, int ret);
/// The ServerBio version of the Ssl::Bio::write method
@@ -197,13 +130,10 @@
/// Flushes any buffered data
virtual void flush(BIO *table);
/// Sets the random number to use in client SSL HELLO message
- void setClientFeatures(const sslFeatures &features);
-
- /// Parses server Hello message if it is recorded and extracts
- /// server-supported features.
- void extractHelloFeatures();
+ void setClientFeatures(Security::TlsDetails::Pointer const &details, SBuf const &hello);
bool resumingSession();
+
/// The write hold state
bool holdWrite() const {return holdWrite_;}
/// Enables or disables the write hold state
@@ -217,8 +147,20 @@
/// The bumping mode
void mode(Ssl::BumpMode m) {bumpMode_ = m;}
Ssl::BumpMode bumpMode() {return bumpMode_;} ///< return the bumping mode
+
+ /// \return the TLS Details advertised by TLS server.
+ const Security::TlsDetails::Pointer &receivedHelloDetails() const {return parser_.details;}
+
private:
- sslFeatures clientFeatures; ///< SSL client features extracted from ClientHello message or SSL object
+ int readAndGive(char *buf, const int size, BIO *table);
+ int readAndParse(char *buf, const int size, BIO *table);
+ int readAndBuffer(BIO *table);
+ int giveBuffered(char *buf, const int size);
+
+ /// SSL client features extracted from ClientHello message or SSL object
+ Security::TlsDetails::Pointer clientTlsDetails;
+ /// TLS client hello message, used to adapt our tls Hello message to the server
+ SBuf clientHelloMessage;
SBuf helloMsg; ///< Used to buffer output data.
mb_size_t helloMsgSize;
bool helloBuild; ///< True if the client hello message sent to the server
@@ -226,16 +168,18 @@
bool allowBump; ///< True if the SSL stream can be bumped
bool holdWrite_; ///< The write hold state of the bio.
bool record_; ///< If true the input data recorded to rbuf for internal use
+ bool parsedHandshake; ///< whether we are done parsing TLS Hello
Ssl::BumpMode bumpMode_;
-};
-inline
-std::ostream &operator <<(std::ostream &os, Ssl::Bio::sslFeatures const &f)
-{
- return f.print(os);
-}
+ /// The size of data stored in rbuf which passed to the openSSL
+ size_t rbufConsumePos;
+ Security::HandshakeParser parser_; ///< The TLS/SSL messages parser.
+};
} // namespace Ssl
+void
+applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode);
+
#endif /* SQUID_SSL_BIO_H */
diff -u -r -N squid-4.0.10/src/ssl/PeekingPeerConnector.cc squid-4.0.11/src/ssl/PeekingPeerConnector.cc
--- squid-4.0.10/src/ssl/PeekingPeerConnector.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/ssl/PeekingPeerConnector.cc 2016-06-10 08:32:57.000000000 +1200
@@ -146,19 +146,13 @@
// or terminate client and server connections
assert(clientConn != NULL);
SBuf *hostName = NULL;
- Ssl::ClientBio *cltBio = NULL;
//Enable Status_request tls extension, required to bump some clients
SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp);
- // In server-first bumping mode, clientSsl is NULL.
- if (auto clientSsl = fd_table[clientConn->fd].ssl.get()) {
- BIO *b = SSL_get_rbio(clientSsl);
- cltBio = static_cast(b->ptr);
- const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
- if (!features.serverName.isEmpty())
- hostName = new SBuf(features.serverName);
- }
+ const Security::TlsDetails::Pointer details = csd->tlsParser.details;
+ if (details && !details->serverName.isEmpty())
+ hostName = new SBuf(details->serverName);
if (!hostName) {
// While we are peeking at the certificate, we may not know the server
@@ -174,16 +168,19 @@
Must(!csd->serverBump() || csd->serverBump()->step <= Ssl::bumpStep2);
if (csd->sslBumpMode == Ssl::bumpPeek || csd->sslBumpMode == Ssl::bumpStare) {
- assert(cltBio);
- const Ssl::Bio::sslFeatures &features = cltBio->receivedHelloFeatures();
- if (features.sslVersion != -1) {
- features.applyToSSL(ssl, csd->sslBumpMode);
+ auto clientSsl = fd_table[clientConn->fd].ssl.get();
+ Must(clientSsl);
+ BIO *bc = SSL_get_rbio(clientSsl);
+ Ssl::ClientBio *cltBio = static_cast(bc->ptr);
+ Must(cltBio);
+ if (details && details->tlsVersion.protocol != AnyP::PROTO_NONE) {
+ applyTlsDetailsToSSL(ssl, details, csd->sslBumpMode);
// Should we allow it for all protocols?
- if (features.sslVersion >= 3) {
+ if (details->tlsVersion.protocol == AnyP::PROTO_TLS || details->tlsVersion == AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0)) {
BIO *b = SSL_get_rbio(ssl);
Ssl::ServerBio *srvBio = static_cast(b->ptr);
// Inherite client features, like SSL version, SNI and other
- srvBio->setClientFeatures(features);
+ srvBio->setClientFeatures(details, cltBio->rBufData());
srvBio->recordInput(true);
srvBio->mode(csd->sslBumpMode);
}
@@ -254,14 +251,9 @@
}
}
- // retrieve TLS server information if any
- serverConnection()->tlsNegotiations()->fillWith(ssl);
if (!error) {
serverCertificateVerified();
if (splice) {
- //retrieved received TLS client informations
- auto clientSsl = fd_table[clientConn->fd].ssl.get();
- clientConn->tlsNegotiations()->fillWith(clientSsl);
switchToTunnel(request.getRaw(), clientConn, serverConn);
tunnelInsteadOfNegotiating();
}
@@ -277,7 +269,7 @@
Ssl::ServerBio *srvBio = static_cast(b->ptr);
if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
- debugs(81, DBG_IMPORTANT, "hold write on SSL connection on FD " << fd);
+ debugs(81, 3, "hold write on SSL connection on FD " << fd);
checkForPeekAndSplice();
return;
}
diff -u -r -N squid-4.0.10/src/ssl/PeerConnector.cc squid-4.0.11/src/ssl/PeerConnector.cc
--- squid-4.0.10/src/ssl/PeerConnector.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/ssl/PeerConnector.cc 2016-06-10 08:32:57.000000000 +1200
@@ -14,7 +14,9 @@
#include "errorpage.h"
#include "fde.h"
#include "HttpRequest.h"
+#include "security/NegotiationHistory.h"
#include "SquidConfig.h"
+#include "ssl/bio.h"
#include "ssl/cert_validate_message.h"
#include "ssl/Config.h"
#include "ssl/helper.h"
@@ -134,6 +136,21 @@
}
void
+Ssl::PeerConnector::recordNegotiationDetails()
+{
+ const int fd = serverConnection()->fd;
+ Security::SessionPtr ssl = fd_table[fd].ssl.get();
+
+ // retrieve TLS server negotiated information if any
+ serverConnection()->tlsNegotiations()->retrieveNegotiatedInfo(ssl);
+ // retrieve TLS parsed extra info
+ BIO *b = SSL_get_rbio(ssl);
+ Ssl::ServerBio *bio = static_cast(b->ptr);
+ if (const Security::TlsDetails::Pointer &details = bio->receivedHelloDetails())
+ serverConnection()->tlsNegotiations()->retrieveParsedInfo(details);
+}
+
+void
Ssl::PeerConnector::negotiateSsl()
{
if (!Comm::IsConnOpen(serverConnection()) || fd_table[serverConnection()->fd].closing())
@@ -147,6 +164,8 @@
return; // we might be gone by now
}
+ recordNegotiationDetails();
+
if (!sslFinalized())
return;
@@ -332,6 +351,9 @@
// no special error handling for all other errors
break;
}
+
+ // Log connection details, if any
+ recordNegotiationDetails();
noteSslNegotiationError(ret, ssl_error, ssl_lib_error);
}
diff -u -r -N squid-4.0.10/src/ssl/PeerConnector.h squid-4.0.11/src/ssl/PeerConnector.h
--- squid-4.0.10/src/ssl/PeerConnector.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/ssl/PeerConnector.h 2016-06-10 08:32:57.000000000 +1200
@@ -155,6 +155,10 @@
/// If called the certificates validator will not used
void bypassCertValidator() {useCertValidator_ = false;}
+ /// Called after negotiation finishes to record connection details for
+ /// logging
+ void recordNegotiationDetails();
+
HttpRequestPointer request; ///< peer connection trigger or cause
Comm::ConnectionPointer serverConn; ///< TCP connection to the peer
AccessLogEntryPointer al; ///< info for the future access.log entry
diff -u -r -N squid-4.0.10/src/ssl/support.cc squid-4.0.11/src/ssl/support.cc
--- squid-4.0.10/src/ssl/support.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/ssl/support.cc 2016-06-10 08:32:57.000000000 +1200
@@ -135,7 +135,7 @@
}
if (newkey) {
- if (do_debug(83, 5))
+ if (Debug::Enabled(83, 5))
PEM_write_RSAPrivateKey(debug_log, rsa, NULL, NULL, 0, NULL, NULL);
debugs(83, DBG_IMPORTANT, "Generated ephemeral RSA key of length " << keylen);
@@ -556,19 +556,18 @@
return true;
}
-Security::ContextPtr
-sslCreateServerContext(AnyP::PortCfg &port)
+bool
+Ssl::InitServerContext(Security::ContextPtr &sslContext, AnyP::PortCfg &port)
{
- Security::ContextPtr sslContext(port.secure.createBlankContext());
if (!sslContext)
- return nullptr;
+ return false;
if (!SSL_CTX_use_certificate(sslContext, port.signingCert.get())) {
const int ssl_error = ERR_get_error();
const auto &keys = port.secure.certs.front();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS certificate '" << keys.certFile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
if (!SSL_CTX_use_PrivateKey(sslContext, port.signPkey.get())) {
@@ -576,7 +575,7 @@
const auto &keys = port.secure.certs.front();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS private key '" << keys.privateKeyFile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
Ssl::addChainToSslContext(sslContext, port.certsToChain.get());
@@ -588,7 +587,7 @@
ssl_error = ERR_get_error();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
debugs(83, DBG_IMPORTANT, "Using private key in " << keyfile);
@@ -598,7 +597,7 @@
ssl_error = ERR_get_error();
debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
debugs(83, 5, "Comparing private and public SSL keys.");
@@ -608,25 +607,24 @@
debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" <<
keyfile << "': " << ERR_error_string(ssl_error, NULL));
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
*/
if (!configureSslContext(sslContext, port)) {
debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context");
SSL_CTX_free(sslContext);
- return NULL;
+ return false;
}
- return sslContext;
+ return true;
}
-Security::ContextPtr
-sslCreateClientContext(Security::PeerOptions &peer, long options, long fl)
+bool
+Ssl::InitClientContext(Security::ContextPtr &sslContext, Security::PeerOptions &peer, long options, long fl)
{
- Security::ContextPtr sslContext(peer.createBlankContext());
if (!sslContext)
- return nullptr;
+ return false;
SSL_CTX_set_options(sslContext, options);
@@ -689,7 +687,7 @@
SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb);
}
- return sslContext;
+ return true;
}
/// \ingroup ServerProtocolSSLInternal
diff -u -r -N squid-4.0.10/src/ssl/support.h squid-4.0.11/src/ssl/support.h
--- squid-4.0.10/src/ssl/support.h 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/ssl/support.h 2016-06-10 08:32:57.000000000 +1200
@@ -111,13 +111,13 @@
extern Ipc::MemMap *SessionCache;
extern const char *SessionCacheName;
-} //namespace Ssl
+/// initialize a TLS server context with OpenSSL specific settings
+bool InitServerContext(Security::ContextPtr &, AnyP::PortCfg &);
-/// \ingroup ServerProtocolSSLAPI
-Security::ContextPtr sslCreateServerContext(AnyP::PortCfg &port);
+/// initialize a TLS client context with OpenSSL specific settings
+bool InitClientContext(Security::ContextPtr &, Security::PeerOptions &, long options, long flags);
-/// \ingroup ServerProtocolSSLAPI
-Security::ContextPtr sslCreateClientContext(Security::PeerOptions &, long options, long flags);
+} //namespace Ssl
/// \ingroup ServerProtocolSSLAPI
int ssl_read_method(int, char *, int);
diff -u -r -N squid-4.0.10/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.0.11/src/store/id_rewriters/file/storeid_file_rewrite.8
--- squid-4.0.10/src/store/id_rewriters/file/storeid_file_rewrite.8 2016-05-07 00:31:09.000000000 +1200
+++ squid-4.0.11/src/store/id_rewriters/file/storeid_file_rewrite.8 2016-06-10 09:29:00.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "STOREID_FILE_REWRITE 8"
-.TH STOREID_FILE_REWRITE 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH STOREID_FILE_REWRITE 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/src/tests/stub_debug.cc squid-4.0.11/src/tests/stub_debug.cc
--- squid-4.0.10/src/tests/stub_debug.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/tests/stub_debug.cc 2016-06-10 08:32:57.000000000 +1200
@@ -17,14 +17,11 @@
#include "Debug.h"
FILE *debug_log = NULL;
-int Debug::TheDepth = 0;
char *Debug::debugOptions;
char *Debug::cache_log= NULL;
int Debug::rotateNumber = 0;
int Debug::Levels[MAX_DEBUG_SECTIONS];
-int Debug::level;
-int Debug::sectionLevel;
int Debug::override_X = 0;
int Debug::log_stderr = 1;
bool Debug::log_syslog = false;
@@ -80,49 +77,48 @@
static void
_db_print_stderr(const char *format, va_list args)
{
- if (1 < Debug::level)
+ if (1 < Debug::Level())
return;
vfprintf(stderr, format, args);
}
-Debug::OutStream *Debug::CurrentDebug(NULL);
+void
+Debug::parseOptions(char const *)
+{}
-std::ostream &
-Debug::getDebugOut()
+const char*
+SkipBuildPrefix(const char* path)
{
- if (!CurrentDebug) {
- CurrentDebug = new Debug::OutStream;
- CurrentDebug->setf(std::ios::fixed);
- CurrentDebug->precision(2);
- }
- return *CurrentDebug;
+ return path;
}
-void
-Debug::parseOptions(char const *)
-{}
+Debug::Context *Debug::Current = nullptr;
-void
-Debug::finishDebug()
+Debug::Context::Context(const int aSection, const int aLevel):
+ level(aLevel),
+ sectionLevel(Levels[aSection]),
+ upper(Current)
{
- std::cerr << "debugs: " << CurrentDebug->str() << std::endl;
- delete CurrentDebug;
- CurrentDebug = NULL;
+ buf.setf(std::ios::fixed);
+ buf.precision(2);
}
-void
-Debug::xassert(const char *msg, const char *file, int line)
+std::ostringstream &
+Debug::Start(const int section, const int level)
{
- getDebugOut() << "assertion failed: " << file << ":" << line <<
- ": \"" << msg << "\"";
- abort();
+ Current = new Context(section, level);
+ return Current->buf;
}
-const char*
-SkipBuildPrefix(const char* path)
+void
+Debug::Finish()
{
- return path;
+ if (Current) {
+ _db_print("%s\n", Current->buf.str().c_str());
+ delete Current;
+ Current = nullptr;
+ }
}
std::ostream &
@@ -136,10 +132,13 @@
// finalize debugging level if no level was set explicitly via minLevel()
const int finalLevel = (level >= 0) ? level :
- (size_ > 40 ? DBG_DATA : Debug::sectionLevel);
- if (finalLevel <= Debug::sectionLevel) {
+ (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
+ if (finalLevel <= Debug::SectionLevel()) {
os << (label_ ? '=' : ' ');
- os.write(data_, size_);
+ if (data_)
+ os.write(data_, size_);
+ else
+ os << "[null]";
}
return os;
diff -u -r -N squid-4.0.10/src/tests/stub_libsecurity.cc squid-4.0.11/src/tests/stub_libsecurity.cc
--- squid-4.0.10/src/tests/stub_libsecurity.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/tests/stub_libsecurity.cc 2016-06-10 08:32:57.000000000 +1200
@@ -34,11 +34,17 @@
void Security::ServerOptions::parse(const char *) STUB
void Security::ServerOptions::dumpCfg(Packable *, const char *) const STUB
Security::ContextPtr Security::ServerOptions::createBlankContext() const STUB
+Security::ContextPtr Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &) STUB_RETVAL(nullptr)
void Security::ServerOptions::updateContextEecdh(Security::ContextPtr &) STUB
#include "security/NegotiationHistory.h"
Security::NegotiationHistory::NegotiationHistory() STUB
-void Security::NegotiationHistory::fillWith(Security::SessionPtr) STUB
+void Security::NegotiationHistory::retrieveNegotiatedInfo(Security::SessionPtr) STUB
+void Security::NegotiationHistory::retrieveParsedInfo(Security::TlsDetails::Pointer const &) STUB
const char *Security::NegotiationHistory::cipherName() const STUB
-const char *Security::NegotiationHistory::printTlsVersion(int) const STUB
+const char *Security::NegotiationHistory::printTlsVersion(AnyP::ProtocolVersion const &v) const STUB
+
+#include "security/Handshake.h"
+Security::HandshakeParser::HandshakeParser() STUB
+bool Security::HandshakeParser::parseHello(const SBuf &) STUB_RETVAL(false)
diff -u -r -N squid-4.0.10/src/tests/stub_libsslsquid.cc squid-4.0.11/src/tests/stub_libsslsquid.cc
--- squid-4.0.10/src/tests/stub_libsslsquid.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/tests/stub_libsslsquid.cc 2016-06-10 08:32:57.000000000 +1200
@@ -55,9 +55,9 @@
CertError & CertError::operator = (const CertError &old) STUB_RETVAL(*this)
bool CertError::operator == (const CertError &ce) const STUB_RETVAL(false)
bool CertError::operator != (const CertError &ce) const STUB_RETVAL(false)
+bool InitServerContext(Security::ContextPtr &, AnyP::PortCfg &) STUB_RETVAL(false)
+bool InitClientContext(Security::ContextPtr &, Security::PeerOptions &, long, const char *) STUB_RETVAL(false)
} // namespace Ssl
-Security::ContextPtr sslCreateServerContext(AnyP::PortCfg &port) STUB_RETVAL(NULL)
-Security::ContextPtr sslCreateClientContext(Security::PeerOptions &, long, const char *) STUB_RETVAL(nullptr)
int ssl_read_method(int, char *, int) STUB_RETVAL(0)
int ssl_write_method(int, const char *, int) STUB_RETVAL(0)
void ssl_shutdown_method(SSL *ssl) STUB
diff -u -r -N squid-4.0.10/src/tests/stub_mime.cc squid-4.0.11/src/tests/stub_mime.cc
--- squid-4.0.10/src/tests/stub_mime.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/tests/stub_mime.cc 2016-06-10 08:32:57.000000000 +1200
@@ -11,5 +11,5 @@
#define STUB_API "mime.cc"
#include "tests/STUB.h"
-size_t headersEnd(const char *mime, size_t l) STUB_RETVAL(0)
+size_t headersEnd(const char *, size_t, bool &) STUB_RETVAL(0)
diff -u -r -N squid-4.0.10/src/tests/testTokenizer.cc squid-4.0.11/src/tests/testTokenizer.cc
--- squid-4.0.10/src/tests/testTokenizer.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/tests/testTokenizer.cc 2016-06-10 08:32:57.000000000 +1200
@@ -204,6 +204,7 @@
const int64_t benchmark = 1234;
CPPUNIT_ASSERT(t.int64(rv, 10));
CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT(t.buf().isEmpty());
}
// successful parse, autodetect base
@@ -213,6 +214,7 @@
const int64_t benchmark = 1234;
CPPUNIT_ASSERT(t.int64(rv));
CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT(t.buf().isEmpty());
}
// successful parse, autodetect base
@@ -222,6 +224,7 @@
const int64_t benchmark = 01234;
CPPUNIT_ASSERT(t.int64(rv));
CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT(t.buf().isEmpty());
}
// successful parse, autodetect base
@@ -231,6 +234,7 @@
const int64_t benchmark = 0x12f4;
CPPUNIT_ASSERT(t.int64(rv));
CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT(t.buf().isEmpty());
}
// API mismatch: don't eat leading space
@@ -238,6 +242,7 @@
int64_t rv;
Parser::Tokenizer t(SBuf(" 1234"));
CPPUNIT_ASSERT(!t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(SBuf(" 1234"), t.buf());
}
// API mismatch: don't eat multiple leading spaces
@@ -245,6 +250,7 @@
int64_t rv;
Parser::Tokenizer t(SBuf(" 1234"));
CPPUNIT_ASSERT(!t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(SBuf(" 1234"), t.buf());
}
// trailing spaces
@@ -282,6 +288,7 @@
int64_t rv;
Parser::Tokenizer t(SBuf("1029397752385698678762234"));
CPPUNIT_ASSERT(!t.int64(rv));
+ CPPUNIT_ASSERT_EQUAL(SBuf("1029397752385698678762234"), t.buf());
}
// buffered sub-string parsing
@@ -293,6 +300,7 @@
CPPUNIT_ASSERT_EQUAL(SBuf("22"),t.buf());
CPPUNIT_ASSERT(t.int64(rv));
CPPUNIT_ASSERT_EQUAL(benchmark,rv);
+ CPPUNIT_ASSERT(t.buf().isEmpty());
}
// base-16, prefix
diff -u -r -N squid-4.0.10/src/tunnel.cc squid-4.0.11/src/tunnel.cc
--- squid-4.0.10/src/tunnel.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/src/tunnel.cc 2016-06-10 08:32:57.000000000 +1200
@@ -21,6 +21,7 @@
#include "comm/Read.h"
#include "comm/Write.h"
#include "errorpage.h"
+#include "fd.h"
#include "fde.h"
#include "FwdState.h"
#include "globals.h"
@@ -164,6 +165,7 @@
MemBuf *connectRespBuf; ///< accumulates peer CONNECT response when we need it
bool connectReqWriting; ///< whether we are writing a CONNECT request to a peer
SBuf preReadClientData;
+ SBuf preReadServerData;
time_t started; ///< when this tunnel was initiated.
void copyRead(Connection &from, IOCB *completion);
@@ -214,6 +216,7 @@
static void ReadConnectResponseDone(const Comm::ConnectionPointer &, char *buf, size_t len, Comm::Flag errcode, int xerrno, void *data);
void readConnectResponseDone(char *buf, size_t len, Comm::Flag errcode, int xerrno);
void copyClientBytes();
+ void copyServerBytes();
};
static const char *const conn_established = "HTTP/1.1 200 Connection established\r\n\r\n";
@@ -734,7 +737,7 @@
CbcPointer safetyLock(this); /* ??? should be locked by the caller... */
if (cbdataReferenceValid(this))
- copyRead(server, ReadServer);
+ copyServerBytes();
}
static void
@@ -826,6 +829,20 @@
copyRead(client, ReadClient);
}
+void
+TunnelStateData::copyServerBytes()
+{
+ if (preReadServerData.length()) {
+ size_t copyBytes = preReadServerData.length() > SQUID_TCP_SO_RCVBUF ? SQUID_TCP_SO_RCVBUF : preReadServerData.length();
+ memcpy(server.buf, preReadServerData.rawContent(), copyBytes);
+ preReadServerData.consume(copyBytes);
+ server.bytesIn(copyBytes);
+ if (keepGoingAfterRead(copyBytes, Comm::OK, 0, server, client))
+ copy(copyBytes, server, client, TunnelStateData::WriteClientDone);
+ } else
+ copyRead(server, ReadServer);
+}
+
/**
* Set the HTTP status for this request and sets the read handlers for client
* and server side connections.
@@ -841,7 +858,7 @@
// Shovel any payload already pushed into reply buffer by the server response
if (!tunnelState->server.len)
- tunnelState->copyRead(tunnelState->server, TunnelStateData::ReadServer);
+ tunnelState->copyServerBytes();
else {
debugs(26, DBG_DATA, "Tunnel server PUSH Payload: \n" << Raw("", tunnelState->server.buf, tunnelState->server.len) << "\n----------");
tunnelState->copy(tunnelState->server.len, tunnelState->server, tunnelState->client, TunnelStateData::WriteClientDone);
@@ -1298,11 +1315,8 @@
assert(ssl);
BIO *b = SSL_get_rbio(ssl);
Ssl::ServerBio *srvBio = static_cast(b->ptr);
- const MemBuf &buf = srvBio->rBufData();
-
- AsyncCall::Pointer call = commCbCall(5,5, "tunnelConnectedWriteDone",
- CommIoCbPtrFun(tunnelConnectedWriteDone, tunnelState));
- tunnelState->client.write(buf.content(), buf.contentSize(), call, NULL);
+ tunnelState->preReadServerData = srvBio->rBufData();
+ tunnelStartShoveling(tunnelState);
}
#endif //USE_OPENSSL
diff -u -r -N squid-4.0.10/test-suite/Makefile.am squid-4.0.11/test-suite/Makefile.am
--- squid-4.0.10/test-suite/Makefile.am 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/test-suite/Makefile.am 2016-06-10 08:32:57.000000000 +1200
@@ -27,10 +27,10 @@
ESI_ALL_TESTS = \
ESIExpressions
-if USE_ESI
+if ENABLE_ESI
ESI_TESTS = $(ESI_ALL_TESTS)
else
- ESI_TESTS =
+ ESI_TESTS =
endif
## Sort by dependencies - test lowest layers first
diff -u -r -N squid-4.0.10/test-suite/Makefile.in squid-4.0.11/test-suite/Makefile.in
--- squid-4.0.10/test-suite/Makefile.in 2016-05-06 23:37:11.000000000 +1200
+++ squid-4.0.11/test-suite/Makefile.in 2016-06-10 08:35:09.000000000 +1200
@@ -169,7 +169,7 @@
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
am__EXEEXT_1 = ESIExpressions$(EXEEXT)
-@USE_ESI_TRUE@am__EXEEXT_2 = $(am__EXEEXT_1)
+@ENABLE_ESI_TRUE@am__EXEEXT_2 = $(am__EXEEXT_1)
am__objects_1 = stub_cbdata.$(OBJEXT) stub_debug.$(OBJEXT) \
stub_MemBuf.$(OBJEXT) stub_SBuf.$(OBJEXT) stub_tools.$(OBJEXT) \
stub_fatal.$(OBJEXT)
@@ -813,8 +813,8 @@
ESI_ALL_TESTS = \
ESIExpressions
-@USE_ESI_FALSE@ESI_TESTS =
-@USE_ESI_TRUE@ESI_TESTS = $(ESI_ALL_TESTS)
+@ENABLE_ESI_FALSE@ESI_TESTS =
+@ENABLE_ESI_TRUE@ESI_TESTS = $(ESI_ALL_TESTS)
tcp_banger2_LDADD = $(top_builddir)/lib/libmiscutil.la
#do not include stub_libmem.cc here, as it would override libmem.la in
diff -u -r -N squid-4.0.10/test-suite/stub_debug.cc squid-4.0.11/test-suite/stub_debug.cc
--- squid-4.0.10/test-suite/stub_debug.cc 2016-05-07 00:32:58.000000000 +1200
+++ squid-4.0.11/test-suite/stub_debug.cc 2016-06-10 09:30:12.000000000 +1200
@@ -17,14 +17,11 @@
#include "Debug.h"
FILE *debug_log = NULL;
-int Debug::TheDepth = 0;
char *Debug::debugOptions;
char *Debug::cache_log= NULL;
int Debug::rotateNumber = 0;
int Debug::Levels[MAX_DEBUG_SECTIONS];
-int Debug::level;
-int Debug::sectionLevel;
int Debug::override_X = 0;
int Debug::log_stderr = 1;
bool Debug::log_syslog = false;
@@ -80,49 +77,48 @@
static void
_db_print_stderr(const char *format, va_list args)
{
- if (1 < Debug::level)
+ if (1 < Debug::Level())
return;
vfprintf(stderr, format, args);
}
-Debug::OutStream *Debug::CurrentDebug(NULL);
+void
+Debug::parseOptions(char const *)
+{}
-std::ostream &
-Debug::getDebugOut()
+const char*
+SkipBuildPrefix(const char* path)
{
- if (!CurrentDebug) {
- CurrentDebug = new Debug::OutStream;
- CurrentDebug->setf(std::ios::fixed);
- CurrentDebug->precision(2);
- }
- return *CurrentDebug;
+ return path;
}
-void
-Debug::parseOptions(char const *)
-{}
+Debug::Context *Debug::Current = nullptr;
-void
-Debug::finishDebug()
+Debug::Context::Context(const int aSection, const int aLevel):
+ level(aLevel),
+ sectionLevel(Levels[aSection]),
+ upper(Current)
{
- std::cerr << "debugs: " << CurrentDebug->str() << std::endl;
- delete CurrentDebug;
- CurrentDebug = NULL;
+ buf.setf(std::ios::fixed);
+ buf.precision(2);
}
-void
-Debug::xassert(const char *msg, const char *file, int line)
+std::ostringstream &
+Debug::Start(const int section, const int level)
{
- getDebugOut() << "assertion failed: " << file << ":" << line <<
- ": \"" << msg << "\"";
- abort();
+ Current = new Context(section, level);
+ return Current->buf;
}
-const char*
-SkipBuildPrefix(const char* path)
+void
+Debug::Finish()
{
- return path;
+ if (Current) {
+ _db_print("%s\n", Current->buf.str().c_str());
+ delete Current;
+ Current = nullptr;
+ }
}
std::ostream &
@@ -136,10 +132,13 @@
// finalize debugging level if no level was set explicitly via minLevel()
const int finalLevel = (level >= 0) ? level :
- (size_ > 40 ? DBG_DATA : Debug::sectionLevel);
- if (finalLevel <= Debug::sectionLevel) {
+ (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
+ if (finalLevel <= Debug::SectionLevel()) {
os << (label_ ? '=' : ' ');
- os.write(data_, size_);
+ if (data_)
+ os.write(data_, size_);
+ else
+ os << "[null]";
}
return os;
diff -u -r -N squid-4.0.10/tools/helper-mux/helper-mux.8 squid-4.0.11/tools/helper-mux/helper-mux.8
--- squid-4.0.10/tools/helper-mux/helper-mux.8 2016-05-07 00:33:04.000000000 +1200
+++ squid-4.0.11/tools/helper-mux/helper-mux.8 2016-06-10 09:30:16.000000000 +1200
@@ -133,7 +133,7 @@
.\" ========================================================================
.\"
.IX Title "HELPER-MUX 8"
-.TH HELPER-MUX 8 "2016-05-06" "perl v5.22.2" "User Contributed Perl Documentation"
+.TH HELPER-MUX 8 "2016-06-09" "perl v5.22.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
diff -u -r -N squid-4.0.10/tools/squidclient/squidclient.cc squid-4.0.11/tools/squidclient/squidclient.cc
--- squid-4.0.10/tools/squidclient/squidclient.cc 2016-05-06 23:35:13.000000000 +1200
+++ squid-4.0.11/tools/squidclient/squidclient.cc 2016-06-10 08:32:57.000000000 +1200
@@ -111,7 +111,7 @@
<< "HTTP Options:" << std::endl
<< " -a Do NOT include Accept: header." << std::endl
<< " -A User-Agent: header. Use \"\" to omit." << std::endl
- << " -H 'string' Extra headers to send. Use '\\n' for new lines." << std::endl
+ << " -H 'string' Extra headers to send. Supports '\\\\', '\\n', '\\r' and '\\t'." << std::endl
<< " -i IMS If-Modified-Since time (in Epoch seconds)." << std::endl
<< " -j hosthdr Host header content" << std::endl
<< " -k Keep the connection active. Default is to do only one request then close." << std::endl
@@ -132,6 +132,56 @@
exit(1);
}
+static void
+shellUnescape(char *buf)
+{
+ if (!buf)
+ return;
+
+ unsigned char *p, *d;
+
+ d = p = reinterpret_cast(buf);
+
+ while (auto ch = *p) {
+
+ if (ch == '\\') {
+ ++p;
+
+ switch (*p) {
+ case 'n':
+ ch = '\n';
+ break;
+ case 'r':
+ ch = '\r';
+ break;
+ case 't':
+ ch = '\t';
+ break;
+ case '\\':
+ ch = '\\';
+ break;
+ default:
+ ch = *p;
+ debugVerbose(1, "Warning: unsupported shell code '\\" << ch << "'");
+ break;
+ }
+
+ *d = ch;
+
+ if (!ch)
+ continue;
+
+ } else {
+ *d = *p;
+ }
+
+ ++p;
+ ++d;
+ }
+
+ *d = '\0';
+}
+
int
main(int argc, char *argv[])
{
@@ -262,10 +312,8 @@
case 'H':
if (strlen(optarg)) {
- char *t;
strncpy(extra_hdrs, optarg, sizeof(extra_hdrs));
- while ((t = strstr(extra_hdrs, "\\n")))
- *t = '\r', *(t + 1) = '\n';
+ shellUnescape(extra_hdrs);
}
break;
diff -u -r -N squid-4.0.10/tools/squidclient/stub_debug.cc squid-4.0.11/tools/squidclient/stub_debug.cc
--- squid-4.0.10/tools/squidclient/stub_debug.cc 2016-05-07 00:33:08.000000000 +1200
+++ squid-4.0.11/tools/squidclient/stub_debug.cc 2016-06-10 09:30:19.000000000 +1200
@@ -17,14 +17,11 @@
#include "Debug.h"
FILE *debug_log = NULL;
-int Debug::TheDepth = 0;
char *Debug::debugOptions;
char *Debug::cache_log= NULL;
int Debug::rotateNumber = 0;
int Debug::Levels[MAX_DEBUG_SECTIONS];
-int Debug::level;
-int Debug::sectionLevel;
int Debug::override_X = 0;
int Debug::log_stderr = 1;
bool Debug::log_syslog = false;
@@ -80,49 +77,48 @@
static void
_db_print_stderr(const char *format, va_list args)
{
- if (1 < Debug::level)
+ if (1 < Debug::Level())
return;
vfprintf(stderr, format, args);
}
-Debug::OutStream *Debug::CurrentDebug(NULL);
+void
+Debug::parseOptions(char const *)
+{}
-std::ostream &
-Debug::getDebugOut()
+const char*
+SkipBuildPrefix(const char* path)
{
- if (!CurrentDebug) {
- CurrentDebug = new Debug::OutStream;
- CurrentDebug->setf(std::ios::fixed);
- CurrentDebug->precision(2);
- }
- return *CurrentDebug;
+ return path;
}
-void
-Debug::parseOptions(char const *)
-{}
+Debug::Context *Debug::Current = nullptr;
-void
-Debug::finishDebug()
+Debug::Context::Context(const int aSection, const int aLevel):
+ level(aLevel),
+ sectionLevel(Levels[aSection]),
+ upper(Current)
{
- std::cerr << "debugs: " << CurrentDebug->str() << std::endl;
- delete CurrentDebug;
- CurrentDebug = NULL;
+ buf.setf(std::ios::fixed);
+ buf.precision(2);
}
-void
-Debug::xassert(const char *msg, const char *file, int line)
+std::ostringstream &
+Debug::Start(const int section, const int level)
{
- getDebugOut() << "assertion failed: " << file << ":" << line <<
- ": \"" << msg << "\"";
- abort();
+ Current = new Context(section, level);
+ return Current->buf;
}
-const char*
-SkipBuildPrefix(const char* path)
+void
+Debug::Finish()
{
- return path;
+ if (Current) {
+ _db_print("%s\n", Current->buf.str().c_str());
+ delete Current;
+ Current = nullptr;
+ }
}
std::ostream &
@@ -136,10 +132,13 @@
// finalize debugging level if no level was set explicitly via minLevel()
const int finalLevel = (level >= 0) ? level :
- (size_ > 40 ? DBG_DATA : Debug::sectionLevel);
- if (finalLevel <= Debug::sectionLevel) {
+ (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
+ if (finalLevel <= Debug::SectionLevel()) {
os << (label_ ? '=' : ' ');
- os.write(data_, size_);
+ if (data_)
+ os.write(data_, size_);
+ else
+ os << "[null]";
}
return os;
diff -u -r -N squid-4.0.10/tools/stub_debug.cc squid-4.0.11/tools/stub_debug.cc
--- squid-4.0.10/tools/stub_debug.cc 2016-05-07 00:33:01.000000000 +1200
+++ squid-4.0.11/tools/stub_debug.cc 2016-06-10 09:30:14.000000000 +1200
@@ -17,14 +17,11 @@
#include "Debug.h"
FILE *debug_log = NULL;
-int Debug::TheDepth = 0;
char *Debug::debugOptions;
char *Debug::cache_log= NULL;
int Debug::rotateNumber = 0;
int Debug::Levels[MAX_DEBUG_SECTIONS];
-int Debug::level;
-int Debug::sectionLevel;
int Debug::override_X = 0;
int Debug::log_stderr = 1;
bool Debug::log_syslog = false;
@@ -80,49 +77,48 @@
static void
_db_print_stderr(const char *format, va_list args)
{
- if (1 < Debug::level)
+ if (1 < Debug::Level())
return;
vfprintf(stderr, format, args);
}
-Debug::OutStream *Debug::CurrentDebug(NULL);
+void
+Debug::parseOptions(char const *)
+{}
-std::ostream &
-Debug::getDebugOut()
+const char*
+SkipBuildPrefix(const char* path)
{
- if (!CurrentDebug) {
- CurrentDebug = new Debug::OutStream;
- CurrentDebug->setf(std::ios::fixed);
- CurrentDebug->precision(2);
- }
- return *CurrentDebug;
+ return path;
}
-void
-Debug::parseOptions(char const *)
-{}
+Debug::Context *Debug::Current = nullptr;
-void
-Debug::finishDebug()
+Debug::Context::Context(const int aSection, const int aLevel):
+ level(aLevel),
+ sectionLevel(Levels[aSection]),
+ upper(Current)
{
- std::cerr << "debugs: " << CurrentDebug->str() << std::endl;
- delete CurrentDebug;
- CurrentDebug = NULL;
+ buf.setf(std::ios::fixed);
+ buf.precision(2);
}
-void
-Debug::xassert(const char *msg, const char *file, int line)
+std::ostringstream &
+Debug::Start(const int section, const int level)
{
- getDebugOut() << "assertion failed: " << file << ":" << line <<
- ": \"" << msg << "\"";
- abort();
+ Current = new Context(section, level);
+ return Current->buf;
}
-const char*
-SkipBuildPrefix(const char* path)
+void
+Debug::Finish()
{
- return path;
+ if (Current) {
+ _db_print("%s\n", Current->buf.str().c_str());
+ delete Current;
+ Current = nullptr;
+ }
}
std::ostream &
@@ -136,10 +132,13 @@
// finalize debugging level if no level was set explicitly via minLevel()
const int finalLevel = (level >= 0) ? level :
- (size_ > 40 ? DBG_DATA : Debug::sectionLevel);
- if (finalLevel <= Debug::sectionLevel) {
+ (size_ > 40 ? DBG_DATA : Debug::SectionLevel());
+ if (finalLevel <= Debug::SectionLevel()) {
os << (label_ ? '=' : ' ');
- os.write(data_, size_);
+ if (data_)
+ os.write(data_, size_);
+ else
+ os << "[null]";
}
return os;