diff -u -r -N squid-4.0.16/cfgaux/config.guess squid-4.0.17/cfgaux/config.guess --- squid-4.0.16/cfgaux/config.guess 2016-10-31 01:26:37.000000000 +1300 +++ squid-4.0.17/cfgaux/config.guess 2016-12-16 23:13:09.000000000 +1300 @@ -2,7 +2,7 @@ # Attempt to guess a canonical system name. # Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2016-04-02' +timestamp='2016-10-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -186,9 +186,12 @@ *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. + # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in - arm*|earm*|i386|m68k|ns32k|sh3*|sparc|vax) + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ @@ -997,6 +1000,9 @@ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; @@ -1029,6 +1035,9 @@ ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; @@ -1408,18 +1417,17 @@ cat >&2 < in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp diff -u -r -N squid-4.0.16/cfgaux/config.sub squid-4.0.17/cfgaux/config.sub --- squid-4.0.16/cfgaux/config.sub 2016-10-31 01:26:37.000000000 +1300 +++ squid-4.0.17/cfgaux/config.sub 2016-12-16 23:13:09.000000000 +1300 @@ -2,7 +2,7 @@ # Configuration validation subroutine script. # Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2016-03-30' +timestamp='2016-11-04' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -117,7 +117,7 @@ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -301,6 +301,7 @@ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ @@ -428,6 +429,7 @@ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ @@ -643,6 +645,14 @@ basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -1022,7 +1032,7 @@ ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1032,7 +1042,7 @@ ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) @@ -1389,7 +1399,7 @@ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ @@ -1399,7 +1409,7 @@ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos*) + | -onefs* | -tirtos* | -phoenix* | -fuchsia*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) diff -u -r -N squid-4.0.16/ChangeLog squid-4.0.17/ChangeLog --- squid-4.0.16/ChangeLog 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/ChangeLog 2016-12-16 23:06:20.000000000 +1300 @@ -1,3 +1,13 @@ +Changes to squid-4.0.17 (16 Dec 2016): + + - Bug 4630: user credentials cache cleanup not re-scheduled + - Bug 4610 partial: compile errors on Solaris 11.3 with Oracle Studio 12.5 + - Bug 4599 partial: initial support for OpenSSL v1.1 + - TLS: Support tunneling of bumped non-HTTP traffic + - ... and many code polishing and performance updates + - ... and some documentation updates + - ... and some fixes from 3.5.23 + Changes to squid-4.0.16 (30 Oct 2016): - Avoid segfaults when lacking the server name for certificate validator @@ -245,6 +255,29 @@ - ... and many documentation changes - ... and much code cleanup and polishing +Changes to squid-3.5.23 (16 Dec 2016): + + - Bug 4627: fix generate-host-certificates and dynamic_cert_mem_cache_size docs + - Bug 4620: NetBSD build error with --enable-ipf-transparent + - Bug 4567: Strange IPv6 shown in access.log + - Bug 4406: SIGSEV in TunnelStateData::handleConnectResponse() during reconfigure and restart + - Bug 4174 partial: fix Write.cc:41 "!ccb->active()" assertion. + - Bug 4169: HIT marked as MISS when If-None-Match does not match + - Bug 4007: Hang on DNS query with dead-end CNAME + - Bug 4004 partial: Fix segfault via Ftp::Client::readControlReply + - Bug 3940 partial: hostHeaderVerify failures MISS when they should be HIT + - Bug 3533: Cache still valid after HTTP/1.1 303 See Other + - Bug 3379: Combination of If-Match and a Cache Hit result in TCP Connection Failure + - Bug 3290: authenticate_ttl not working for digest authentication + - Bug 2258: bypassing cache but not destroying cache entry + - HTTP/1.1: make Vary:* objects cacheable + - HTTP/1.1: Add registered codes entry for new 103 (Early Hints) status code + - Support IPv6 NAT with PF for NetBSD and FreeBSD + - TLS: Make key= before cert= an error instead of quietly hiding the issue + - ... and some debug updates + - ... and some build fixes + - ... and several documentation updates + Changes to squid-3.5.22 (09 Oct 2016): - Bug 4594: build failure with clang 3.9 diff -u -r -N squid-4.0.16/compat/compat.h squid-4.0.17/compat/compat.h --- squid-4.0.16/compat/compat.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/compat/compat.h 2016-12-16 23:06:20.000000000 +1300 @@ -29,19 +29,6 @@ /******************************************************/ #include "compat/osdetect.h" -/* ugly hack. But we need to set this REALLY soon in the header */ -#if _SQUID_SOLARIS_ && !defined(__GNUC__) && !defined(__GNUG__) -#ifndef __EXTENSIONS__ -#define __EXTENSIONS__ 1 -#endif -#ifndef _XOPEN_SOURCE -#define _XOPEN_SOURCE 1 -#endif -#ifndef _XOPEN_SOURCE_EXTENDED -#define _XOPEN_SOURCE_EXTENDED 1 -#endif -#endif - /* Solaris 10 has a broken definition for minor_t in IPFilter compat. * We must pre-define before doing anything with OS headers so the OS * do not. Then un-define it before using the IPFilter *_compat.h headers. diff -u -r -N squid-4.0.16/compat/os/solaris.h squid-4.0.17/compat/os/solaris.h --- squid-4.0.16/compat/os/solaris.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/compat/os/solaris.h 2016-12-16 23:06:20.000000000 +1300 @@ -48,6 +48,11 @@ #include SQUIDCEXTERN int getrusage(int, struct rusage *); +// Solaris 11 needs this before to get the definition for msg_control +// and possibly other type definitions we dont know about specifically +#define _XPG4_2 1 +#include + /** * prototypes for system function missing from system includes * on some Solaris systems. diff -u -r -N squid-4.0.16/configure squid-4.0.17/configure --- squid-4.0.16/configure 2016-10-31 01:28:43.000000000 +1300 +++ squid-4.0.17/configure 2016-12-16 23:19:31.000000000 +1300 @@ -1,7 +1,7 @@ #! /bin/sh # From configure.ac Revision. # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.16. +# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.17. # # Report bugs to . # @@ -595,8 +595,8 @@ # Identity of this package. PACKAGE_NAME='Squid Web Proxy' PACKAGE_TARNAME='squid' -PACKAGE_VERSION='4.0.16' -PACKAGE_STRING='Squid Web Proxy 4.0.16' +PACKAGE_VERSION='4.0.17' +PACKAGE_STRING='Squid Web Proxy 4.0.17' PACKAGE_BUGREPORT='http://bugs.squid-cache.org/' PACKAGE_URL='' @@ -1648,7 +1648,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures Squid Web Proxy 4.0.16 to adapt to many kinds of systems. +\`configure' configures Squid Web Proxy 4.0.17 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1719,7 +1719,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Squid Web Proxy 4.0.16:";; + short | recursive ) echo "Configuration of Squid Web Proxy 4.0.17:";; esac cat <<\_ACEOF @@ -2148,7 +2148,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Squid Web Proxy configure 4.0.16 +Squid Web Proxy configure 4.0.17 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -3252,7 +3252,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by Squid Web Proxy $as_me 4.0.16, which was +It was created by Squid Web Proxy $as_me 4.0.17, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4119,7 +4119,7 @@ # Define the identity of the package. PACKAGE='squid' - VERSION='4.0.16' + VERSION='4.0.17' cat >>confdefs.h <<_ACEOF @@ -42599,7 +42599,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by Squid Web Proxy $as_me 4.0.16, which was +This file was extended by Squid Web Proxy $as_me 4.0.17, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -42665,7 +42665,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -Squid Web Proxy config.status 4.0.16 +Squid Web Proxy config.status 4.0.17 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -u -r -N squid-4.0.16/configure.ac squid-4.0.17/configure.ac --- squid-4.0.16/configure.ac 2016-10-31 01:28:42.000000000 +1300 +++ squid-4.0.17/configure.ac 2016-12-16 23:19:28.000000000 +1300 @@ -5,7 +5,7 @@ ## Please see the COPYING and CONTRIBUTORS files for details. ## -AC_INIT([Squid Web Proxy],[4.0.16],[http://bugs.squid-cache.org/],[squid]) +AC_INIT([Squid Web Proxy],[4.0.17],[http://bugs.squid-cache.org/],[squid]) AC_PREREQ(2.61) AC_CONFIG_HEADERS([include/autoconf.h]) AC_CONFIG_AUX_DIR(cfgaux) diff -u -r -N squid-4.0.16/doc/release-notes/release-4.html squid-4.0.17/doc/release-notes/release-4.html --- squid-4.0.16/doc/release-notes/release-4.html 2016-10-31 03:14:55.000000000 +1300 +++ squid-4.0.17/doc/release-notes/release-4.html 2016-12-17 07:18:56.000000000 +1300 @@ -2,10 +2,10 @@ - Squid 4.0.16 release notes + Squid 4.0.17 release notes -

Squid 4.0.16 release notes

+

Squid 4.0.17 release notes

Squid Developers


@@ -61,7 +61,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.0.16 for testing.

+

The Squid Team are pleased to announce the release of Squid-4.0.17 for testing.

This new release is available for download from http://www.squid-cache.org/Versions/v4/ or the mirrors.

@@ -355,6 +355,7 @@

Removed version= option. Use tls-options= instead.

Manual squid.conf update may be required on upgrade.

Replaced cafile= with tls-cafile= which takes multiple entries.

+

Changed default value of generate-host-certificates to ON.

https_port

New option tls-min-version=1.N to set minimum TLS version allowed.

@@ -366,6 +367,7 @@

Removed version= option. Use tls-options= instead.

Manual squid.conf update may be required on upgrade.

Replaced cafile= with tls-cafile= which takes multiple entries.

+

Changed default value of generate-host-certificates to ON.

icap_service

New scheme icaps:// to enable TLS/SSL connections to Secure ICAP diff -u -r -N squid-4.0.16/include/version.h squid-4.0.17/include/version.h --- squid-4.0.16/include/version.h 2016-10-31 01:28:44.000000000 +1300 +++ squid-4.0.17/include/version.h 2016-12-16 23:19:32.000000000 +1300 @@ -7,7 +7,7 @@ */ #ifndef SQUID_RELEASE_TIME -#define SQUID_RELEASE_TIME 1477830283 +#define SQUID_RELEASE_TIME 1481882763 #endif /* diff -u -r -N squid-4.0.16/RELEASENOTES.html squid-4.0.17/RELEASENOTES.html --- squid-4.0.16/RELEASENOTES.html 2016-10-31 03:14:55.000000000 +1300 +++ squid-4.0.17/RELEASENOTES.html 2016-12-17 07:18:56.000000000 +1300 @@ -2,10 +2,10 @@ - Squid 4.0.16 release notes + Squid 4.0.17 release notes -

Squid 4.0.16 release notes

+

Squid 4.0.17 release notes

Squid Developers


@@ -61,7 +61,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.0.16 for testing.

+

The Squid Team are pleased to announce the release of Squid-4.0.17 for testing.

This new release is available for download from http://www.squid-cache.org/Versions/v4/ or the mirrors.

@@ -355,6 +355,7 @@

Removed version= option. Use tls-options= instead.

Manual squid.conf update may be required on upgrade.

Replaced cafile= with tls-cafile= which takes multiple entries.

+

Changed default value of generate-host-certificates to ON.

https_port

New option tls-min-version=1.N to set minimum TLS version allowed.

@@ -366,6 +367,7 @@

Removed version= option. Use tls-options= instead.

Manual squid.conf update may be required on upgrade.

Replaced cafile= with tls-cafile= which takes multiple entries.

+

Changed default value of generate-host-certificates to ON.

icap_service

