diff -u -r -N squid-4.0.10/acinclude/lib-checks.m4 squid-4.0.11/acinclude/lib-checks.m4 --- squid-4.0.10/acinclude/lib-checks.m4 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/acinclude/lib-checks.m4 2016-06-10 08:32:57.000000000 +1200 @@ -297,11 +297,12 @@ ssl->init_num = 0; ssl->s3->wpend_ret = 0; ssl->s3->wpend_tot = 0; + SSL_CIPHER *cipher = 0; + assert(SSL_CIPHER_get_id(cipher)); ]) ], [ - AC_DEFINE(SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK, 1) - AC_MSG_RESULT([yes]) + AC_MSG_RESULT([possibly; to try, set SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK macro value to 1]) ], [ AC_MSG_RESULT([no]) diff -u -r -N squid-4.0.10/ChangeLog squid-4.0.11/ChangeLog --- squid-4.0.10/ChangeLog 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/ChangeLog 2016-06-10 08:32:57.000000000 +1200 @@ -1,3 +1,20 @@ +Changes to squid-4.0.11 (09 Jun 2016): + + - Bug 4517: error: comparison between signed and unsigned integer + - Bug 4492: chunked parser needs to accept BWS after chunk size + - HTTP/1.1: allow chunking the last HTTP response on a connection + - HTTP/1.1: unfold mime header blocks + - TLS: fast SNI peek + - TLS: check for SSL_CIPHER_get_id() support required in adjustSSL() + - TLS: never enable OPENSSL_HELLO_OVERWRITE_HACK automatically + - squidclient: improve shell-escape support in -H option + - Do not allow low-level debugging to hide important/critical messages + - Replace new/delete operators using modern C++ rules + - Remove ie_refresh configuration option + - Deprecating SMB LanMan helpers + - Mark refresh-waiting transactions with REFRESH + - ... and some code cleanup and polishing + Changes to squid-4.0.10 (06 May 2016): - Accumulate fewer unknown-size responses to avoid overwhelming disks. diff -u -r -N squid-4.0.10/compat/os/macosx.h squid-4.0.11/compat/os/macosx.h --- squid-4.0.10/compat/os/macosx.h 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/compat/os/macosx.h 2016-06-10 08:32:57.000000000 +1200 @@ -28,11 +28,6 @@ #include "compat/cmsg.h" -// MacOS GCC 4.0.1 and 4.2.1 supply __GNUC_GNU_INLINE__ but do not actually define __attribute__((gnu_inline)) -#if defined(__cplusplus) && !defined(_SQUID_EXTERNNEW_) -#define _SQUID_EXTERNNEW_ extern inline -#endif - #endif /* _SQUID_APPLE_ */ #endif /* SQUID_OS_MACOSX_H */ diff -u -r -N squid-4.0.10/compat/os/sgi.h squid-4.0.11/compat/os/sgi.h --- squid-4.0.10/compat/os/sgi.h 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/compat/os/sgi.h 2016-06-10 08:32:57.000000000 +1200 @@ -25,15 +25,6 @@ #define _ABI_SOURCE #endif /* USE_ASYNC_IO */ -#if defined(__cplusplus) && !defined(_SQUID_EXTERNNEW_) && !defined(_GNUC_) -/* - * The gcc compiler treats extern inline functions as being extern, - * while the SGI MIPSpro compilers treat them as inline. To get equivalent - * behavior, remove the inline keyword. - */ -#define _SQUID_EXTERNNEW_ extern -#endif - #endif /* _SQUID_SGI_ */ #endif /* SQUID_OS_SGI_H */ diff -u -r -N squid-4.0.10/compat/os/solaris.h squid-4.0.11/compat/os/solaris.h --- squid-4.0.10/compat/os/solaris.h 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/compat/os/solaris.h 2016-06-10 08:32:57.000000000 +1200 @@ -59,13 +59,6 @@ #endif /* - * SunPro CC handles extern inline as inline, PLUS extern symbols. - */ -#if !defined(_SQUID_EXTERNNEW_) && defined(__SUNPRO_CC) -#define _SQUID_EXTERNNEW_ extern -#endif - -/* * SunStudio CC does not define C++ portability API __FUNCTION__ */ #if defined(__SUNPRO_CC) && !defined(__FUNCTION__) diff -u -r -N squid-4.0.10/configure squid-4.0.11/configure --- squid-4.0.10/configure 2016-05-06 23:37:23.000000000 +1200 +++ squid-4.0.11/configure 2016-06-10 08:35:21.000000000 +1200 @@ -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.10. +# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.0.11. # # Report bugs to . # @@ -595,8 +595,8 @@ # Identity of this package. PACKAGE_NAME='Squid Web Proxy' PACKAGE_TARNAME='squid' -PACKAGE_VERSION='4.0.10' -PACKAGE_STRING='Squid Web Proxy 4.0.10' +PACKAGE_VERSION='4.0.11' +PACKAGE_STRING='Squid Web Proxy 4.0.11' PACKAGE_BUGREPORT='http://bugs.squid-cache.org/' PACKAGE_URL='' @@ -652,18 +652,18 @@ PO2TEXT PO2HTML REGEXLIB -USE_DEVPOLL_FALSE -USE_DEVPOLL_TRUE -USE_KQUEUE_FALSE -USE_KQUEUE_TRUE -USE_SELECT_WIN32_FALSE -USE_SELECT_WIN32_TRUE -USE_SELECT_FALSE -USE_SELECT_TRUE -USE_EPOLL_FALSE -USE_EPOLL_TRUE -USE_POLL_FALSE -USE_POLL_TRUE +ENABLE_DEVPOLL_FALSE +ENABLE_DEVPOLL_TRUE +ENABLE_KQUEUE_FALSE +ENABLE_KQUEUE_TRUE +ENABLE_SELECT_WIN32_FALSE +ENABLE_SELECT_WIN32_TRUE +ENABLE_SELECT_FALSE +ENABLE_SELECT_TRUE +ENABLE_EPOLL_FALSE +ENABLE_EPOLL_TRUE +ENABLE_POLL_FALSE +ENABLE_POLL_TRUE LIBOBJS LIB_DB ALLOCA @@ -681,6 +681,8 @@ EXTERNAL_ACL_HELPERS WBINFO LOG_DAEMON_HELPERS +ENABLE_SMBLIB_FALSE +ENABLE_SMBLIB_TRUE AUTH_LIBS_TO_BUILD AUTH_MODULES NTLM_AUTH_HELPERS @@ -700,13 +702,11 @@ ENABLE_AUTH_FALSE ENABLE_AUTH_TRUE DEFAULT_HOSTS -MAKE_LEAKFINDER_FALSE -MAKE_LEAKFINDER_TRUE +ENABLE_LEAKFINDER_FALSE +ENABLE_LEAKFINDER_TRUE EPOLL_LIBS LBERLIB LDAPLIB -HAVE_SPNEGO_FALSE -HAVE_SPNEGO_TRUE KRB5LIBS KRB5INCS LIB_KRB5_LIBS @@ -723,34 +723,34 @@ NETTLELIB ENABLE_HTCP_FALSE ENABLE_HTCP_TRUE -USE_SQUID_EUI_FALSE -USE_SQUID_EUI_TRUE +ENABLE_EUI_FALSE +ENABLE_EUI_TRUE EUILIB SNMPLIB ENABLE_SNMP_FALSE ENABLE_SNMP_TRUE ADAPTATION_LIBS -USE_ADAPTATION_FALSE -USE_ADAPTATION_TRUE +ENABLE_ADAPTATION_FALSE +ENABLE_ADAPTATION_TRUE ECAP_LIBS -USE_ECAP_FALSE -USE_ECAP_TRUE +ENABLE_ECAP_FALSE +ENABLE_ECAP_TRUE EXT_LIBECAP_LIBS EXT_LIBECAP_CFLAGS PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG ICAP_LIBS -USE_ICAP_CLIENT_FALSE -USE_ICAP_CLIENT_TRUE +ENABLE_ICAP_CLIENT_FALSE +ENABLE_ICAP_CLIENT_TRUE XMLLIB -HAVE_LIBXML2_FALSE -HAVE_LIBXML2_TRUE +ENABLE_LIBXML2_FALSE +ENABLE_LIBXML2_TRUE EXPATLIB -HAVE_LIBEXPAT_FALSE -HAVE_LIBEXPAT_TRUE -USE_ESI_FALSE -USE_ESI_TRUE +ENABLE_LIBEXPAT_FALSE +ENABLE_LIBEXPAT_TRUE +ENABLE_ESI_FALSE +ENABLE_ESI_TRUE ENABLE_DELAY_POOLS_FALSE ENABLE_DELAY_POOLS_TRUE ENABLE_PINGER_FALSE @@ -761,10 +761,10 @@ STORE_TESTS STORE_LIBS_TO_ADD STORE_LIBS_TO_BUILD -HAVE_FS_ROCK_FALSE -HAVE_FS_ROCK_TRUE -HAVE_FS_UFS_FALSE -HAVE_FS_UFS_TRUE +ENABLE_FS_ROCK_FALSE +ENABLE_FS_ROCK_TRUE +ENABLE_FS_UFS_FALSE +ENABLE_FS_UFS_TRUE ENABLE_DISKIO_MMAPPED_FALSE ENABLE_DISKIO_MMAPPED_TRUE ENABLE_DISKIO_IPCIO_FALSE @@ -1650,7 +1650,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.10 to adapt to many kinds of systems. +\`configure' configures Squid Web Proxy 4.0.11 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1721,7 +1721,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Squid Web Proxy 4.0.10:";; + short | recursive ) echo "Configuration of Squid Web Proxy 4.0.11:";; 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.10 +Squid Web Proxy configure 4.0.11 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.10, which was +It was created by Squid Web Proxy $as_me 4.0.11, 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.10' + VERSION='4.0.11' cat >>confdefs.h <<_ACEOF @@ -6809,8 +6809,11 @@ fi -# Check for C++11 compiler support - ax_cxx_compile_cxx11_required=true +# If the user did not specify a C++ version. +user_cxx=`echo "$PRESET_CXXFLAGS" | grep -o -E "\-std="` +if test "x$user_cxx" = "x"; then + # Check for C++11 compiler support + ax_cxx_compile_cxx11_required=true ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -6956,6 +6959,7 @@ fi +fi # test for programs if test -n "$ac_tool_prefix"; then @@ -21857,7 +21861,6 @@ fi - squid_opt_enable_storeio=auto # Check whether --enable-storeio was given. if test "${enable_storeio+set}" = set; then : @@ -21964,20 +21967,20 @@ esac done - if test "x$squid_do_build_ufs" = "xtrue" ; then - HAVE_FS_UFS_TRUE= - HAVE_FS_UFS_FALSE='#' + if test "x$squid_do_build_ufs" = "xtrue"; then + ENABLE_FS_UFS_TRUE= + ENABLE_FS_UFS_FALSE='#' else - HAVE_FS_UFS_TRUE='#' - HAVE_FS_UFS_FALSE= + ENABLE_FS_UFS_TRUE='#' + ENABLE_FS_UFS_FALSE= fi - if test "x$squid_do_build_rock" = "xtrue" ; then - HAVE_FS_ROCK_TRUE= - HAVE_FS_ROCK_FALSE='#' + if test "x$squid_do_build_rock" = "xtrue"; then + ENABLE_FS_ROCK_TRUE= + ENABLE_FS_ROCK_FALSE='#' else - HAVE_FS_ROCK_TRUE='#' - HAVE_FS_ROCK_FALSE= + ENABLE_FS_ROCK_TRUE='#' + ENABLE_FS_ROCK_FALSE= fi @@ -22336,28 +22339,28 @@ fi if test "x$squid_opt_use_esi" = "xyes"; then - USE_ESI_TRUE= - USE_ESI_FALSE='#' + ENABLE_ESI_TRUE= + ENABLE_ESI_FALSE='#' else - USE_ESI_TRUE='#' - USE_ESI_FALSE= + ENABLE_ESI_TRUE='#' + ENABLE_ESI_FALSE= fi if test "$HAVE_LIBEXPAT" = 1; then - HAVE_LIBEXPAT_TRUE= - HAVE_LIBEXPAT_FALSE='#' + ENABLE_LIBEXPAT_TRUE= + ENABLE_LIBEXPAT_FALSE='#' else - HAVE_LIBEXPAT_TRUE='#' - HAVE_LIBEXPAT_FALSE= + ENABLE_LIBEXPAT_TRUE='#' + ENABLE_LIBEXPAT_FALSE= fi if test "$HAVE_LIBXML2" = 1; then - HAVE_LIBXML2_TRUE= - HAVE_LIBXML2_FALSE='#' + ENABLE_LIBXML2_TRUE= + ENABLE_LIBXML2_FALSE='#' else - HAVE_LIBXML2_TRUE='#' - HAVE_LIBXML2_FALSE= + ENABLE_LIBXML2_TRUE='#' + ENABLE_LIBXML2_FALSE= fi @@ -22388,22 +22391,21 @@ unset squid_tmp_define - if test "x$enable_icap_client" != "xno" ; then - USE_ICAP_CLIENT_TRUE= - USE_ICAP_CLIENT_FALSE='#' -else - USE_ICAP_CLIENT_TRUE='#' - USE_ICAP_CLIENT_FALSE= -fi - +ICAP_LIBS="" if test "x$enable_icap_client" != "xno" ; then ICAP_LIBS="icap/libicap.la" squid_opt_use_adaptation=yes +fi + if test "x$enable_icap_client" != "xno"; then + ENABLE_ICAP_CLIENT_TRUE= + ENABLE_ICAP_CLIENT_FALSE='#' else - ICAP_LIBS="" + ENABLE_ICAP_CLIENT_TRUE='#' + ENABLE_ICAP_CLIENT_FALSE= fi + squid_opt_use_ecap=1 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to support eCAP" >&5 $as_echo_n "checking whether to support eCAP... " >&6; } @@ -22650,52 +22652,63 @@ fi fi - if test "x$squid_opt_use_ecap" = "xyes"; then - USE_ECAP_TRUE= - USE_ECAP_FALSE='#' -else - USE_ECAP_TRUE='#' - USE_ECAP_FALSE= -fi - -if test "x$squid_opt_use_ecap" = "xyes"; -then - -$as_echo "#define USE_ECAP 1" >>confdefs.h - +ECAP_LIBS="" +if test "x$squid_opt_use_ecap" = "xyes"; then ECAP_LIBS="ecap/libecapsquid.la" squid_opt_use_adaptation=yes -else - -$as_echo "#define USE_ECAP 0" >>confdefs.h - - ECAP_LIBS="" fi +squid_tmp_define="" +case "${squid_opt_use_ecap:=no}" in + yes|true|1) squid_tmp_define="1" ;; + no|false|0|"") squid_tmp_define="0" ;; + *) as_fn_error $? "SQUID_DEFINE_BOOL: unrecognized value for USE_ECAP: '${squid_opt_use_ecap:=no}'" "$LINENO" 5 ;; +esac +cat >>confdefs.h <<_ACEOF +#define USE_ECAP $squid_tmp_define +_ACEOF - if test "x$squid_opt_use_adaptation" = "xyes"; then - USE_ADAPTATION_TRUE= - USE_ADAPTATION_FALSE='#' +unset squid_tmp_define + + if test "x$squid_opt_use_ecap" = "xyes"; then + ENABLE_ECAP_TRUE= + ENABLE_ECAP_FALSE='#' else - USE_ADAPTATION_TRUE='#' - USE_ADAPTATION_FALSE= + ENABLE_ECAP_TRUE='#' + ENABLE_ECAP_FALSE= fi -if test "x$squid_opt_use_adaptation" = "xyes" -then -$as_echo "#define USE_ADAPTATION 1" >>confdefs.h +ADAPTATION_LIBS="" +if test "x$squid_opt_use_adaptation" = "xyes"; then ADAPTATION_LIBS="adaptation/libadaptation.la" -else +fi + +squid_tmp_define="" +case "${squid_opt_use_adaptation:=no}" in + yes|true|1) squid_tmp_define="1" ;; + no|false|0|"") squid_tmp_define="0" ;; + *) as_fn_error $? "SQUID_DEFINE_BOOL: unrecognized value for USE_ADAPTATION: '${squid_opt_use_adaptation:=no}'" "$LINENO" 5 ;; +esac -$as_echo "#define USE_ADAPTATION 0" >>confdefs.h +cat >>confdefs.h <<_ACEOF +#define USE_ADAPTATION $squid_tmp_define +_ACEOF + +unset squid_tmp_define - ADAPTATION_LIBS="" + if test "x$squid_opt_use_adaptation" = "xyes"; then + ENABLE_ADAPTATION_TRUE= + ENABLE_ADAPTATION_FALSE='#' +else + ENABLE_ADAPTATION_TRUE='#' + ENABLE_ADAPTATION_FALSE= fi + test "x$squid_host_os" = "xmingw" && enable_wccp=no # Check whether --enable-wccp was given. if test "${enable_wccp+set}" = set; then : @@ -22956,11 +22969,11 @@ unset squid_tmp_define if test "x$enable_eui" = "xyes" ; then - USE_SQUID_EUI_TRUE= - USE_SQUID_EUI_FALSE='#' + ENABLE_EUI_TRUE= + ENABLE_EUI_FALSE='#' else - USE_SQUID_EUI_TRUE='#' - USE_SQUID_EUI_FALSE= + ENABLE_EUI_TRUE='#' + ENABLE_EUI_FALSE= fi @@ -23624,7 +23637,7 @@ $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lcrypto $LIBS" +LIBS="-lcrypto $LIBOPENSSL_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23668,7 +23681,7 @@ $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lssl $LIBS" +LIBS="-lssl $LIBOPENSSL_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23727,7 +23740,7 @@ $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lcrypto $LIBS" +LIBS="-lcrypto $LIBOPENSSL_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23771,7 +23784,7 @@ $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lssl $LIBS" +LIBS="-lssl $LIBOPENSSL_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -24327,6 +24340,8 @@ ssl->init_num = 0; ssl->s3->wpend_ret = 0; ssl->s3->wpend_tot = 0; + SSL_CIPHER *cipher = 0; + assert(SSL_CIPHER_get_id(cipher)); ; return 0; @@ -24335,10 +24350,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : - $as_echo "#define SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK 1" >>confdefs.h - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: possibly; to try, set SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK macro value to 1" >&5 +$as_echo "possibly; to try, set SQUID_USE_OPENSSL_HELLO_OVERWRITE_HACK macro value to 1" >&6; } else @@ -31100,14 +31113,6 @@ $as_echo "$as_me: $KRB5_FLAVOUR Kerberos library support: ${with_krb5:=no} ${LIB_KRB5_PATH} ${LIB_KRB5_LIBS}" >&6;} - if test x"$squid_cv_have_spnego" = x"yes" ; then - HAVE_SPNEGO_TRUE= - HAVE_SPNEGO_FALSE='#' -else - HAVE_SPNEGO_TRUE='#' - HAVE_SPNEGO_FALSE= -fi - case "$squid_host_os" in mingw) @@ -32695,11 +32700,11 @@ unset squid_tmp_define if test "x$enable_leakfinder" = "xyes"; then - MAKE_LEAKFINDER_TRUE= - MAKE_LEAKFINDER_FALSE='#' + ENABLE_LEAKFINDER_TRUE= + ENABLE_LEAKFINDER_FALSE='#' else - MAKE_LEAKFINDER_TRUE='#' - MAKE_LEAKFINDER_FALSE= + ENABLE_LEAKFINDER_TRUE='#' + ENABLE_LEAKFINDER_FALSE= fi @@ -32817,6 +32822,7 @@ fi AUTH_MODULES="" +require_smblib=0 # Check whether --enable-auth-basic was given. if test "${enable_auth_basic+set}" = set; then : @@ -33351,10 +33357,11 @@ ## Please see the COPYING and CONTRIBUTORS files for details. ## -BUILD_HELPER="SMB_LM" - # DONT build this helper on Windows -for ac_header in w32api/windows.h windows.h +# DONT build this helper by default +if test "x$auto_auth_basic_modules" != "xyes";then + BUILD_HELPER="SMB_LM" + for ac_header in w32api/windows.h windows.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -33367,6 +33374,8 @@ done + require_smblib=`test "x$BUILD_HELPER" = "xSMB_LM"` +fi elif test "x$helper" = "xSSPI" ; then @@ -33920,9 +33929,10 @@ # # DONT build this helper on Windows +# DONT build this helper by default # # XXX: do we really need the mingw check? -if test "$squid_host_os" != "mingw"; then +if test "$squid_host_os" != "mingw" -a "x$auto_auth_ntlm_modules" != "xyes"; then BUILD_HELPER="SMB_LM" for ac_header in w32api/windows.h windows.h do : @@ -33937,6 +33947,7 @@ done + require_smblib=`test "x$BUILD_HELPER" = "xSMB_LM"` fi @@ -34041,6 +34052,14 @@ done + if $require_smblib; then + ENABLE_SMBLIB_TRUE= + ENABLE_SMBLIB_FALSE='#' +else + ENABLE_SMBLIB_TRUE='#' + ENABLE_SMBLIB_FALSE= +fi + # Check whether --enable-log-daemon-helpers was given. if test "${enable_log_daemon_helpers+set}" = set; then : @@ -39783,52 +39802,52 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: Using ${squid_opt_io_loop_engine} for the IO loop." >&5 $as_echo "$as_me: Using ${squid_opt_io_loop_engine} for the IO loop." >&6;} - if test $squid_opt_io_loop_engine = poll; then - USE_POLL_TRUE= - USE_POLL_FALSE='#' + if test "x$squid_opt_io_loop_engine" = "xpoll"; then + ENABLE_POLL_TRUE= + ENABLE_POLL_FALSE='#' else - USE_POLL_TRUE='#' - USE_POLL_FALSE= + ENABLE_POLL_TRUE='#' + ENABLE_POLL_FALSE= fi - if test $squid_opt_io_loop_engine = epoll; then - USE_EPOLL_TRUE= - USE_EPOLL_FALSE='#' + if test "x$squid_opt_io_loop_engine" = "xepoll"; then + ENABLE_EPOLL_TRUE= + ENABLE_EPOLL_FALSE='#' else - USE_EPOLL_TRUE='#' - USE_EPOLL_FALSE= + ENABLE_EPOLL_TRUE='#' + ENABLE_EPOLL_FALSE= fi - if test $squid_opt_io_loop_engine = select; then - USE_SELECT_TRUE= - USE_SELECT_FALSE='#' + if test "x$squid_opt_io_loop_engine" = "xselect"; then + ENABLE_SELECT_TRUE= + ENABLE_SELECT_FALSE='#' else - USE_SELECT_TRUE='#' - USE_SELECT_FALSE= + ENABLE_SELECT_TRUE='#' + ENABLE_SELECT_FALSE= fi - if test $squid_opt_io_loop_engine = select_win32; then - USE_SELECT_WIN32_TRUE= - USE_SELECT_WIN32_FALSE='#' + if test "x$squid_opt_io_loop_engine" = "xselect_win32"; then + ENABLE_SELECT_WIN32_TRUE= + ENABLE_SELECT_WIN32_FALSE='#' else - USE_SELECT_WIN32_TRUE='#' - USE_SELECT_WIN32_FALSE= + ENABLE_SELECT_WIN32_TRUE='#' + ENABLE_SELECT_WIN32_FALSE= fi - if test $squid_opt_io_loop_engine = kqueue; then - USE_KQUEUE_TRUE= - USE_KQUEUE_FALSE='#' + if test "x$squid_opt_io_loop_engine" = "xkqueue"; then + ENABLE_KQUEUE_TRUE= + ENABLE_KQUEUE_FALSE='#' else - USE_KQUEUE_TRUE='#' - USE_KQUEUE_FALSE= + ENABLE_KQUEUE_TRUE='#' + ENABLE_KQUEUE_FALSE= fi - if test $squid_opt_io_loop_engine = devpoll; then - USE_DEVPOLL_TRUE= - USE_DEVPOLL_FALSE='#' + if test "x$squid_opt_io_loop_engine" = "xdevpoll"; then + ENABLE_DEVPOLL_TRUE= + ENABLE_DEVPOLL_FALSE='#' else - USE_DEVPOLL_TRUE='#' - USE_DEVPOLL_FALSE= + ENABLE_DEVPOLL_TRUE='#' + ENABLE_DEVPOLL_FALSE= fi @@ -41951,12 +41970,12 @@ as_fn_error $? "conditional \"ENABLE_DISKIO_MMAPPED\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_FS_UFS_TRUE}" && test -z "${HAVE_FS_UFS_FALSE}"; then - as_fn_error $? "conditional \"HAVE_FS_UFS\" was never defined. +if test -z "${ENABLE_FS_UFS_TRUE}" && test -z "${ENABLE_FS_UFS_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_FS_UFS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_FS_ROCK_TRUE}" && test -z "${HAVE_FS_ROCK_FALSE}"; then - as_fn_error $? "conditional \"HAVE_FS_ROCK\" was never defined. +if test -z "${ENABLE_FS_ROCK_TRUE}" && test -z "${ENABLE_FS_ROCK_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_FS_ROCK\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_PINGER_TRUE}" && test -z "${ENABLE_PINGER_FALSE}"; then @@ -41975,36 +41994,36 @@ as_fn_error $? "conditional \"ENABLE_DELAY_POOLS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_ESI_TRUE}" && test -z "${USE_ESI_FALSE}"; then - as_fn_error $? "conditional \"USE_ESI\" was never defined. +if test -z "${ENABLE_ESI_TRUE}" && test -z "${ENABLE_ESI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_ESI\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_LIBEXPAT_TRUE}" && test -z "${HAVE_LIBEXPAT_FALSE}"; then - as_fn_error $? "conditional \"HAVE_LIBEXPAT\" was never defined. +if test -z "${ENABLE_LIBEXPAT_TRUE}" && test -z "${ENABLE_LIBEXPAT_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_LIBEXPAT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_LIBXML2_TRUE}" && test -z "${HAVE_LIBXML2_FALSE}"; then - as_fn_error $? "conditional \"HAVE_LIBXML2\" was never defined. +if test -z "${ENABLE_LIBXML2_TRUE}" && test -z "${ENABLE_LIBXML2_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_LIBXML2\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_ICAP_CLIENT_TRUE}" && test -z "${USE_ICAP_CLIENT_FALSE}"; then - as_fn_error $? "conditional \"USE_ICAP_CLIENT\" was never defined. +if test -z "${ENABLE_ICAP_CLIENT_TRUE}" && test -z "${ENABLE_ICAP_CLIENT_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_ICAP_CLIENT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_ECAP_TRUE}" && test -z "${USE_ECAP_FALSE}"; then - as_fn_error $? "conditional \"USE_ECAP\" was never defined. +if test -z "${ENABLE_ECAP_TRUE}" && test -z "${ENABLE_ECAP_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_ECAP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_ADAPTATION_TRUE}" && test -z "${USE_ADAPTATION_FALSE}"; then - as_fn_error $? "conditional \"USE_ADAPTATION\" was never defined. +if test -z "${ENABLE_ADAPTATION_TRUE}" && test -z "${ENABLE_ADAPTATION_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_ADAPTATION\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_SNMP_TRUE}" && test -z "${ENABLE_SNMP_FALSE}"; then as_fn_error $? "conditional \"ENABLE_SNMP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_SQUID_EUI_TRUE}" && test -z "${USE_SQUID_EUI_FALSE}"; then - as_fn_error $? "conditional \"USE_SQUID_EUI\" was never defined. +if test -z "${ENABLE_EUI_TRUE}" && test -z "${ENABLE_EUI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_EUI\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_HTCP_TRUE}" && test -z "${ENABLE_HTCP_FALSE}"; then @@ -42015,12 +42034,8 @@ as_fn_error $? "conditional \"ENABLE_SSL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${HAVE_SPNEGO_TRUE}" && test -z "${HAVE_SPNEGO_FALSE}"; then - as_fn_error $? "conditional \"HAVE_SPNEGO\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${MAKE_LEAKFINDER_TRUE}" && test -z "${MAKE_LEAKFINDER_FALSE}"; then - as_fn_error $? "conditional \"MAKE_LEAKFINDER\" was never defined. +if test -z "${ENABLE_LEAKFINDER_TRUE}" && test -z "${ENABLE_LEAKFINDER_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_LEAKFINDER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ENABLE_AUTH_TRUE}" && test -z "${ENABLE_AUTH_FALSE}"; then @@ -42043,6 +42058,10 @@ as_fn_error $? "conditional \"ENABLE_AUTH_NTLM\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${ENABLE_SMBLIB_TRUE}" && test -z "${ENABLE_SMBLIB_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SMBLIB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${ENABLE_UNLINKD_TRUE}" && test -z "${ENABLE_UNLINKD_FALSE}"; then as_fn_error $? "conditional \"ENABLE_UNLINKD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -42052,28 +42071,28 @@ Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_POLL_TRUE}" && test -z "${USE_POLL_FALSE}"; then - as_fn_error $? "conditional \"USE_POLL\" was never defined. +if test -z "${ENABLE_POLL_TRUE}" && test -z "${ENABLE_POLL_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_POLL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_EPOLL_TRUE}" && test -z "${USE_EPOLL_FALSE}"; then - as_fn_error $? "conditional \"USE_EPOLL\" was never defined. +if test -z "${ENABLE_EPOLL_TRUE}" && test -z "${ENABLE_EPOLL_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_EPOLL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_SELECT_TRUE}" && test -z "${USE_SELECT_FALSE}"; then - as_fn_error $? "conditional \"USE_SELECT\" was never defined. +if test -z "${ENABLE_SELECT_TRUE}" && test -z "${ENABLE_SELECT_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SELECT\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_SELECT_WIN32_TRUE}" && test -z "${USE_SELECT_WIN32_FALSE}"; then - as_fn_error $? "conditional \"USE_SELECT_WIN32\" was never defined. +if test -z "${ENABLE_SELECT_WIN32_TRUE}" && test -z "${ENABLE_SELECT_WIN32_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_SELECT_WIN32\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_KQUEUE_TRUE}" && test -z "${USE_KQUEUE_FALSE}"; then - as_fn_error $? "conditional \"USE_KQUEUE\" was never defined. +if test -z "${ENABLE_KQUEUE_TRUE}" && test -z "${ENABLE_KQUEUE_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_KQUEUE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi -if test -z "${USE_DEVPOLL_TRUE}" && test -z "${USE_DEVPOLL_FALSE}"; then - as_fn_error $? "conditional \"USE_DEVPOLL\" was never defined. +if test -z "${ENABLE_DEVPOLL_TRUE}" && test -z "${ENABLE_DEVPOLL_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_DEVPOLL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi @@ -42473,7 +42492,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.10, which was +This file was extended by Squid Web Proxy $as_me 4.0.11, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -42539,7 +42558,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.10 +Squid Web Proxy config.status 4.0.11 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -u -r -N squid-4.0.10/configure.ac squid-4.0.11/configure.ac --- squid-4.0.10/configure.ac 2016-05-06 23:37:23.000000000 +1200 +++ squid-4.0.11/configure.ac 2016-06-10 08:35:21.000000000 +1200 @@ -5,7 +5,7 @@ ## Please see the COPYING and CONTRIBUTORS files for details. ## -AC_INIT([Squid Web Proxy],[4.0.10],[http://bugs.squid-cache.org/],[squid]) +AC_INIT([Squid Web Proxy],[4.0.11],[http://bugs.squid-cache.org/],[squid]) AC_PREREQ(2.61) AC_CONFIG_HEADERS([include/autoconf.h]) AC_CONFIG_AUX_DIR(cfgaux) @@ -92,8 +92,12 @@ AC_USE_SYSTEM_EXTENSIONS fi -# Check for C++11 compiler support -AX_CXX_COMPILE_STDCXX_11([noext],[mandatory]) +# If the user did not specify a C++ version. +user_cxx=`echo "$PRESET_CXXFLAGS" | grep -o -E "\-std="` +if test "x$user_cxx" = "x"; then + # Check for C++11 compiler support + AX_CXX_COMPILE_STDCXX_11([noext],[mandatory]) +fi # test for programs AC_PROG_RANLIB @@ -724,17 +728,16 @@ AC_MSG_NOTICE([IO Modules built: $DISK_MODULES]) AC_SUBST(DISK_MODULES) AC_SUBST(DISK_LIBS) -AM_CONDITIONAL([ENABLE_DISKIO_AIO], [test "x$squid_disk_module_candidates_AIO" = "xyes"]) +AM_CONDITIONAL(ENABLE_DISKIO_AIO, test "x$squid_disk_module_candidates_AIO" = "xyes") AC_SUBST(AIOLIB) -AM_CONDITIONAL([ENABLE_WIN32_AIO], [test "x$squid_disk_module_candidates_AIO" = "xyes" -a "x$ENABLE_WIN32_AIO" = "x1"]) -AM_CONDITIONAL([ENABLE_DISKIO_BLOCKING], [test "x$squid_disk_module_candidates_Blocking" = "xyes"]) -AM_CONDITIONAL([ENABLE_DISKIO_DISKDAEMON], [test "x$squid_disk_module_candidates_DiskDaemon" = "xyes"]) -AM_CONDITIONAL([ENABLE_DISKIO_DISKTHREADS], [test "x$squid_disk_module_candidates_DiskThreads" = "xyes"]) +AM_CONDITIONAL(ENABLE_WIN32_AIO, test "x$squid_disk_module_candidates_AIO" = "xyes" -a "x$ENABLE_WIN32_AIO" = "x1") +AM_CONDITIONAL(ENABLE_DISKIO_BLOCKING, test "x$squid_disk_module_candidates_Blocking" = "xyes") +AM_CONDITIONAL(ENABLE_DISKIO_DISKDAEMON, test "x$squid_disk_module_candidates_DiskDaemon" = "xyes") +AM_CONDITIONAL(ENABLE_DISKIO_DISKTHREADS, test "x$squid_disk_module_candidates_DiskThreads" = "xyes") AC_SUBST(LIBPTHREADS) -AM_CONDITIONAL([ENABLE_WIN32_AIOPS], [test "x$squid_disk_module_candidates_DiskThreads" = "xyes" -a "x$ENABLE_WIN32_AIOPS" = "x1"]) -AM_CONDITIONAL([ENABLE_DISKIO_IPCIO], [test "x$squid_disk_module_candidates_IpcIo" = "xyes"]) -AM_CONDITIONAL([ENABLE_DISKIO_MMAPPED], [test "x$squid_disk_module_candidates_Mmapped" = "xyes"]) - +AM_CONDITIONAL(ENABLE_WIN32_AIOPS, test "x$squid_disk_module_candidates_DiskThreads" = "xyes" -a "x$ENABLE_WIN32_AIOPS" = "x1") +AM_CONDITIONAL(ENABLE_DISKIO_IPCIO, test "x$squid_disk_module_candidates_IpcIo" = "xyes") +AM_CONDITIONAL(ENABLE_DISKIO_MMAPPED, test "x$squid_disk_module_candidates_Mmapped" = "xyes") dnl Check what Storage formats are wanted. dnl This version will error out with a message saying why if a required DiskIO is missing. @@ -803,8 +806,8 @@ esac done -AM_CONDITIONAL(HAVE_FS_UFS,[test "x$squid_do_build_ufs" = "xtrue" ]) -AM_CONDITIONAL(HAVE_FS_ROCK,[test "x$squid_do_build_rock" = "xtrue" ]) +AM_CONDITIONAL(ENABLE_FS_UFS, test "x$squid_do_build_ufs" = "xtrue") +AM_CONDITIONAL(ENABLE_FS_ROCK, test "x$squid_do_build_rock" = "xtrue") dnl hack: need to define those even if not used in the build system to dnl make sure that global FS objects are linked to the squid binary. AH_TEMPLATE(HAVE_FS_UFS, "Define to 1 if ufs filesystem module is build") @@ -951,10 +954,10 @@ fi fi -AM_CONDITIONAL(USE_ESI, test "x$squid_opt_use_esi" = "xyes") -AM_CONDITIONAL(HAVE_LIBEXPAT, test "$HAVE_LIBEXPAT" = 1) +AM_CONDITIONAL(ENABLE_ESI, test "x$squid_opt_use_esi" = "xyes") +AM_CONDITIONAL(ENABLE_LIBEXPAT, test "$HAVE_LIBEXPAT" = 1) AC_SUBST(EXPATLIB) -AM_CONDITIONAL(HAVE_LIBXML2, test "$HAVE_LIBXML2" = 1) +AM_CONDITIONAL(ENABLE_LIBXML2, test "$HAVE_LIBXML2" = 1) AC_SUBST(XMLLIB) # icap argument handling @@ -963,13 +966,12 @@ SQUID_YESNO([$enableval],[Unrecognized argument to --disable-icap-client: $enableval]) ]) SQUID_DEFINE_BOOL(ICAP_CLIENT,${enable_icap_client:=yes}, [Enable ICAP client features in Squid]) -AM_CONDITIONAL(USE_ICAP_CLIENT, [test "x$enable_icap_client" != "xno" ]) +ICAP_LIBS="" if test "x$enable_icap_client" != "xno" ; then ICAP_LIBS="icap/libicap.la" squid_opt_use_adaptation=yes -else - ICAP_LIBS="" fi +AM_CONDITIONAL(ENABLE_ICAP_CLIENT, test "x$enable_icap_client" != "xno") AC_SUBST(ICAP_LIBS) squid_opt_use_ecap=1 @@ -1010,30 +1012,22 @@ fi fi -AM_CONDITIONAL(USE_ECAP, test "x$squid_opt_use_ecap" = "xyes") -if test "x$squid_opt_use_ecap" = "xyes"; -then - AC_DEFINE(USE_ECAP,1,[Enable eCAP support]) +ECAP_LIBS="" +if test "x$squid_opt_use_ecap" = "xyes"; then ECAP_LIBS="ecap/libecapsquid.la" squid_opt_use_adaptation=yes -else - AC_DEFINE(USE_ECAP,0,[Disable eCAP support]) - ECAP_LIBS="" fi -dnl convenience library +SQUID_DEFINE_BOOL(USE_ECAP,${squid_opt_use_ecap:=no},[Whether to use eCAP support]) +AM_CONDITIONAL(ENABLE_ECAP, test "x$squid_opt_use_ecap" = "xyes") AC_SUBST(ECAP_LIBS) - dnl enable adaptation if requested by specific adaptation mechanisms -AM_CONDITIONAL(USE_ADAPTATION, test "x$squid_opt_use_adaptation" = "xyes") -if test "x$squid_opt_use_adaptation" = "xyes" -then - AC_DEFINE(USE_ADAPTATION,1,[common adaptation support]) +ADAPTATION_LIBS="" +if test "x$squid_opt_use_adaptation" = "xyes"; then ADAPTATION_LIBS="adaptation/libadaptation.la" -else - AC_DEFINE(USE_ADAPTATION,0,[common adaptation support]) - ADAPTATION_LIBS="" fi +SQUID_DEFINE_BOOL(USE_ADAPTATION,${squid_opt_use_adaptation:=no}, [common adaptation support]) +AM_CONDITIONAL(ENABLE_ADAPTATION, test "x$squid_opt_use_adaptation" = "xyes") AC_SUBST(ADAPTATION_LIBS) test "x$squid_host_os" = "xmingw" && enable_wccp=no @@ -1150,7 +1144,7 @@ AC_MSG_NOTICE([EUI (MAC address) controls enabled: $enable_eui]) SQUID_DEFINE_BOOL(USE_SQUID_EUI,$enable_eui, [Define this to include code which lets you use ethernet addresses. This code uses API initially defined in 4.4-BSD.]) -AM_CONDITIONAL(USE_SQUID_EUI, [test "x$enable_eui" = "xyes" ]) +AM_CONDITIONAL(ENABLE_EUI, [test "x$enable_eui" = "xyes" ]) AC_ARG_ENABLE(htcp, @@ -1324,10 +1318,10 @@ AC_CHECK_LIB(crypto,[CRYPTO_new_ex_data],[LIBOPENSSL_LIBS="-lcrypto $LIBOPENSSL_LIBS"],[ AC_MSG_ERROR([library 'crypto' is required for OpenSSL]) - ]) + ],$LIBOPENSSL_LIBS) AC_CHECK_LIB(ssl,[SSL_library_init],[LIBOPENSSL_LIBS="-lssl $LIBOPENSSL_LIBS"],[ AC_MSG_ERROR([library 'ssl' is required for OpenSSL]) - ]) + ],$LIBOPENSSL_LIBS) ]) # This is a workaround for RedHat 9 brain damage.. @@ -1839,9 +1833,8 @@ AC_MSG_NOTICE([$KRB5_FLAVOUR Kerberos library support: ${with_krb5:=no} ${LIB_KRB5_PATH} ${LIB_KRB5_LIBS}]) AC_SUBST(KRB5INCS) AC_SUBST(KRB5LIBS) -AM_CONDITIONAL(HAVE_SPNEGO, test x"$squid_cv_have_spnego" = x"yes" ) -dnl On MinGW OpenLDAP is not available, so LDAP helpers can be linked +dnl On MinGW OpenLDAP is not available, so LDAP helpers can be linked dnl only with Windows LDAP libraries using -lwldap32 case "$squid_host_os" in mingw) @@ -2425,7 +2418,7 @@ AC_MSG_NOTICE([Leak Finder enabled: ${enable_leakfinder:=no}]) SQUID_DEFINE_BOOL(USE_LEAKFINDER,$enable_leakfinder, [Enable code for assisting in finding memory leaks. Not for the faint of heart]) -AM_CONDITIONAL(MAKE_LEAKFINDER, [test "x$enable_leakfinder" = "xyes"]) +AM_CONDITIONAL(ENABLE_LEAKFINDER, [test "x$enable_leakfinder" = "xyes"]) AC_ARG_ENABLE(follow-x-forwarded-for, @@ -2479,6 +2472,7 @@ SQUID_DEFINE_BOOL(USE_AUTH,$enable_auth,[Enable support for authentication]) AM_CONDITIONAL(ENABLE_AUTH, test "x$enable_auth" != "xno") AUTH_MODULES="" +require_smblib=0 AC_ARG_ENABLE(auth-basic, AS_HELP_STRING([--enable-auth-basic="list of helpers"], @@ -2538,6 +2532,7 @@ done AC_SUBST(AUTH_MODULES) AC_SUBST(AUTH_LIBS_TO_BUILD) +AM_CONDITIONAL(ENABLE_SMBLIB, $require_smblib) dnl Select logging daemon helpers to build AC_ARG_ENABLE(log-daemon-helpers, @@ -3438,12 +3433,12 @@ AC_MSG_NOTICE([Using ${squid_opt_io_loop_engine} for the IO loop.]) -AM_CONDITIONAL([USE_POLL], [test $squid_opt_io_loop_engine = poll]) -AM_CONDITIONAL([USE_EPOLL], [test $squid_opt_io_loop_engine = epoll]) -AM_CONDITIONAL([USE_SELECT], [test $squid_opt_io_loop_engine = select]) -AM_CONDITIONAL([USE_SELECT_WIN32], [test $squid_opt_io_loop_engine = select_win32]) -AM_CONDITIONAL([USE_KQUEUE], [test $squid_opt_io_loop_engine = kqueue]) -AM_CONDITIONAL([USE_DEVPOLL], [test $squid_opt_io_loop_engine = devpoll]) +AM_CONDITIONAL(ENABLE_POLL, test "x$squid_opt_io_loop_engine" = "xpoll") +AM_CONDITIONAL(ENABLE_EPOLL, test "x$squid_opt_io_loop_engine" = "xepoll") +AM_CONDITIONAL(ENABLE_SELECT, test "x$squid_opt_io_loop_engine" = "xselect") +AM_CONDITIONAL(ENABLE_SELECT_WIN32, test "x$squid_opt_io_loop_engine" = "xselect_win32") +AM_CONDITIONAL(ENABLE_KQUEUE, test "x$squid_opt_io_loop_engine" = "xkqueue") +AM_CONDITIONAL(ENABLE_DEVPOLL, test "x$squid_opt_io_loop_engine" = "xdevpoll") case $squid_opt_io_loop_engine in epoll) AC_DEFINE(USE_EPOLL,1,[Use epoll() for the IO loop]) ;; diff -u -r -N squid-4.0.10/doc/release-notes/release-4.html squid-4.0.11/doc/release-notes/release-4.html --- squid-4.0.10/doc/release-notes/release-4.html 2016-05-07 00:29:29.000000000 +1200 +++ squid-4.0.11/doc/release-notes/release-4.html 2016-06-10 09:27:51.000000000 +1200 @@ -1,11 +1,11 @@ - - Squid 4.0.10 release notes + + Squid 4.0.11 release notes -

Squid 4.0.10 release notes

+

Squid 4.0.11 release notes

Squid Developers


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

1. Notice

-

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

+

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

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

@@ -425,6 +425,9 @@

Superceded by cache_peer_access. Use dstdomain ACL in the access control list to restrict domains requested.

+
ie_refresh
+

Removed. MSIE 3.x, 4.x, 5.0 and 5.01 are no longer popular browsers.

+
sslproxy_cafile

Replaced by tls_outgoing_options cafile=. Which now takes multiple entries.

@@ -482,8 +485,8 @@
--enable-security-cert-generators

New option to control which TLS/SSL dynamic certificate generator helpers are built and installed.

-

Helper ssl_crtd has been renamed to security_file_certgen -and built with module name file. Requires --with-openssl.

+

Helper ssl_crtd has been renamed to security_file_certgen +and built with module name file. Requires --with-openssl.

--enable-security-cert-validators

New option to control which TLS/SSL certificate validation @@ -502,10 +505,14 @@

--enable-auth-basic

The MSNT-multi-domain helper has been removed.

+

The SMB LanMan helper SMB_LM is no longer built by default. +It needs to be explicitly listed to be built.

--enable-auth-ntlm

The SMB LanMan helper is now built using SMB_LM (was lower case smb_lm).

+

The SMB LanMan helper SMB_LM is no longer built by default. +It needs to be explicitly listed to be built.

--enable-diskio

Auto-detection of SMP related modules has been fixed to diff -u -r -N squid-4.0.10/include/autoconf.h.in squid-4.0.11/include/autoconf.h.in --- squid-4.0.10/include/autoconf.h.in 2016-05-06 23:35:46.000000000 +1200 +++ squid-4.0.11/include/autoconf.h.in 2016-06-10 08:33:50.000000000 +1200 @@ -1367,7 +1367,7 @@ /* DiskIO modules are expected to be available. */ #undef USE_DISKIO -/* Disable eCAP support */ +/* Whether to use eCAP support */ #undef USE_ECAP /* Use epoll() for the IO loop */ diff -u -r -N squid-4.0.10/include/SquidNew.h squid-4.0.11/include/SquidNew.h --- squid-4.0.10/include/SquidNew.h 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/include/SquidNew.h 1970-01-01 12:00:00.000000000 +1200 @@ -1,41 +0,0 @@ -/* - * Copyright (C) 1996-2016 The Squid Software Foundation and contributors - * - * Squid software is distributed under GPLv2+ license and includes - * contributions from numerous individuals and organizations. - * Please see the COPYING and CONTRIBUTORS files for details. - */ - -#ifndef SQUID_NEW_H -#define SQUID_NEW_H - -#if !defined(__SUNPRO_CC) && !defined(__clang__) -/* Any code using libstdc++ must have externally resolvable overloads - * for void * operator new - which means in the .o for the binary, - * or in a shared library. static libs don't propogate the symbol - * so, look in the translation unit containing main() in squid - * for the extern version in squid - */ -#include - -_SQUID_EXTERNNEW_ void *operator new(size_t size) throw (std::bad_alloc) -{ - return xmalloc(size); -} -_SQUID_EXTERNNEW_ void operator delete (void *address) throw() -{ - xfree(address); -} -_SQUID_EXTERNNEW_ void *operator new[] (size_t size) throw (std::bad_alloc) -{ - return xmalloc(size); -} -_SQUID_EXTERNNEW_ void operator delete[] (void *address) throw() -{ - xfree(address); -} - -#endif /* !__SUNPRO_CC && !__clang__*/ - -#endif /* SQUID_NEW_H */ - diff -u -r -N squid-4.0.10/include/util.h squid-4.0.11/include/util.h --- squid-4.0.10/include/util.h 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/include/util.h 2016-06-10 08:32:57.000000000 +1200 @@ -19,23 +19,6 @@ SQUIDCEXTERN int tvSubUsec(struct timeval, struct timeval); SQUIDCEXTERN double tvSubDsec(struct timeval, struct timeval); SQUIDCEXTERN void Tolower(char *); -#if defined(__cplusplus) -/* - * Any code using libstdc++ must have externally resolvable overloads - * for void * operator new - which means in the .o for the binary, - * or in a shared library. static libs don't propogate the symbol - * so, look in the translation unit containing main() in squid - * for the extern version in squid - */ -#if !defined(_SQUID_EXTERNNEW_) -#if defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__) -#define _SQUID_EXTERNNEW_ extern inline __attribute__((gnu_inline)) -#else -#define _SQUID_EXTERNNEW_ extern inline -#endif -#endif -#include "SquidNew.h" -#endif SQUIDCEXTERN time_t parse_iso3307_time(const char *buf); diff -u -r -N squid-4.0.10/include/version.h squid-4.0.11/include/version.h --- squid-4.0.10/include/version.h 2016-05-06 23:37:24.000000000 +1200 +++ squid-4.0.11/include/version.h 2016-06-10 08:35:21.000000000 +1200 @@ -7,7 +7,7 @@ */ #ifndef SQUID_RELEASE_TIME -#define SQUID_RELEASE_TIME 1462534506 +#define SQUID_RELEASE_TIME 1465504370 #endif /* diff -u -r -N squid-4.0.10/lib/Makefile.am squid-4.0.11/lib/Makefile.am --- squid-4.0.10/lib/Makefile.am 2016-05-06 23:35:13.000000000 +1200 +++ squid-4.0.11/lib/Makefile.am 2016-06-10 08:32:57.000000000 +1200 @@ -11,7 +11,7 @@ SUBDIRS= EXTRA_DIST= -if USE_ESI +if ENABLE_ESI SUBDIRS += libTrie endif if ENABLE_SNMP @@ -37,9 +37,12 @@ noinst_LTLIBRARIES += libsspwin32.la libsspwin32_la_SOURCES = sspwin32.cc else -SUBDIRS += rfcnb smblib EXTRA_DIST += sspwin32.cc endif +if ENABLE_SMBLIB +# smblib is the only user of the rfcnb library +SUBDIRS += rfcnb smblib +endif if ENABLE_AUTH_NTLM SUBDIRS += ntlmauth endif diff -u -r -N squid-4.0.10/lib/Makefile.in squid-4.0.11/lib/Makefile.in --- squid-4.0.10/lib/Makefile.in 2016-05-06 23:36:23.000000000 +1200 +++ squid-4.0.11/lib/Makefile.in 2016-06-10 08:34:22.000000000 +1200 @@ -91,7 +91,7 @@ check_PROGRAMS = tests/testRFC1738$(EXEEXT) TESTS = tests/testRFC1738$(EXEEXT) testHeaders @ENABLE_LOADABLE_MODULES_TRUE@am__append_1 = $(INCLTDL) -@USE_ESI_TRUE@am__append_2 = libTrie +@ENABLE_ESI_TRUE@am__append_2 = libTrie @ENABLE_SNMP_TRUE@am__append_3 = snmplib @ENABLE_XPROF_STATS_TRUE@am__append_4 = profiler @@ -100,8 +100,9 @@ # and others are unable to be built. # @ENABLE_WIN32SPECIFIC_TRUE@am__append_5 = libsspwin32.la -@ENABLE_WIN32SPECIFIC_FALSE@am__append_6 = rfcnb smblib -@ENABLE_WIN32SPECIFIC_FALSE@am__append_7 = sspwin32.cc +@ENABLE_WIN32SPECIFIC_FALSE@am__append_6 = sspwin32.cc +# smblib is the only user of the rfcnb library +@ENABLE_SMBLIB_TRUE@am__append_7 = rfcnb smblib @ENABLE_AUTH_NTLM_TRUE@am__append_8 = ntlmauth subdir = lib ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -804,8 +805,8 @@ subst_perlshell = sed -e 's,[@]PERL[@],$(PERL),g' <$(srcdir)/$@.pl.in >$@ || ($(RM) -f $@ ; exit 1) DIST_SUBDIRS = ntlmauth profiler rfcnb smblib libTrie snmplib SUBDIRS = $(am__append_2) $(am__append_3) $(am__append_4) \ - $(am__append_6) $(am__append_8) -EXTRA_DIST = $(am__append_7) + $(am__append_7) $(am__append_8) +EXTRA_DIST = $(am__append_6) noinst_LTLIBRARIES = libmiscencoding.la libmisccontainers.la \ libmiscutil.la $(am__append_5) @ENABLE_WIN32SPECIFIC_TRUE@libsspwin32_la_SOURCES = sspwin32.cc diff -u -r -N squid-4.0.10/RELEASENOTES.html squid-4.0.11/RELEASENOTES.html --- squid-4.0.10/RELEASENOTES.html 2016-05-07 00:29:29.000000000 +1200 +++ squid-4.0.11/RELEASENOTES.html 2016-06-10 09:27:51.000000000 +1200 @@ -1,11 +1,11 @@ - - Squid 4.0.10 release notes + + Squid 4.0.11 release notes -

Squid 4.0.10 release notes

+

Squid 4.0.11 release notes

Squid Developers


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

1. Notice

-

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

+

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

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

@@ -425,6 +425,9 @@

Superceded by cache_peer_access. Use dstdomain ACL in the access control list to restrict domains requested.

+
ie_refresh
+

Removed. MSIE 3.x, 4.x, 5.0 and 5.01 are no longer popular browsers.

+
sslproxy_cafile

Replaced by tls_outgoing_options cafile=. Which now takes multiple entries.

@@ -482,8 +485,8 @@
--enable-security-cert-generators

New option to control which TLS/SSL dynamic certificate generator helpers are built and installed.

-

Helper ssl_crtd has been renamed to security_file_certgen -and built with module name file. Requires --with-openssl.

+

Helper ssl_crtd has been renamed to security_file_certgen +and built with module name file. Requires --with-openssl.

--enable-security-cert-validators

New option to control which TLS/SSL certificate validation @@ -502,10 +505,14 @@

--enable-auth-basic

The MSNT-multi-domain helper has been removed.

+

The SMB LanMan helper SMB_LM is no longer built by default. +It needs to be explicitly listed to be built.

--enable-auth-ntlm

The SMB LanMan helper is now built using SMB_LM (was lower case smb_lm).

+

The SMB LanMan helper SMB_LM is no longer built by default. +It needs to be explicitly listed to be built.

--enable-diskio

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