New scheme icaps:// to enable TLS/SSL connections to Secure ICAP diff -u -r -N squid-4.0.16/src/acl/external/delayer/ext_delayer_acl.8 squid-4.0.17/src/acl/external/delayer/ext_delayer_acl.8 --- squid-4.0.16/src/acl/external/delayer/ext_delayer_acl.8 2016-10-31 03:17:46.000000000 +1300 +++ squid-4.0.17/src/acl/external/delayer/ext_delayer_acl.8 2016-12-17 07:21:40.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "EXT_DELAYER_ACL 8" -.TH EXT_DELAYER_ACL 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH EXT_DELAYER_ACL 8 "2016-12-16" "perl v5.24.1" "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.16/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.0.17/src/acl/external/SQL_session/ext_sql_session_acl.8 --- squid-4.0.16/src/acl/external/SQL_session/ext_sql_session_acl.8 2016-10-31 03:18:16.000000000 +1300 +++ squid-4.0.17/src/acl/external/SQL_session/ext_sql_session_acl.8 2016-12-17 07:22:03.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "EXT_SQL_SESSION_ACL 8" -.TH EXT_SQL_SESSION_ACL 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH EXT_SQL_SESSION_ACL 8 "2016-12-16" "perl v5.24.1" "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.16/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.0.17/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 --- squid-4.0.16/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2016-10-31 03:18:28.000000000 +1300 +++ squid-4.0.17/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2016-12-17 07:22:13.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "EXT_WBINFO_GROUP_ACL 8" -.TH EXT_WBINFO_GROUP_ACL 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH EXT_WBINFO_GROUP_ACL 8 "2016-12-16" "perl v5.24.1" "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.16/src/acl/ServerCertificate.cc squid-4.0.17/src/acl/ServerCertificate.cc --- squid-4.0.16/src/acl/ServerCertificate.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/acl/ServerCertificate.cc 2016-12-16 23:06:20.000000000 +1300 @@ -21,16 +21,16 @@ int ACLServerCertificateStrategy::match(ACLData * &data, ACLFilledChecklist *checklist, ACLFlags &) { - X509 *cert = NULL; - if (checklist->serverCert.get()) - cert = checklist->serverCert.get(); + Security::CertPointer cert; + if (checklist->serverCert) + cert = checklist->serverCert; else if (checklist->conn() != NULL && checklist->conn()->serverBump()) - cert = checklist->conn()->serverBump()->serverCert.get(); + cert = checklist->conn()->serverBump()->serverCert; if (!cert) return 0; - return data->match(cert); + return data->match(cert.get()); } ACLServerCertificateStrategy * diff -u -r -N squid-4.0.16/src/acl/Tree.cc squid-4.0.17/src/acl/Tree.cc --- squid-4.0.16/src/acl/Tree.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/acl/Tree.cc 2016-12-16 23:06:20.000000000 +1300 @@ -57,35 +57,6 @@ InnerNode::add(rule); } -SBufList -Acl::Tree::treeDump(const char *prefix, const ActionToString &convert) const -{ - SBufList text; - Actions::const_iterator action = actions.begin(); - typedef Nodes::const_iterator NCI; - for (NCI node = nodes.begin(); node != nodes.end(); ++node) { - - text.push_back(SBuf(prefix)); - - if (action != actions.end()) { - const char *act = convert ? convert[action->kind] : - (*action == ACCESS_ALLOWED ? "allow" : "deny"); - text.push_back(act?SBuf(act):SBuf("???")); - ++action; - } - -#if __cplusplus >= 201103L - text.splice(text.end(), (*node)->dump()); -#else - // temp is needed until c++11 move constructor - SBufList temp = (*node)->dump(); - text.splice(text.end(), temp); -#endif - text.push_back(SBuf("\n")); - } - return text; -} - bool Acl::Tree::bannedAction(ACLChecklist *checklist, Nodes::const_iterator node) const { diff -u -r -N squid-4.0.16/src/acl/Tree.h squid-4.0.17/src/acl/Tree.h --- squid-4.0.16/src/acl/Tree.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/acl/Tree.h 2016-12-16 23:06:20.000000000 +1300 @@ -25,9 +25,9 @@ public: /// dumps tuples - /// action.kind is mapped to a string using the supplied conversion table - typedef const char **ActionToString; - SBufList treeDump(const char *name, const ActionToString &convert) const; + /// the supplied converter maps action.kind to a string + template + SBufList treeDump(const char *name, ActionToStringConverter converter) const; /// Returns the corresponding action after a successful tree match. allow_t winningAction() const; @@ -49,6 +49,42 @@ Actions actions; }; +inline const char * +AllowOrDeny(const allow_t &action) +{ + return action == ACCESS_ALLOWED ? "allow" : "deny"; +} + +template +inline SBufList +Tree::treeDump(const char *prefix, ActionToStringConverter converter) const +{ + SBufList text; + Actions::const_iterator action = actions.begin(); + typedef Nodes::const_iterator NCI; + for (NCI node = nodes.begin(); node != nodes.end(); ++node) { + + text.push_back(SBuf(prefix)); + + if (action != actions.end()) { + static const SBuf DefaultActString("???"); + const char *act = converter(*action); + text.push_back(act ? SBuf(act) : DefaultActString); + ++action; + } + +#if __cplusplus >= 201103L + text.splice(text.end(), (*node)->dump()); +#else + // temp is needed until c++11 move constructor + SBufList temp = (*node)->dump(); + text.splice(text.end(), temp); +#endif + text.push_back(SBuf("\n")); + } + return text; +} + } // namespace Acl #endif /* SQUID_ACL_TREE_H */ diff -u -r -N squid-4.0.16/src/anyp/ProtocolType.cc squid-4.0.17/src/anyp/ProtocolType.cc --- squid-4.0.16/src/anyp/ProtocolType.cc 2016-10-31 03:16:31.000000000 +1300 +++ squid-4.0.17/src/anyp/ProtocolType.cc 2016-12-17 07:20:24.000000000 +1300 @@ -25,6 +25,7 @@ "ICY", "TLS", "SSL", + "AUTHORITY_FORM", "UNKNOWN", "MAX" }; diff -u -r -N squid-4.0.16/src/anyp/ProtocolType.h squid-4.0.17/src/anyp/ProtocolType.h --- squid-4.0.16/src/anyp/ProtocolType.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/anyp/ProtocolType.h 2016-12-16 23:06:20.000000000 +1300 @@ -38,6 +38,7 @@ PROTO_ICY, PROTO_TLS, PROTO_SSL, + PROTO_AUTHORITY_FORM, PROTO_UNKNOWN, PROTO_MAX } ProtocolType; diff -u -r -N squid-4.0.16/src/auth/basic/DB/basic_db_auth.8 squid-4.0.17/src/auth/basic/DB/basic_db_auth.8 --- squid-4.0.16/src/auth/basic/DB/basic_db_auth.8 2016-10-31 03:20:15.000000000 +1300 +++ squid-4.0.17/src/auth/basic/DB/basic_db_auth.8 2016-12-17 07:23:24.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_DB_AUTH 8" -.TH BASIC_DB_AUTH 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH BASIC_DB_AUTH 8 "2016-12-16" "perl v5.24.1" "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.16/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.0.17/src/auth/basic/POP3/basic_pop3_auth.8 --- squid-4.0.16/src/auth/basic/POP3/basic_pop3_auth.8 2016-10-31 03:20:41.000000000 +1300 +++ squid-4.0.17/src/auth/basic/POP3/basic_pop3_auth.8 2016-12-17 07:23:49.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_POP3_AUTH 8" -.TH BASIC_POP3_AUTH 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH BASIC_POP3_AUTH 8 "2016-12-16" "perl v5.24.1" "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.16/src/auth/CredentialsCache.cc squid-4.0.17/src/auth/CredentialsCache.cc --- squid-4.0.16/src/auth/CredentialsCache.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/auth/CredentialsCache.cc 2016-12-16 23:06:20.000000000 +1300 @@ -98,6 +98,7 @@ ++i; } } + gcScheduled_ = false; scheduleCleanup(); } diff -u -r -N squid-4.0.16/src/auth/digest/Config.cc squid-4.0.17/src/auth/digest/Config.cc --- squid-4.0.16/src/auth/digest/Config.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/auth/digest/Config.cc 2016-12-16 23:06:20.000000000 +1300 @@ -215,7 +215,7 @@ if (!digest_nonce_cache) { digest_nonce_cache = hash_create((HASHCMP *) strcmp, 7921, hash_string); assert(digest_nonce_cache); - eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, static_cast(Auth::Config::Find("digest"))->nonceGCInterval, 1); + eventAdd("Digest nonce cache maintenance", authenticateDigestNonceCacheCleanup, NULL, static_cast(Auth::Config::Find("digest"))->nonceGCInterval, 1); } } @@ -279,7 +279,7 @@ debugs(29, 3, "Finished cleaning the nonce cache."); if (static_cast(Auth::Config::Find("digest"))->active()) - eventAdd("Digest none cache maintenance", authenticateDigestNonceCacheCleanup, NULL, static_cast(Auth::Config::Find("digest"))->nonceGCInterval, 1); + eventAdd("Digest nonce cache maintenance", authenticateDigestNonceCacheCleanup, NULL, static_cast(Auth::Config::Find("digest"))->nonceGCInterval, 1); } static void @@ -1064,6 +1064,10 @@ * the user agent won't change user name without warning. */ authDigestUserLinkNonce(digest_user, nonce); + + /* auth_user is now linked, we reset these values + * after external auth occurs anyway */ + auth_user->expiretime = current_time.tv_sec; } else { debugs(29, 9, "Found user '" << username << "' in the user cache as '" << auth_user << "'"); digest_user = static_cast(auth_user.getRaw()); diff -u -r -N squid-4.0.16/src/auth/digest/UserRequest.cc squid-4.0.17/src/auth/digest/UserRequest.cc --- squid-4.0.16/src/auth/digest/UserRequest.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/auth/digest/UserRequest.cc 2016-12-16 23:06:20.000000000 +1300 @@ -187,12 +187,7 @@ auth_user->credentials(Auth::Ok); /* password was checked and did match */ - debugs(29, 4, HERE << "user '" << auth_user->username() << "' validated OK"); - - /* auth_user is now linked, we reset these values - * after external auth occurs anyway */ - auth_user->expiretime = current_time.tv_sec; - return; + debugs(29, 4, "user '" << auth_user->username() << "' validated OK"); } Auth::Direction diff -u -r -N squid-4.0.16/src/base/HardFun.h squid-4.0.17/src/base/HardFun.h --- squid-4.0.16/src/base/HardFun.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/base/HardFun.h 2016-12-16 23:06:20.000000000 +1300 @@ -14,7 +14,7 @@ */ template struct HardFun { - ReturnType operator()(ArgType arg) { fun(arg); } + ReturnType operator()(ArgType arg) { return fun(arg); } }; #endif /* _SQUID_SRC_BASE_HARDFUN_H */ diff -u -r -N squid-4.0.16/src/cache_cf.cc squid-4.0.17/src/cache_cf.cc --- squid-4.0.16/src/cache_cf.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/cache_cf.cc 2016-12-16 23:06:20.000000000 +1300 @@ -1340,7 +1340,7 @@ dump_acl_access(StoreEntry * entry, const char *name, acl_access * head) { if (head) - dump_SBufList(entry, head->treeDump(name,NULL)); + dump_SBufList(entry, head->treeDump(name, &Acl::AllowOrDeny)); } static void @@ -1826,6 +1826,23 @@ } #endif /* USE_AUTH */ +static void +ParseAclWithAction(acl_access **access, const allow_t &action, const char *desc, ACL *acl = nullptr) +{ + assert(access); + SBuf name; + if (!*access) { + *access = new Acl::Tree; + name.Printf("(%s rules)", desc); + (*access)->context(name.c_str(), config_input_line); + } + Acl::AndNode *rule = new Acl::AndNode; + name.Printf("(%s rule)", desc); + rule->context(name.c_str(), config_input_line); + acl ? rule->add(acl) : rule->lineParse(); + (*access)->add(rule, action); +} + /* TODO: just return the object, the # is irrelevant */ static int find_fstype(char *type) @@ -2291,17 +2308,14 @@ static void dump_cachemgrpasswd(StoreEntry * entry, const char *name, Mgr::ActionPasswordList * list) { - wordlist *w; - - while (list != NULL) { + while (list) { if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable")) storeAppendPrintf(entry, "%s XXXXXXXXXX", name); else storeAppendPrintf(entry, "%s %s", name, list->passwd); - for (w = list->actions; w != NULL; w = w->next) { - storeAppendPrintf(entry, " %s", w->key); - } + for (auto w : list->actions) + entry->appendf(" " SQUIDSBUFPH, SQUIDSBUFPRINT(w)); storeAppendPrintf(entry, "\n"); list = list->next; @@ -2311,16 +2325,16 @@ static void parse_cachemgrpasswd(Mgr::ActionPasswordList ** head) { - char *passwd = NULL; - wordlist *actions = NULL; - Mgr::ActionPasswordList *p; - Mgr::ActionPasswordList **P; + char *passwd = nullptr; parse_string(&passwd); - parse_wordlist(&actions); - p = new Mgr::ActionPasswordList; + + Mgr::ActionPasswordList *p = new Mgr::ActionPasswordList; p->passwd = passwd; - p->actions = actions; + while (char *token = ConfigParser::NextQuotedToken()) + p->actions.push_back(SBuf(token)); + + Mgr::ActionPasswordList **P; for (P = head; *P; P = &(*P)->next) { /* * See if any of the actions from this line already have a @@ -2330,15 +2344,12 @@ * requested action. Thus, we should warn users who might * think they can have two passwords for the same action. */ - wordlist *w; - wordlist *u; - - for (w = (*P)->actions; w; w = w->next) { - for (u = actions; u; u = u->next) { - if (strcmp(w->key, u->key)) + for (const auto &w : (*P)->actions) { + for (const auto &u : p->actions) { + if (w != u) continue; - debugs(0, DBG_CRITICAL, "WARNING: action '" << u->key << "' (line " << config_lineno << ") already has a password"); + debugs(0, DBG_PARSE_NOTE(1), "ERROR: action '" << u << "' (line " << config_lineno << ") already has a password"); } } } @@ -2349,14 +2360,8 @@ static void free_cachemgrpasswd(Mgr::ActionPasswordList ** head) { - Mgr::ActionPasswordList *p; - - while ((p = *head) != NULL) { - *head = p->next; - xfree(p->passwd); - wordlistDestroy(&p->actions); - xfree(p); - } + delete *head; + *head = nullptr; } static void @@ -4638,24 +4643,16 @@ bumpCfgStyleLast = bumpCfgStyleNow; - Acl::AndNode *rule = new Acl::AndNode; - rule->context("(ssl_bump rule)", config_input_line); - rule->lineParse(); // empty rule OK - - assert(ssl_bump); - if (!*ssl_bump) { - *ssl_bump = new Acl::Tree; - (*ssl_bump)->context("(ssl_bump rules)", config_input_line); - } - - (*ssl_bump)->add(rule, action); + ParseAclWithAction(ssl_bump, action, "ssl_bump"); } static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump) { if (ssl_bump) - dump_SBufList(entry, ssl_bump->treeDump(name, Ssl::BumpModeStr)); + dump_SBufList(entry, ssl_bump->treeDump(name, [](const allow_t &action) { + return Ssl::BumpModeStr.at(action.kind); + })); } static void free_sslproxy_ssl_bump(acl_access **ssl_bump) @@ -4782,21 +4779,16 @@ if (ftpEpsvIsDeprecatedRule) { // overwrite previous ftp_epsv lines delete *ftp_epsv; + *ftp_epsv = nullptr; + if (ftpEpsvDeprecatedAction == allow_t(ACCESS_DENIED)) { - Acl::AndNode *ftpEpsvRule = new Acl::AndNode; - ftpEpsvRule->context("(ftp_epsv rule)", config_input_line); - ACL *a = ACL::FindByName("all"); - if (!a) { - delete ftpEpsvRule; + if (ACL *a = ACL::FindByName("all")) + ParseAclWithAction(ftp_epsv, ftpEpsvDeprecatedAction, "ftp_epsv", a); + else { self_destruct(); return; } - ftpEpsvRule->add(a); - *ftp_epsv = new Acl::Tree; - (*ftp_epsv)->context("(ftp_epsv rules)", config_input_line); - (*ftp_epsv)->add(ftpEpsvRule, ftpEpsvDeprecatedAction); - } else - *ftp_epsv = NULL; + } FtpEspvDeprecated = true; } else { aclParseAccessLine(cfg_directive, LegacyParser, ftp_epsv); @@ -4806,7 +4798,7 @@ static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv) { if (ftp_epsv) - dump_SBufList(entry, ftp_epsv->treeDump(name, NULL)); + dump_SBufList(entry, ftp_epsv->treeDump(name, Acl::AllowOrDeny)); } static void free_ftp_epsv(acl_access **ftp_epsv) @@ -4931,31 +4923,22 @@ return; } - Acl::AndNode *rule = new Acl::AndNode; - rule->context("(on_unsupported_protocol rule)", config_input_line); - rule->lineParse(); // empty rule OK - - assert(access); - if (!*access) { - *access = new Acl::Tree; - (*access)->context("(on_unsupported_protocol rules)", config_input_line); - } - - (*access)->add(rule, action); + ParseAclWithAction(access, action, "on_unsupported_protocol"); } static void dump_on_unsupported_protocol(StoreEntry *entry, const char *name, acl_access *access) { - const char *on_error_tunnel_mode_str[] = { + static const std::vector onErrorTunnelMode = { "none", "tunnel", - "respond", - NULL + "respond" }; if (access) { - SBufList lines = access->treeDump(name, on_error_tunnel_mode_str); + SBufList lines = access->treeDump(name, [](const allow_t &action) { + return onErrorTunnelMode.at(action.kind); + }); dump_SBufList(entry, lines); } } diff -u -r -N squid-4.0.16/src/cache_manager.cc squid-4.0.17/src/cache_manager.cc --- squid-4.0.16/src/cache_manager.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/cache_manager.cc 2016-12-16 23:06:20.000000000 +1300 @@ -445,14 +445,13 @@ char * CacheManager::PasswdGet(Mgr::ActionPasswordList * a, const char *action) { - wordlist *w; - - while (a != NULL) { - for (w = a->actions; w != NULL; w = w->next) { - if (0 == strcmp(w->key, action)) + while (a) { + for (auto &w : a->actions) { + if (w.cmp(action) == 0) return a->passwd; - if (0 == strcmp(w->key, "all")) + static const SBuf allAction("all"); + if (w == allAction) return a->passwd; } diff -u -r -N squid-4.0.16/src/cf.data.pre squid-4.0.17/src/cf.data.pre --- squid-4.0.16/src/cf.data.pre 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/cf.data.pre 2016-12-16 23:06:20.000000000 +1300 @@ -3402,7 +3402,7 @@ certificate. If not specified the peer hostname will be used. - front-end-https + front-end-https[=off|on|auto] Enable the "Front-End-Https: On" header needed when using Squid as a SSL frontend in front of Microsoft OWA. See MS KB document Q307347 for details on this header. diff -u -r -N squid-4.0.16/src/clients/FtpClient.cc squid-4.0.17/src/clients/FtpClient.cc --- squid-4.0.16/src/clients/FtpClient.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/clients/FtpClient.cc 2016-12-16 23:06:20.000000000 +1300 @@ -442,6 +442,11 @@ char *buf; debugs(9, 3, status()); + if (!Comm::IsConnOpen(ctrl.conn)) { + debugs(9, 5, "The control connection to the remote end is closed"); + return false; + } + if (code != 227) { debugs(9, 2, "PASV not supported by remote end"); return false; @@ -473,6 +478,11 @@ char *buf; debugs(9, 3, status()); + if (!Comm::IsConnOpen(ctrl.conn)) { + debugs(9, 5, "The control connection to the remote end is closed"); + return false; + } + if (code != 229 && code != 522) { if (code == 200) { /* handle broken servers (RFC 2428 says OK code for EPSV MUST be 229 not 200) */ @@ -735,6 +745,11 @@ void Ftp::Client::connectDataChannel() { + if (!Comm::IsConnOpen(ctrl.conn)) { + debugs(9, 5, "The control connection to the remote end is closed"); + return; + } + safe_free(ctrl.last_command); safe_free(ctrl.last_reply); diff -u -r -N squid-4.0.16/src/clients/FtpGateway.cc squid-4.0.17/src/clients/FtpGateway.cc --- squid-4.0.16/src/clients/FtpGateway.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/clients/FtpGateway.cc 2016-12-16 23:06:20.000000000 +1300 @@ -209,7 +209,9 @@ static FTPSM ftpReadMdtm; static FTPSM ftpSendSize; static FTPSM ftpReadSize; +#if 0 static FTPSM ftpSendEPRT; +#endif static FTPSM ftpReadEPRT; static FTPSM ftpSendPORT; static FTPSM ftpReadPORT; @@ -443,6 +445,11 @@ void Ftp::Gateway::listenForDataChannel(const Comm::ConnectionPointer &conn) { + if (!Comm::IsConnOpen(ctrl.conn)) { + debugs(9, 5, "The control connection to the remote end is closed"); + return; + } + assert(!Comm::IsConnOpen(data.conn)); typedef CommCbMemFunT AcceptDialer; @@ -1164,7 +1171,7 @@ checkUrlpath(); buildTitleUrl(); - debugs(9, 5, "FD " << ctrl.conn->fd << " : host=" << request->url.host() << + debugs(9, 5, "FD " << (ctrl.conn ? ctrl.conn->fd : -1) << " : host=" << request->url.host() << ", path=" << request->url.path() << ", user=" << user << ", passwd=" << password); state = BEGIN; Ftp::Client::start(); @@ -1719,7 +1726,9 @@ if (ftpState->handlePasvReply(srvAddr)) ftpState->connectDataChannel(); else { - ftpSendEPRT(ftpState); + ftpFail(ftpState); + // Currently disabled, does not work correctly: + // ftpSendEPRT(ftpState); return; } } @@ -1759,6 +1768,11 @@ } safe_free(ftpState->data.host); + if (!Comm::IsConnOpen(ftpState->ctrl.conn)) { + debugs(9, 5, "The control connection to the remote end is closed"); + return; + } + /* * Set up a listen socket on the same local address as the * control connection. @@ -1850,9 +1864,14 @@ ftpRestOrList(ftpState); } +#if 0 static void ftpSendEPRT(Ftp::Gateway * ftpState) { + /* check the server control channel is still available */ + if (!ftpState || !ftpState->haveControlChannel("ftpSendEPRT")) + return; + if (Config.Ftp.epsv_all && ftpState->flags.epsv_all_sent) { debugs(9, DBG_IMPORTANT, "FTP does not allow EPRT method after 'EPSV ALL' has been sent."); return; @@ -1888,6 +1907,7 @@ ftpState->writeCommand(cbuf); ftpState->state = Ftp::Client::SENT_EPRT; } +#endif static void ftpReadEPRT(Ftp::Gateway * ftpState) @@ -1914,10 +1934,8 @@ { debugs(9, 3, HERE); - if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - abortAll("entry aborted when accepting data conn"); - data.listenConn->close(); - data.listenConn = NULL; + if (!Comm::IsConnOpen(ctrl.conn)) { /*Close handlers will cleanup*/ + debugs(9, 5, "The control connection to the remote end is closed"); return; } @@ -1930,6 +1948,14 @@ return; } + if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) { + abortAll("entry aborted when accepting data conn"); + data.listenConn->close(); + data.listenConn = NULL; + io.conn->close(); + return; + } + /* data listening conn is no longer even open. abort. */ if (!Comm::IsConnOpen(data.listenConn)) { data.listenConn = NULL; // ensure that it's cleared and not just closed. @@ -2682,8 +2708,8 @@ Ftp::Gateway::completeForwarding() { if (fwd == NULL || flags.completed_forwarding) { - debugs(9, 3, HERE << "completeForwarding avoids " << - "double-complete on FD " << ctrl.conn->fd << ", Data FD " << data.conn->fd << + debugs(9, 3, "avoid double-complete on FD " << + (ctrl.conn ? ctrl.conn->fd : -1) << ", Data FD " << data.conn->fd << ", this " << this << ", fwd " << fwd); return; } diff -u -r -N squid-4.0.16/src/client_side.cc squid-4.0.17/src/client_side.cc --- squid-4.0.16/src/client_side.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/client_side.cc 2016-12-16 23:06:20.000000000 +1300 @@ -229,6 +229,7 @@ statCounter.client_http.nearHitSvcTime.count(svc_time); break; + case LOG_TCP_INM_HIT: case LOG_TCP_IMS_HIT: statCounter.client_http.nearMissSvcTime.count(svc_time); break; @@ -814,6 +815,8 @@ // TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2 if (context != http->getConn()->pipeline.front()) context->deferRecipientForLater(node, rep, receivedData); + else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending + context->deferRecipientForLater(node, rep, receivedData); else http->getConn()->handleReply(rep, receivedData); @@ -1298,8 +1301,6 @@ { const bool parsedOk = hp->parse(csd->inBuf); - if (csd->port->flags.isIntercepted() && Config.accessList.on_unsupported_protocol) - csd->preservedClientData = csd->inBuf; // sync the buffers after parsing. csd->inBuf = hp->remaining(); @@ -1308,6 +1309,11 @@ return NULL; } + if (csd->mayTunnelUnsupportedProto()) { + csd->preservedClientData = hp->parsed(); + csd->preservedClientData.append(csd->inBuf); + } + if (!parsedOk) { const bool tooBig = hp->parseStatusCode == Http::scRequestHeaderFieldsTooLarge || @@ -1564,11 +1570,10 @@ * or false otherwise */ bool -clientTunnelOnError(ConnStateData *conn, Http::Stream *context, HttpRequest *request, const HttpRequestMethod& method, err_type requestError, Http::StatusCode errStatusCode, const char *requestErrorBytes) +clientTunnelOnError(ConnStateData *conn, Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod& method, err_type requestError) { - if (conn->port->flags.isIntercepted() && - Config.accessList.on_unsupported_protocol && conn->pipeline.nrequests <= 1) { - ACLFilledChecklist checklist(Config.accessList.on_unsupported_protocol, request, NULL); + if (conn->mayTunnelUnsupportedProto()) { + ACLFilledChecklist checklist(Config.accessList.on_unsupported_protocol, request.getRaw(), nullptr); checklist.requestErrorType = requestError; checklist.src_addr = conn->clientConnection->remote; checklist.my_addr = conn->clientConnection->local; @@ -1577,30 +1582,16 @@ if (answer == ACCESS_ALLOWED && answer.kind == 1) { debugs(33, 3, "Request will be tunneled to server"); if (context) { - // XXX: Either the context is finished() or it should stay queued. - // The below may leak client streams BodyPipe objects. BUT, we need - // to check if client-streams detatch is safe to do here (finished() will detatch). assert(conn->pipeline.front() == context); // XXX: still assumes HTTP/1 semantics - conn->pipeline.popMe(Http::StreamPointer(context)); + context->finished(); // Will remove from conn->pipeline queue } Comm::SetSelect(conn->clientConnection->fd, COMM_SELECT_READ, NULL, NULL, 0); - return conn->fakeAConnectRequest("unknown-protocol", conn->preservedClientData); + return conn->initiateTunneledRequest(request, Http::METHOD_NONE, "unknown-protocol", conn->preservedClientData); } else { debugs(33, 3, "Continue with returning the error: " << requestError); } } - if (context) { - conn->quitAfterError(request); - clientStreamNode *node = context->getClientReplyContext(); - clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); - assert (repContext); - - repContext->setReplyToError(requestError, errStatusCode, method, context->http->uri, conn->clientConnection->remote, NULL, requestErrorBytes, NULL); - - assert(context->http->out.offset == 0); - context->pullData(); - } // else Probably an ERR_REQUEST_START_TIMEOUT error so just return. return false; } @@ -2155,7 +2146,7 @@ if (needProxyProtocolHeader_ && !parseProxyProtocolHeader()) break; - if (Http::Stream *context = parseOneRequest()) { + if (Http::StreamPointer context = parseOneRequest()) { debugs(33, 5, clientConnection << ": done parsing a request"); AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout", @@ -2375,23 +2366,12 @@ if (!Comm::IsConnOpen(io.conn)) return; - if (Config.accessList.on_unsupported_protocol && !receivedFirstByte_) { -#if USE_OPENSSL - if (serverBump() && (serverBump()->act.step1 == Ssl::bumpPeek || serverBump()->act.step1 == Ssl::bumpStare)) { - if (spliceOnError(ERR_REQUEST_START_TIMEOUT)) { - receivedFirstByte(); - return; - } - } else if (!fd_table[io.conn->fd].ssl) -#endif - { - const HttpRequestMethod method; - if (clientTunnelOnError(this, NULL, NULL, method, ERR_REQUEST_START_TIMEOUT, Http::scNone, NULL)) { - // Tunnel established. Set receivedFirstByte to avoid loop. - receivedFirstByte(); - return; - } - } + if (mayTunnelUnsupportedProto() && !receivedFirstByte_) { + Http::StreamPointer context = pipeline.front(); + Must(context && context->http); + HttpRequest::Pointer request = context->http->request; + if (clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_REQUEST_START_TIMEOUT)) + return; } /* * Just close the connection to not confuse browsers @@ -2624,7 +2604,7 @@ debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error); } else { debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " << - (xerrno == 0 ? ERR_error_string(ssl_error, NULL) : xstrerr(xerrno))); + (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno))); } return -1; @@ -2634,7 +2614,7 @@ default: debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << - fd << ": " << ERR_error_string(ERR_get_error(), NULL) << + fd << ": " << Security::ErrorString(ERR_get_error()) << " (" << ssl_error << "/" << ret << ")"); return -1; } @@ -2759,7 +2739,7 @@ // Require both a match and a positive bump mode to work around exceptional // cases where ACL code may return ACCESS_ALLOWED with zero answer.kind. - if (answer == ACCESS_ALLOWED && (answer.kind != Ssl::bumpNone && answer.kind != Ssl::bumpSplice)) { + if (answer == ACCESS_ALLOWED && answer.kind != Ssl::bumpNone) { debugs(33, 2, "sslBump needed for " << connState->clientConnection << " method " << answer.kind); connState->sslBumpMode = static_cast(answer.kind); } else { @@ -2891,22 +2871,9 @@ { certProperties.commonName = sslCommonName_.isEmpty() ? sslConnectHostOrIp.termedBuf() : sslCommonName_.c_str(); - // fake certificate adaptation requires bump-server-first mode - if (!sslServerBump) { - assert(port->signingCert.get()); - certProperties.signWithX509.resetAndLock(port->signingCert.get()); - if (port->signPkey.get()) - certProperties.signWithPkey.resetAndLock(port->signPkey.get()); - certProperties.signAlgorithm = Ssl::algSignTrusted; - return; - } - - // In case of an error while connecting to the secure server, use a fake - // trusted certificate, with no mimicked fields and no adaptation - // algorithms. There is nothing we can mimic so we want to minimize the - // number of warnings the user will have to see to get to the error page. - assert(sslServerBump->entry); - if (sslServerBump->entry->isEmpty()) { + const bool triedToConnect = sslServerBump && sslServerBump->entry; + const bool connectedOK = triedToConnect && sslServerBump->entry->isEmpty(); + if (connectedOK) { if (X509 *mimicCert = sslServerBump->serverCert.get()) certProperties.mimicCert.resetAndLock(mimicCert); @@ -2949,11 +2916,13 @@ break; } } - } else {// if (!sslServerBump->entry->isEmpty()) - // Use trusted certificate for a Squid-generated error - // or the user would have to add a security exception - // just to see the error page. We will close the connection - // so that the trust is not extended to non-Squid content. + } else {// did not try to connect (e.g. client-first) or failed to connect + // In case of an error while connecting to the secure server, use a + // trusted certificate, with no mimicked fields and no adaptation + // algorithms. There is nothing we can mimic, so we want to minimize the + // number of warnings the user will have to see to get to the error page. + // We will close the connection, so that the trust is not extended to + // non-Squid content. certProperties.signAlgorithm = Ssl::algSignTrusted; } @@ -3176,6 +3145,9 @@ parsingTlsHandshake = false; + if (mayTunnelUnsupportedProto()) + preservedClientData = inBuf; + // Even if the parser failed, each TLS detail should either be set // correctly or still be "unknown"; copying unknown detail is a no-op. Security::TlsDetails::Pointer const &details = tlsParser.details; @@ -3190,7 +3162,18 @@ 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 + if (unsupportedProtocol) { + Http::StreamPointer context = pipeline.front(); + Must(context && context->http); + HttpRequest::Pointer request = context->http->request; + debugs(83, 5, "Got something other than TLS Client Hello. Cannot SslBump."); + sslBumpMode = Ssl::bumpNone; + if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_PROTOCOL_UNKNOWN)) + clientConnection->close(); + return; + } + + if (!sslServerBump || sslServerBump->act.step1 == Ssl::bumpClientFirst) { // Either means client-first. getSslContextStart(); return; } else if (sslServerBump->act.step1 == Ssl::bumpServerFirst) { @@ -3198,36 +3181,8 @@ FwdState::fwdStart(clientConnection, sslServerBump->entry, sslServerBump->request.getRaw()); } else { Must(sslServerBump->act.step1 == Ssl::bumpPeek || sslServerBump->act.step1 == Ssl::bumpStare); - startPeekAndSplice(unsupportedProtocol); - } -} - -bool -ConnStateData::spliceOnError(const err_type err) -{ - if (Config.accessList.on_unsupported_protocol) { - assert(serverBump()); - ACLFilledChecklist checklist(Config.accessList.on_unsupported_protocol, serverBump()->request.getRaw(), NULL); - checklist.requestErrorType = err; - checklist.conn(this); - allow_t answer = checklist.fastCheck(); - if (answer == ACCESS_ALLOWED && answer.kind == 1) { - return splice(); - } - } - return false; -} - -void -ConnStateData::startPeekAndSplice(const bool unsupportedProtocol) -{ - if (unsupportedProtocol) { - if (!spliceOnError(ERR_PROTOCOL_UNKNOWN)) - clientConnection->close(); - return; + startPeekAndSplice(); } - - startPeekAndSpliceDone(); } void httpsSslBumpStep2AccessCheckDone(allow_t answer, void *data) @@ -3252,7 +3207,7 @@ if (bumpAction == Ssl::bumpTerminate) { connState->clientConnection->close(); } else if (bumpAction != Ssl::bumpSplice) { - connState->startPeekAndSpliceDone(); + connState->startPeekAndSplice(); } else if (!connState->splice()) connState->clientConnection->close(); } @@ -3268,37 +3223,30 @@ 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(); - 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(); - Http::StreamPointer context = pipeline.front(); - ClientHttpRequest *http = context->http; - tunnelStart(http); - return true; - } + // 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(); + assert(!pipeline.empty()); + Http::StreamPointer context = pipeline.front(); + ClientHttpRequest *http = context->http; + tunnelStart(http); + return true; } void -ConnStateData::startPeekAndSpliceDone() +ConnStateData::startPeekAndSplice() { // This is the Step2 of the SSL bumping assert(sslServerBump); Http::StreamPointer context = pipeline.front(); - ClientHttpRequest *http = context ? context->http : NULL; + ClientHttpRequest *http = context ? context->http : nullptr; if (sslServerBump->step == Ssl::bumpStep1) { sslServerBump->step = Ssl::bumpStep2; // Run a accessList check to check if want to splice or continue bumping - ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, sslServerBump->request.getRaw(), NULL); - acl_checklist->al = http ? http->al : NULL; + ACLFilledChecklist *acl_checklist = new ACLFilledChecklist(Config.accessList.ssl_bump, sslServerBump->request.getRaw(), nullptr); + acl_checklist->al = http ? http->al : nullptr; //acl_checklist->src_addr = params.conn->remote; //acl_checklist->my_addr = s->s; acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpNone)); @@ -3330,8 +3278,8 @@ 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)) + HttpRequest::Pointer request(http ? http->request : nullptr); + if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_SECURE_ACCEPT_FAIL)) clientConnection->close(); return; } @@ -3382,41 +3330,125 @@ #endif /* USE_OPENSSL */ bool -ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload) +ConnStateData::initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload) { // fake a CONNECT request to force connState to tunnel SBuf connectHost; + unsigned short connectPort = 0; + + if (pinning.serverConnection != nullptr) { + static char ip[MAX_IPSTRLEN]; + connectHost.assign(pinning.serverConnection->remote.toStr(ip, sizeof(ip))); + connectPort = pinning.serverConnection->remote.port(); + } else if (cause && cause->method == Http::METHOD_CONNECT) { + // We are inside a (not fully established) CONNECT request + connectHost = cause->url.host(); + connectPort = cause->url.port(); + } else { + debugs(33, 2, "Not able to compute URL, abort request tunneling for " << reason); + return false; + } + + debugs(33, 2, "Request tunneling for " << reason); + ClientHttpRequest *http = buildFakeRequest(method, connectHost, connectPort, payload); + HttpRequest::Pointer request = http->request; + request->flags.forceTunnel = true; + http->calloutContext = new ClientRequestContext(http); + http->doCallouts(); + clientProcessRequestFinished(this, request); + return true; +} + +bool +ConnStateData::fakeAConnectRequest(const char *reason, const SBuf &payload) +{ + debugs(33, 2, "fake a CONNECT request to force connState to tunnel for " << reason); + + SBuf connectHost; + assert(transparent()); + const unsigned short connectPort = clientConnection->local.port(); + #if USE_OPENSSL - if (serverBump() && !serverBump()->clientSni.isEmpty()) { + if (serverBump() && !serverBump()->clientSni.isEmpty()) connectHost.assign(serverBump()->clientSni); - if (clientConnection->local.port() > 0) - connectHost.appendf(":%d",clientConnection->local.port()); - } else + else #endif { static char ip[MAX_IPSTRLEN]; - connectHost.assign(clientConnection->local.toUrl(ip, sizeof(ip))); + connectHost.assign(clientConnection->local.toStr(ip, sizeof(ip))); } - // Pre-pend this fake request to the TLS bits already in the buffer - SBuf retStr; - retStr.append("CONNECT "); - retStr.append(connectHost); - retStr.append(" HTTP/1.1\r\nHost: "); - retStr.append(connectHost); - retStr.append("\r\n\r\n"); - retStr.append(payload); - inBuf = retStr; - bool ret = handleReadData(); - if (ret) - ret = clientParseRequests(); - if (!ret) { - debugs(33, 2, "Failed to start fake CONNECT request for " << reason << " connection: " << clientConnection); - return false; - } + ClientHttpRequest *http = buildFakeRequest(Http::METHOD_CONNECT, connectHost, connectPort, payload); + + http->calloutContext = new ClientRequestContext(http); + HttpRequest::Pointer request = http->request; + http->doCallouts(); + clientProcessRequestFinished(this, request); return true; } +ClientHttpRequest * +ConnStateData::buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload) +{ + ClientHttpRequest *http = new ClientHttpRequest(this); + Http::Stream *stream = new Http::Stream(clientConnection, http); + + StoreIOBuffer tempBuffer; + tempBuffer.data = stream->reqbuf; + tempBuffer.length = HTTP_REQBUF_SZ; + + ClientStreamData newServer = new clientReplyContext(http); + ClientStreamData newClient = stream; + clientStreamInit(&http->client_stream, clientGetMoreData, clientReplyDetach, + clientReplyStatus, newServer, clientSocketRecipient, + clientSocketDetach, newClient, tempBuffer); + + http->uri = SBufToCstring(useHost); + stream->flags.parsed_ok = 1; // Do we need it? + stream->mayUseConnection(true); + + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "clientLifetimeTimeout", + CommTimeoutCbPtrFun(clientLifetimeTimeout, stream->http)); + commSetConnTimeout(clientConnection, Config.Timeout.lifetime, timeoutCall); + + stream->registerWithConn(); + + // Setup Http::Request object. Maybe should be replaced by a call to (modified) + // clientProcessRequest + HttpRequest::Pointer request = new HttpRequest(); + AnyP::ProtocolType proto = (method == Http::METHOD_NONE) ? AnyP::PROTO_AUTHORITY_FORM : AnyP::PROTO_HTTP; + request->url.setScheme(proto, nullptr); + request->method = method; + request->url.host(useHost.c_str()); + request->url.port(usePort); + http->request = request.getRaw(); + HTTPMSGLOCK(http->request); + + request->clientConnectionManager = this; + + if (proto == AnyP::PROTO_HTTP) + request->header.putStr(Http::HOST, useHost.c_str()); + request->flags.intercepted = ((clientConnection->flags & COMM_INTERCEPTION) != 0); + request->flags.interceptTproxy = ((clientConnection->flags & COMM_TRANSPARENT) != 0 ); + request->sources |= ((switchedToHttps() || port->transport.protocol == AnyP::PROTO_HTTPS) ? HttpMsg::srcHttps : HttpMsg::srcHttp); +#if USE_AUTH + if (getAuth()) + request->auth_user_request = getAuth(); +#endif + request->client_addr = clientConnection->remote; +#if FOLLOW_X_FORWARDED_FOR + request->indirect_client_addr = clientConnection->remote; +#endif /* FOLLOW_X_FORWARDED_FOR */ + request->my_addr = clientConnection->local; + request->myportname = port->name; + + inBuf = payload; + flags.readMore = false; + + setLogUri(http, urlCanonicalClean(request.getRaw())); + return http; +} + /// check FD after clientHttp[s]ConnectionOpened, adjust HttpSockets as needed static bool OpenedHttpSocket(const Comm::ConnectionPointer &c, const Ipc::FdNoteId portType) @@ -3794,7 +3826,10 @@ typedef CommCbMemFunT Dialer; AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, HttpControlMsgSink::wroteControlMsg); - writeControlMsgAndCall(rep.getRaw(), call); + if (!writeControlMsgAndCall(rep.getRaw(), call)) { + // but still inform the caller (so it may resume its operation) + doneWithControlMsg(); + } return; } @@ -3802,6 +3837,17 @@ clientConnection->close(); } +void +ConnStateData::doneWithControlMsg() +{ + HttpControlMsgSink::doneWithControlMsg(); + + if (Http::StreamPointer deferredRequest = pipeline.front()) { + debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote"); + ClientSocketContextPushDeferredIfNeeded(deferredRequest, this); + } +} + /// Our close handler called by Comm when the pinned connection is closed void ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io) @@ -4052,10 +4098,7 @@ // do not log connections that closed after a transaction (it is normal) // TODO: access_log needs ACLs to match received-no-bytes connections - // XXX: TLS may return here even though we got no transactions yet - // XXX: PROXY protocol may return here even though we got no - // transactions yet - if (receivedFirstByte_ && inBuf.isEmpty()) + if (pipeline.nrequests && inBuf.isEmpty()) return; /* Create a temporary ClientHttpRequest object. Its destructor will log. */ @@ -4066,3 +4109,15 @@ setLogUri(&http, uri); } +bool +ConnStateData::mayTunnelUnsupportedProto() +{ + return Config.accessList.on_unsupported_protocol +#if USE_OPENSSL + && + ((port->flags.isIntercepted() && port->flags.tunnelSslBumping) + || (serverBump() && pinning.serverConnection)) +#endif + ; +} + diff -u -r -N squid-4.0.16/src/client_side.h squid-4.0.17/src/client_side.h --- squid-4.0.16/src/client_side.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/client_side.h 2016-12-16 23:06:20.000000000 +1300 @@ -77,6 +77,7 @@ /* HttpControlMsgSink API */ virtual void sendControlMsg(HttpControlMsg); + virtual void doneWithControlMsg(); /// Traffic parsing bool clientParseRequests(); @@ -203,9 +204,8 @@ void postHttpsAccept(); /// Initializes and starts a peek-and-splice negotiation with the SSL client - void startPeekAndSplice(const bool unknownProtocol); - /// Called when the initialization of peek-and-splice negotiation finidhed - void startPeekAndSpliceDone(); + void startPeekAndSplice(); + /// Called when a peek-and-splice step finished. For example after /// server SSL certificates received and fake server SSL certificates /// generated @@ -216,11 +216,6 @@ /// Splice a bumped client connection on peek-and-splice mode bool splice(); - /// Check on_unsupported_protocol access list and splice if required - /// \retval true on splice - /// \retval false otherwise - bool spliceOnError(const err_type err); - /// Start to create dynamic Security::ContextPointer for host or uses static port SSL context. void getSslContextStart(); /** @@ -269,7 +264,7 @@ void connectionTag(const char *aTag) { connectionTag_ = aTag; } /// handle a control message received by context from a peer and call back - virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0; + virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0; /// ClientStream calls this to supply response header (once) and data /// for the current Http::Stream. @@ -287,6 +282,15 @@ /// at the beginning of the client I/O buffer bool fakeAConnectRequest(const char *reason, const SBuf &payload); + /// generates and sends to tunnel.cc a fake request with a given payload + bool initiateTunneledRequest(HttpRequest::Pointer const &cause, Http::MethodType const method, const char *reason, const SBuf &payload); + + /// whether tunneling of unsupported protocol is allowed for this connection + bool mayTunnelUnsupportedProto(); + + /// build a fake http request + ClientHttpRequest *buildFakeRequest(Http::MethodType const method, SBuf &useHost, unsigned short usePort, const SBuf &payload); + /// client data which may need to forward as-is to server after an /// on_unsupported_protocol tunnel decision. SBuf preservedClientData; @@ -316,7 +320,7 @@ virtual Http::Stream *parseOneRequest() = 0; /// start processing a freshly parsed request - virtual void processParsedRequest(Http::Stream *) = 0; + virtual void processParsedRequest(Http::StreamPointer &) = 0; /// returning N allows a pipeline of 1+N requests (see pipeline_prefetch) virtual int pipelinePrefetchMax() const; diff -u -r -N squid-4.0.16/src/client_side_reply.cc squid-4.0.17/src/client_side_reply.cc --- squid-4.0.16/src/client_side_reply.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/client_side_reply.cc 2016-12-16 23:06:20.000000000 +1300 @@ -415,6 +415,15 @@ if (result.flags.error && !EBIT_TEST(http->storeEntry()->flags, ENTRY_ABORTED)) return; + if (collapsedRevalidation == crSlave && EBIT_TEST(http->storeEntry()->flags, KEY_PRIVATE)) { + debugs(88, 3, "CF slave hit private " << *http->storeEntry() << ". MISS"); + // restore context to meet processMiss() expectations + restoreState(); + http->logType = LOG_TCP_MISS; + processMiss(); + return; + } + /* update size of the request */ reqsize = result.length + reqofs; @@ -536,6 +545,16 @@ return; } + // The previously identified hit suddenly became unsharable! + // This is common for collapsed forwarding slaves but might also + // happen to regular hits because we are called asynchronously. + if (EBIT_TEST(e->flags, KEY_PRIVATE)) { + debugs(88, 3, "unsharable " << *e << ". MISS"); + http->logType = LOG_TCP_MISS; + processMiss(); + return; + } + if (result.length == 0) { debugs(88, 5, "store IO buffer has no content. MISS"); /* the store couldn't get enough data from the file for us to id the @@ -607,6 +626,7 @@ debugs(88, 5, "negative-HIT"); http->logType = LOG_TCP_NEGATIVE_HIT; sendMoreData(result); + return; } else if (blockedHit()) { debugs(88, 5, "send_hit forces a MISS"); http->logType = LOG_TCP_MISS; @@ -659,27 +679,29 @@ http->logType = LOG_TCP_MISS; processMiss(); } + return; } else if (r->conditional()) { debugs(88, 5, "conditional HIT"); - processConditional(result); - } else { - /* - * plain ol' cache hit - */ - debugs(88, 5, "plain old HIT"); + if (processConditional(result)) + return; + } + + /* + * plain ol' cache hit + */ + debugs(88, 5, "plain old HIT"); #if USE_DELAY_POOLS - if (e->store_status != STORE_OK) - http->logType = LOG_TCP_MISS; - else + if (e->store_status != STORE_OK) + http->logType = LOG_TCP_MISS; + else #endif - if (e->mem_status == IN_MEMORY) - http->logType = LOG_TCP_MEM_HIT; - else if (Config.onoff.offline) - http->logType = LOG_TCP_OFFLINE_HIT; + if (e->mem_status == IN_MEMORY) + http->logType = LOG_TCP_MEM_HIT; + else if (Config.onoff.offline) + http->logType = LOG_TCP_OFFLINE_HIT; - sendMoreData(result); - } + sendMoreData(result); } /** @@ -773,17 +795,16 @@ } /// process conditional request from client -void +bool clientReplyContext::processConditional(StoreIOBuffer &result) { StoreEntry *const e = http->storeEntry(); if (e->getReply()->sline.status() != Http::scOkay) { - debugs(88, 4, "clientReplyContext::processConditional: Reply code " << - e->getReply()->sline.status() << " != 200"); + debugs(88, 4, "Reply code " << e->getReply()->sline.status() << " != 200"); http->logType = LOG_TCP_MISS; processMiss(); - return; + return true; } HttpRequest &r = *http->request; @@ -791,51 +812,39 @@ if (r.header.has(Http::HdrType::IF_MATCH) && !e->hasIfMatchEtag(r)) { // RFC 2616: reply with 412 Precondition Failed if If-Match did not match sendPreconditionFailedError(); - return; + return true; } - bool matchedIfNoneMatch = false; if (r.header.has(Http::HdrType::IF_NONE_MATCH)) { - if (!e->hasIfNoneMatchEtag(r)) { - // RFC 2616: ignore IMS if If-None-Match did not match - r.flags.ims = false; - r.ims = -1; - r.imslen = 0; - r.header.delById(Http::HdrType::IF_MODIFIED_SINCE); - http->logType = LOG_TCP_MISS; - sendMoreData(result); - return; - } + // RFC 7232: If-None-Match recipient MUST ignore IMS + r.flags.ims = false; + r.ims = -1; + r.imslen = 0; + r.header.delById(Http::HdrType::IF_MODIFIED_SINCE); - if (!r.flags.ims) { - // RFC 2616: if If-None-Match matched and there is no IMS, - // reply with 304 Not Modified or 412 Precondition Failed + if (e->hasIfNoneMatchEtag(r)) { sendNotModifiedOrPreconditionFailedError(); - return; + return true; } - // otherwise check IMS below to decide if we reply with 304 or 412 - matchedIfNoneMatch = true; + // None-Match is true (no ETag matched); treat as an unconditional hit + return false; } if (r.flags.ims) { // handle If-Modified-Since requests from the client if (e->modifiedSince(r.ims, r.imslen)) { - http->logType = LOG_TCP_IMS_HIT; - sendMoreData(result); - return; - } + // Modified-Since is true; treat as an unconditional hit + return false; - if (matchedIfNoneMatch) { - // If-None-Match matched, reply with 304 Not Modified or - // 412 Precondition Failed - sendNotModifiedOrPreconditionFailedError(); - return; + } else { + // otherwise reply with 304 Not Modified + sendNotModified(); } - - // otherwise reply with 304 Not Modified - sendNotModified(); + return true; } + + return false; } /// whether squid.conf send_hit prevents us from serving this hit @@ -1361,7 +1370,7 @@ hdr->delById(HDR_ETAG); #endif - if (is_hit) + if (is_hit || collapsedRevalidation == crSlave) hdr->delById(Http::HdrType::SET_COOKIE); // TODO: RFC 2965 : Must honour Cache-Control: no-cache="set-cookie2" and remove header. @@ -1663,7 +1672,9 @@ { HttpRequest *r = http->request; - if (r->flags.cachable || r->flags.internal) { + // client sent CC:no-cache or some other condition has been + // encountered which prevents delivering a public/cached object. + if (!r->flags.noCache || r->flags.internal) { lookingforstore = 5; StoreEntry::getPublicByRequest (this, r); } else { @@ -1986,7 +1997,12 @@ StoreEntry *e = http->storeEntry(); const time_t timestamp = e->timestamp; HttpReply *const temprep = e->getReply()->make304(); - http->logType = LOG_TCP_IMS_HIT; + // log as TCP_INM_HIT if code 304 generated for + // If-None-Match request + if (!http->request->flags.ims) + http->logType = LOG_TCP_INM_HIT; + else + http->logType = LOG_TCP_IMS_HIT; removeClientStoreReference(&sc, http); createStoreEntry(http->request->method, RequestFlags()); e = http->storeEntry(); diff -u -r -N squid-4.0.16/src/client_side_reply.h squid-4.0.17/src/client_side_reply.h --- squid-4.0.16/src/client_side_reply.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/client_side_reply.h 2016-12-16 23:06:20.000000000 +1300 @@ -115,7 +115,7 @@ bool alwaysAllowResponse(Http::StatusCode sline) const; int checkTransferDone(); void processOnlyIfCachedMiss(); - void processConditional(StoreIOBuffer &result); + bool processConditional(StoreIOBuffer &result); void cacheHit(StoreIOBuffer result); void handleIMSReply(StoreIOBuffer result); void sendMoreData(StoreIOBuffer result); diff -u -r -N squid-4.0.16/src/client_side_request.cc squid-4.0.17/src/client_side_request.cc --- squid-4.0.16/src/client_side_request.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/client_side_request.cc 2016-12-16 23:06:20.000000000 +1300 @@ -1412,6 +1412,11 @@ return false; } + if (http->request->flags.forceTunnel) { + debugs(85, 5, "not needed; already decided to tunnel " << http->getConn()); + return false; + } + // If SSL connection tunneling or bumping decision has been made, obey it. const Ssl::BumpMode bumpMode = http->getConn()->sslBumpMode; if (bumpMode != Ssl::bumpEnd) { @@ -1490,13 +1495,17 @@ { debugs(85, 4, request->method << ' ' << uri); - if (request->method == Http::METHOD_CONNECT && !redirect.status) { + const bool untouchedConnect = request->method == Http::METHOD_CONNECT && !redirect.status; + #if USE_OPENSSL - if (sslBumpNeeded()) { - sslBumpStart(); - return; - } + if (untouchedConnect && sslBumpNeeded()) { + assert(!request->flags.forceTunnel); + sslBumpStart(); + return; + } #endif + + if (untouchedConnect || request->flags.forceTunnel) { getConn()->stopReading(); // tunnels read for themselves tunnelStart(this); return; @@ -1795,7 +1804,7 @@ // We have to serve an error, so bump the client first. sslBumpNeed(Ssl::bumpClientFirst); // set final error but delay sending until we bump - Ssl::ServerBump *srvBump = new Ssl::ServerBump(request, e); + Ssl::ServerBump *srvBump = new Ssl::ServerBump(request, e, Ssl::bumpClientFirst); errorAppendEntry(e, calloutContext->error); calloutContext->error = NULL; getConn()->setServerBump(srvBump); diff -u -r -N squid-4.0.16/src/format/Config.cc squid-4.0.17/src/format/Config.cc --- squid-4.0.16/src/format/Config.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/format/Config.cc 2016-12-16 23:06:20.000000000 +1300 @@ -20,10 +20,12 @@ { char *name, *def; - if ((name = ConfigParser::NextToken()) == NULL) + if ((name = ConfigParser::NextToken()) == nullptr) { self_destruct(); + return; + } - if ((def = ConfigParser::NextQuotedOrToEol()) == NULL) { + if ((def = ConfigParser::NextQuotedOrToEol()) == nullptr) { self_destruct(); return; } diff -u -r -N squid-4.0.16/src/fqdncache.cc squid-4.0.17/src/fqdncache.cc --- squid-4.0.16/src/fqdncache.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/fqdncache.cc 2016-12-16 23:06:20.000000000 +1300 @@ -22,7 +22,6 @@ #include "StatCounters.h" #include "Store.h" #include "util.h" -#include "wordlist.h" #if SQUID_SNMP #include "snmp_core.h" @@ -642,27 +641,20 @@ } /** - \ingroup FQDNCacheAPI - * * Adds a "static" entry from /etc/hosts. - \par - * The worldist is to be managed by the caller, - * including pointed-to strings * \param addr FQDN name to be added. - \param hostnames ?? + \param hostnames list of hostnames for the addr */ void -fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames) +fqdncacheAddEntryFromHosts(char *addr, SBufList &hostnames) { - fqdncache_entry *fce; - int j = 0; - - if ((fce = fqdncache_get(addr))) { + fqdncache_entry *fce= fqdncache_get(addr); + if (fce) { if (1 == fce->flags.fromhosts) { fqdncacheUnlockEntry(fce); } else if (fce->locks > 0) { - debugs(35, DBG_IMPORTANT, "fqdncacheAddEntryFromHosts: can't add static entry for locked address '" << addr << "'"); + debugs(35, DBG_IMPORTANT, "WARNING: can't add static entry for locked address '" << addr << "'"); return; } else { fqdncacheRelease(fce); @@ -671,11 +663,11 @@ fce = new fqdncache_entry(addr); - while (hostnames) { - fce->names[j] = xstrdup(hostnames->key); + int j = 0; + for (auto &h : hostnames) { + fce->names[j] = xstrdup(h.c_str()); Tolower(fce->names[j]); ++j; - hostnames = hostnames->next; if (j >= FQDN_MAX_NAMES) break; diff -u -r -N squid-4.0.16/src/fqdncache.h squid-4.0.17/src/fqdncache.h --- squid-4.0.16/src/fqdncache.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/fqdncache.h 2016-12-16 23:06:20.000000000 +1300 @@ -12,9 +12,9 @@ #define SQUID_FQDNCACHE_H_ #include "ip/Address.h" +#include "sbuf/forward.h" class StoreEntry; -class wordlist; namespace Dns { class LookupDetails; @@ -27,7 +27,7 @@ void fqdncacheFreeMemory(void); void fqdncache_restart(void); void fqdncache_purgelru(void *); -void fqdncacheAddEntryFromHosts(char *addr, wordlist * hostnames); +void fqdncacheAddEntryFromHosts(char *addr, SBufList &hostnames); const char *fqdncache_gethostbyaddr(const Ip::Address &, int flags); void fqdncache_nbgethostbyaddr(const Ip::Address &, FQDNH *, void *); diff -u -r -N squid-4.0.16/src/FwdState.cc squid-4.0.17/src/FwdState.cc --- squid-4.0.16/src/FwdState.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/FwdState.cc 2016-12-16 23:06:20.000000000 +1300 @@ -847,28 +847,24 @@ ConnStateData *pinned_connection = request->pinnedConnection(); debugs(17,7, "pinned peer connection: " << pinned_connection); // pinned_connection may become nil after a pconn race - if (pinned_connection) { - serverConn = pinned_connection->borrowPinnedConnection(request, serverDestinations[0]->getPeer()); - if (Comm::IsConnOpen(serverConn)) { - pinned_connection->stopPinnedConnectionMonitoring(); - flags.connected_okay = true; - ++n_tries; - request->flags.pinned = true; - if (pinned_connection->pinnedAuth()) - request->flags.auth = true; + serverConn = pinned_connection ? pinned_connection->borrowPinnedConnection(request, serverDestinations[0]->getPeer()) : nullptr; + if (Comm::IsConnOpen(serverConn)) { + flags.connected_okay = true; + ++n_tries; + request->flags.pinned = true; - closeHandler = comm_add_close_handler(serverConn->fd, fwdServerClosedWrapper, this); + if (pinned_connection->pinnedAuth()) + request->flags.auth = true; - syncWithServerConn(pinned_connection->pinning.host); + closeHandler = comm_add_close_handler(serverConn->fd, fwdServerClosedWrapper, this); - // the server may close the pinned connection before this request - pconnRace = racePossible; - dispatch(); - return; - } + syncWithServerConn(pinned_connection->pinning.host); - } else - serverConn = nullptr; + // the server may close the pinned connection before this request + pconnRace = racePossible; + dispatch(); + return; + } // Pinned connection failure. debugs(17,2,HERE << "Pinned connection failed: " << pinned_connection); diff -u -r -N squid-4.0.16/src/htcp.cc squid-4.0.17/src/htcp.cc --- squid-4.0.16/src/htcp.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/htcp.cc 2016-12-16 23:06:20.000000000 +1300 @@ -22,7 +22,6 @@ #include "htcp.h" #include "http.h" #include "HttpRequest.h" -#include "HttpStateFlags.h" #include "icmp/net_db.h" #include "ip/tools.h" #include "md5.h" @@ -1428,7 +1427,7 @@ ssize_t pktlen; char vbuf[32]; HttpHeader hdr(hoRequest); - HttpStateFlags flags; + Http::StateFlags flags; if (!Comm::IsConnOpen(htcpIncomingConn)) return 0; @@ -1478,7 +1477,7 @@ char vbuf[32]; HttpHeader hdr(hoRequest); MemBuf mb; - HttpStateFlags flags; + Http::StateFlags flags; if (!Comm::IsConnOpen(htcpIncomingConn)) return; diff -u -r -N squid-4.0.16/src/http/Makefile.am squid-4.0.17/src/http/Makefile.am --- squid-4.0.16/src/http/Makefile.am 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http/Makefile.am 2016-12-16 23:06:20.000000000 +1300 @@ -25,6 +25,7 @@ RegisteredHeadersHash.cci \ RequestMethod.cc \ RequestMethod.h \ + StateFlags.h \ StatusCode.cc \ StatusCode.h \ StatusLine.cc \ diff -u -r -N squid-4.0.16/src/http/Makefile.in squid-4.0.17/src/http/Makefile.in --- squid-4.0.16/src/http/Makefile.in 2016-10-31 01:27:19.000000000 +1300 +++ squid-4.0.17/src/http/Makefile.in 2016-12-16 23:16:56.000000000 +1300 @@ -769,6 +769,7 @@ RegisteredHeadersHash.cci \ RequestMethod.cc \ RequestMethod.h \ + StateFlags.h \ StatusCode.cc \ StatusCode.h \ StatusLine.cc \ diff -u -r -N squid-4.0.16/src/http/one/RequestParser.cc squid-4.0.17/src/http/one/RequestParser.cc --- squid-4.0.16/src/http/one/RequestParser.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http/one/RequestParser.cc 2016-12-16 23:06:20.000000000 +1300 @@ -20,8 +20,9 @@ return Config.onoff.relaxed_header_parser < 0 ? DBG_IMPORTANT : 5; } -Http::One::RequestParser::RequestParser() : - Parser() +Http::One::RequestParser::RequestParser(bool preserveParsed) : + Parser(), + preserveParsed_(preserveParsed) {} Http1::Parser::size_type @@ -347,6 +348,19 @@ bool Http::One::RequestParser::parse(const SBuf &aBuf) { + const bool result = doParse(aBuf); + if (preserveParsed_) { + assert(aBuf.length() >= remaining().length()); + parsed_.append(aBuf.substr(0, aBuf.length() - remaining().length())); // newly parsed bytes + } + + return result; +} + +// raw is not a reference because a reference might point back to our own buf_ or parsed_ +bool +Http::One::RequestParser::doParse(const SBuf &aBuf) +{ buf_ = aBuf; debugs(74, DBG_DATA, "Parse buf={length=" << aBuf.length() << ", data='" << aBuf << "'}"); diff -u -r -N squid-4.0.16/src/http/one/RequestParser.h squid-4.0.17/src/http/one/RequestParser.h --- squid-4.0.16/src/http/one/RequestParser.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http/one/RequestParser.h 2016-12-16 23:06:20.000000000 +1300 @@ -30,7 +30,7 @@ class RequestParser : public Http1::Parser { public: - RequestParser(); + explicit RequestParser(bool preserveParsed = false); virtual ~RequestParser() {} /* Http::One::Parser API */ @@ -44,9 +44,14 @@ /// the request-line URI if this is a request message, or an empty string. const SBuf &requestUri() const {return uri_;} + /// the accumulated parsed bytes + const SBuf &parsed() const { Must(preserveParsed_); return parsed_; } + private: void skipGarbageLines(); int parseRequestFirstLine(); + /// called from parse() to do the parsing + bool doParse(const SBuf &aBuf); /* all these return false and set parseStatusCode on parsing failures */ bool parseMethodField(Http1::Tokenizer &); @@ -63,6 +68,11 @@ /// raw copy of the original client request-line URI field SBuf uri_; + + /// all parsed bytes (i.e., input prefix consumed by parse() calls) + /// meaningless unless preserveParsed_ is true + SBuf parsed_; + bool preserveParsed_; ///< whether to accumulate parsed bytes (in parsed_) }; } // namespace One diff -u -r -N squid-4.0.16/src/http/StateFlags.h squid-4.0.17/src/http/StateFlags.h --- squid-4.0.16/src/http/StateFlags.h 1970-01-01 12:00:00.000000000 +1200 +++ squid-4.0.17/src/http/StateFlags.h 2016-12-16 23:06:20.000000000 +1300 @@ -0,0 +1,37 @@ +/* + * 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_HTTP_STATEFLAGS_H +#define SQUID_SRC_HTTP_STATEFLAGS_H + +namespace Http +{ + +class StateFlags +{ +public: + unsigned int front_end_https = 0; ///< send "Front-End-Https: On" header (off/on/auto=2) + bool proxying = false; + bool keepalive = false; + bool only_if_cached = false; + bool handling1xx = false; ///< we are ignoring or forwarding 1xx response + bool headers_parsed = false; + bool originpeer = false; + bool keepalive_broken = false; + bool abuse_detected = false; + bool request_sent = false; + bool do_next_read = false; + bool chunked = false; ///< reading a chunked response; TODO: rename + bool chunked_request = false; ///< writing a chunked request + bool sentLastChunk = false; ///< do not try to write last-chunk again +}; + +} // namespace Http + +#endif /* SQUID_SRC_HTTP_STATEFLAGS_H */ + diff -u -r -N squid-4.0.16/src/http/StatusCode.cc squid-4.0.17/src/http/StatusCode.cc --- squid-4.0.16/src/http/StatusCode.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http/StatusCode.cc 2016-12-16 23:06:20.000000000 +1300 @@ -33,6 +33,10 @@ return "Processing"; break; + case Http::scEarlyHints: // 103 + return "Early Hints"; + break; + // 200-299 case Http::scOkay: return "OK"; diff -u -r -N squid-4.0.16/src/http/StatusCode.h squid-4.0.17/src/http/StatusCode.h --- squid-4.0.16/src/http/StatusCode.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http/StatusCode.h 2016-12-16 23:06:20.000000000 +1300 @@ -22,6 +22,7 @@ scContinue = 100, scSwitchingProtocols = 101, scProcessing = 102, /**< RFC2518 section 10.1 */ + scEarlyHints = 103, /**< draft-kazuho-early-hints-status-code */ scOkay = 200, scCreated = 201, scAccepted = 202, diff -u -r -N squid-4.0.16/src/http/Stream.h squid-4.0.17/src/http/Stream.h --- squid-4.0.16/src/http/Stream.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http/Stream.h 2016-12-16 23:06:20.000000000 +1300 @@ -75,6 +75,9 @@ /// register this stream with the Server void registerWithConn(); + /// whether it is registered with a Server + bool connRegistered() const {return connRegistered_;}; + /// whether the reply has started being sent bool startOfOutput() const; diff -u -r -N squid-4.0.16/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.0.17/src/http/url_rewriters/LFS/url_lfs_rewrite.8 --- squid-4.0.16/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2016-10-31 03:22:00.000000000 +1300 +++ squid-4.0.17/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2016-12-17 07:25:18.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "URL_LFS_REWRITE 8" -.TH URL_LFS_REWRITE 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH URL_LFS_REWRITE 8 "2016-12-16" "perl v5.24.1" "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.16/src/http.cc squid-4.0.17/src/http.cc --- squid-4.0.16/src/http.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http.cc 2016-12-16 23:06:20.000000000 +1300 @@ -41,7 +41,6 @@ #include "HttpHeaderTools.h" #include "HttpReply.h" #include "HttpRequest.h" -#include "HttpStateFlags.h" #include "log/access_log.h" #include "MemBuf.h" #include "MemObject.h" @@ -82,7 +81,7 @@ static void httpMaybeRemovePublic(StoreEntry *, Http::StatusCode); static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request, - HttpHeader * hdr_out, const int we_do_ranges, const HttpStateFlags &); + HttpHeader * hdr_out, const int we_do_ranges, const Http::StateFlags &); HttpStateData::HttpStateData(FwdState *theFwdState) : AsyncJob("HttpStateData"), @@ -190,6 +189,12 @@ if (!EBIT_TEST(e->flags, KEY_PRIVATE)) return; + // If the new/incoming response cannot be stored, then it does not + // compete with the old stored response for the public key, and the + // old stored response should be left as is. + if (e->mem_obj->request && !e->mem_obj->request->flags.cachable) + return; + switch (status) { case Http::scOkay: @@ -202,6 +207,8 @@ case Http::scFound: + case Http::scSeeOther: + case Http::scGone: case Http::scNotFound: @@ -1660,7 +1667,7 @@ * Fixup authentication request headers for special cases */ static void -httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHeader * hdr_out, const HttpStateFlags &flags) +httpFixupAuthentication(HttpRequest * request, const HttpHeader * hdr_in, HttpHeader * hdr_out, const Http::StateFlags &flags) { Http::HdrType header = flags.originpeer ? Http::HdrType::AUTHORIZATION : Http::HdrType::PROXY_AUTHORIZATION; @@ -1766,7 +1773,7 @@ StoreEntry * entry, const AccessLogEntryPointer &al, HttpHeader * hdr_out, - const HttpStateFlags &flags) + const Http::StateFlags &flags) { /* building buffer for complex strings */ #define BBUF_SZ (MAX_URL+32) @@ -1956,7 +1963,7 @@ * to our outgoing fetch request. */ void -copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request, HttpHeader * hdr_out, const int we_do_ranges, const HttpStateFlags &flags) +copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request, HttpHeader * hdr_out, const int we_do_ranges, const Http::StateFlags &flags) { debugs(11, 5, "httpBuildRequestHeader: " << e->name << ": " << e->value ); diff -u -r -N squid-4.0.16/src/HttpControlMsg.cc squid-4.0.17/src/HttpControlMsg.cc --- squid-4.0.16/src/HttpControlMsg.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/HttpControlMsg.cc 2016-12-16 23:06:20.000000000 +1300 @@ -11,6 +11,15 @@ #include "CommCalls.h" #include "HttpControlMsg.h" +void +HttpControlMsgSink::doneWithControlMsg() +{ + if (cbControlMsgSent) { + ScheduleCallHere(cbControlMsgSent); + cbControlMsgSent = nullptr; + } +} + /// called when we wrote the 1xx response void HttpControlMsgSink::wroteControlMsg(const CommIoCbParams ¶ms) @@ -19,8 +28,7 @@ return; if (params.flag == Comm::OK) { - if (cbControlMsgSent) - ScheduleCallHere(cbControlMsgSent); + doneWithControlMsg(); return; } diff -u -r -N squid-4.0.16/src/HttpControlMsg.h squid-4.0.17/src/HttpControlMsg.h --- squid-4.0.16/src/HttpControlMsg.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/HttpControlMsg.h 2016-12-16 23:06:20.000000000 +1300 @@ -33,6 +33,8 @@ /// called to send the 1xx message and notify the Source virtual void sendControlMsg(HttpControlMsg msg) = 0; + virtual void doneWithControlMsg(); + /// callback to handle Comm::Write completion void wroteControlMsg(const CommIoCbParams &); diff -u -r -N squid-4.0.16/src/http.h squid-4.0.17/src/http.h --- squid-4.0.16/src/http.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/http.h 2016-12-16 23:06:20.000000000 +1300 @@ -12,7 +12,7 @@ #include "clients/Client.h" #include "comm.h" #include "http/forward.h" -#include "HttpStateFlags.h" +#include "http/StateFlags.h" #include "sbuf/SBuf.h" class FwdState; @@ -30,7 +30,7 @@ StoreEntry * entry, const AccessLogEntryPointer &al, HttpHeader * hdr_out, - const HttpStateFlags &flags); + const Http::StateFlags &flags); virtual const Comm::ConnectionPointer & dataConnection() const; /* should be private */ @@ -46,7 +46,7 @@ CachePeer *_peer; /* CachePeer request made to */ int eof; /* reached end-of-object? */ int lastChunk; /* reached last chunk of a chunk-encoded reply */ - HttpStateFlags flags; + Http::StateFlags flags; size_t read_sz; SBuf inBuf; ///< I/O buffer for receiving server responses bool ignoreCacheControl; diff -u -r -N squid-4.0.16/src/HttpRequest.cc squid-4.0.17/src/HttpRequest.cc --- squid-4.0.16/src/HttpRequest.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/HttpRequest.cc 2016-12-16 23:06:20.000000000 +1300 @@ -543,8 +543,13 @@ if (!method.respMaybeCacheable()) return false; - // XXX: this would seem the correct place to detect request cache-controls - // no-store, private and related which block cacheability + // RFC 7234 section 5.2.1.5: + // "cache MUST NOT store any part of either this request or any response to it" + // + // NP: refresh_pattern ignore-no-store only applies to response messages + // this test is handling request message CC header. + if (!flags.ignoreCc && cache_control && cache_control->noStore()) + return false; break; case AnyP::PROTO_GOPHER: @@ -657,7 +662,7 @@ const SBuf & HttpRequest::effectiveRequestUri() const { - if (method.id() == Http::METHOD_CONNECT) + if (method.id() == Http::METHOD_CONNECT || url.getScheme() == AnyP::PROTO_AUTHORITY_FORM) return url.authority(true); // host:port return url.absolute(); } diff -u -r -N squid-4.0.16/src/HttpStateFlags.h squid-4.0.17/src/HttpStateFlags.h --- squid-4.0.16/src/HttpStateFlags.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/HttpStateFlags.h 1970-01-01 12:00:00.000000000 +1200 @@ -1,34 +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_HTTPSTATEFLAGS_H_ -#define SQUID_HTTPSTATEFLAGS_H_ - -// POD -class HttpStateFlags -{ -public: - bool proxying:1; - bool keepalive:1; - bool only_if_cached:1; - bool handling1xx:1; ///< we are ignoring or forwarding 1xx response - bool headers_parsed:1; - unsigned int front_end_https:2; //XXX: huh? - bool originpeer:1; - bool keepalive_broken:1; - bool abuse_detected:1; - bool request_sent:1; - bool do_next_read:1; - bool consume_body_data:1; //XXX: seems unused - bool chunked:1; ///< reading a chunked response; TODO: rename - bool chunked_request:1; ///< writing a chunked request - bool sentLastChunk:1; ///< do not try to write last-chunk again -}; - -#endif /* SQUID_HTTPSTATEFLAGS_H_ */ - diff -u -r -N squid-4.0.16/src/ip/Intercept.cc squid-4.0.17/src/ip/Intercept.cc --- squid-4.0.16/src/ip/Intercept.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ip/Intercept.cc 2016-12-16 23:06:20.000000000 +1300 @@ -343,13 +343,20 @@ } memset(&nl, 0, sizeof(struct pfioc_natlook)); - newConn->remote.getInAddr(nl.saddr.v4); - nl.sport = htons(newConn->remote.port()); - newConn->local.getInAddr(nl.daddr.v4); + if (newConn->remote.isIPv6()) { + newConn->remote.getInAddr(nl.saddr.v6); + newConn->local.getInAddr(nl.daddr.v6); + nl.af = AF_INET6; + } else { + newConn->remote.getInAddr(nl.saddr.v4); + newConn->local.getInAddr(nl.daddr.v4); + nl.af = AF_INET; + } + + nl.sport = htons(newConn->remote.port()); nl.dport = htons(newConn->local.port()); - nl.af = AF_INET; nl.proto = IPPROTO_TCP; nl.direction = PF_OUT; @@ -366,7 +373,10 @@ debugs(89, 9, HERE << "address: " << newConn); return false; } else { - newConn->local = nl.rdaddr.v4; + if (newConn->remote.isIPv6()) + newConn->local = nl.rdaddr.v6; + else + newConn->local = nl.rdaddr.v4; newConn->local.port(ntohs(nl.rdport)); debugs(89, 5, HERE << "address NAT: " << newConn); return true; diff -u -r -N squid-4.0.16/src/ipcache.cc squid-4.0.17/src/ipcache.cc --- squid-4.0.16/src/ipcache.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ipcache.cc 2016-12-16 23:06:20.000000000 +1300 @@ -129,7 +129,6 @@ static FREE ipcacheFreeEntry; static IDNSCB ipcacheHandleReply; static int ipcacheExpiredEntry(ipcache_entry *); -static int ipcacheParse(ipcache_entry *, const rfc1035_rr *, int, const char *error); static ipcache_entry *ipcache_get(const char *); static void ipcacheLockEntry(ipcache_entry *); static void ipcacheStatPrint(ipcache_entry *, StoreEntry *); @@ -333,8 +332,7 @@ ipcacheUnlockEntry(i); } -/// \ingroup IPCacheAPI -static int +static void ipcacheParse(ipcache_entry *i, const rfc1035_rr * answers, int nr, const char *error_message) { int k; @@ -355,25 +353,25 @@ i->addrs.count = 0; if (nr < 0) { - debugs(14, 3, "ipcacheParse: Lookup failed '" << error_message << "' for '" << (const char *)i->hash.key << "'"); + debugs(14, 3, "Lookup failed '" << error_message << "' for '" << (const char *)i->hash.key << "'"); i->error_message = xstrdup(error_message); - return -1; + return; } if (nr == 0) { - debugs(14, 3, "ipcacheParse: No DNS records in response to '" << name << "'"); + debugs(14, 3, "No DNS records in response to '" << name << "'"); i->error_message = xstrdup("No DNS records"); - return -1; + return; } - debugs(14, 3, "ipcacheParse: " << nr << " answers for '" << name << "'"); + debugs(14, 3, nr << " answers for '" << name << "'"); assert(answers); for (k = 0; k < nr; ++k) { if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) { if (answers[k].rdlength != sizeof(struct in6_addr)) { - debugs(14, DBG_IMPORTANT, "ipcacheParse: Invalid IPv6 address in response to '" << name << "'"); + debugs(14, DBG_IMPORTANT, MYNAME << "Invalid IPv6 address in response to '" << name << "'"); continue; } ++na; @@ -383,7 +381,7 @@ if (answers[k].type == RFC1035_TYPE_A) { if (answers[k].rdlength != sizeof(struct in_addr)) { - debugs(14, DBG_IMPORTANT, "ipcacheParse: Invalid IPv4 address in response to '" << name << "'"); + debugs(14, DBG_IMPORTANT, MYNAME << "Invalid IPv4 address in response to '" << name << "'"); continue; } ++na; @@ -399,14 +397,14 @@ } // otherwise its an unknown RR. debug at level 9 since we usually want to ignore these and they are common. - debugs(14, 9, HERE << "Unknown RR type received: type=" << answers[k].type << " starting at " << &(answers[k]) ); + debugs(14, 9, "Unknown RR type received: type=" << answers[k].type << " starting at " << &(answers[k]) ); } if (na == 0) { - debugs(14, DBG_IMPORTANT, "ipcacheParse: No Address records in response to '" << name << "'"); + debugs(14, DBG_IMPORTANT, MYNAME << "No Address records in response to '" << name << "'"); i->error_message = xstrdup("No Address records"); if (cname_found) ++IpcacheStats.cname_only; - return 0; + return; } i->addrs.in_addrs = static_cast(xcalloc(na, sizeof(Ip::Address))); @@ -424,7 +422,7 @@ memcpy(&temp, answers[k].rdata, sizeof(struct in_addr)); i->addrs.in_addrs[j] = temp; - debugs(14, 3, "ipcacheParse: " << name << " #" << j << " " << i->addrs.in_addrs[j]); + debugs(14, 3, name << " #" << j << " " << i->addrs.in_addrs[j]); ++j; } else if (Ip::EnableIpv6 && answers[k].type == RFC1035_TYPE_AAAA) { @@ -435,7 +433,7 @@ memcpy(&temp, answers[k].rdata, sizeof(struct in6_addr)); i->addrs.in_addrs[j] = temp; - debugs(14, 3, "ipcacheParse: " << name << " #" << j << " " << i->addrs.in_addrs[j] ); + debugs(14, 3, name << " #" << j << " " << i->addrs.in_addrs[j] ); ++j; } if (ttl == 0 || (int) answers[k].ttl < ttl) @@ -458,8 +456,6 @@ i->expires = squid_curtime + ttl; i->flags.negcached = false; - - return i->addrs.count; } /// \ingroup IPCacheInternal @@ -472,13 +468,9 @@ const int age = i->age(); statCounter.dns.svcTime.count(age); - int done = ipcacheParse(i, answers, na, error_message); - - /* If we have not produced either IPs or Error immediately, wait for recursion to finish. */ - if (done != 0 || error_message != NULL) { - ipcacheAddEntry(i); - ipcacheCallback(i, age); - } + ipcacheParse(i, answers, na, error_message); + ipcacheAddEntry(i); + ipcacheCallback(i, age); } /** diff -u -r -N squid-4.0.16/src/log/DB/log_db_daemon.8 squid-4.0.17/src/log/DB/log_db_daemon.8 --- squid-4.0.16/src/log/DB/log_db_daemon.8 2016-10-31 03:22:14.000000000 +1300 +++ squid-4.0.17/src/log/DB/log_db_daemon.8 2016-12-17 07:25:42.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "LOG_DB_DAEMON 8" -.TH LOG_DB_DAEMON 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH LOG_DB_DAEMON 8 "2016-12-16" "perl v5.24.1" "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.16/src/LogTags.cc squid-4.0.17/src/LogTags.cc --- squid-4.0.16/src/LogTags.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/LogTags.cc 2016-12-16 23:06:20.000000000 +1300 @@ -21,6 +21,7 @@ "TCP_REFRESH", "TCP_CLIENT_REFRESH_MISS", "TCP_IMS_HIT", + "TCP_INM_HIT", "TCP_SWAPFAIL_MISS", "TCP_NEGATIVE_HIT", "TCP_MEM_HIT", @@ -73,6 +74,7 @@ return (oldType == LOG_TCP_HIT) || (oldType == LOG_TCP_IMS_HIT) || + (oldType == LOG_TCP_INM_HIT) || (oldType == LOG_TCP_REFRESH_FAIL_OLD) || (oldType == LOG_TCP_REFRESH_UNMODIFIED) || (oldType == LOG_TCP_NEGATIVE_HIT) || diff -u -r -N squid-4.0.16/src/LogTags.h squid-4.0.17/src/LogTags.h --- squid-4.0.16/src/LogTags.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/LogTags.h 2016-12-16 23:06:20.000000000 +1300 @@ -28,6 +28,7 @@ LOG_TCP_REFRESH, // refresh from origin started, but still pending LOG_TCP_CLIENT_REFRESH_MISS, LOG_TCP_IMS_HIT, + LOG_TCP_INM_HIT, LOG_TCP_SWAPFAIL_MISS, LOG_TCP_NEGATIVE_HIT, LOG_TCP_MEM_HIT, diff -u -r -N squid-4.0.16/src/Makefile.am squid-4.0.17/src/Makefile.am --- squid-4.0.16/src/Makefile.am 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/Makefile.am 2016-12-16 23:06:20.000000000 +1300 @@ -312,7 +312,6 @@ hier_code.h \ HierarchyLogEntry.h \ $(HTCPSOURCE) \ - HttpStateFlags.h \ http.cc \ http.h \ HttpHeaderFieldStat.h \ @@ -1263,7 +1262,6 @@ hier_code.h \ helper.cc \ $(HTCPSOURCE) \ - HttpStateFlags.h \ http.cc \ HttpBody.h \ HttpBody.cc \ diff -u -r -N squid-4.0.16/src/Makefile.in squid-4.0.17/src/Makefile.in --- squid-4.0.16/src/Makefile.in 2016-10-31 01:26:51.000000000 +1300 +++ squid-4.0.17/src/Makefile.in 2016-12-16 23:14:21.000000000 +1300 @@ -265,9 +265,9 @@ fde.cc fde.h FileMap.h filemap.cc fqdncache.h fqdncache.cc \ FwdState.cc FwdState.h Generic.h globals.h gopher.h gopher.cc \ helper.cc helper.h hier_code.h HierarchyLogEntry.h htcp.cc \ - htcp.h HttpStateFlags.h http.cc http.h HttpHeaderFieldStat.h \ - HttpHdrCc.h HttpHdrCc.cc HttpHdrCc.cci HttpHdrRange.cc \ - HttpHdrSc.cc HttpHdrSc.h HttpHdrScTarget.cc HttpHdrScTarget.h \ + htcp.h http.cc http.h HttpHeaderFieldStat.h HttpHdrCc.h \ + HttpHdrCc.cc HttpHdrCc.cci HttpHdrRange.cc HttpHdrSc.cc \ + HttpHdrSc.h HttpHdrScTarget.cc HttpHdrScTarget.h \ HttpHdrContRange.cc HttpHdrContRange.h HttpHeaderStat.h \ HttpHeader.h HttpHeader.cc HttpHeaderMask.h HttpHeaderRange.h \ HttpHeaderFieldInfo.h HttpHeaderTools.h HttpHeaderTools.cc \ @@ -538,23 +538,23 @@ external_acl.cc ExternalACLEntry.cc fatal.h \ tests/stub_fatal.cc fd.h fd.cc fde.cc FileMap.h filemap.cc \ fqdncache.h fqdncache.cc FwdState.cc FwdState.h gopher.h \ - gopher.cc hier_code.h helper.cc htcp.cc htcp.h \ - HttpStateFlags.h http.cc HttpBody.h HttpBody.cc HttpHeader.h \ - HttpHeader.cc HttpHeaderFieldInfo.h HttpHeaderTools.h \ - HttpHeaderTools.cc HttpHeaderFieldStat.h HttpHdrCc.h \ - HttpHdrCc.cc HttpHdrCc.cci HttpHdrContRange.cc HttpHdrRange.cc \ - HttpHdrSc.cc HttpHdrScTarget.cc HttpMsg.cc HttpReply.cc \ - icp_v2.cc icp_v3.cc SquidIpc.h ipc.cc ipc_win32.cc ipcache.cc \ - int.h int.cc internal.h internal.cc LogTags.cc \ - tests/stub_libsecurity.cc MasterXaction.cc MasterXaction.h \ - multicast.h multicast.cc mem_node.cc MemBuf.cc MemObject.cc \ - mime.h mime.cc mime_header.h mime_header.cc neighbors.h \ - neighbors.cc Notes.cc Notes.h Parsing.cc pconn.cc \ - peer_digest.cc peer_proxy_negotiate_auth.h \ - peer_proxy_negotiate_auth.cc peer_select.cc peer_sourcehash.h \ - peer_sourcehash.cc peer_userhash.h peer_userhash.cc \ - PeerPoolMgr.h PeerPoolMgr.cc Pipeline.cc Pipeline.h redirect.h \ - tests/stub_redirect.cc refresh.h refresh.cc RemovalPolicy.cc \ + gopher.cc hier_code.h helper.cc htcp.cc htcp.h http.cc \ + HttpBody.h HttpBody.cc HttpHeader.h HttpHeader.cc \ + HttpHeaderFieldInfo.h HttpHeaderTools.h HttpHeaderTools.cc \ + HttpHeaderFieldStat.h HttpHdrCc.h HttpHdrCc.cc HttpHdrCc.cci \ + HttpHdrContRange.cc HttpHdrRange.cc HttpHdrSc.cc \ + HttpHdrScTarget.cc HttpMsg.cc HttpReply.cc icp_v2.cc icp_v3.cc \ + SquidIpc.h ipc.cc ipc_win32.cc ipcache.cc int.h int.cc \ + internal.h internal.cc LogTags.cc tests/stub_libsecurity.cc \ + MasterXaction.cc MasterXaction.h multicast.h multicast.cc \ + mem_node.cc MemBuf.cc MemObject.cc mime.h mime.cc \ + mime_header.h mime_header.cc neighbors.h neighbors.cc Notes.cc \ + Notes.h Parsing.cc pconn.cc peer_digest.cc \ + peer_proxy_negotiate_auth.h peer_proxy_negotiate_auth.cc \ + peer_select.cc peer_sourcehash.h peer_sourcehash.cc \ + peer_userhash.h peer_userhash.cc PeerPoolMgr.h PeerPoolMgr.cc \ + Pipeline.cc Pipeline.h redirect.h tests/stub_redirect.cc \ + refresh.h refresh.cc RemovalPolicy.cc \ tests/stub_SBufDetailedStats.cc SnmpRequest.h snmp_core.h \ snmp_core.cc snmp_agent.h snmp_agent.cc SquidMath.h \ SquidMath.cc IoStats.h stat.h stat.cc StatCounters.h \ @@ -2867,16 +2867,16 @@ fde.cc fde.h FileMap.h filemap.cc fqdncache.h fqdncache.cc \ FwdState.cc FwdState.h Generic.h globals.h gopher.h gopher.cc \ helper.cc helper.h hier_code.h HierarchyLogEntry.h \ - $(HTCPSOURCE) HttpStateFlags.h http.cc http.h \ - HttpHeaderFieldStat.h HttpHdrCc.h HttpHdrCc.cc HttpHdrCc.cci \ - HttpHdrRange.cc HttpHdrSc.cc HttpHdrSc.h HttpHdrScTarget.cc \ - HttpHdrScTarget.h HttpHdrContRange.cc HttpHdrContRange.h \ - HttpHeaderStat.h HttpHeader.h HttpHeader.cc HttpHeaderMask.h \ - HttpHeaderRange.h HttpHeaderFieldInfo.h HttpHeaderTools.h \ - HttpHeaderTools.cc HttpBody.h HttpBody.cc HttpControlMsg.cc \ - HttpControlMsg.h HttpMsg.cc HttpMsg.h HttpReply.cc HttpReply.h \ - RequestFlags.h RequestFlags.cc HttpRequest.cc HttpRequest.h \ - ICP.h icp_opcode.h icp_v2.cc icp_v3.cc int.h int.cc internal.h \ + $(HTCPSOURCE) http.cc http.h HttpHeaderFieldStat.h HttpHdrCc.h \ + HttpHdrCc.cc HttpHdrCc.cci HttpHdrRange.cc HttpHdrSc.cc \ + HttpHdrSc.h HttpHdrScTarget.cc HttpHdrScTarget.h \ + HttpHdrContRange.cc HttpHdrContRange.h HttpHeaderStat.h \ + HttpHeader.h HttpHeader.cc HttpHeaderMask.h HttpHeaderRange.h \ + HttpHeaderFieldInfo.h HttpHeaderTools.h HttpHeaderTools.cc \ + HttpBody.h HttpBody.cc HttpControlMsg.cc HttpControlMsg.h \ + HttpMsg.cc HttpMsg.h HttpReply.cc HttpReply.h RequestFlags.h \ + RequestFlags.cc HttpRequest.cc HttpRequest.h ICP.h \ + icp_opcode.h icp_v2.cc icp_v3.cc int.h int.cc internal.h \ internal.cc $(IPC_SOURCE) ipcache.cc ipcache.h \ $(LEAKFINDERSOURCE) LogTags.cc LogTags.h lookup_t.h main.cc \ MasterXaction.cc MasterXaction.h mem_node.cc mem_node.h \ @@ -3532,7 +3532,6 @@ hier_code.h \ helper.cc \ $(HTCPSOURCE) \ - HttpStateFlags.h \ http.cc \ HttpBody.h \ HttpBody.cc \ diff -u -r -N squid-4.0.16/src/mgr/ActionPasswordList.cc squid-4.0.17/src/mgr/ActionPasswordList.cc --- squid-4.0.16/src/mgr/ActionPasswordList.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/mgr/ActionPasswordList.cc 2016-12-16 23:06:20.000000000 +1300 @@ -8,12 +8,11 @@ #include "squid.h" #include "mgr/ActionPasswordList.h" -#include "wordlist.h" +#include "sbuf/List.h" Mgr::ActionPasswordList::~ActionPasswordList() { - safe_free(passwd); - wordlistDestroy(&actions); - delete next; + xfree(passwd); + delete next; // recurse, these lists are usually not long } diff -u -r -N squid-4.0.16/src/mgr/ActionPasswordList.h squid-4.0.17/src/mgr/ActionPasswordList.h --- squid-4.0.16/src/mgr/ActionPasswordList.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/mgr/ActionPasswordList.h 2016-12-16 23:06:20.000000000 +1300 @@ -9,7 +9,7 @@ #ifndef SQUID_MGR_CACHEMGRPASSWD_H_ #define SQUID_MGR_CACHEMGRPASSWD_H_ -class wordlist; +#include "sbuf/forward.h" namespace Mgr { @@ -18,12 +18,11 @@ class ActionPasswordList { public: - ActionPasswordList() : passwd(NULL), actions(NULL), next(NULL) {} ~ActionPasswordList(); - char *passwd; - wordlist *actions; - ActionPasswordList *next; + char *passwd = nullptr; + SBufList actions; + ActionPasswordList *next = nullptr; }; } //namespace Mgr diff -u -r -N squid-4.0.16/src/RequestFlags.h squid-4.0.17/src/RequestFlags.h --- squid-4.0.16/src/RequestFlags.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/RequestFlags.h 2016-12-16 23:06:20.000000000 +1300 @@ -13,108 +13,107 @@ /** request-related flags * - * The bit-field contains both flags marking a request's current state, + * Contains both flags marking a request's current state, * and flags requesting some processing to be done at a later stage. * TODO: better distinguish the two cases. */ class RequestFlags { public: - RequestFlags() { - memset(this,0,sizeof(RequestFlags)); - } - /** true if the response to this request may not be READ from cache */ - bool noCache :1; + bool noCache = false; /** request is if-modified-since */ - bool ims :1; + bool ims = false; /** request is authenticated */ - bool auth :1; + bool auth = false; /** do not use keytabs for peer Kerberos authentication */ - bool auth_no_keytab :1; + bool auth_no_keytab = false; /** he response to the request may be stored in the cache */ - bool cachable :1; + bool cachable = false; /** the request can be forwarded through the hierarchy */ - bool hierarchical :1; + bool hierarchical = false; /** a loop was detected on this request */ - bool loopDetected :1; + bool loopDetected = false; /** the connection can be kept alive */ - bool proxyKeepalive :1; + bool proxyKeepalive = false; /* this should be killed, also in httpstateflags */ - bool proxying :1; + bool proxying = false; /** content has expired, need to refresh it */ - bool refresh :1; + bool refresh = false; /** request was redirected by redirectors */ - bool redirected :1; + bool redirected = false; /** the requested object needs to be validated. See client_side_reply.cc * for further information. */ - bool needValidation :1; + bool needValidation = false; /** whether we should fail if validation fails */ - bool failOnValidationError :1; + bool failOnValidationError = false; /** reply is stale if it is a hit */ - bool staleIfHit :1; + bool staleIfHit = false; /** request to override no-cache directives * * always use noCacheHack() for reading. * \note only meaningful if USE_HTTP_VIOLATIONS is defined at build time */ - bool nocacheHack :1; + bool nocacheHack = false; /** this request is accelerated (reverse-proxy) */ - bool accelerated :1; + bool accelerated = false; /** if set, ignore Cache-Control headers */ - bool ignoreCc :1; + bool ignoreCc = false; /** set for intercepted requests */ - bool intercepted :1; + bool intercepted = false; /** set if the Host: header passed verification */ - bool hostVerified :1; + bool hostVerified = false; /// Set for requests handled by a "tproxy" port. - bool interceptTproxy :1; + bool interceptTproxy = false; /// The client IP address should be spoofed when connecting to the web server. /// This applies to TPROXY traffic that has not had spoofing disabled through /// the spoof_client_ip squid.conf ACL. - bool spoofClientIp :1; + bool spoofClientIp = false; /** set if the request is internal (\see ClientHttpRequest::flags.internal)*/ - bool internal :1; - /** set for internally-generated requests */ + bool internal = false; //XXX this is set in in clientBeginRequest, but never tested. - bool internalClient :1; + /** set for internally-generated requests */ + bool internalClient = false; /** if set, request to try very hard to keep the connection alive */ - bool mustKeepalive :1; + bool mustKeepalive = false; /** set if the rquest wants connection oriented auth */ - bool connectionAuth :1; + bool connectionAuth = false; /** set if connection oriented auth can not be supported */ - bool connectionAuthDisabled :1; - /** Request wants connection oriented auth */ + bool connectionAuthDisabled = false; // XXX This is set in clientCheckPinning but never tested - bool connectionProxyAuth :1; + /** Request wants connection oriented auth */ + bool connectionProxyAuth = false; /** set if the request was sent on a pinned connection */ - bool pinned :1; + bool pinned = false; /** Authentication was already sent upstream (e.g. due tcp-level auth) */ - bool authSent :1; + bool authSent = false; /** Deny direct forwarding unless overriden by always_direct * Used in accelerator mode */ - bool noDirect :1; + bool noDirect = false; /** Reply with chunked transfer encoding */ - bool chunkedReply :1; + bool chunkedReply = false; /** set if stream error has occured */ - bool streamError :1; + bool streamError = false; /** internal ssl-bump request to get server cert */ - bool sslPeek :1; + bool sslPeek = false; /** set if X-Forwarded-For checking is complete * * do not read directly; use doneFollowXff for reading */ - bool done_follow_x_forwarded_for :1; + bool done_follow_x_forwarded_for = false; /** set for ssl-bumped requests */ - bool sslBumped :1; + bool sslBumped = false; /// carries a representation of an FTP command [received on ftp_port] - bool ftpNative :1; - bool destinationIpLookedUp:1; + bool ftpNative = false; + bool destinationIpLookedUp = false; /** request to reset the TCP stream */ - bool resetTcp:1; + bool resetTcp = false; /** set if the request is ranged */ - bool isRanged :1; + bool isRanged = false; + + /// whether to forward via TunnelStateData (instead of FwdState) + bool forceTunnel = false; /** clone the flags, resetting to default those which are not safe in * a related (e.g. ICAP-adapted) request. diff -u -r -N squid-4.0.16/src/sbuf/SBuf.cc squid-4.0.17/src/sbuf/SBuf.cc --- squid-4.0.16/src/sbuf/SBuf.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/sbuf/SBuf.cc 2016-12-16 23:06:20.000000000 +1300 @@ -139,7 +139,8 @@ if (!mustRealloc && len_ >= req.maxCapacity) return spaceSize(); // but we cannot reallocate - const size_type newSpace = std::min(req.idealSpace, maxSize - len_); + const size_type desiredSpace = std::max(req.minSpace, req.idealSpace); + const size_type newSpace = std::min(desiredSpace, maxSize - len_); reserveCapacity(std::min(len_ + newSpace, req.maxCapacity)); debugs(24, 7, id << " now: " << off_ << '+' << len_ << '+' << spaceSize() << '=' << store_->capacity); @@ -187,6 +188,9 @@ SBuf& SBuf::append(const SBuf &S) { + if (isEmpty() && store_ == GetStorePrototype()) + return (*this = S); // optimization: avoid needless copying + const Locker blobKeeper(this, S.buf()); return lowAppend(S.buf(), S.length()); } diff -u -r -N squid-4.0.16/src/sbuf/SBuf.h squid-4.0.17/src/sbuf/SBuf.h --- squid-4.0.16/src/sbuf/SBuf.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/sbuf/SBuf.h 2016-12-16 23:06:20.000000000 +1300 @@ -610,6 +610,11 @@ // TODO: possibly implement erase() similar to std::string's erase // TODO: possibly implement a replace() call + + /// SBuf object identifier meant for test cases and debugging. + /// Does not change when object does, including during assignment. + const InstanceId id; + private: /** @@ -638,10 +643,6 @@ size_type len_; ///< number of our content bytes in shared store_ static SBufStats stats; ///< class-wide statistics - /// SBuf object identifier; does not change when contents do, - /// including during assignment - const InstanceId id; - /** obtain prototype store * * Just-created SBufs all share to the same MemBlob. @@ -693,9 +694,10 @@ /* * Parameters are listed in the reverse order of importance: Satisfaction of * the lower-listed requirements may violate the higher-listed requirements. + * For example, idealSpace has no effect unless it exceeds minSpace. */ size_type idealSpace = 0; ///< if allocating anyway, provide this much space - size_type minSpace = 0; ///< allocate if spaceSize() is smaller + size_type minSpace = 0; ///< allocate [at least this much] if spaceSize() is smaller size_type maxCapacity = SBuf::maxSize; ///< do not allocate more than this bool allowShared = true; ///< whether sharing our storage with others is OK }; diff -u -r -N squid-4.0.16/src/security/cert_generators/file/security_file_certgen.cc squid-4.0.17/src/security/cert_generators/file/security_file_certgen.cc --- squid-4.0.16/src/security/cert_generators/file/security_file_certgen.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/cert_generators/file/security_file_certgen.cc 2016-12-16 23:06:20.000000000 +1300 @@ -200,7 +200,7 @@ error = err.what(); } - if (cert.get()) { + if (cert) { if (!Ssl::certificateMatchesProperties(cert.get(), certProperties)) { // The certificate changed (renewed or other reason). // Generete a new one with the updated fields. diff -u -r -N squid-4.0.16/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.0.17/src/security/cert_validators/fake/security_fake_certverify.8 --- squid-4.0.16/src/security/cert_validators/fake/security_fake_certverify.8 2016-10-31 03:22:36.000000000 +1300 +++ squid-4.0.17/src/security/cert_validators/fake/security_fake_certverify.8 2016-12-17 07:26:25.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "SECURITY_FAKE_CERTVERIFY 8" -.TH SECURITY_FAKE_CERTVERIFY 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH SECURITY_FAKE_CERTVERIFY 8 "2016-12-16" "perl v5.24.1" "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.16/src/security/Context.h squid-4.0.17/src/security/Context.h --- squid-4.0.16/src/security/Context.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/Context.h 2016-12-16 23:06:20.000000000 +1300 @@ -9,6 +9,7 @@ #ifndef SQUID_SRC_SECURITY_CONTEXT_H #define SQUID_SRC_SECURITY_CONTEXT_H +#include "security/forward.h" #include "security/LockingPointer.h" #if USE_OPENSSL @@ -26,15 +27,18 @@ #if USE_OPENSSL CtoCpp1(SSL_CTX_free, SSL_CTX *); -typedef LockingPointer ContextPointer; +#if defined(CRYPTO_LOCK_SSL_CTX) // OpenSSL 1.0 +inline int SSL_CTX_up_ref(SSL_CTX *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_SSL_CTX); return 0;} +#endif +typedef Security::LockingPointer > ContextPointer; #elif USE_GNUTLS CtoCpp1(gnutls_certificate_free_credentials, gnutls_certificate_credentials_t); -typedef Security::LockingPointer ContextPointer; +typedef Security::LockingPointer ContextPointer; #else // use void* so we can check against nullptr -typedef Security::LockingPointer ContextPointer; +typedef Security::LockingPointer ContextPointer; #endif diff -u -r -N squid-4.0.16/src/security/forward.h squid-4.0.17/src/security/forward.h --- squid-4.0.16/src/security/forward.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/forward.h 2016-12-16 23:06:20.000000000 +1300 @@ -13,12 +13,13 @@ #include "security/Context.h" #include "security/Session.h" -#if USE_GNUTLS -#if HAVE_GNUTLS_X509_H +#if USE_GNUTLS && HAVE_GNUTLS_X509_H #include #endif -#endif #include +#if USE_OPENSSL && HAVE_OPENSSL_ERR_H +#include +#endif #include #if USE_OPENSSL @@ -50,20 +51,26 @@ #if USE_OPENSSL CtoCpp1(X509_free, X509 *) -typedef Security::LockingPointer CertPointer; +#if defined(CRYPTO_LOCK_X509) // OpenSSL 1.0 +inline int X509_up_ref(X509 *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509); return 0;} +#endif +typedef Security::LockingPointer > CertPointer; #elif USE_GNUTLS CtoCpp1(gnutls_x509_crt_deinit, gnutls_x509_crt_t) -typedef Security::LockingPointer CertPointer; +typedef Security::LockingPointer CertPointer; #else typedef void * CertPointer; #endif #if USE_OPENSSL CtoCpp1(X509_CRL_free, X509_CRL *) -typedef LockingPointer CrlPointer; +#if defined(CRYPTO_LOCK_X509_CRL) // OpenSSL 1.0 +inline int X509_CRL_up_ref(X509_CRL *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509_CRL); return 0;} +#endif +typedef Security::LockingPointer > CrlPointer; #elif USE_GNUTLS CtoCpp1(gnutls_x509_crl_deinit, gnutls_x509_crl_t) -typedef Security::LockingPointer CrlPointer; +typedef Security::LockingPointer CrlPointer; #else typedef void *CrlPointer; #endif @@ -74,7 +81,10 @@ #if USE_OPENSSL CtoCpp1(DH_free, DH *); -typedef Security::LockingPointer DhePointer; +#if defined(CRYPTO_LOCK_DH) // OpenSSL 1.0 +inline int DH_up_ref(DH *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_DH); return 0;} +#endif +typedef Security::LockingPointer > DhePointer; #else typedef void *DhePointer; #endif @@ -84,6 +94,16 @@ /// Squid defined error code (<0), an error code returned by X.509 API, or SSL_ERROR_NONE typedef int ErrorCode; +inline const char *ErrorString(const ErrorCode code) { +#if USE_OPENSSL + return ERR_error_string(code, nullptr); +#elif USE_GNUTLS + return gnutls_strerror(code); +#else + return "[no TLS library]"; +#endif +} + /// set of Squid defined TLS error codes /// \note using std::unordered_set ensures values are unique, with fast lookup typedef std::unordered_set Errors; diff -u -r -N squid-4.0.16/src/security/LockingPointer.h squid-4.0.17/src/security/LockingPointer.h --- squid-4.0.16/src/security/LockingPointer.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/LockingPointer.h 2016-12-16 23:06:20.000000000 +1300 @@ -9,6 +9,8 @@ #ifndef SQUID_SRC_SECURITY_LOCKINGPOINTER_H #define SQUID_SRC_SECURITY_LOCKINGPOINTER_H +#include "base/HardFun.h" + #if USE_OPENSSL #if HAVE_OPENSSL_CRYPTO_H #include @@ -34,6 +36,9 @@ namespace Security { +inline bool nilFunction(const void *) { return false; } +typedef HardFun NilFunctor; + /** * A shared pointer to a reference-counting Object with library-specific * absorption, locking, and unlocking implementations. The API largely @@ -44,12 +49,12 @@ * pre-lock objects before they are fed to LockingPointer, necessitating * this resetWithoutLocking() customization hook. */ -template +template class LockingPointer { public: /// a helper label to simplify this objects API definitions below - typedef Security::LockingPointer SelfType; + typedef Security::LockingPointer SelfType; /** * Construct directly from a raw pointer. @@ -119,14 +124,10 @@ private: /// The lock() method increments Object's reference counter. void lock(T *t) { -#if USE_OPENSSL - if (t) - CRYPTO_add(&t->references, 1, lockId); -#elif USE_GNUTLS - // XXX: GnuTLS does not provide locking ? -#else - assert(false); -#endif + if (t) { + Locker doLock; + doLock(t); + } } /// Become a nil pointer. Decrements any pointed-to Object's reference counter diff -u -r -N squid-4.0.16/src/security/PeerConnector.cc squid-4.0.17/src/security/PeerConnector.cc --- squid-4.0.16/src/security/PeerConnector.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/PeerConnector.cc 2016-12-16 23:06:20.000000000 +1300 @@ -104,9 +104,11 @@ assert(ctx); if (!Ssl::CreateClient(ctx, serverConnection(), "server https start")) { + const auto xerrno = errno; + const auto ssl_error = ERR_get_error(); ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, Http::scInternalServerError, request.getRaw()); - anErr->xerrno = errno; - debugs(83, DBG_IMPORTANT, "Error allocating TLS handle: " << ERR_error_string(ERR_get_error(), NULL)); + anErr->xerrno = xerrno; + debugs(83, DBG_IMPORTANT, "Error allocating TLS handle: " << Security::ErrorString(ssl_error)); noteNegotiationDone(anErr); bail(anErr); return false; @@ -443,7 +445,7 @@ const int fd = serverConnection()->fd; debugs(83, DBG_IMPORTANT, "Error negotiating SSL on FD " << fd << - ": " << ERR_error_string(ssl_lib_error, NULL) << " (" << + ": " << Security::ErrorString(ssl_lib_error) << " (" << ssl_error << "/" << ret << "/" << errno << ")"); ErrorState *anErr = NULL; diff -u -r -N squid-4.0.16/src/security/PeerOptions.cc squid-4.0.17/src/security/PeerOptions.cc --- squid-4.0.16/src/security/PeerOptions.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/PeerOptions.cc 2016-12-16 23:06:20.000000000 +1300 @@ -59,7 +59,7 @@ certs.emplace_back(t); } else if (strncmp(token, "key=", 4) == 0) { if (certs.empty() || certs.back().certFile.isEmpty()) { - debugs(3, DBG_PARSE_NOTE(1), "ERROR: cert= option must be set before key= is used."); + fatal("cert= option must be set before key= is used."); return; } KeyData &t = certs.back(); @@ -228,8 +228,8 @@ SSL_CTX *t = SSL_CTX_new(SSLv23_client_method()); #endif if (!t) { - const auto x = ERR_error_string(ERR_get_error(), nullptr); - fatalf("Failed to allocate TLS client context: %s\n", x); + const auto x = ERR_get_error(); + fatalf("Failed to allocate TLS client context: %s\n", Security::ErrorString(x)); } ctx.resetWithoutLocking(t); @@ -237,7 +237,7 @@ // Initialize for X.509 certificate exchange gnutls_certificate_credentials_t t; if (const int x = gnutls_certificate_allocate_credentials(&t)) { - fatalf("Failed to allocate TLS client context: error=%d\n", x); + fatalf("Failed to allocate TLS client context: %s\n", Security::ErrorString(x)); } ctx.resetWithoutLocking(t); @@ -574,12 +574,12 @@ { #if USE_OPENSSL if (SSL_CTX_set_default_verify_paths(ctx.get()) == 0) - return ERR_error_string(ERR_get_error(), nullptr); + return Security::ErrorString(ERR_get_error()); #elif USE_GNUTLS auto x = gnutls_certificate_set_x509_system_trust(ctx.get()); if (x < 0) - return gnutls_strerror(x); + return Security::ErrorString(x); #endif return nullptr; @@ -595,12 +595,15 @@ for (auto i : caFiles) { #if USE_OPENSSL if (!SSL_CTX_load_verify_locations(ctx.get(), i.c_str(), path)) { - const int ssl_error = ERR_get_error(); - debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL)); + const auto x = ERR_get_error(); + debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " << + i << ": " << Security::ErrorString(x)); } #elif USE_GNUTLS - if (gnutls_certificate_set_x509_trust_file(ctx.get(), i.c_str(), GNUTLS_X509_FMT_PEM) < 0) { - debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location: " << i); + const auto x = gnutls_certificate_set_x509_trust_file(ctx.get(), i.c_str(), GNUTLS_X509_FMT_PEM); + if (x < 0) { + debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate location " << + i << ": " << Security::ErrorString(x)); } #endif } diff -u -r -N squid-4.0.16/src/security/ServerOptions.cc squid-4.0.17/src/security/ServerOptions.cc --- squid-4.0.16/src/security/ServerOptions.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/ServerOptions.cc 2016-12-16 23:06:20.000000000 +1300 @@ -98,8 +98,8 @@ SSL_CTX *t = SSL_CTX_new(SSLv23_server_method()); #endif if (!t) { - const auto x = ERR_error_string(ERR_get_error(), nullptr); - debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << x); + const auto x = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << Security::ErrorString(x)); } ctx.resetWithoutLocking(t); @@ -107,7 +107,7 @@ // Initialize for X.509 certificate exchange gnutls_certificate_credentials_t t; if (const int x = gnutls_certificate_allocate_credentials(&t)) { - debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: error=" << x); + debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: " << Security::ErrorString(x)); } ctx.resetWithoutLocking(t); @@ -183,14 +183,14 @@ auto ecdh = EC_KEY_new_by_curve_name(nid); if (!ecdh) { - auto ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Unable to configure Ephemeral ECDH: " << ERR_error_string(ssl_error, NULL)); + const auto x = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Unable to configure Ephemeral ECDH: " << Security::ErrorString(x)); return; } if (!SSL_CTX_set_tmp_ecdh(ctx.get(), ecdh)) { - auto ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Unable to set Ephemeral ECDH: " << ERR_error_string(ssl_error, NULL)); + const auto x = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Unable to set Ephemeral ECDH: " << Security::ErrorString(x)); } EC_KEY_free(ecdh); @@ -202,7 +202,7 @@ // set DH parameters into the server context #if USE_OPENSSL - if (parsedDhParams.get()) { + if (parsedDhParams) { SSL_CTX_set_tmp_dh(ctx.get(), parsedDhParams.get()); } #endif diff -u -r -N squid-4.0.16/src/security/Session.cc squid-4.0.17/src/security/Session.cc --- squid-4.0.16/src/security/Session.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/Session.cc 2016-12-16 23:06:20.000000000 +1300 @@ -43,7 +43,7 @@ gnutls_datum_t *tmp = nullptr; const auto x = gnutls_session_get_data2(s.get(), tmp); if (x != GNUTLS_E_SUCCESS) { - debugs(83, 3, "session=" << (void*)s.get() << " error: " << gnutls_strerror(x)); + debugs(83, 3, "session=" << (void*)s.get() << " error: " << Security::ErrorString(x)); } data.reset(tmp); #endif @@ -61,13 +61,13 @@ if (!SSL_set_session(s.get(), data.get())) { const auto ssl_error = ERR_get_error(); debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() << - " resume error: " << ERR_error_string(ssl_error, nullptr)); + " resume error: " << Security::ErrorString(ssl_error)); } #elif USE_GNUTLS const auto x = gnutls_session_set_data(s.get(), data->data, data->size); if (x != GNUTLS_E_SUCCESS) { debugs(83, 3, "session=" << (void*)s.get() << " data=" << (void*)data.get() << - " resume error: " << gnutls_strerror(x)); + " resume error: " << Security::ErrorString(x)); } #else // critical because, how did it get here? diff -u -r -N squid-4.0.16/src/security/Session.h squid-4.0.17/src/security/Session.h --- squid-4.0.16/src/security/Session.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/security/Session.h 2016-12-16 23:06:20.000000000 +1300 @@ -9,7 +9,6 @@ #ifndef SQUID_SRC_SECURITY_SESSION_H #define SQUID_SRC_SECURITY_SESSION_H -#include "base/HardFun.h" #include "security/LockingPointer.h" #include @@ -30,7 +29,10 @@ #if USE_OPENSSL CtoCpp1(SSL_free, SSL *); -typedef LockingPointer SessionPointer; +#if defined(CRYPTO_LOCK_SSL) // OpenSSL 1.0 +inline int SSL_up_ref(SSL *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_SSL); return 0;} +#endif +typedef Security::LockingPointer > SessionPointer; typedef std::unique_ptr> SessionStatePointer; @@ -39,7 +41,7 @@ // objects using the gnutls_session_set_ptr()/gnutls_session_get_ptr () // library functions CtoCpp1(gnutls_deinit, gnutls_session_t); -typedef LockingPointer SessionPointer; +typedef Security::LockingPointer SessionPointer; // wrapper function to get around gnutls_free being a typedef inline void squid_gnutls_free(void *d) {gnutls_free(d);} @@ -48,7 +50,7 @@ #else // use void* so we can check against NULL CtoCpp1(xfree, void *); -typedef LockingPointer SessionPointer; +typedef Security::LockingPointer SessionPointer; typedef std::unique_ptr SessionStatePointer; diff -u -r -N squid-4.0.16/src/servers/FtpServer.cc squid-4.0.17/src/servers/FtpServer.cc --- squid-4.0.16/src/servers/FtpServer.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/servers/FtpServer.cc 2016-12-16 23:06:20.000000000 +1300 @@ -152,7 +152,7 @@ } void -Ftp::Server::processParsedRequest(Http::Stream *) +Ftp::Server::processParsedRequest(Http::StreamPointer &) { Must(pipeline.count() == 1); @@ -1153,12 +1153,13 @@ writeErrorReply(reply, 451); } -void +bool Ftp::Server::writeControlMsgAndCall(HttpReply *reply, AsyncCall::Pointer &call) { // the caller guarantees that we are dealing with the current context only // the caller should also make sure reply->header.has(Http::HdrType::FTP_STATUS) writeForwardedReplyAndCall(reply, call); + return true; } void diff -u -r -N squid-4.0.16/src/servers/FtpServer.h squid-4.0.17/src/servers/FtpServer.h --- squid-4.0.16/src/servers/FtpServer.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/servers/FtpServer.h 2016-12-16 23:06:20.000000000 +1300 @@ -92,12 +92,12 @@ /* ConnStateData API */ virtual Http::Stream *parseOneRequest() override; - virtual void processParsedRequest(Http::Stream *context) override; + virtual void processParsedRequest(Http::StreamPointer &context) override; virtual void notePeerConnection(Comm::ConnectionPointer conn) override; virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io) override; virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) override; virtual int pipelinePrefetchMax() const override; - virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) override; + virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) override; virtual time_t idleTimeout() const override; /* BodyPipe API */ diff -u -r -N squid-4.0.16/src/servers/Http1Server.cc squid-4.0.17/src/servers/Http1Server.cc --- squid-4.0.16/src/servers/Http1Server.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/servers/Http1Server.cc 2016-12-16 23:06:20.000000000 +1300 @@ -80,7 +80,7 @@ // a) dont have one already // b) have completed the previous request parsing already if (!parser_ || !parser_->needsMoreData()) - parser_ = new Http1::RequestParser(); + parser_ = new Http1::RequestParser(mayTunnelUnsupportedProto()); /* Process request */ Http::Stream *context = parseHttpRequest(this, parser_); @@ -90,10 +90,10 @@ } void clientProcessRequestFinished(ConnStateData *conn, const HttpRequest::Pointer &request); -bool clientTunnelOnError(ConnStateData *conn, Http::Stream *context, HttpRequest *request, const HttpRequestMethod& method, err_type requestError, Http::StatusCode errStatusCode, const char *requestErrorBytes); +bool clientTunnelOnError(ConnStateData *conn, Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod& method, err_type requestError); bool -Http::One::Server::buildHttpRequest(Http::Stream *context) +Http::One::Server::buildHttpRequest(Http::StreamPointer &context) { HttpRequest::Pointer request; ClientHttpRequest *http = context->http; @@ -123,7 +123,8 @@ // setLogUri should called before repContext->setReplyToError setLogUri(http, http->uri, true); const char * requestErrorBytes = inBuf.c_str(); - if (!clientTunnelOnError(this, context, request.getRaw(), parser_->method(), errPage, parser_->parseStatusCode, requestErrorBytes)) { + if (!clientTunnelOnError(this, context, request, parser_->method(), errPage)) { + setReplyError(context, request, parser_->method(), errPage, parser_->parseStatusCode, requestErrorBytes); // HttpRequest object not build yet, there is no reason to call // clientProcessRequestFinished method } @@ -137,7 +138,8 @@ setLogUri(http, http->uri, true); const char * requestErrorBytes = inBuf.c_str(); - if (!clientTunnelOnError(this, context, request.getRaw(), parser_->method(), ERR_INVALID_URL, Http::scBadRequest, requestErrorBytes)) { + if (!clientTunnelOnError(this, context, request, parser_->method(), ERR_INVALID_URL)) { + setReplyError(context, request, parser_->method(), ERR_INVALID_URL, Http::scBadRequest, requestErrorBytes); // HttpRequest object not build yet, there is no reason to call // clientProcessRequestFinished method } @@ -155,7 +157,8 @@ setLogUri(http, http->uri, true); const char * requestErrorBytes = NULL; //HttpParserHdrBuf(parser_); - if (!clientTunnelOnError(this, context, request.getRaw(), parser_->method(), ERR_UNSUP_HTTPVERSION, Http::scHttpVersionNotSupported, requestErrorBytes)) { + if (!clientTunnelOnError(this, context, request, parser_->method(), ERR_UNSUP_HTTPVERSION)) { + setReplyError(context, request, parser_->method(), ERR_UNSUP_HTTPVERSION, Http::scHttpVersionNotSupported, requestErrorBytes); clientProcessRequestFinished(this, request); } return false; @@ -167,7 +170,8 @@ // setLogUri should called before repContext->setReplyToError setLogUri(http, http->uri, true); const char * requestErrorBytes = NULL; //HttpParserHdrBuf(parser_); - if (!clientTunnelOnError(this, context, request.getRaw(), parser_->method(), ERR_INVALID_REQ, Http::scBadRequest, requestErrorBytes)) { + if (!clientTunnelOnError(this, context, request, parser_->method(), ERR_INVALID_REQ)) { + setReplyError(context, request, parser_->method(), ERR_INVALID_REQ, Http::scBadRequest, requestErrorBytes); clientProcessRequestFinished(this, request); } return false; @@ -190,6 +194,25 @@ } void +Http::One::Server::setReplyError(Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod& method, err_type requestError, Http::StatusCode errStatusCode, const char *requestErrorBytes) +{ + quitAfterError(request.getRaw()); + if (!context->connRegistered()) { + debugs(33, 2, "Client stream deregister it self, nothing to do"); + clientConnection->close(); + return; + } + clientStreamNode *node = context->getClientReplyContext(); + clientReplyContext *repContext = dynamic_cast(node->data.getRaw()); + assert (repContext); + + repContext->setReplyToError(requestError, errStatusCode, method, context->http->uri, clientConnection->remote, nullptr, requestErrorBytes, nullptr); + + assert(context->http->out.offset == 0); + context->pullData(); +} + +void Http::One::Server::proceedAfterBodyContinuation(Http::StreamPointer context) { debugs(33, 5, "Body Continuation written"); @@ -197,7 +220,7 @@ } void -Http::One::Server::processParsedRequest(Http::Stream *context) +Http::One::Server::processParsedRequest(Http::StreamPointer &context) { if (!buildHttpRequest(context)) return; @@ -239,7 +262,7 @@ } } } - clientProcessRequest(this, parser_, context); + clientProcessRequest(this, parser_, context.getRaw()); } void @@ -283,10 +306,20 @@ context->sendStartOfMessage(rep, receivedData); } -void +bool Http::One::Server::writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) { - const ClientHttpRequest *http = pipeline.front()->http; + Http::StreamPointer context = pipeline.front(); + Must(context != nullptr); + + // Ignore this late control message if we have started sending a + // reply to the user already (e.g., after an error). + if (context->reply) { + debugs(11, 2, "drop 1xx made late by " << context->reply); + return false; + } + + const ClientHttpRequest *http = context->http; // apply selected clientReplyContext::buildReplyHeader() mods // it is not clear what headers are required for control messages @@ -302,6 +335,7 @@ Comm::Write(clientConnection, mb, call); delete mb; + return true; } ConnStateData * diff -u -r -N squid-4.0.16/src/servers/Http1Server.h squid-4.0.17/src/servers/Http1Server.h --- squid-4.0.16/src/servers/Http1Server.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/servers/Http1Server.h 2016-12-16 23:06:20.000000000 +1300 @@ -30,9 +30,9 @@ protected: /* ConnStateData API */ virtual Http::Stream *parseOneRequest(); - virtual void processParsedRequest(Http::Stream *context); + virtual void processParsedRequest(Http::StreamPointer &context); virtual void handleReply(HttpReply *rep, StoreIOBuffer receivedData); - virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call); + virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call); virtual time_t idleTimeout() const; /* BodyPipe API */ @@ -52,7 +52,9 @@ /// to the client if parsing is failed, or parses the url and build the /// HttpRequest object using parsing results. /// Return false if parsing is failed, true otherwise. - bool buildHttpRequest(Http::Stream *context); + bool buildHttpRequest(Http::StreamPointer &context); + + void setReplyError(Http::StreamPointer &context, HttpRequest::Pointer &request, const HttpRequestMethod& method, err_type requestError, Http::StatusCode errStatusCode, const char *requestErrorBytes); Http1::RequestParserPointer parser_; HttpRequestMethod method_; ///< parsed HTTP method diff -u -r -N squid-4.0.16/src/SquidConfig.h squid-4.0.17/src/SquidConfig.h --- squid-4.0.16/src/SquidConfig.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/SquidConfig.h 2016-12-16 23:06:20.000000000 +1300 @@ -492,8 +492,6 @@ } SSL; #endif - wordlist *ext_methods; - struct { int high_rptm; int high_pf; diff -u -r -N squid-4.0.16/src/ssl/bio.cc squid-4.0.17/src/ssl/bio.cc --- squid-4.0.16/src/ssl/bio.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/bio.cc 2016-12-16 23:06:20.000000000 +1300 @@ -42,6 +42,7 @@ /* SSL callbacks */ static void squid_ssl_info(const SSL *ssl, int where, int ret); +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /// Initialization structure for the BIO table with /// Squid-specific methods and BIO method wrappers. static BIO_METHOD SquidMethods = { @@ -56,14 +57,30 @@ squid_bio_destroy, NULL // squid_callback_ctrl not supported }; +#else +static BIO_METHOD *SquidMethods = NULL; +#endif BIO * Ssl::Bio::Create(const int fd, Ssl::Bio::Type type) { +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) if (BIO *bio = BIO_new(&SquidMethods)) { BIO_int_ctrl(bio, BIO_C_SET_FD, type, fd); return bio; } +#else + if (!SquidMethods) { + SquidMethods = BIO_meth_new(BIO_TYPE_SOCKET, "squid"); + BIO_meth_set_write(SquidMethods, squid_bio_write); + BIO_meth_set_read(SquidMethods, squid_bio_read); + BIO_meth_set_puts(SquidMethods, squid_bio_puts); + BIO_meth_set_gets(SquidMethods, NULL); + BIO_meth_set_ctrl(SquidMethods, squid_bio_ctrl); + BIO_meth_set_create(SquidMethods, squid_bio_create); + BIO_meth_set_destroy(SquidMethods, squid_bio_destroy); + } +#endif return NULL; } @@ -147,18 +164,6 @@ SSL_state_string(ssl) << " (" << SSL_state_string_long(ssl) << ")"); } -bool -Ssl::ClientBio::isClientHello(int state) -{ - return ( - state == SSL3_ST_SR_CLNT_HELLO_A || - state == SSL23_ST_SR_CLNT_HELLO_A || - state == SSL23_ST_SR_CLNT_HELLO_B || - state == SSL3_ST_SR_CLNT_HELLO_B || - state == SSL3_ST_SR_CLNT_HELLO_C - ); -} - void Ssl::ClientBio::stateChanged(const SSL *ssl, int where, int ret) { @@ -509,10 +514,15 @@ static int squid_bio_create(BIO *bi) { +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) bi->init = 0; // set when we store Bio object and socket fd (BIO_C_SET_FD) bi->num = 0; - bi->ptr = NULL; bi->flags = 0; +#else + // No need to set more, openSSL initialize BIO memory to zero. +#endif + + BIO_set_data(bi, NULL); return 1; } @@ -520,8 +530,8 @@ static int squid_bio_destroy(BIO *table) { - delete static_cast(table->ptr); - table->ptr = NULL; + delete static_cast(BIO_get_data(table)); + BIO_set_data(table, NULL); return 1; } @@ -529,7 +539,7 @@ static int squid_bio_write(BIO *table, const char *buf, int size) { - Ssl::Bio *bio = static_cast(table->ptr); + Ssl::Bio *bio = static_cast(BIO_get_data(table)); assert(bio); return bio->write(buf, size, table); } @@ -538,7 +548,7 @@ static int squid_bio_read(BIO *table, char *buf, int size) { - Ssl::Bio *bio = static_cast(table->ptr); + Ssl::Bio *bio = static_cast(BIO_get_data(table)); assert(bio); return bio->read(buf, size, table); } @@ -566,15 +576,15 @@ bio = new Ssl::ServerBio(fd); else bio = new Ssl::ClientBio(fd); - assert(!table->ptr); - table->ptr = bio; - table->init = 1; + assert(!BIO_get_data(table)); + BIO_set_data(table, bio); + BIO_set_init(table, 1); return 0; } case BIO_C_GET_FD: - if (table->init) { - Ssl::Bio *bio = static_cast(table->ptr); + if (BIO_get_init(table)) { + Ssl::Bio *bio = static_cast(BIO_get_data(table)); assert(bio); if (arg2) *static_cast(arg2) = bio->fd(); @@ -588,8 +598,8 @@ return 0; case BIO_CTRL_FLUSH: - if (table->init) { - Ssl::Bio *bio = static_cast(table->ptr); + if (BIO_get_init(table)) { + Ssl::Bio *bio = static_cast(BIO_get_data(table)); assert(bio); bio->flush(table); return 1; @@ -619,7 +629,7 @@ squid_ssl_info(const SSL *ssl, int where, int ret) { if (BIO *table = SSL_get_rbio(ssl)) { - if (Ssl::Bio *bio = static_cast(table->ptr)) + if (Ssl::Bio *bio = static_cast(BIO_get_data(table))) bio->stateChanged(ssl, where, ret); } } @@ -648,16 +658,16 @@ cbytes[0] = (cipherId >> 8) & 0xFF; cbytes[1] = cipherId & 0xFF; cbytes[2] = 0; -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) - const SSL_METHOD *method = TLS_method(); -#else +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) const SSL_METHOD *method = SSLv23_method(); -#endif const SSL_CIPHER *c = method->get_cipher_by_char(cbytes); +#else + const SSL_CIPHER *c = SSL_CIPHER_find(ssl, cbytes); +#endif if (c != NULL) { if (!strCiphers.isEmpty()) strCiphers.append(":"); - strCiphers.append(c->name); + strCiphers.append(SSL_CIPHER_get_name(c)); } } if (!strCiphers.isEmpty()) diff -u -r -N squid-4.0.16/src/ssl/bio.h squid-4.0.17/src/ssl/bio.h --- squid-4.0.16/src/ssl/bio.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/bio.h 2016-12-16 23:06:20.000000000 +1300 @@ -89,8 +89,6 @@ /// 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. int helloSize; ///< The SSL hello message sent by client size @@ -196,5 +194,13 @@ void applyTlsDetailsToSSL(SSL *ssl, Security::TlsDetails::Pointer const &details, Ssl::BumpMode bumpMode); +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) +// OpenSSL v1.0 bio compatibility functions +inline void *BIO_get_data(BIO *table) { return table->ptr; } +inline void BIO_set_data(BIO *table, void *data) { table->ptr = data; } +inline int BIO_get_init(BIO *table) { return table->init; } +inline void BIO_set_init(BIO *table, int init) { table->init = init; } +#endif + #endif /* SQUID_SSL_BIO_H */ diff -u -r -N squid-4.0.16/src/ssl/ErrorDetail.cc squid-4.0.17/src/ssl/ErrorDetail.cc --- squid-4.0.16/src/ssl/ErrorDetail.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/ErrorDetail.cc 2016-12-16 23:06:20.000000000 +1300 @@ -553,7 +553,7 @@ if (errReason.size() > 0) return errReason.termedBuf(); else if (lib_error_no != SSL_ERROR_NONE) - return ERR_error_string(lib_error_no, NULL); + return Security::ErrorString(lib_error_no); else return "[No Error]"; } @@ -564,7 +564,7 @@ * Error meta information: * %err_name: The name of a high-level SSL error (e.g., X509_V_ERR_*) * %ssl_error_descr: A short description of the SSL error - * %ssl_lib_error: human-readable low-level error string by ERR_error_string(3SSL) + * %ssl_lib_error: human-readable low-level error string by Security::ErrorString() * * Certificate information extracted from broken (not necessarily peer!) cert * %ssl_cn: The comma-separated list of common and alternate names diff -u -r -N squid-4.0.16/src/ssl/gadgets.cc squid-4.0.17/src/ssl/gadgets.cc --- squid-4.0.16/src/ssl/gadgets.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/gadgets.cc 2016-12-16 23:06:20.000000000 +1300 @@ -109,7 +109,7 @@ if (!pkey || !cert) return false; - Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal())); + Ssl::BIO_Pointer bio(BIO_new(BIO_s_file())); if (!bio) return false; if (!BIO_write_filename(bio.get(), const_cast(filename))) @@ -650,7 +650,7 @@ { if (!certFilename) return NULL; - Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal())); + Ssl::BIO_Pointer bio(BIO_new(BIO_s_file())); if (!bio) return NULL; if (!BIO_read_filename(bio.get(), certFilename)) @@ -663,7 +663,7 @@ { if (!keyFilename) return NULL; - Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal())); + Ssl::BIO_Pointer bio(BIO_new(BIO_s_file())); if (!bio) return NULL; if (!BIO_read_filename(bio.get(), keyFilename)) diff -u -r -N squid-4.0.16/src/ssl/gadgets.h squid-4.0.17/src/ssl/gadgets.h --- squid-4.0.16/src/ssl/gadgets.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/gadgets.h 2016-12-16 23:06:20.000000000 +1300 @@ -46,7 +46,10 @@ typedef std::unique_ptr X509_STACK_Pointer; CtoCpp1(EVP_PKEY_free, EVP_PKEY *) -typedef Security::LockingPointer EVP_PKEY_Pointer; +#if defined(CRYPTO_LOCK_EVP_PKEY) // OpenSSL 1.0 +inline int EVP_PKEY_up_ref(EVP_PKEY *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_EVP_PKEY); return 0;} +#endif +typedef Security::LockingPointer > EVP_PKEY_Pointer; typedef std::unique_ptr> BIGNUM_Pointer; diff -u -r -N squid-4.0.16/src/ssl/helper.cc squid-4.0.17/src/ssl/helper.cc --- squid-4.0.16/src/ssl/helper.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/helper.cc 2016-12-16 23:06:20.000000000 +1300 @@ -181,7 +181,7 @@ public: std::string query; AsyncCall::Pointer callback; - SSL *ssl; + Security::SessionPointer ssl; }; CBDATA_CLASS_INIT(submitData); @@ -193,7 +193,7 @@ std::string error; submitData *crtdvdData = static_cast(data); - STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(crtdvdData->ssl); + STACK_OF(X509) *peerCerts = SSL_get_peer_cert_chain(crtdvdData->ssl.get()); if (reply.result == ::Helper::BrokenHelper) { debugs(83, DBG_IMPORTANT, "\"ssl_crtvd\" helper error response: " << reply.other().content()); validationResponse->resultCode = ::Helper::BrokenHelper; @@ -220,7 +220,6 @@ delete item; } - SSL_free(crtdvdData->ssl); delete crtdvdData; } @@ -237,8 +236,7 @@ crtdvdData->query = message.compose(); crtdvdData->query += '\n'; crtdvdData->callback = callback; - crtdvdData->ssl = request.ssl; - CRYPTO_add(&crtdvdData->ssl->references,1,CRYPTO_LOCK_SSL); + crtdvdData->ssl.resetAndLock(request.ssl); Ssl::CertValidationResponse::Pointer const*validationResponse; if (CertValidationHelper::HelperCache && @@ -248,7 +246,6 @@ Must(dialer); dialer->arg1 = *validationResponse; ScheduleCallHere(callback); - SSL_free(crtdvdData->ssl); delete crtdvdData; return; } @@ -260,8 +257,6 @@ Must(dialer); dialer->arg1 = resp; ScheduleCallHere(callback); - - SSL_free(crtdvdData->ssl); delete crtdvdData; return; } diff -u -r -N squid-4.0.16/src/ssl/PeekingPeerConnector.cc squid-4.0.17/src/ssl/PeekingPeerConnector.cc --- squid-4.0.16/src/ssl/PeekingPeerConnector.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/PeekingPeerConnector.cc 2016-12-16 23:06:20.000000000 +1300 @@ -65,7 +65,7 @@ acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpServerFirst)); Security::SessionPointer session(fd_table[serverConn->fd].ssl); BIO *b = SSL_get_rbio(session.get()); - Ssl::ServerBio *srvBio = static_cast(b->ptr); + Ssl::ServerBio *srvBio = static_cast(BIO_get_data(b)); if (!srvBio->canSplice()) acl_checklist->banAction(allow_t(ACCESS_ALLOWED, Ssl::bumpSplice)); if (!srvBio->canBump()) @@ -78,7 +78,7 @@ { Security::SessionPointer session(fd_table[serverConn->fd].ssl); BIO *b = SSL_get_rbio(session.get()); - Ssl::ServerBio *srvBio = static_cast(b->ptr); + Ssl::ServerBio *srvBio = static_cast(BIO_get_data(b)); debugs(83,5, "Will check for peek and splice on FD " << serverConn->fd); Ssl::BumpMode finalAction = action; @@ -169,14 +169,14 @@ auto clientSession = fd_table[clientConn->fd].ssl.get(); Must(clientSession); BIO *bc = SSL_get_rbio(clientSession); - Ssl::ClientBio *cltBio = static_cast(bc->ptr); + Ssl::ClientBio *cltBio = static_cast(BIO_get_data(bc)); Must(cltBio); if (details && details->tlsVersion.protocol != AnyP::PROTO_NONE) { applyTlsDetailsToSSL(serverSession.get(), details, csd->sslBumpMode); // Should we allow it for all protocols? if (details->tlsVersion.protocol == AnyP::PROTO_TLS || details->tlsVersion == AnyP::ProtocolVersion(AnyP::PROTO_SSL, 3, 0)) { BIO *b = SSL_get_rbio(serverSession.get()); - Ssl::ServerBio *srvBio = static_cast(b->ptr); + Ssl::ServerBio *srvBio = static_cast(BIO_get_data(b)); // Inherite client features, like SSL version, SNI and other srvBio->setClientFeatures(details, cltBio->rBufData()); srvBio->recordInput(true); @@ -201,10 +201,10 @@ } if (Ssl::ServerBump *serverBump = csd->serverBump()) { - serverBump->attachServerSSL(serverSession.get()); + serverBump->attachServerSession(serverSession); // store peeked cert to check SQUID_X509_V_ERR_CERT_CHANGE if (X509 *peeked_cert = serverBump->serverCert.get()) { - CRYPTO_add(&(peeked_cert->references),1,CRYPTO_LOCK_X509); + X509_up_ref(peeked_cert); SSL_set_ex_data(serverSession.get(), ssl_ex_index_ssl_peeked_cert, peeked_cert); } } @@ -262,7 +262,7 @@ const int fd = serverConnection()->fd; Security::SessionPointer session(fd_table[fd].ssl); BIO *b = SSL_get_rbio(session.get()); - Ssl::ServerBio *srvBio = static_cast(b->ptr); + Ssl::ServerBio *srvBio = static_cast(BIO_get_data(b)); if ((srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) { debugs(81, 3, "hold write on SSL connection on FD " << fd); @@ -279,7 +279,7 @@ const int fd = serverConnection()->fd; Security::SessionPointer session(fd_table[fd].ssl); BIO *b = SSL_get_rbio(session.get()); - Ssl::ServerBio *srvBio = static_cast(b->ptr); + Ssl::ServerBio *srvBio = static_cast(BIO_get_data(b)); // In Peek mode, the ClientHello message sent to the server. If the // server resuming a previous (spliced) SSL session with the client, @@ -308,7 +308,7 @@ (srvBio->bumpMode() == Ssl::bumpPeek || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) { Security::CertPointer serverCert(SSL_get_peer_certificate(session.get())); if (serverCert) { - debugs(81, 3, "Error (" << ERR_error_string(ssl_lib_error, NULL) << ") but, hold write on SSL connection on FD " << fd); + debugs(81, 3, "Error (" << Security::ErrorString(ssl_lib_error) << ") but, hold write on SSL connection on FD " << fd); checkForPeekAndSplice(); return; } diff -u -r -N squid-4.0.16/src/ssl/ServerBump.cc squid-4.0.17/src/ssl/ServerBump.cc --- squid-4.0.16/src/ssl/ServerBump.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/ServerBump.cc 2016-12-16 23:06:20.000000000 +1300 @@ -53,21 +53,21 @@ } void -Ssl::ServerBump::attachServerSSL(SSL *ssl) +Ssl::ServerBump::attachServerSession(const Security::SessionPointer &s) { - if (serverSSL.get()) + if (serverSession) return; - serverSSL.resetAndLock(ssl); + serverSession = s; } const Security::CertErrors * Ssl::ServerBump::sslErrors() const { - if (!serverSSL.get()) + if (!serverSession) return NULL; - const Security::CertErrors *errs = static_cast(SSL_get_ex_data(serverSSL.get(), ssl_ex_index_ssl_errors)); + const Security::CertErrors *errs = static_cast(SSL_get_ex_data(serverSession.get(), ssl_ex_index_ssl_errors)); return errs; } diff -u -r -N squid-4.0.16/src/ssl/ServerBump.h squid-4.0.17/src/ssl/ServerBump.h --- squid-4.0.16/src/ssl/ServerBump.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/ServerBump.h 2016-12-16 23:06:20.000000000 +1300 @@ -32,14 +32,14 @@ public: explicit ServerBump(HttpRequest *fakeRequest, StoreEntry *e = NULL, Ssl::BumpMode mode = Ssl::bumpServerFirst); ~ServerBump(); - void attachServerSSL(SSL *); ///< Sets the server SSL object + void attachServerSession(const Security::SessionPointer &); ///< Sets the server TLS session object const Security::CertErrors *sslErrors() const; ///< SSL [certificate validation] errors /// faked, minimal request; required by Client API HttpRequest::Pointer request; StoreEntry *entry; ///< for receiving Squid-generated error messages /// HTTPS server certificate. Maybe it is different than the one - /// it is stored in serverSSL object (error SQUID_X509_V_ERR_CERT_CHANGE) + /// it is stored in serverSession object (error SQUID_X509_V_ERR_CERT_CHANGE) Security::CertPointer serverCert; struct { Ssl::BumpMode step1; ///< The SSL bump mode at step1 @@ -48,9 +48,9 @@ } act; ///< bumping actions at various bumping steps Ssl::BumpStep step; ///< The SSL bumping step SBuf clientSni; ///< the SSL client SNI name - Security::SessionPointer serverSSL; ///< The SSL object on server side. private: + Security::SessionPointer serverSession; ///< The TLS session object on server side. store_client *sc; ///< dummy client to prevent entry trimming }; diff -u -r -N squid-4.0.16/src/ssl/support.cc squid-4.0.17/src/ssl/support.cc --- squid-4.0.16/src/ssl/support.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/support.cc 2016-12-16 23:06:20.000000000 +1300 @@ -44,7 +44,7 @@ const EVP_MD *Ssl::DefaultSignHash = NULL; -const char *Ssl::BumpModeStr[] = { +std::vector Ssl::BumpModeStr = { "none", "client-first", "server-first", @@ -52,9 +52,8 @@ "stare", "bump", "splice", - "terminate", - /*"err",*/ - NULL + "terminate" + /*,"err"*/ }; /** @@ -455,7 +454,7 @@ if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) { const int ssl_error = ERR_get_error(); - fatalf("Failed to initialise SSL engine: %s\n", ERR_error_string(ssl_error, NULL)); + fatalf("Failed to initialise SSL engine: %s\n", Security::ErrorString(ssl_error)); } } #else @@ -519,7 +518,7 @@ if (!SSL_CTX_set_cipher_list(ctx.get(), port.secure.sslCipher.c_str())) { ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" << port.secure.sslCipher << "': " << ERR_error_string(ssl_error, NULL)); + debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" << port.secure.sslCipher << "': " << Security::ErrorString(ssl_error)); return false; } } @@ -536,7 +535,7 @@ SSL_CTX_set_client_CA_list(ctx.get(), clientca); } else { ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to dupe the client CA list: " << ERR_error_string(ssl_error, NULL)); + debugs(83, DBG_CRITICAL, "ERROR: Failed to dupe the client CA list: " << Security::ErrorString(ssl_error)); return false; } @@ -572,14 +571,14 @@ if (!SSL_CTX_use_certificate(ctx.get(), 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)); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS certificate '" << keys.certFile << "': " << Security::ErrorString(ssl_error)); return false; } if (!SSL_CTX_use_PrivateKey(ctx.get(), port.signPkey.get())) { const int ssl_error = ERR_get_error(); 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)); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS private key '" << keys.privateKeyFile << "': " << Security::ErrorString(ssl_error)); return false; } @@ -590,7 +589,7 @@ if (!SSL_CTX_use_certificate_chain_file(ctx.get(), certfile)) { ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL)); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << Security::ErrorString(ssl_error)); return false; } @@ -599,7 +598,7 @@ if (!SSL_CTX_use_PrivateKey_file(ctx.get(), keyfile, SSL_FILETYPE_PEM)) { ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL)); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << Security::ErrorString(ssl_error)); return false; } @@ -608,7 +607,7 @@ if (!SSL_CTX_check_private_key(ctx.get())) { ssl_error = ERR_get_error(); debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" << - keyfile << "': " << ERR_error_string(ssl_error, NULL)); + keyfile << "': " << Security::ErrorString(ssl_error)); return false; } */ @@ -640,7 +639,7 @@ if (!SSL_CTX_set_cipher_list(ctx.get(), cipher)) { const int ssl_error = ERR_get_error(); fatalf("Failed to set SSL cipher suite '%s': %s\n", - cipher, ERR_error_string(ssl_error, NULL)); + cipher, Security::ErrorString(ssl_error)); } } @@ -654,7 +653,7 @@ if (!SSL_CTX_use_certificate_chain_file(ctx.get(), certfile)) { const int ssl_error = ERR_get_error(); fatalf("Failed to acquire SSL certificate '%s': %s\n", - certfile, ERR_error_string(ssl_error, NULL)); + certfile, Security::ErrorString(ssl_error)); } debugs(83, DBG_IMPORTANT, "Using private key in " << keys.privateKeyFile); @@ -664,7 +663,7 @@ if (!SSL_CTX_use_PrivateKey_file(ctx.get(), keyfile, SSL_FILETYPE_PEM)) { const int ssl_error = ERR_get_error(); fatalf("Failed to acquire SSL private key '%s': %s\n", - keyfile, ERR_error_string(ssl_error, NULL)); + keyfile, Security::ErrorString(ssl_error)); } debugs(83, 5, "Comparing private and public SSL keys."); @@ -672,7 +671,7 @@ if (!SSL_CTX_check_private_key(ctx.get())) { const int ssl_error = ERR_get_error(); fatalf("SSL private key '%s' does not match public key '%s': %s\n", - certfile, keyfile, ERR_error_string(ssl_error, NULL)); + certfile, keyfile, Security::ErrorString(ssl_error)); } } } @@ -975,10 +974,10 @@ X509 *signingCert = port.signingCert.get(); if (SSL_CTX_add_extra_chain_cert(ctx.get(), signingCert)) { // increase the certificate lock - CRYPTO_add(&(signingCert->references),1,CRYPTO_LOCK_X509); + X509_up_ref(signingCert); } else { const int ssl_error = ERR_get_error(); - debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL)); + debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << Security::ErrorString(ssl_error)); } Ssl::addChainToSslContext(ctx, port.certsToChain.get()); } @@ -1069,7 +1068,7 @@ if (!SSL_set_tlsext_host_name(ssl, fqdn)) { const int ssl_error = ERR_get_error(); debugs(83, 3, "WARNING: unable to set TLS servername extension (SNI): " << - ERR_error_string(ssl_error, NULL) << "\n"); + Security::ErrorString(ssl_error) << "\n"); return false; } return true; @@ -1089,10 +1088,10 @@ X509 *cert = sk_X509_value(chain, i); if (SSL_CTX_add_extra_chain_cert(ctx.get(), cert)) { // increase the certificate lock - CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509); + X509_up_ref(cert); } else { const int ssl_error = ERR_get_error(); - debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL)); + debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL context chain: " << Security::ErrorString(ssl_error)); } } } @@ -1330,7 +1329,7 @@ { if (!certFilename) return NULL; - Ssl::BIO_Pointer bio(BIO_new(BIO_s_file_internal())); + Ssl::BIO_Pointer bio(BIO_new(BIO_s_file())); if (!bio) return NULL; if (!BIO_read_filename(bio.get(), certFilename)) @@ -1372,10 +1371,17 @@ pem_password_cb *cb = ::Config.Program.ssl_password ? &ssl_ask_password_cb : NULL; pkey.resetWithoutLocking(readSslPrivateKey(keyFilename, cb)); cert.resetWithoutLocking(readSslX509CertificatesChain(certFilename, chain.get())); - if (!pkey || !cert || !X509_check_private_key(cert.get(), pkey.get())) { - pkey.reset(); - cert.reset(); - } + if (!cert) { + debugs(83, DBG_IMPORTANT, "WARNING: missing cert in '" << certFilename << "'"); + } else if (!pkey) { + debugs(83, DBG_IMPORTANT, "WARNING: missing private key in '" << keyFilename << "'"); + } else if (!X509_check_private_key(cert.get(), pkey.get())) { + debugs(83, DBG_IMPORTANT, "WARNING: X509_check_private_key() failed to verify signing cert"); + } else + return; // everything is okay + + pkey.reset(); + cert.reset(); } bool Ssl::generateUntrustedCert(Security::CertPointer &untrustedCert, EVP_PKEY_Pointer &untrustedPkey, Security::CertPointer const &cert, EVP_PKEY_Pointer const & pkey) @@ -1432,7 +1438,7 @@ } debugs(83, DBG_IMPORTANT, "ERROR: " << squidCtx << ' ' << errAction << - ": " << ERR_error_string(errCode, NULL)); + ": " << Security::ErrorString(errCode)); return false; } diff -u -r -N squid-4.0.16/src/ssl/support.h squid-4.0.17/src/ssl/support.h --- squid-4.0.16/src/ssl/support.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/ssl/support.h 2016-12-16 23:06:20.000000000 +1300 @@ -91,6 +91,12 @@ /// initialize a TLS client context with OpenSSL specific settings bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, long options, long flags); +#if defined(CRYPTO_LOCK_X509) +// portability wrapper for OpenSSL 1.0 vs 1.1 +// use Security::CertPointer instead where possible +inline int X509_up_ref(X509 *t) {if (t) CRYPTO_add(&t->references, 1, CRYPTO_LOCK_X509); return 0;} +#endif + } //namespace Ssl /// \ingroup ServerProtocolSSLAPI @@ -145,7 +151,7 @@ \ingroup ServerProtocolSSLAPI * Short names for ssl-bump modes */ -extern const char *BumpModeStr[]; +extern std::vectorBumpModeStr; /** \ingroup ServerProtocolSSLAPI @@ -153,7 +159,7 @@ */ inline const char *bumpMode(int bm) { - return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr[bm] : NULL; + return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr.at(bm) : NULL; } /// certificates indexed by issuer name diff -u -r -N squid-4.0.16/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.0.17/src/store/id_rewriters/file/storeid_file_rewrite.8 --- squid-4.0.16/src/store/id_rewriters/file/storeid_file_rewrite.8 2016-10-31 03:19:23.000000000 +1300 +++ squid-4.0.17/src/store/id_rewriters/file/storeid_file_rewrite.8 2016-12-17 07:22:45.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "STOREID_FILE_REWRITE 8" -.TH STOREID_FILE_REWRITE 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH STOREID_FILE_REWRITE 8 "2016-12-16" "perl v5.24.1" "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.16/src/tests/stub_HttpControlMsg.cc squid-4.0.17/src/tests/stub_HttpControlMsg.cc --- squid-4.0.16/src/tests/stub_HttpControlMsg.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/tests/stub_HttpControlMsg.cc 2016-12-16 23:06:20.000000000 +1300 @@ -13,4 +13,5 @@ #include "HttpControlMsg.h" void HttpControlMsgSink::wroteControlMsg(CommIoCbParams const&) STUB +void HttpControlMsgSink::doneWithControlMsg() STUB diff -u -r -N squid-4.0.16/src/tests/stub_libsslsquid.cc squid-4.0.17/src/tests/stub_libsslsquid.cc --- squid-4.0.16/src/tests/stub_libsslsquid.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/tests/stub_libsslsquid.cc 2016-12-16 23:06:20.000000000 +1300 @@ -66,7 +66,7 @@ //GETX509ATTRIBUTE GetX509UserAttribute; //GETX509ATTRIBUTE GetX509CAAttribute; //GETX509ATTRIBUTE GetX509Fingerprint; -const char *BumpModeStr[] = {""}; +std::vector BumpModeStr = {""}; bool generateUntrustedCert(Security::CertPointer & untrustedCert, EVP_PKEY_Pointer & untrustedPkey, Security::CertPointer const & cert, EVP_PKEY_Pointer const & pkey) STUB_RETVAL(false) Security::ContextPointer generateSslContext(CertificateProperties const &, AnyP::PortCfg &) STUB_RETVAL(Security::ContextPointer()) bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &) STUB_RETVAL(false) diff -u -r -N squid-4.0.16/src/tests/stub_wordlist.cc squid-4.0.17/src/tests/stub_wordlist.cc --- squid-4.0.16/src/tests/stub_wordlist.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/tests/stub_wordlist.cc 2016-12-16 23:06:20.000000000 +1300 @@ -13,7 +13,5 @@ #include "tests/STUB.h" const char *wordlistAdd(wordlist **, const char *) STUB_RETVAL(NULL) -void wordlistAddWl(wordlist **, wordlist *) STUB -void wordlistJoin(wordlist **, wordlist **) STUB void wordlistDestroy(wordlist **) STUB diff -u -r -N squid-4.0.16/src/tests/testSBuf.cc squid-4.0.17/src/tests/testSBuf.cc --- squid-4.0.16/src/tests/testSBuf.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/tests/testSBuf.cc 2016-12-16 23:06:20.000000000 +1300 @@ -151,9 +151,22 @@ void testSBuf::testAppendSBuf() { - SBuf s1(fox1),s2(fox2); - s1.append(s2); - CPPUNIT_ASSERT_EQUAL(s1,literal); + const SBuf appendix(fox1); + const char * const rawAppendix = appendix.rawContent(); + + // check whether the optimization that prevents copying when append()ing to + // default-constructed SBuf actually works + SBuf s0; + s0.append(appendix); + CPPUNIT_ASSERT_EQUAL(s0.rawContent(), appendix.rawContent()); + CPPUNIT_ASSERT_EQUAL(s0, appendix); + + // paranoid: check that the above code can actually detect copies + SBuf s1(fox1); + s1.append(appendix); + CPPUNIT_ASSERT(s1.rawContent() != appendix.rawContent()); + CPPUNIT_ASSERT(s1 != appendix); + CPPUNIT_ASSERT_EQUAL(rawAppendix, appendix.rawContent()); } void @@ -828,6 +841,15 @@ b.append('X'); } } + + // the minimal space requirement should overwrite idealSpace preferences + requirements.minSpace = 10; + for (const int delta: {-1,0,+1}) { + requirements.idealSpace = requirements.minSpace + delta; + SBuf buffer; + buffer.reserve(requirements); + CPPUNIT_ASSERT(buffer.spaceSize() >= requirements.minSpace); + } } void diff -u -r -N squid-4.0.16/src/tools.cc squid-4.0.17/src/tools.cc --- squid-4.0.16/src/tools.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/tools.cc 2016-12-16 23:06:20.000000000 +1300 @@ -1014,7 +1014,7 @@ if (!fp) { int xerrno = errno; - debugs(1, DBG_IMPORTANT, "parseEtcHosts: " << Config.etcHostsPath << ": " << xstrerr(xerrno)); + debugs(1, DBG_IMPORTANT, "parseEtcHosts: '" << Config.etcHostsPath << "' : " << xstrerr(xerrno)); return; } @@ -1023,8 +1023,6 @@ #endif while (fgets(buf, 1024, fp)) { /* for each line */ - wordlist *hosts = NULL; - char *addr; if (buf[0] == '#') /* MS-windows likes to add comments */ continue; @@ -1033,7 +1031,7 @@ lt = buf; - addr = buf; + char *addr = buf; debugs(1, 5, "etc_hosts: line is '" << buf << "'"); @@ -1048,6 +1046,8 @@ lt = nt + 1; + SBufList hosts; + while ((nt = strpbrk(lt, w_space))) { char *host = NULL; @@ -1073,19 +1073,16 @@ if (ipcacheAddEntryFromHosts(host, addr) != 0) { /* invalid address, continuing is useless */ - wordlistDestroy(&hosts); - hosts = NULL; + hosts.clear(); break; } - wordlistAdd(&hosts, host); + hosts.emplace_back(SBuf(host)); lt = nt + 1; } - if (hosts) { + if (!hosts.empty()) fqdncacheAddEntryFromHosts(addr, hosts); - wordlistDestroy(&hosts); - } } fclose (fp); diff -u -r -N squid-4.0.16/src/tunnel.cc squid-4.0.17/src/tunnel.cc --- squid-4.0.16/src/tunnel.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/tunnel.cc 2016-12-16 23:06:20.000000000 +1300 @@ -28,7 +28,6 @@ #include "http.h" #include "http/Stream.h" #include "HttpRequest.h" -#include "HttpStateFlags.h" #include "ip/QosConfig.h" #include "LogTags.h" #include "MemBuf.h" @@ -68,7 +67,7 @@ CBDATA_CLASS(TunnelStateData); public: - TunnelStateData(); + TunnelStateData(ClientHttpRequest *); ~TunnelStateData(); TunnelStateData(const TunnelStateData &); // do not implement TunnelStateData &operator =(const TunnelStateData &); // do not implement @@ -105,6 +104,10 @@ /// Whether the client sent a CONNECT request to us. bool clientExpectsConnectResponse() const { + // If we are forcing a tunnel after receiving a client CONNECT, then we + // have already responded to that CONNECT before tunnel.cc started. + if (request && request->flags.forceTunnel) + return false; #if USE_OPENSSL // We are bumping and we had already send "OK CONNECTED" if (http.valid() && http->getConn() && http->getConn()->serverBump() && http->getConn()->serverBump()->step > Ssl::bumpStep1) @@ -285,12 +288,7 @@ } } -TunnelStateData::TunnelStateData() : - url(NULL), - http(), - request(NULL), - status_ptr(NULL), - logTag_ptr(NULL), +TunnelStateData::TunnelStateData(ClientHttpRequest *clientRequest) : connectRespBuf(NULL), connectReqWriting(false), started(squid_curtime) @@ -298,6 +296,23 @@ debugs(26, 3, "TunnelStateData constructed this=" << this); client.readPendingFunc = &tunnelDelayedClientRead; server.readPendingFunc = &tunnelDelayedServerRead; + + assert(clientRequest); + url = xstrdup(clientRequest->uri); + request = clientRequest->request; + server.size_ptr = &clientRequest->out.size; + client.size_ptr = &clientRequest->al->http.clientRequestSz.payloadData; + status_ptr = &clientRequest->al->http.code; + logTag_ptr = &clientRequest->logType; + al = clientRequest->al; + http = clientRequest; + + client.conn = clientRequest->getConn()->clientConnection; + comm_add_close_handler(client.conn->fd, tunnelClientClosed, this); + + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, this)); + commSetConnTimeout(client.conn, Config.Timeout.lifetime, timeoutCall); } TunnelStateData::~TunnelStateData() @@ -498,7 +513,8 @@ *status_ptr = rep.sline.status(); // we need to relay the 401/407 responses when login=PASS(THRU) - const char *pwd = server.conn->getPeer()->login; + const CachePeer *peer = server.conn->getPeer(); + const char *pwd = (peer ? peer->login : nullptr); const bool relay = pwd && (strcmp(pwd, "PASS") == 0 || strcmp(pwd, "PASSTHRU") == 0) && (*status_ptr == Http::scProxyAuthenticationRequired || *status_ptr == Http::scUnauthorized); @@ -1075,28 +1091,10 @@ ++statCounter.server.all.requests; ++statCounter.server.other.requests; - tunnelState = new TunnelStateData; + tunnelState = new TunnelStateData(http); #if USE_DELAY_POOLS - tunnelState->server.setDelayId(DelayId::DelayClient(http)); + //server.setDelayId called from tunnelConnectDone after server side connection established #endif - tunnelState->url = xstrdup(url); - tunnelState->request = request; - tunnelState->server.size_ptr = &http->out.size; - tunnelState->client.size_ptr = &http->al->http.clientRequestSz.payloadData; - tunnelState->status_ptr = &http->al->http.code; - tunnelState->logTag_ptr = &http->logType; - tunnelState->client.conn = http->getConn()->clientConnection; - tunnelState->http = http; - tunnelState->al = http->al; - //tunnelState->started is set in TunnelStateData ctor - - comm_add_close_handler(tunnelState->client.conn->fd, - tunnelClientClosed, - tunnelState); - - AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", - CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); - commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall); peerSelect(&(tunnelState->serverDestinations), request, http->al, NULL, @@ -1143,7 +1141,7 @@ TunnelStateData *tunnelState = (TunnelStateData *)data; assert(!tunnelState->waitingForConnectExchange()); HttpHeader hdr_out(hoRequest); - HttpStateFlags flags; + Http::StateFlags flags; debugs(26, 3, HERE << srv << ", tunnelState=" << tunnelState); memset(&flags, '\0', sizeof(flags)); flags.proxying = tunnelState->request->flags.proxying; @@ -1183,13 +1181,40 @@ commSetConnTimeout(srv, Config.Timeout.read, timeoutCall); } +static Comm::ConnectionPointer +borrowPinnedConnection(HttpRequest *request, Comm::ConnectionPointer &serverDestination) +{ + // pinned_connection may become nil after a pconn race + if (ConnStateData *pinned_connection = request ? request->pinnedConnection() : nullptr) { + Comm::ConnectionPointer serverConn = pinned_connection->borrowPinnedConnection(request, serverDestination->getPeer()); + return serverConn; + } + + return nullptr; +} + static void tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, ErrorState *err, void *data) { TunnelStateData *tunnelState = (TunnelStateData *)data; - if (peer_paths == NULL || peer_paths->size() < 1) { + bool bail = false; + if (!peer_paths || peer_paths->empty()) { debugs(26, 3, HERE << "No paths found. Aborting CONNECT"); + bail = true; + } + + if (!bail && tunnelState->serverDestinations[0]->peerType == PINNED) { + Comm::ConnectionPointer serverConn = borrowPinnedConnection(tunnelState->request.getRaw(), tunnelState->serverDestinations[0]); + debugs(26,7, "pinned peer connection: " << serverConn); + if (Comm::IsConnOpen(serverConn)) { + tunnelConnectDone(serverConn, Comm::OK, 0, (void *)tunnelState); + return; + } + bail = true; + } + + if (bail) { if (!err) { err = new ErrorState(ERR_CANNOT_FORWARD, Http::scServiceUnavailable, tunnelState->request.getRaw()); } @@ -1237,51 +1262,33 @@ switchToTunnel(HttpRequest *request, Comm::ConnectionPointer &clientConn, Comm::ConnectionPointer &srvConn) { debugs(26,5, "Revert to tunnel FD " << clientConn->fd << " with FD " << srvConn->fd); - /* Create state structure. */ - const SBuf url(request->effectiveRequestUri()); - debugs(26, 3, request->method << " " << url << " " << request->http_ver); + /* Create state structure. */ ++statCounter.server.all.requests; ++statCounter.server.other.requests; - TunnelStateData *tunnelState = new TunnelStateData; - tunnelState->url = SBufToCstring(url); - tunnelState->request = request; - tunnelState->server.size_ptr = NULL; //Set later if Http::Stream is available - - // Temporary static variable to store the unneeded for our case status code - static int status_code = 0; - tunnelState->status_ptr = &status_code; - tunnelState->client.conn = clientConn; - - if (auto conn = request->clientConnectionManager.get()) { - Http::StreamPointer context = conn->pipeline.front(); - if (context && context->http) { - tunnelState->logTag_ptr = &context->http->logType; - tunnelState->server.size_ptr = &context->http->out.size; - tunnelState->al = context->http->al; + auto conn = request->clientConnectionManager.get(); + Must(conn); + Http::StreamPointer context = conn->pipeline.front(); + Must(context && context->http); -#if USE_DELAY_POOLS - /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */ - if (srvConn->getPeer() && srvConn->getPeer()->options.no_delay) - tunnelState->server.setDelayId(DelayId::DelayClient(context->http)); -#endif - } - } + debugs(26, 3, request->method << " " << context->http->uri << " " << request->http_ver); - comm_add_close_handler(tunnelState->client.conn->fd, - tunnelClientClosed, - tunnelState); + TunnelStateData *tunnelState = new TunnelStateData(context->http); - AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", - CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); - commSetConnTimeout(tunnelState->client.conn, Config.Timeout.lifetime, timeoutCall); fd_table[clientConn->fd].read_method = &default_read_method; fd_table[clientConn->fd].write_method = &default_write_method; request->hier.note(srvConn, tunnelState->getHost()); tunnelState->server.conn = srvConn; + +#if USE_DELAY_POOLS + /* no point using the delayIsNoDelay stuff since tunnel is nice and simple */ + if (srvConn->getPeer() && srvConn->getPeer()->options.no_delay) + tunnelState->server.setDelayId(DelayId::DelayClient(context->http)); +#endif + request->peer_host = srvConn->getPeer() ? srvConn->getPeer()->host : nullptr; comm_add_close_handler(srvConn->fd, tunnelServerClosed, tunnelState); @@ -1298,8 +1305,8 @@ request->flags.proxying = false; } - timeoutCall = commCbCall(5, 4, "tunnelTimeout", - CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); + AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout", + CommTimeoutCbPtrFun(tunnelTimeout, tunnelState)); commSetConnTimeout(srvConn, Config.Timeout.read, timeoutCall); fd_table[srvConn->fd].read_method = &default_read_method; fd_table[srvConn->fd].write_method = &default_write_method; diff -u -r -N squid-4.0.16/src/wordlist.cc squid-4.0.17/src/wordlist.cc --- squid-4.0.16/src/wordlist.cc 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/wordlist.cc 2016-12-16 23:06:20.000000000 +1300 @@ -32,28 +32,6 @@ } void -wordlistJoin(wordlist ** list, wordlist ** wl) -{ - while (*list) - list = &(*list)->next; - - *list = *wl; - - *wl = NULL; -} - -void -wordlistAddWl(wordlist ** list, wordlist * wl) -{ - while (*list) - list = &(*list)->next; - - for (; wl; wl = wl->next, list = &(*list)->next) { - *list = new wordlist(wl->key); - } -} - -void wordlistCat(const wordlist * w, MemBuf * mb) { while (NULL != w) { diff -u -r -N squid-4.0.16/src/wordlist.h squid-4.0.17/src/wordlist.h --- squid-4.0.16/src/wordlist.h 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/src/wordlist.h 2016-12-16 23:06:20.000000000 +1300 @@ -52,18 +52,6 @@ */ void wordlistCat(const wordlist *, MemBuf *); -/** append a wordlist to another - * - * \deprecated use SBufList.merge(otherwordlist) instead - */ -void wordlistAddWl(wordlist **, wordlist *); - -/** Concatenate the words in a wordlist - * - * \deprecated use SBufListContainerJoin(SBuf()) from sbuf/Algorithms.h instead - */ -void wordlistJoin(wordlist **, wordlist **); - /// destroy a wordlist void wordlistDestroy(wordlist **); diff -u -r -N squid-4.0.16/test-suite/squidconf/mgr_passwd squid-4.0.17/test-suite/squidconf/mgr_passwd --- squid-4.0.16/test-suite/squidconf/mgr_passwd 1970-01-01 12:00:00.000000000 +1200 +++ squid-4.0.17/test-suite/squidconf/mgr_passwd 2016-12-16 23:06:20.000000000 +1300 @@ -0,0 +1,22 @@ +# +# Tests for cachemgr_passwd directive + +# accept passwords +cachemgr_passwd password1 utilization +cachemgr_passwd password1 store_io + +# accept list of actions for one password +cachemgr_passwd password2 io counters + +# specaial case 'none' +cachemgr_passwd none menu +cachemgr_passwd none index + +# special case 'disable' +cachemgr_passwd disable + +# repeating actions should produce a warning +cachemgr_passwd none menu + +# unknown action ?? +cachemgr_passwd none blah_blah_blah diff -u -r -N squid-4.0.16/tools/helper-mux/helper-mux.8 squid-4.0.17/tools/helper-mux/helper-mux.8 --- squid-4.0.16/tools/helper-mux/helper-mux.8 2016-10-31 03:22:52.000000000 +1300 +++ squid-4.0.17/tools/helper-mux/helper-mux.8 2016-12-17 07:27:19.000000000 +1300 @@ -129,7 +129,7 @@ .\" ======================================================================== .\" .IX Title "HELPER-MUX 8" -.TH HELPER-MUX 8 "2016-10-30" "perl v5.24.1" "User Contributed Perl Documentation" +.TH HELPER-MUX 8 "2016-12-16" "perl v5.24.1" "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.16/tools/purge/purge.1 squid-4.0.17/tools/purge/purge.1 --- squid-4.0.16/tools/purge/purge.1 2016-10-31 01:24:50.000000000 +1300 +++ squid-4.0.17/tools/purge/purge.1 2016-12-16 23:06:20.000000000 +1300 @@ -19,7 +19,7 @@ .B squid does not seem to know about any longer. .PP -This is a tool for expert usage only, use it under your own responsability. +This is a tool for expert usage only, use it under your own responsibility. . .SH OPTIONS .if !'po4a'hide' .TP 12 @@ -58,7 +58,7 @@ . .if !'po4a'hide' .TP .if !'po4a'hide' .B \-d l -lets you specify a debug level. Differents bits are reserved for +lets you specify a debug level. Different bits are reserved for different output. .br default: 0