diff -u -r -N squid-4.11/acinclude/os-deps.m4 squid-4.12/acinclude/os-deps.m4 --- squid-4.11/acinclude/os-deps.m4 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/acinclude/os-deps.m4 2020-06-08 03:42:16.000000000 +1200 @@ -925,11 +925,13 @@ ## Solaris 10+ backported IPv6 NAT to their IPFilter v4.1 instead of using v5 AC_CHECK_MEMBERS([ struct natlookup.nl_inipaddr.in6, - struct natlookup.nl_realipaddr.in6 - ],,,[ + struct natlookup.nl_realipaddr.in6],,,[ #if USE_SOLARIS_IPFILTER_MINOR_T_HACK #define minor_t fubar #endif +#if HAVE_SYS_PARAM_H +#include +#endif #if HAVE_SYS_TYPES_H #include #endif @@ -955,7 +957,11 @@ #elif HAVE_NETINET_IP_FIL_H #include #endif +#if HAVE_IP_NAT_H #include +#elif HAVE_NETINET_IP_NAT_H +#include +#endif ]) ]) diff -u -r -N squid-4.11/ChangeLog squid-4.12/ChangeLog --- squid-4.11/ChangeLog 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/ChangeLog 2020-06-08 03:42:16.000000000 +1200 @@ -1,3 +1,17 @@ +Changes to squid-4.12 (05 Jun 2020): + + - Regression Fix: Revert to slow search for new SMP shm pages + - Bug 5045: ext_edirectory_userip_acl is missing include files + - Bug 5041: Missing Debug::Extra breaks build on hosts with systemd + - Bug 5030: Negative responses are never cached + - HTTP: validate Content-Length value prefix + - HTTP: add flexible RFC 3986 URI encoder + - SslBump: disable OpenSSL TLSv1.3 support for older TLS traffic + - Tests: Support passing a custom config.cache to test builds + - Fix IPFilter IPv6 detection, especially on NetBSD + - Fix stall if transaction overwrites a recently active cache entry + - ... and some compile fixes + Changes to squid-4.11 (18 Apr 2020): - Bug 5036: capital 'L's in logs when daemon queue overflows diff -u -r -N squid-4.11/configure squid-4.12/configure --- squid-4.11/configure 2020-04-20 00:39:06.000000000 +1200 +++ squid-4.12/configure 2020-06-09 19:15:48.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.11. +# Generated by GNU Autoconf 2.69 for Squid Web Proxy 4.12. # # Report bugs to . # @@ -595,8 +595,8 @@ # Identity of this package. PACKAGE_NAME='Squid Web Proxy' PACKAGE_TARNAME='squid' -PACKAGE_VERSION='4.11' -PACKAGE_STRING='Squid Web Proxy 4.11' +PACKAGE_VERSION='4.12' +PACKAGE_STRING='Squid Web Proxy 4.12' PACKAGE_BUGREPORT='http://bugs.squid-cache.org/' PACKAGE_URL='' @@ -1656,7 +1656,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.11 to adapt to many kinds of systems. +\`configure' configures Squid Web Proxy 4.12 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1727,7 +1727,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of Squid Web Proxy 4.11:";; + short | recursive ) echo "Configuration of Squid Web Proxy 4.12:";; esac cat <<\_ACEOF @@ -2166,7 +2166,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -Squid Web Proxy configure 4.11 +Squid Web Proxy configure 4.12 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -3270,7 +3270,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.11, which was +It was created by Squid Web Proxy $as_me 4.12, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4137,7 +4137,7 @@ # Define the identity of the package. PACKAGE='squid' - VERSION='4.11' + VERSION='4.12' cat >>confdefs.h <<_ACEOF @@ -21120,8 +21120,9 @@ $as_echo "$as_me: With dl" >&6;} fi + + ## check for atomics library before anything that might need it -# AC_SEARCH_LIBS pollutes LIBS # save state, key is LIBATOMIC LIBATOMIC_CFLAGS="${CFLAGS}" @@ -21138,63 +21139,76 @@ eval "${squid_util_var_tosave2}=\"${squid_util_var_tosave}\"" done -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing __atomic_load_8" >&5 -$as_echo_n "checking for library containing __atomic_load_8... " >&6; } -if ${ac_cv_search___atomic_load_8+:} false; then : - $as_echo_n "(cached) " >&6 -else - ac_func_search_save_LIBS=$LIBS -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether linking without -latomic works" >&5 +$as_echo_n "checking whether linking without -latomic works... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char __atomic_load_8 (); -int -main () -{ -return __atomic_load_8 (); - ; - return 0; -} + +#include +#include + int + main(int, char **) { + return std::atomic{}.is_lock_free() ? 0 : 1; + } + _ACEOF -for ac_lib in '' atomic; do - if test -z "$ac_lib"; then - ac_res="none required" - else - ac_res=-l$ac_lib - LIBS="-l$ac_lib $ac_func_search_save_LIBS" - fi - if ac_fn_cxx_try_link "$LINENO"; then : - ac_cv_search___atomic_load_8=$ac_res +if ac_fn_cxx_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + libatomic_checker_result="yes" +else + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + libatomic_checker_result="no" + fi rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext - if ${ac_cv_search___atomic_load_8+:} false; then : - break -fi -done -if ${ac_cv_search___atomic_load_8+:} false; then : + conftest$ac_exeext conftest.$ac_ext +if test "x$libatomic_checker_result" = "xno"; then : + + LIBS="$LIBS -latomic" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether linking with -latomic works" >&5 +$as_echo_n "checking whether linking with -latomic works... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +#include + int + main(int, char **) { + return std::atomic{}.is_lock_free() ? 0 : 1; + } +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + libatomic_checker_result="yes" else - ac_cv_search___atomic_load_8=no -fi -rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search___atomic_load_8" >&5 -$as_echo "$ac_cv_search___atomic_load_8" >&6; } -ac_res=$ac_cv_search___atomic_load_8 -if test "$ac_res" != no; then : - test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" - test "$ac_res" = "none required" || ATOMICLIB=$ac_res + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + libatomic_checker_result="no" + fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test "x$libatomic_checker_result" = "xyes"; then : + + ATOMICLIB="-latomic" +else + + as_fn_error $? "Required library libatomic not found." "$LINENO" 5 +fi +fi # rollback state, key is LIBATOMIC CFLAGS="${LIBATOMIC_CFLAGS}" @@ -33915,6 +33929,7 @@ fi if test "x$SYSTEMD_LIBS" != "x" ; then CXXFLAGS="$SYSTEMD_CFLAGS $CXXFLAGS" + LDFLAGS="$SYSTEMD_LIBS $LDFLAGS" $as_echo "#define USE_SYSTEMD 1" >>confdefs.h @@ -42343,6 +42358,9 @@ #if USE_SOLARIS_IPFILTER_MINOR_T_HACK #define minor_t fubar #endif +#if HAVE_SYS_PARAM_H +#include +#endif #if HAVE_SYS_TYPES_H #include #endif @@ -42368,7 +42386,11 @@ #elif HAVE_NETINET_IP_FIL_H #include #endif +#if HAVE_IP_NAT_H #include +#elif HAVE_NETINET_IP_NAT_H +#include +#endif " if test "x$ac_cv_member_struct_natlookup_nl_inipaddr_in6" = xyes; then : @@ -42379,11 +42401,13 @@ fi -ac_fn_cxx_check_member "$LINENO" "struct natlookup" "nl_realipaddr.in6" - "ac_cv_member_struct_natlookup_nl_realipaddr_in6___" " +ac_fn_cxx_check_member "$LINENO" "struct natlookup" "nl_realipaddr.in6" "ac_cv_member_struct_natlookup_nl_realipaddr_in6" " #if USE_SOLARIS_IPFILTER_MINOR_T_HACK #define minor_t fubar #endif +#if HAVE_SYS_PARAM_H +#include +#endif #if HAVE_SYS_TYPES_H #include #endif @@ -42409,13 +42433,17 @@ #elif HAVE_NETINET_IP_FIL_H #include #endif +#if HAVE_IP_NAT_H #include +#elif HAVE_NETINET_IP_NAT_H +#include +#endif " -if test "x$ac_cv_member_struct_natlookup_nl_realipaddr_in6___" = xyes; then : +if test "x$ac_cv_member_struct_natlookup_nl_realipaddr_in6" = xyes; then : cat >>confdefs.h <<_ACEOF -#define HAVE_STRUCT_NATLOOKUP_NL_REALIPADDR_IN6___ 1 +#define HAVE_STRUCT_NATLOOKUP_NL_REALIPADDR_IN6 1 _ACEOF @@ -44582,7 +44610,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.11, which was +This file was extended by Squid Web Proxy $as_me 4.12, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -44648,7 +44676,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.11 +Squid Web Proxy config.status 4.12 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -u -r -N squid-4.11/configure.ac squid-4.12/configure.ac --- squid-4.11/configure.ac 2020-04-20 00:39:06.000000000 +1200 +++ squid-4.12/configure.ac 2020-06-09 19:15:47.000000000 +1200 @@ -5,7 +5,7 @@ ## Please see the COPYING and CONTRIBUTORS files for details. ## -AC_INIT([Squid Web Proxy],[4.11],[http://bugs.squid-cache.org/],[squid]) +AC_INIT([Squid Web Proxy],[4.12],[http://bugs.squid-cache.org/],[squid]) AC_PREREQ(2.61) AC_CONFIG_HEADERS([include/autoconf.h]) AC_CONFIG_AUX_DIR(cfgaux) @@ -462,11 +462,33 @@ AC_MSG_NOTICE([With dl]) fi +AC_DEFUN([LIBATOMIC_CHECKER],[ + AC_MSG_CHECKING(whether linking $1 -latomic works) + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ +#include +#include + int + main(int, char **) { + return std::atomic{}.is_lock_free() ? 0 : 1; + } + ]])],[ + AC_MSG_RESULT(yes) + libatomic_checker_result="yes"],[ + AC_MSG_RESULT(no) + libatomic_checker_result="no" +])]) + ## check for atomics library before anything that might need it -# AC_SEARCH_LIBS pollutes LIBS SQUID_STATE_SAVE(LIBATOMIC) -AC_SEARCH_LIBS([__atomic_load_8],[atomic],[ - test "$ac_res" = "none required" || ATOMICLIB=$ac_res],[]) +LIBATOMIC_CHECKER(without) +AS_IF([test "x$libatomic_checker_result" = "xno"],[ + LIBS="$LIBS -latomic" + LIBATOMIC_CHECKER(with) + AS_IF([test "x$libatomic_checker_result" = "xyes"],[ + ATOMICLIB="-latomic"],[ + AC_MSG_ERROR([Required library libatomic not found.]) +])]) SQUID_STATE_ROLLBACK(LIBATOMIC) AC_SUBST(ATOMICLIB) @@ -2162,6 +2184,7 @@ fi if test "x$SYSTEMD_LIBS" != "x" ; then CXXFLAGS="$SYSTEMD_CFLAGS $CXXFLAGS" + LDFLAGS="$SYSTEMD_LIBS $LDFLAGS" AC_DEFINE(USE_SYSTEMD,1,[systemd support is available]) else with_systemd=no diff -u -r -N squid-4.11/CONTRIBUTORS squid-4.12/CONTRIBUTORS --- squid-4.11/CONTRIBUTORS 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/CONTRIBUTORS 2020-06-08 03:42:16.000000000 +1200 @@ -25,6 +25,7 @@ Alex Wu Alin Nastac Alter + Amit Klein Amos Jeffries Amos Jeffries Amos Jeffries diff -u -r -N squid-4.11/doc/release-notes/release-4.html squid-4.12/doc/release-notes/release-4.html --- squid-4.11/doc/release-notes/release-4.html 2020-04-20 00:50:33.000000000 +1200 +++ squid-4.12/doc/release-notes/release-4.html 2020-06-09 19:27:13.000000000 +1200 @@ -1,12 +1,12 @@ - + - Squid 4.11 release notes + Squid 4.12 release notes -

Squid 4.11 release notes

+

Squid 4.12 release notes

Squid Developers


@@ -64,7 +64,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.11.

+

The Squid Team are pleased to announce the release of Squid-4.12.

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

diff -u -r -N squid-4.11/include/autoconf.h.in squid-4.12/include/autoconf.h.in --- squid-4.11/include/autoconf.h.in 2020-04-20 00:39:00.000000000 +1200 +++ squid-4.12/include/autoconf.h.in 2020-06-09 19:15:40.000000000 +1200 @@ -1044,8 +1044,8 @@ /* Define to 1 if `nl_inipaddr.in6' is a member of `struct natlookup'. */ #undef HAVE_STRUCT_NATLOOKUP_NL_INIPADDR_IN6 -/* Define to 1 if `nl_realipaddr.in6' is a member of `struct natlookup '. */ -#undef HAVE_STRUCT_NATLOOKUP_NL_REALIPADDR_IN6___ +/* Define to 1 if `nl_realipaddr.in6' is a member of `struct natlookup'. */ +#undef HAVE_STRUCT_NATLOOKUP_NL_REALIPADDR_IN6 /* The system provides struct rusage */ #undef HAVE_STRUCT_RUSAGE diff -u -r -N squid-4.11/include/version.h squid-4.12/include/version.h --- squid-4.11/include/version.h 2020-04-20 00:39:06.000000000 +1200 +++ squid-4.12/include/version.h 2020-06-09 19:15:48.000000000 +1200 @@ -7,7 +7,7 @@ */ #ifndef SQUID_RELEASE_TIME -#define SQUID_RELEASE_TIME 1587299937 +#define SQUID_RELEASE_TIME 1591686937 #endif /* diff -u -r -N squid-4.11/RELEASENOTES.html squid-4.12/RELEASENOTES.html --- squid-4.11/RELEASENOTES.html 2020-04-20 00:50:33.000000000 +1200 +++ squid-4.12/RELEASENOTES.html 2020-06-09 19:27:13.000000000 +1200 @@ -1,12 +1,12 @@ - + - Squid 4.11 release notes + Squid 4.12 release notes -

Squid 4.11 release notes

+

Squid 4.12 release notes

Squid Developers


@@ -64,7 +64,7 @@

1. Notice

-

The Squid Team are pleased to announce the release of Squid-4.11.

+

The Squid Team are pleased to announce the release of Squid-4.12.

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

diff -u -r -N squid-4.11/src/acl/external/delayer/ext_delayer_acl.8 squid-4.12/src/acl/external/delayer/ext_delayer_acl.8 --- squid-4.11/src/acl/external/delayer/ext_delayer_acl.8 2020-04-20 00:50:35.000000000 +1200 +++ squid-4.12/src/acl/external/delayer/ext_delayer_acl.8 2020-06-09 19:27:16.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_DELAYER_ACL 8" -.TH EXT_DELAYER_ACL 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH EXT_DELAYER_ACL 8 "2020-06-09" "perl v5.30.3" "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.11/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc squid-4.12/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc --- squid-4.11/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/acl/external/eDirectory_userip/ext_edirectory_userip_acl.cc 2020-06-08 03:42:16.000000000 +1200 @@ -69,6 +69,12 @@ #ifdef HAVE_NETDB_H #include #endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif #ifdef HELPER_INPUT_BUFFER #define EDUI_MAXLEN HELPER_INPUT_BUFFER diff -u -r -N squid-4.11/src/acl/external/kerberos_ldap_group/support_krb5.cc squid-4.12/src/acl/external/kerberos_ldap_group/support_krb5.cc --- squid-4.11/src/acl/external/kerberos_ldap_group/support_krb5.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/acl/external/kerberos_ldap_group/support_krb5.cc 2020-06-08 03:42:16.000000000 +1200 @@ -467,10 +467,15 @@ } // overwrite limitation of enctypes +#if USE_HEIMDAL_KRB5 + creds->session.keytype = 0; + if (creds->session.keyvalue.length > 0) + krb5_free_keyblock_contents(kparam.context, &creds->session); +#else creds->keyblock.enctype = 0; if (creds->keyblock.contents) krb5_free_keyblock_contents(kparam.context, &creds->keyblock); - +#endif code = krb5_get_credentials(kparam.context, 0, kparam.cc[ccindex], creds, &tgt_creds); if (code) { k5_error("Error while getting tgt", code); diff -u -r -N squid-4.11/src/acl/external/SQL_session/ext_sql_session_acl.8 squid-4.12/src/acl/external/SQL_session/ext_sql_session_acl.8 --- squid-4.11/src/acl/external/SQL_session/ext_sql_session_acl.8 2020-04-20 00:50:35.000000000 +1200 +++ squid-4.12/src/acl/external/SQL_session/ext_sql_session_acl.8 2020-06-09 19:27:16.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_SQL_SESSION_ACL 8" -.TH EXT_SQL_SESSION_ACL 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH EXT_SQL_SESSION_ACL 8 "2020-06-09" "perl v5.30.3" "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.11/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 squid-4.12/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 --- squid-4.11/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2020-04-20 00:50:36.000000000 +1200 +++ squid-4.12/src/acl/external/wbinfo_group/ext_wbinfo_group_acl.8 2020-06-09 19:27:16.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "EXT_WBINFO_GROUP_ACL 8" -.TH EXT_WBINFO_GROUP_ACL 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH EXT_WBINFO_GROUP_ACL 8 "2020-06-09" "perl v5.30.3" "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.11/src/anyp/ProtocolVersion.h squid-4.12/src/anyp/ProtocolVersion.h --- squid-4.11/src/anyp/ProtocolVersion.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/anyp/ProtocolVersion.h 2020-06-08 03:42:16.000000000 +1200 @@ -40,6 +40,9 @@ unsigned int major; ///< major version number unsigned int minor; ///< minor version number + /// whether the version is "known" (e.g., has been parsed or explicitly set) + explicit operator bool() const { return protocol != PROTO_NONE; } + bool operator==(const ProtocolVersion& that) const { if (this->protocol != that.protocol) return false; diff -u -r -N squid-4.11/src/anyp/Uri.cc squid-4.12/src/anyp/Uri.cc --- squid-4.11/src/anyp/Uri.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/anyp/Uri.cc 2020-06-08 03:42:16.000000000 +1200 @@ -30,6 +30,56 @@ "[:]" ; +/// Characters which are valid within a URI userinfo section +static const CharacterSet & +UserInfoChars() +{ + /* + * RFC 3986 section 3.2.1 + * + * userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * pct-encoded = "%" HEXDIG HEXDIG + * sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" + */ + static const auto userInfoValid = CharacterSet("userinfo", ":-._~%!$&'()*+,;=") + + CharacterSet::ALPHA + + CharacterSet::DIGIT; + return userInfoValid; +} + +/** + * Governed by RFC 3986 section 2.1 + */ +SBuf +AnyP::Uri::Encode(const SBuf &buf, const CharacterSet &ignore) +{ + if (buf.isEmpty()) + return buf; + + Parser::Tokenizer tk(buf); + SBuf goodSection; + // optimization for the arguably common "no encoding necessary" case + if (tk.prefix(goodSection, ignore) && tk.atEnd()) + return buf; + + SBuf output; + output.reserveSpace(buf.length() * 3); // worst case: encode all chars + output.append(goodSection); // may be empty + + while (!tk.atEnd()) { + // TODO: Add Tokenizer::parseOne(void). + const auto ch = tk.remaining()[0]; + output.appendf("%%%02X", static_cast(ch)); // TODO: Optimize using a table + (void)tk.skip(ch); + + if (tk.prefix(goodSection, ignore)) + output.append(goodSection); + } + + return output; +} + const SBuf & AnyP::Uri::Asterisk() { @@ -557,7 +607,10 @@ getScheme() == AnyP::PROTO_UNKNOWN; if (allowUserInfo && !userInfo().isEmpty()) { - absolute_.append(userInfo()); + static const CharacterSet uiChars = CharacterSet(UserInfoChars()) + .remove('%') + .rename("userinfo-reserved"); + absolute_.append(Encode(userInfo(), uiChars)); absolute_.append("@", 1); } absolute_.append(authority()); @@ -565,7 +618,7 @@ absolute_.append(host()); absolute_.append(":", 1); } - absolute_.append(path()); + absolute_.append(path()); // TODO: Encode each URI subcomponent in path_ as needed. } return absolute_; @@ -619,102 +672,76 @@ return request->canonicalCleanUrl(); } -/* - * Test if a URL is relative. +/** + * Test if a URL is a relative reference. + * + * Governed by RFC 3986 section 4.2 + * + * relative-ref = relative-part [ "?" query ] [ "#" fragment ] * - * RFC 2396, Section 5 (Page 17) implies that in a relative URL, a '/' will - * appear before a ':'. + * relative-part = "//" authority path-abempty + * / path-absolute + * / path-noscheme + * / path-empty */ bool urlIsRelative(const char *url) { - const char *p; + if (!url) + return false; // no URL - if (url == NULL) { - return (false); - } - if (*url == '\0') { - return (false); - } + /* + * RFC 3986 section 5.2.3 + * + * path = path-abempty ; begins with "/" or is empty + * / path-absolute ; begins with "/" but not "//" + * / path-noscheme ; begins with a non-colon segment + * / path-rootless ; begins with a segment + * / path-empty ; zero characters + */ - for (p = url; *p != '\0' && *p != ':' && *p != '/'; ++p); + if (*url == '\0') + return true; // path-empty - if (*p == ':') { - return (false); + if (*url == '/') { + // RFC 3986 section 5.2.3 + // path-absolute ; begins with "/" but not "//" + if (url[1] == '/') + return true; // network-path reference, aka. 'scheme-relative URI' + else + return true; // path-absolute, aka 'absolute-path reference' } - return (true); -} - -/* - * Convert a relative URL to an absolute URL using the context of a given - * request. - * - * It is assumed that you have already ensured that the URL is relative. - * - * If NULL is returned it is an indication that the method in use in the - * request does not distinguish between relative and absolute and you should - * use the url unchanged. - * - * If non-NULL is returned, it is up to the caller to free the resulting - * memory using safe_free(). - */ -char * -urlMakeAbsolute(const HttpRequest * req, const char *relUrl) -{ - if (req->method.id() == Http::METHOD_CONNECT) { - return (NULL); + for (const auto *p = url; *p != '\0' && *p != '/' && *p != '?' && *p != '#'; ++p) { + if (*p == ':') + return false; // colon is forbidden in first segment } - char *urlbuf = (char *)xmalloc(MAX_URL * sizeof(char)); + return true; // path-noscheme, path-abempty, path-rootless +} - if (req->url.getScheme() == AnyP::PROTO_URN) { - // XXX: this is what the original code did, but it seems to break the - // intended behaviour of this function. It returns the stored URN path, - // not converting the given one into a URN... - snprintf(urlbuf, MAX_URL, SQUIDSBUFPH, SQUIDSBUFPRINT(req->url.absolute())); - return (urlbuf); - } +void +AnyP::Uri::addRelativePath(const char *relUrl) +{ + // URN cannot be merged + if (getScheme() == AnyP::PROTO_URN) + return; - SBuf authorityForm = req->url.authority(); // host[:port] - const SBuf &scheme = req->url.getScheme().image(); - size_t urllen = snprintf(urlbuf, MAX_URL, SQUIDSBUFPH "://" SQUIDSBUFPH "%s" SQUIDSBUFPH, - SQUIDSBUFPRINT(scheme), - SQUIDSBUFPRINT(req->url.userInfo()), - !req->url.userInfo().isEmpty() ? "@" : "", - SQUIDSBUFPRINT(authorityForm)); + // TODO: Handle . and .. segment normalization - // if the first char is '/' assume its a relative path - // XXX: this breaks on scheme-relative URLs, - // but we should not see those outside ESI, and rarely there. - // XXX: also breaks on any URL containing a '/' in the query-string portion - if (relUrl[0] == '/') { - xstrncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); + const auto lastSlashPos = path_.rfind('/'); + // TODO: To optimize and simplify, add and use SBuf::replace(). + const auto relUrlLength = strlen(relUrl); + if (lastSlashPos == SBuf::npos) { + // start replacing the whole path + path_.reserveCapacity(1 + relUrlLength); + path_.assign("/", 1); } else { - SBuf path = req->url.path(); - SBuf::size_type lastSlashPos = path.rfind('/'); - - if (lastSlashPos == SBuf::npos) { - // replace the whole path with the given bit(s) - urlbuf[urllen] = '/'; - ++urllen; - xstrncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); - } else { - // replace only the last (file?) segment with the given bit(s) - ++lastSlashPos; - if (lastSlashPos > MAX_URL - urllen - 1) { - // XXX: crops bits in the middle of the combined URL. - lastSlashPos = MAX_URL - urllen - 1; - } - SBufToCstring(&urlbuf[urllen], path.substr(0,lastSlashPos)); - urllen += lastSlashPos; - if (urllen + 1 < MAX_URL) { - xstrncpy(&urlbuf[urllen], relUrl, MAX_URL - urllen - 1); - } - } + // start replacing just the last segment + path_.reserveCapacity(lastSlashPos + 1 + relUrlLength); + path_.chop(0, lastSlashPos+1); } - - return (urlbuf); + path_.append(relUrl, relUrlLength); } int @@ -890,105 +917,6 @@ return rc; } -/* - * Quick-n-dirty host extraction from a URL. Steps: - * Look for a colon - * Skip any '/' after the colon - * Copy the next SQUID_MAXHOSTNAMELEN bytes to host[] - * Look for an ending '/' or ':' and terminate - * Look for login info preceeded by '@' - */ - -class URLHostName -{ - -public: - char * extract(char const *url); - -private: - static char Host [SQUIDHOSTNAMELEN]; - void init(char const *); - void findHostStart(); - void trimTrailingChars(); - void trimAuth(); - char const *hostStart; - char const *url; -}; - -char * -urlHostname(const char *url) -{ - return URLHostName().extract(url); -} - -char URLHostName::Host[SQUIDHOSTNAMELEN]; - -void -URLHostName::init(char const *aUrl) -{ - Host[0] = '\0'; - url = aUrl; -} - -void -URLHostName::findHostStart() -{ - if (NULL == (hostStart = strchr(url, ':'))) - return; - - ++hostStart; - - while (*hostStart != '\0' && *hostStart == '/') - ++hostStart; - - if (*hostStart == ']') - ++hostStart; -} - -void -URLHostName::trimTrailingChars() -{ - char *t; - - if ((t = strchr(Host, '/'))) - *t = '\0'; - - if ((t = strrchr(Host, ':'))) - *t = '\0'; - - if ((t = strchr(Host, ']'))) - *t = '\0'; -} - -void -URLHostName::trimAuth() -{ - char *t; - - if ((t = strrchr(Host, '@'))) { - ++t; - memmove(Host, t, strlen(t) + 1); - } -} - -char * -URLHostName::extract(char const *aUrl) -{ - init(aUrl); - findHostStart(); - - if (hostStart == NULL) - return NULL; - - xstrncpy(Host, hostStart, SQUIDHOSTNAMELEN); - - trimTrailingChars(); - - trimAuth(); - - return Host; -} - AnyP::Uri::Uri(AnyP::UriScheme const &aScheme) : scheme_(aScheme), hostIsNumeric_(false), diff -u -r -N squid-4.11/src/anyp/Uri.h squid-4.12/src/anyp/Uri.h --- squid-4.11/src/anyp/Uri.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/anyp/Uri.h 2020-06-08 03:42:16.000000000 +1200 @@ -78,6 +78,8 @@ } void userInfo(const SBuf &s) {userInfo_=s; touch();} + /// \returns raw userinfo subcomponent (or an empty string) + /// the caller is responsible for caller-specific encoding const SBuf &userInfo() const {return userInfo_;} void host(const char *src); @@ -97,12 +99,27 @@ void path(const SBuf &p) {path_=p; touch();} const SBuf &path() const; + /** + * Merge a relative-path URL into the existing URI details. + * Implements RFC 3986 section 5.2.3 + * + * The caller must ensure relUrl is a valid relative-path. + * + * NP: absolute-path are also accepted, but path() method + * should be used instead when possible. + */ + void addRelativePath(const char *relUrl); + /// the static '/' default URL-path static const SBuf &SlashPath(); /// the static '*' pseudo-URI static const SBuf &Asterisk(); + /// %-encode characters in a buffer which do not conform to + /// the provided set of expected characters. + static SBuf Encode(const SBuf &, const CharacterSet &expected); + /** * The authority-form URI for currently stored values. * @@ -198,7 +215,6 @@ char *urlCanonicalCleanWithoutRequest(const SBuf &url, const HttpRequestMethod &, const AnyP::UriScheme &); const char *urlCanonicalFakeHttps(const HttpRequest * request); bool urlIsRelative(const char *); -char *urlMakeAbsolute(const HttpRequest *, const char *); char *urlRInternal(const char *host, unsigned short port, const char *dir, const char *name); char *urlInternal(const char *dir, const char *name); bool urlAppendDomain(char *host); ///< apply append_domain config to the given hostname @@ -244,7 +260,6 @@ */ int matchDomainName(const char *host, const char *domain, uint8_t flags = mdnNone); int urlCheckRequest(const HttpRequest *); -char *urlHostname(const char *url); void urlExtMethodConfigure(void); #endif /* SQUID_SRC_ANYP_URI_H */ diff -u -r -N squid-4.11/src/auth/basic/DB/basic_db_auth.8 squid-4.12/src/auth/basic/DB/basic_db_auth.8 --- squid-4.11/src/auth/basic/DB/basic_db_auth.8 2020-04-20 00:50:36.000000000 +1200 +++ squid-4.12/src/auth/basic/DB/basic_db_auth.8 2020-06-09 19:27:17.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_DB_AUTH 8" -.TH BASIC_DB_AUTH 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH BASIC_DB_AUTH 8 "2020-06-09" "perl v5.30.3" "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.11/src/auth/basic/POP3/basic_pop3_auth.8 squid-4.12/src/auth/basic/POP3/basic_pop3_auth.8 --- squid-4.11/src/auth/basic/POP3/basic_pop3_auth.8 2020-04-20 00:50:37.000000000 +1200 +++ squid-4.12/src/auth/basic/POP3/basic_pop3_auth.8 2020-06-09 19:27:17.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "BASIC_POP3_AUTH 8" -.TH BASIC_POP3_AUTH 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH BASIC_POP3_AUTH 8 "2020-06-09" "perl v5.30.3" "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.11/src/base/CharacterSet.cc squid-4.12/src/base/CharacterSet.cc --- squid-4.11/src/base/CharacterSet.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/base/CharacterSet.cc 2020-06-08 03:42:16.000000000 +1200 @@ -51,6 +51,13 @@ } CharacterSet & +CharacterSet::remove(const unsigned char c) +{ + chars_[static_cast(c)] = 0; + return *this; +} + +CharacterSet & CharacterSet::addRange(unsigned char low, unsigned char high) { //manual loop splitting is needed to cover case where high is 255 diff -u -r -N squid-4.11/src/base/CharacterSet.h squid-4.12/src/base/CharacterSet.h --- squid-4.11/src/base/CharacterSet.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/base/CharacterSet.h 2020-06-08 03:42:16.000000000 +1200 @@ -41,6 +41,9 @@ /// add a given character to the character set CharacterSet & add(const unsigned char c); + /// remove a given character from the character set + CharacterSet & remove(const unsigned char c); + /// add a list of character ranges, expressed as pairs [low,high], including both ends CharacterSet & addRange(unsigned char low, unsigned char high); diff -u -r -N squid-4.11/src/clients/Client.cc squid-4.12/src/clients/Client.cc --- squid-4.11/src/clients/Client.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/clients/Client.cc 2020-06-08 03:42:16.000000000 +1200 @@ -439,7 +439,7 @@ static bool sameUrlHosts(const char *url1, const char *url2) { - // XXX: Want urlHostname() here, but it uses static storage and copying + // XXX: Want AnyP::Uri::parse() here, but it uses static storage and copying const char *host1 = strchr(url1, ':'); const char *host2 = strchr(url2, ':'); @@ -468,33 +468,40 @@ static void purgeEntriesByHeader(HttpRequest *req, const char *reqUrl, HttpMsg *rep, Http::HdrType hdr) { - const char *hdrUrl, *absUrl; - - absUrl = NULL; - hdrUrl = rep->header.getStr(hdr); - if (hdrUrl == NULL) { + const auto hdrUrl = rep->header.getStr(hdr); + if (!hdrUrl) return; - } /* * If the URL is relative, make it absolute so we can find it. * If it's absolute, make sure the host parts match to avoid DOS attacks * as per RFC 2616 13.10. */ + SBuf absUrlMaker; + const char *absUrl = nullptr; if (urlIsRelative(hdrUrl)) { - absUrl = urlMakeAbsolute(req, hdrUrl); - if (absUrl != NULL) { - hdrUrl = absUrl; + if (req->method.id() == Http::METHOD_CONNECT) + absUrl = hdrUrl; // TODO: merge authority-uri and hdrUrl + else if (req->url.getScheme() == AnyP::PROTO_URN) + absUrl = req->url.absolute().c_str(); + else { + AnyP::Uri tmpUrl = req->url; + if (*hdrUrl == '/') { + // RFC 3986 section 4.2: absolute-path reference + // for this logic replace the entire request-target URI path + tmpUrl.path(hdrUrl); + } else { + tmpUrl.addRelativePath(reqUrl); + } + absUrlMaker = tmpUrl.absolute(); + absUrl = absUrlMaker.c_str(); } } else if (!sameUrlHosts(reqUrl, hdrUrl)) { return; - } + } else + absUrl = hdrUrl; - purgeEntriesByUrl(req, hdrUrl); - - if (absUrl != NULL) { - safe_free(absUrl); - } + purgeEntriesByUrl(req, absUrl); } // some HTTP methods should purge matching cache entries diff -u -r -N squid-4.11/src/client_side.cc squid-4.12/src/client_side.cc --- squid-4.11/src/client_side.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/client_side.cc 2020-06-08 03:42:16.000000000 +1200 @@ -2365,6 +2365,7 @@ bodyParser(nullptr), #if USE_OPENSSL sslBumpMode(Ssl::bumpEnd), + tlsParser(Security::HandshakeParser::fromClient), #endif needProxyProtocolHeader_(false), #if USE_OPENSSL diff -u -r -N squid-4.11/src/client_side_reply.cc squid-4.12/src/client_side_reply.cc --- squid-4.11/src/client_side_reply.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/client_side_reply.cc 2020-06-08 03:42:16.000000000 +1200 @@ -907,7 +907,7 @@ const cache_key *key = storeKeyPublic(url, m); debugs(88, 5, m << ' ' << url << ' ' << storeKeyText(key)); #if USE_HTCP - neighborsHtcpClear(nullptr, url, req, m, HTCP_CLR_INVALIDATION); + neighborsHtcpClear(nullptr, req, m, HTCP_CLR_INVALIDATION); #endif Store::Root().evictIfFound(key); } @@ -1040,7 +1040,7 @@ /* Release the cached URI */ debugs(88, 4, "clientPurgeRequest: GET '" << newEntry->url() << "'" ); #if USE_HTCP - neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE); + neighborsHtcpClear(newEntry, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE); #endif newEntry->release(true); purgeStatus = Http::scOkay; @@ -1056,7 +1056,7 @@ if (newEntry && !newEntry->isNull()) { debugs(88, 4, "HEAD " << newEntry->url()); #if USE_HTCP - neighborsHtcpClear(newEntry, NULL, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE); + neighborsHtcpClear(newEntry, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE); #endif newEntry->release(true); purgeStatus = Http::scOkay; @@ -1072,7 +1072,7 @@ if (entry) { debugs(88, 4, "Vary GET " << entry->url()); #if USE_HTCP - neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE); + neighborsHtcpClear(entry, http->request, HttpRequestMethod(Http::METHOD_GET), HTCP_CLR_PURGE); #endif entry->release(true); purgeStatus = Http::scOkay; @@ -1083,13 +1083,16 @@ if (entry) { debugs(88, 4, "Vary HEAD " << entry->url()); #if USE_HTCP - neighborsHtcpClear(entry, NULL, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE); + neighborsHtcpClear(entry, http->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_PURGE); #endif entry->release(true); purgeStatus = Http::scOkay; } } + if (purgeStatus == Http::scNone) + purgeStatus = Http::scNotFound; + /* * Make a new entry to hold the reply to be written * to the client. diff -u -r -N squid-4.11/src/Debug.h squid-4.12/src/Debug.h --- squid-4.11/src/Debug.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/Debug.h 2020-06-08 03:42:16.000000000 +1200 @@ -99,6 +99,10 @@ /// configures the active debugging context to write syslog ALERT static void ForceAlert(); + + /// prefixes each grouped debugs() line after the first one in the group + static std::ostream& Extra(std::ostream &os) { return os << "\n "; } + private: static Context *Current; ///< deepest active context; nil outside debugs() }; diff -u -r -N squid-4.11/src/format/Format.cc squid-4.12/src/format/Format.cc --- squid-4.11/src/format/Format.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/format/Format.cc 2020-06-08 03:42:16.000000000 +1200 @@ -322,15 +322,6 @@ *p = '\0'; } -#if USE_OPENSSL -static char * -sslErrorName(Security::ErrorCode err, char *buf, size_t size) -{ - snprintf(buf, size, "SSL_ERR=%d", err); - return buf; -} -#endif - /// XXX: Misnamed. TODO: Split request && al->request->errType == ERR_SECURE_CONNECT_FAIL) { - out = Ssl::GetErrorName(al->request->errDetail); - if (!out) - out = sslErrorName(al->request->errDetail, tmp, sizeof(tmp)); + out = Ssl::GetErrorName(al->request->errDetail, true); } else #endif if (al->request && al->request->errDetail != ERR_DETAIL_NONE) { @@ -1263,10 +1252,7 @@ for (const Security::CertErrors *sslError = srvBump->sslErrors(); sslError; sslError = sslError->next) { if (!sb.isEmpty()) sb.append(separator); - if (const char *errorName = Ssl::GetErrorName(sslError->element.code)) - sb.append(errorName); - else - sb.append(sslErrorName(sslError->element.code, tmp, sizeof(tmp))); + sb.append(Ssl::GetErrorName(sslError->element.code, true)); if (sslError->element.depth >= 0) sb.appendf("@depth=%d", sslError->element.depth); } diff -u -r -N squid-4.11/src/htcp.cc squid-4.12/src/htcp.cc --- squid-4.11/src/htcp.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/htcp.cc 2020-06-08 03:42:16.000000000 +1200 @@ -138,7 +138,7 @@ public: const char *method = nullptr; - char *uri = nullptr; + const char *uri = nullptr; char *version = nullptr; char *req_hdrs = nullptr; size_t reqHdrsSz = 0; ///< size of the req_hdrs content @@ -791,6 +791,7 @@ if (spec) { stuff.S.method = spec->method; + stuff.S.request = spec->request; stuff.S.uri = spec->uri; stuff.S.version = spec->version; stuff.S.req_hdrs = spec->req_hdrs; @@ -825,15 +826,15 @@ hdr.clean(); #if USE_ICMP - if (char *host = urlHostname(spec->uri)) { + if (const char *host = spec->request->url.host()) { int rtt = 0; int hops = 0; int samp = 0; netdbHostData(host, &samp, &rtt, &hops); if (rtt || hops) { - char cto_buf[128]; - snprintf(cto_buf, 128, "%s %d %f %d", + char cto_buf[SQUIDHOSTNAMELEN+128]; + snprintf(cto_buf, sizeof(cto_buf), "%s %d %f %d", host, samp, 0.001 * rtt, hops); hdr.putExt("Cache-to-Origin", cto_buf); } @@ -1470,7 +1471,7 @@ * Send an HTCP CLR message for a specified item to a given CachePeer. */ void -htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &, CachePeer * p, htcp_clr_reason reason) +htcpClear(StoreEntry * e, HttpRequest * req, const HttpRequestMethod &, CachePeer * p, htcp_clr_reason reason) { static char pkt[8192]; ssize_t pktlen; @@ -1492,14 +1493,9 @@ SBuf sb = req->method.image(); stuff.S.method = sb.c_str(); - if (e == NULL || e->mem_obj == NULL) { - if (uri == NULL) { - return; - } - stuff.S.uri = xstrdup(uri); - } else { - stuff.S.uri = (char *) e->url(); - } + stuff.S.request = req; + SBuf uri = req->effectiveRequestUri(); + stuff.S.uri = uri.c_str(); stuff.S.version = vbuf; if (reason != HTCP_CLR_INVALIDATION) { HttpStateData::httpBuildRequestHeader(req, e, NULL, &hdr, flags); @@ -1514,9 +1510,6 @@ if (reason != HTCP_CLR_INVALIDATION) { mb.clean(); } - if (e == NULL) { - xfree(stuff.S.uri); - } if (!pktlen) { debugs(31, 3, "htcpClear: htcpBuildPacket() failed"); return; diff -u -r -N squid-4.11/src/htcp.h squid-4.12/src/htcp.h --- squid-4.11/src/htcp.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/htcp.h 2020-06-08 03:42:16.000000000 +1200 @@ -57,7 +57,7 @@ int htcpQuery(StoreEntry * e, HttpRequest * req, CachePeer * p); /// \ingroup ServerProtocolHTCP -void htcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, CachePeer * p, htcp_clr_reason reason); +void htcpClear(StoreEntry * e, HttpRequest * req, const HttpRequestMethod &method, CachePeer * p, htcp_clr_reason reason); /// \ingroup ServerProtocolHTCP void htcpSocketShutdown(void); diff -u -r -N squid-4.11/src/http/ContentLengthInterpreter.cc squid-4.12/src/http/ContentLengthInterpreter.cc --- squid-4.11/src/http/ContentLengthInterpreter.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/http/ContentLengthInterpreter.cc 2020-06-08 03:42:16.000000000 +1200 @@ -28,6 +28,24 @@ { } +/// checks whether all characters before the Content-Length number are allowed +/// \returns the start of the digit sequence (or nil on errors) +const char * +Http::ContentLengthInterpreter::findDigits(const char *prefix, const char * const valueEnd) const +{ + // skip leading OWS in RFC 7230's `OWS field-value OWS` + const CharacterSet &whitespace = Http::One::Parser::WhitespaceCharacters(); + while (prefix < valueEnd) { + const auto ch = *prefix; + if (CharacterSet::DIGIT[ch]) + return prefix; // common case: a pre-trimmed field value + if (!whitespace[ch]) + return nullptr; // (trimmed) length does not start with a digit + ++prefix; + } + return nullptr; // empty or whitespace-only value +} + /// checks whether all characters after the Content-Length are allowed bool Http::ContentLengthInterpreter::goodSuffix(const char *suffix, const char * const end) const @@ -52,10 +70,19 @@ { Must(!sawBad); + const auto valueEnd = rawValue + valueSize; + + const auto digits = findDigits(rawValue, valueEnd); + if (!digits) { + debugs(55, debugLevel, "WARNING: Leading garbage or empty value in" << Raw("Content-Length", rawValue, valueSize)); + sawBad = true; + return false; + } + int64_t latestValue = -1; char *suffix = nullptr; - // TODO: Handle malformed values with leading signs (e.g., "-0" or "+1"). - if (!httpHeaderParseOffset(rawValue, &latestValue, &suffix)) { + + if (!httpHeaderParseOffset(digits, &latestValue, &suffix)) { debugs(55, DBG_IMPORTANT, "WARNING: Malformed" << Raw("Content-Length", rawValue, valueSize)); sawBad = true; return false; @@ -68,7 +95,7 @@ } // check for garbage after the number - if (!goodSuffix(suffix, rawValue + valueSize)) { + if (!goodSuffix(suffix, valueEnd)) { debugs(55, debugLevel, "WARNING: Trailing garbage in" << Raw("Content-Length", rawValue, valueSize)); sawBad = true; return false; diff -u -r -N squid-4.11/src/http/ContentLengthInterpreter.h squid-4.12/src/http/ContentLengthInterpreter.h --- squid-4.11/src/http/ContentLengthInterpreter.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/http/ContentLengthInterpreter.h 2020-06-08 03:42:16.000000000 +1200 @@ -46,6 +46,7 @@ bool sawGood; protected: + const char *findDigits(const char *prefix, const char *valueEnd) const; bool goodSuffix(const char *suffix, const char * const end) const; bool checkValue(const char *start, const int size); bool checkList(const String &list); diff -u -r -N squid-4.11/src/http/StatusLine.cc squid-4.12/src/http/StatusLine.cc --- squid-4.11/src/http/StatusLine.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/http/StatusLine.cc 2020-06-08 03:42:16.000000000 +1200 @@ -47,6 +47,17 @@ { assert(p); + auto packedStatus = status(); + auto packedReason = reason(); + + if (packedStatus == Http::scNone) { + static unsigned int reports = 0; + if (++reports <= 100) + debugs(57, DBG_IMPORTANT, "BUG: Generated response lacks status code"); + packedStatus = Http::scInternalServerError; + packedReason = Http::StatusCodeString(packedStatus); // ignore custom reason_ (if any) + } + /* local constants */ /* AYJ: see bug 2469 - RFC2616 confirms stating 'SP characters' plural! */ static const char *Http1StatusLineFormat = "HTTP/%d.%d %3d %s\r\n"; @@ -56,15 +67,15 @@ if (protocol == AnyP::PROTO_ICY) { debugs(57, 9, "packing sline " << this << " using " << p << ":"); debugs(57, 9, "FORMAT=" << IcyStatusLineFormat ); - debugs(57, 9, "ICY " << status() << " " << reason()); - p->appendf(IcyStatusLineFormat, status(), reason()); + debugs(57, 9, "ICY " << packedStatus << " " << packedReason); + p->appendf(IcyStatusLineFormat, packedStatus, packedReason); return; } debugs(57, 9, "packing sline " << this << " using " << p << ":"); debugs(57, 9, "FORMAT=" << Http1StatusLineFormat ); - debugs(57, 9, "HTTP/" << version.major << "." << version.minor << " " << status() << " " << reason()); - p->appendf(Http1StatusLineFormat, version.major, version.minor, status(), reason()); + debugs(57, 9, "HTTP/" << version.major << "." << version.minor << " " << packedStatus << " " << packedReason); + p->appendf(Http1StatusLineFormat, version.major, version.minor, packedStatus, packedReason); } /* diff -u -r -N squid-4.11/src/http/url_rewriters/LFS/url_lfs_rewrite.8 squid-4.12/src/http/url_rewriters/LFS/url_lfs_rewrite.8 --- squid-4.11/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2020-04-20 00:50:37.000000000 +1200 +++ squid-4.12/src/http/url_rewriters/LFS/url_lfs_rewrite.8 2020-06-09 19:27:18.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "URL_LFS_REWRITE 8" -.TH URL_LFS_REWRITE 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH URL_LFS_REWRITE 8 "2020-06-09" "perl v5.30.3" "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.11/src/http.cc squid-4.12/src/http.cc --- squid-4.11/src/http.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/http.cc 2020-06-08 03:42:16.000000000 +1200 @@ -249,7 +249,7 @@ if (pe != NULL) { assert(e != pe); #if USE_HTCP - neighborsHtcpClear(e, NULL, e->mem_obj->request, e->mem_obj->method, HTCP_CLR_INVALIDATION); + neighborsHtcpClear(e, e->mem_obj->request, e->mem_obj->method, HTCP_CLR_INVALIDATION); #endif pe->release(true); } @@ -266,7 +266,7 @@ if (pe != NULL) { assert(e != pe); #if USE_HTCP - neighborsHtcpClear(e, NULL, e->mem_obj->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_INVALIDATION); + neighborsHtcpClear(e, e->mem_obj->request, HttpRequestMethod(Http::METHOD_HEAD), HTCP_CLR_INVALIDATION); #endif pe->release(true); } diff -u -r -N squid-4.11/src/ip/Intercept.cc squid-4.12/src/ip/Intercept.cc --- squid-4.11/src/ip/Intercept.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/ip/Intercept.cc 2020-06-08 03:42:16.000000000 +1200 @@ -204,7 +204,7 @@ memset(&natLookup, 0, sizeof(natLookup)); // for NAT lookup set local and remote IP:port's if (newConn->remote.isIPv6()) { -#if HAVE_NATLOOKUP_NL_INIPADDR_IN6 +#if HAVE_STRUCT_NATLOOKUP_NL_INIPADDR_IN6 natLookup.nl_v = 6; newConn->local.getInAddr(natLookup.nl_inipaddr.in6); newConn->remote.getInAddr(natLookup.nl_outipaddr.in6); @@ -292,7 +292,7 @@ debugs(89, 9, HERE << "address: " << newConn); return false; } else { -#if HAVE_NATLOOKUP_NL_REALIPADDR_IN6 +#if HAVE_STRUCT_NATLOOKUP_NL_REALIPADDR_IN6 if (newConn->remote.isIPv6()) newConn->local = natLookup.nl_realipaddr.in6; else diff -u -r -N squid-4.11/src/log/DB/log_db_daemon.8 squid-4.12/src/log/DB/log_db_daemon.8 --- squid-4.11/src/log/DB/log_db_daemon.8 2020-04-20 00:50:38.000000000 +1200 +++ squid-4.12/src/log/DB/log_db_daemon.8 2020-06-09 19:27:18.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "LOG_DB_DAEMON 8" -.TH LOG_DB_DAEMON 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH LOG_DB_DAEMON 8 "2020-06-09" "perl v5.30.3" "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.11/src/neighbors.cc squid-4.12/src/neighbors.cc --- squid-4.11/src/neighbors.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/neighbors.cc 2020-06-08 03:42:16.000000000 +1200 @@ -1748,7 +1748,7 @@ * Send HTCP CLR messages to all peers configured to receive them. */ void -neighborsHtcpClear(StoreEntry * e, const char *uri, HttpRequest * req, const HttpRequestMethod &method, htcp_clr_reason reason) +neighborsHtcpClear(StoreEntry * e, HttpRequest * req, const HttpRequestMethod &method, htcp_clr_reason reason) { CachePeer *p; char buf[128]; @@ -1764,7 +1764,7 @@ continue; } debugs(15, 3, "neighborsHtcpClear: sending CLR to " << p->in_addr.toUrl(buf, 128)); - htcpClear(e, uri, req, method, p, reason); + htcpClear(e, req, method, p, reason); } } diff -u -r -N squid-4.11/src/neighbors.h squid-4.12/src/neighbors.h --- squid-4.11/src/neighbors.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/neighbors.h 2020-06-08 03:42:16.000000000 +1200 @@ -39,7 +39,7 @@ void neighborAdd(const char *, const char *, int, int, int, int, int); void neighbors_init(void); #if USE_HTCP -void neighborsHtcpClear(StoreEntry *, const char *, HttpRequest *, const HttpRequestMethod &, htcp_clr_reason); +void neighborsHtcpClear(StoreEntry *, HttpRequest *, const HttpRequestMethod &, htcp_clr_reason); #endif CachePeer *peerFindByName(const char *); CachePeer *peerFindByNameAndPort(const char *, unsigned short); diff -u -r -N squid-4.11/src/security/cert_validators/fake/security_fake_certverify.8 squid-4.12/src/security/cert_validators/fake/security_fake_certverify.8 --- squid-4.11/src/security/cert_validators/fake/security_fake_certverify.8 2020-04-20 00:50:38.000000000 +1200 +++ squid-4.12/src/security/cert_validators/fake/security_fake_certverify.8 2020-06-09 19:27:18.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "SECURITY_FAKE_CERTVERIFY 8" -.TH SECURITY_FAKE_CERTVERIFY 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH SECURITY_FAKE_CERTVERIFY 8 "2020-06-09" "perl v5.30.3" "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.11/src/security/Handshake.cc squid-4.12/src/security/Handshake.cc --- squid-4.11/src/security/Handshake.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/security/Handshake.cc 2020-06-08 03:42:16.000000000 +1200 @@ -106,11 +106,11 @@ } // namespace Security -/// Convenience helper: We parse ProtocolVersion but store "int". +/// parse TLS ProtocolVersion (uint16) and convert it to AnyP::ProtocolVersion static AnyP::ProtocolVersion -ParseProtocolVersion(Parser::BinaryTokenizer &tk) +ParseProtocolVersion(Parser::BinaryTokenizer &tk, const char *contextLabel = ".version") { - Parser::BinaryTokenizerContext context(tk, ".version"); + Parser::BinaryTokenizerContext context(tk, contextLabel); uint8_t vMajor = tk.uint8(".major"); uint8_t vMinor = tk.uint8(".minor"); if (vMajor == 0 && vMinor == 2) @@ -187,10 +187,11 @@ /* Security::HandshakeParser */ -Security::HandshakeParser::HandshakeParser(): +Security::HandshakeParser::HandshakeParser(const MessageSource source): details(new TlsDetails), state(atHelloNone), resumingSession(false), + messageSource(source), currentContentType(0), done(nullptr), expectingModernRecords(false) @@ -285,12 +286,19 @@ { Must(currentContentType == ContentType::ctChangeCipherSpec); // We are currently ignoring Change Cipher Spec Protocol messages. - skipMessage("ChangeCipherCpec msg [fragment]"); + skipMessage("ChangeCipherSpec msg [fragment]"); + + // In TLS v1.2 and earlier, ChangeCipherSpec is sent after Hello (when + // tlsSupportedVersion is already known) and indicates session resumption. + // In later TLS versions, ChangeCipherSpec may be sent before and after + // Hello, but it is unused for session resumption and should be ignored. + if (!details->tlsSupportedVersion || Tls1p3orLater(details->tlsSupportedVersion)) + return; - // Everything after the ChangeCipherCpec message may be encrypted. - // Continuing parsing is pointless. Stop here. resumingSession = true; - done = "ChangeCipherCpec"; + + // Everything after the ChangeCipherSpec message may be encrypted. Stop. + done = "ChangeCipherSpec in v1.2-"; } void @@ -316,14 +324,19 @@ switch (message.msg_type) { case HandshakeType::hskClientHello: Must(state < atHelloReceived); + Must(messageSource == fromClient); Security::HandshakeParser::parseClientHelloHandshakeMessage(message.msg_body); state = atHelloReceived; done = "ClientHello"; return; case HandshakeType::hskServerHello: Must(state < atHelloReceived); + Must(messageSource == fromServer); parseServerHelloHandshakeMessage(message.msg_body); state = atHelloReceived; + // for TLSv1.3 and later, anything after the server Hello is encrypted + if (Tls1p3orLater(details->tlsSupportedVersion)) + done = "ServerHello in v1.3+"; return; case HandshakeType::hskCertificate: Must(state < atCertificatesReceived); @@ -424,6 +437,10 @@ case 35: // SessionTicket TLS Extension; RFC 5077 details->tlsTicketsExtension = true; details->hasTlsTicket = !extension.data.isEmpty(); + break; + case 43: // supported_versions extension; RFC 8446 + parseSupportedVersionsExtension(extension.data); + break; case 13172: // Next Protocol Negotiation Extension (expired draft?) default: break; @@ -504,6 +521,78 @@ return SBuf(); // SNI extension lacks host_name } +/// RFC 8446 Section 4.2.1: SupportedVersions extension +void +Security::HandshakeParser::parseSupportedVersionsExtension(const SBuf &extensionData) const +{ + // Upon detecting a quoted RFC MUST violation, this parser immediately + // returns, ignoring the entire extension and resulting in Squid relying on + // the legacy_version field value or another (valid) supported_versions + // extension. The alternative would be to reject the whole handshake as + // invalid. Deployment experience will show which alternative is the best. + + // Please note that several of these MUSTs also imply certain likely + // handling of a hypothetical next TLS version (e.g., v1.4). + + // RFC 8446 Section 4.1.2: + // In TLS 1.3, the client indicates its version preferences in the + // "supported_versions" extension (Section 4.2.1) and the legacy_version + // field MUST be set to 0x0303, which is the version number for TLS 1.2. + // + // RFC 8446 Section 4.2.1: + // A server which negotiates TLS 1.3 MUST respond by sending a + // "supported_versions" extension containing the selected version value + // (0x0304). It MUST set the ServerHello.legacy_version field to 0x0303 + // (TLS 1.2). + // + // Ignore supported_versions senders violating legacy_version MUSTs above: + if (details->tlsSupportedVersion != AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 2)) + return; + + AnyP::ProtocolVersion supportedVersionMax; + if (messageSource == fromClient) { + Parser::BinaryTokenizer tkList(extensionData); + Parser::BinaryTokenizer tkVersions(tkList.pstring8("SupportedVersions")); + while (!tkVersions.atEnd()) { + const auto version = ParseProtocolVersion(tkVersions, "supported_version"); + if (!supportedVersionMax || TlsVersionEarlierThan(supportedVersionMax, version)) + supportedVersionMax = version; + } + + // ignore empty supported_versions + if (!supportedVersionMax) + return; + + // supportedVersionMax here may be "earlier" than tlsSupportedVersion: A + // TLS v1.3 client may try to negotiate a _legacy_ version X with a TLS + // v1.3 server by sending supported_versions containing just X. + } else { + assert(messageSource == fromServer); + Parser::BinaryTokenizer tkVersion(extensionData); + const auto version = ParseProtocolVersion(tkVersion, "selected_version"); + // RFC 8446 Section 4.2.1: + // A server which negotiates a version of TLS prior to TLS 1.3 [...] + // MUST NOT send the "supported_versions" extension. + if (Tls1p2orEarlier(version)) + return; + supportedVersionMax = version; + } + + // We overwrite Hello-derived legacy_version because the following MUSTs + // indicate that it is ignored in the presence of valid supported_versions + // as far as the negotiated version is concerned. For simplicity sake, we + // may also overwrite previous valid supported_versions extensions (if any). + // + // RFC 8446 Section 4.2.1: + // If this extension is present in the ClientHello, servers MUST NOT use the + // ClientHello.legacy_version value for version negotiation and MUST use + // only the "supported_versions" extension to determine client preferences. + // Servers MUST only select a version of TLS present in that extension + debugs(83, 7, "found " << supportedVersionMax); + assert(supportedVersionMax); + details->tlsSupportedVersion = supportedVersionMax; +} + void Security::HandshakeParser::skipMessage(const char *description) { @@ -647,6 +736,9 @@ #if defined(TLSEXT_TYPE_next_proto_neg) // 13172 extensions.insert(TLSEXT_TYPE_next_proto_neg); #endif +#if defined(TLSEXT_TYPE_supported_versions) // 43 + extensions.insert(TLSEXT_TYPE_supported_versions); +#endif /* * OpenSSL does not support these last extensions by default, but those diff -u -r -N squid-4.11/src/security/Handshake.h squid-4.12/src/security/Handshake.h --- squid-4.11/src/security/Handshake.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/security/Handshake.h 2020-06-08 03:42:16.000000000 +1200 @@ -29,7 +29,11 @@ std::ostream & print(std::ostream &os) const; AnyP::ProtocolVersion tlsVersion; ///< The TLS hello message version - AnyP::ProtocolVersion tlsSupportedVersion; ///< The requested/used TLS version + + /// For most compliant TLS v1.3+ agents, this is supported_versions maximum. + /// For others agents, this is the legacy_version field. + AnyP::ProtocolVersion tlsSupportedVersion; + bool compressionSupported; ///< The requested/used compressed method SBuf serverName; ///< The SNI hostname, if any bool doHeartBeats; @@ -59,7 +63,10 @@ /// The parsing states typedef enum {atHelloNone = 0, atHelloStarted, atHelloReceived, atCertificatesReceived, atHelloDoneReceived, atNstReceived, atCcsReceived, atFinishReceived} ParserState; - HandshakeParser(); + /// the originator of the TLS handshake being parsed + typedef enum { fromClient = 0, fromServer } MessageSource; + + explicit HandshakeParser(MessageSource); /// Parses the initial sequence of raw bytes sent by the TLS/SSL agent. /// Returns true upon successful completion (e.g., got HelloDone). @@ -67,7 +74,7 @@ /// Throws on errors. bool parseHello(const SBuf &data); - TlsDetails::Pointer details; ///< TLS handshake meta info or nil. + TlsDetails::Pointer details; ///< TLS handshake meta info. Never nil. Security::CertList serverCertificates; ///< parsed certificates chain @@ -75,6 +82,9 @@ bool resumingSession; ///< True if this is a resuming session + /// whether we are parsing Server or Client TLS handshake messages + MessageSource messageSource; + private: bool isSslv2Record(const SBuf &raw) const; void parseRecord(); @@ -96,6 +106,7 @@ bool parseCompressionMethods(const SBuf &raw); void parseExtensions(const SBuf &raw); SBuf parseSniExtension(const SBuf &extensionData) const; + void parseSupportedVersionsExtension(const SBuf &extensionData) const; void parseCiphers(const SBuf &raw); void parseV23Ciphers(const SBuf &raw); @@ -120,6 +131,40 @@ YesNoNone expectingModernRecords; }; +/// whether the given protocol belongs to the TLS/SSL group of protocols +inline bool +TlsFamilyProtocol(const AnyP::ProtocolVersion &version) +{ + return (version.protocol == AnyP::PROTO_TLS || version.protocol == AnyP::PROTO_SSL); +} + +/// whether TLS/SSL protocol `a` precedes TLS/SSL protocol `b` +inline bool +TlsVersionEarlierThan(const AnyP::ProtocolVersion &a, const AnyP::ProtocolVersion &b) +{ + Must(TlsFamilyProtocol(a)); + Must(TlsFamilyProtocol(b)); + + if (a.protocol == b.protocol) + return a < b; + + return a.protocol == AnyP::PROTO_SSL; // implies that b is TLS +} + +/// whether the given TLS/SSL protocol is TLS v1.2 or earlier, including SSL +inline bool +Tls1p2orEarlier(const AnyP::ProtocolVersion &p) +{ + return TlsVersionEarlierThan(p, AnyP::ProtocolVersion(AnyP::PROTO_TLS, 1, 3)); +} + +/// whether the given TLS/SSL protocol is TLS v1.3 or later +inline bool +Tls1p3orLater(const AnyP::ProtocolVersion &p) +{ + return !Tls1p2orEarlier(p); +} + } #endif // SQUID_SECURITY_HANDSHAKE_H diff -u -r -N squid-4.11/src/security/NegotiationHistory.cc squid-4.12/src/security/NegotiationHistory.cc --- squid-4.11/src/security/NegotiationHistory.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/security/NegotiationHistory.cc 2020-06-08 03:42:16.000000000 +1200 @@ -25,7 +25,7 @@ const char * Security::NegotiationHistory::printTlsVersion(AnyP::ProtocolVersion const &v) const { - if (v.protocol != AnyP::PROTO_SSL && v.protocol != AnyP::PROTO_TLS) + if (!TlsFamilyProtocol(v)) return nullptr; static char buf[512]; diff -u -r -N squid-4.11/src/ssl/bio.cc squid-4.12/src/ssl/bio.cc --- squid-4.11/src/ssl/bio.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/ssl/bio.cc 2020-06-08 03:42:16.000000000 +1200 @@ -250,7 +250,8 @@ parsedHandshake(false), parseError(false), bumpMode_(bumpNone), - rbufConsumePos(0) + rbufConsumePos(0), + parser_(Security::HandshakeParser::fromServer) { } @@ -554,6 +555,13 @@ return parser_.resumingSession; } +bool +Ssl::ServerBio::encryptedCertificates() const +{ + return parser_.details->tlsSupportedVersion && + Security::Tls1p3orLater(parser_.details->tlsSupportedVersion); +} + /// initializes BIO table after allocation static int squid_bio_create(BIO *bi) @@ -717,6 +725,12 @@ SSL_set_options(ssl, SSL_OP_NO_COMPRESSION); #endif +#if defined(SSL_OP_NO_TLSv1_3) + // avoid "inappropriate fallback" OpenSSL error messages + if (details->tlsSupportedVersion && Security::Tls1p2orEarlier(details->tlsSupportedVersion)) + SSL_set_options(ssl, SSL_OP_NO_TLSv1_3); +#endif + #if defined(TLSEXT_STATUSTYPE_ocsp) if (details->tlsStatusRequest) SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); diff -u -r -N squid-4.11/src/ssl/bio.h squid-4.12/src/ssl/bio.h --- squid-4.11/src/ssl/bio.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/ssl/bio.h 2020-06-08 03:42:16.000000000 +1200 @@ -143,6 +143,10 @@ bool resumingSession(); + /// whether the server encrypts its certificate (e.g., TLS v1.3) + /// \retval false the server uses plain certs or its intent is unknown + bool encryptedCertificates() const; + /// The write hold state bool holdWrite() const {return holdWrite_;} /// Enables or disables the write hold state diff -u -r -N squid-4.11/src/ssl/ErrorDetail.cc squid-4.12/src/ssl/ErrorDetail.cc --- squid-4.11/src/ssl/ErrorDetail.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/ssl/ErrorDetail.cc 2020-06-08 03:42:16.000000000 +1200 @@ -233,6 +233,9 @@ "X509_V_ERR_SUBTREE_MINMAX" }, #endif + { X509_V_ERR_APPLICATION_VERIFICATION, //50 + "X509_V_ERR_APPLICATION_VERIFICATION" + }, #if defined(X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE) { X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, //51 @@ -257,9 +260,132 @@ "X509_V_ERR_CRL_PATH_VALIDATION_ERROR" }, #endif - { X509_V_ERR_APPLICATION_VERIFICATION, - "X509_V_ERR_APPLICATION_VERIFICATION" +#if defined(X509_V_ERR_PATH_LOOP) + { + X509_V_ERR_PATH_LOOP, //55 + "X509_V_ERR_PATH_LOOP" + }, +#endif +#if defined(X509_V_ERR_SUITE_B_INVALID_VERSION) + { + X509_V_ERR_SUITE_B_INVALID_VERSION, //56 + "X509_V_ERR_SUITE_B_INVALID_VERSION" + }, +#endif +#if defined(X509_V_ERR_SUITE_B_INVALID_ALGORITHM) + { + X509_V_ERR_SUITE_B_INVALID_ALGORITHM, //57 + "X509_V_ERR_SUITE_B_INVALID_ALGORITHM" + }, +#endif +#if defined(X509_V_ERR_SUITE_B_INVALID_CURVE) + { + X509_V_ERR_SUITE_B_INVALID_CURVE, //58 + "X509_V_ERR_SUITE_B_INVALID_CURVE" + }, +#endif +#if defined(X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM) + { + X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM, //59 + "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM" + }, +#endif +#if defined(X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED) + { + X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED, //60 + "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED" + }, +#endif +#if defined(X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256) + { + X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256, //61 + "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256" + }, +#endif +#if defined(X509_V_ERR_HOSTNAME_MISMATCH) + { + X509_V_ERR_HOSTNAME_MISMATCH, //62 + "X509_V_ERR_HOSTNAME_MISMATCH" + }, +#endif +#if defined(X509_V_ERR_EMAIL_MISMATCH) + { + X509_V_ERR_EMAIL_MISMATCH, //63 + "X509_V_ERR_EMAIL_MISMATCH" + }, +#endif +#if defined(X509_V_ERR_IP_ADDRESS_MISMATCH) + { + X509_V_ERR_IP_ADDRESS_MISMATCH, //64 + "X509_V_ERR_IP_ADDRESS_MISMATCH" + }, +#endif +#if defined(X509_V_ERR_DANE_NO_MATCH) + { + X509_V_ERR_DANE_NO_MATCH, //65 + "X509_V_ERR_DANE_NO_MATCH" }, +#endif +#if defined(X509_V_ERR_EE_KEY_TOO_SMALL) + { + X509_V_ERR_EE_KEY_TOO_SMALL, //66 + "X509_V_ERR_EE_KEY_TOO_SMALL" + }, +#endif +#if defined(X509_V_ERR_CA_KEY_TOO_SMALL) + { + X509_V_ERR_CA_KEY_TOO_SMALL, //67 + "X509_V_ERR_CA_KEY_TOO_SMALL" + }, +#endif +#if defined(X509_V_ERR_CA_MD_TOO_WEAK) + { + X509_V_ERR_CA_MD_TOO_WEAK, //68 + "X509_V_ERR_CA_MD_TOO_WEAK" + }, +#endif +#if defined(X509_V_ERR_INVALID_CALL) + { + X509_V_ERR_INVALID_CALL, //69 + "X509_V_ERR_INVALID_CALL" + }, +#endif +#if defined(X509_V_ERR_STORE_LOOKUP) + { + X509_V_ERR_STORE_LOOKUP, //70 + "X509_V_ERR_STORE_LOOKUP" + }, +#endif +#if defined(X509_V_ERR_NO_VALID_SCTS) + { + X509_V_ERR_NO_VALID_SCTS, //71 + "X509_V_ERR_NO_VALID_SCTS" + }, +#endif +#if defined(X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION) + { + X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION, //72 + "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION" + }, +#endif +#if defined(X509_V_ERR_OCSP_VERIFY_NEEDED) + { + X509_V_ERR_OCSP_VERIFY_NEEDED, //73 + "X509_V_ERR_OCSP_VERIFY_NEEDED" + }, +#endif +#if defined(X509_V_ERR_OCSP_VERIFY_FAILED) + { + X509_V_ERR_OCSP_VERIFY_FAILED, //74 + "X509_V_ERR_OCSP_VERIFY_FAILED" + }, +#endif +#if defined(X509_V_ERR_OCSP_CERT_UNKNOWN) + { + X509_V_ERR_OCSP_CERT_UNKNOWN, //75 + "X509_V_ERR_OCSP_CERT_UNKNOWN" + }, +#endif { SSL_ERROR_NONE, "SSL_ERROR_NONE"}, {SSL_ERROR_NONE, NULL} }; @@ -286,6 +412,27 @@ "X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX", "X509_V_ERR_UNSUPPORTED_NAME_SYNTAX", "X509_V_ERR_CRL_PATH_VALIDATION_ERROR", + "X509_V_ERR_PATH_LOOP", + "X509_V_ERR_SUITE_B_INVALID_VERSION", + "X509_V_ERR_SUITE_B_INVALID_ALGORITHM", + "X509_V_ERR_SUITE_B_INVALID_CURVE", + "X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM", + "X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED", + "X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256", + "X509_V_ERR_HOSTNAME_MISMATCH", + "X509_V_ERR_EMAIL_MISMATCH", + "X509_V_ERR_IP_ADDRESS_MISMATCH", + "X509_V_ERR_DANE_NO_MATCH", + "X509_V_ERR_EE_KEY_TOO_SMALL", + "X509_V_ERR_CA_KEY_TOO_SMALL", + "X509_V_ERR_CA_MD_TOO_WEAK", + "X509_V_ERR_INVALID_CALL", + "X509_V_ERR_STORE_LOOKUP", + "X509_V_ERR_NO_VALID_SCTS", + "X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION", + "X509_V_ERR_OCSP_VERIFY_NEEDED", + "X509_V_ERR_OCSP_VERIFY_FAILED", + "X509_V_ERR_OCSP_CERT_UNKNOWN", NULL }; @@ -390,7 +537,7 @@ return false; // not reached } -const char *Ssl::GetErrorName(Security::ErrorCode value) +const char *Ssl::GetErrorName(Security::ErrorCode value, const bool prefixRawCode) { if (TheSslErrors.empty()) loadSslErrorMap(); @@ -399,7 +546,9 @@ if (it != TheSslErrors.end()) return it->second->name; - return NULL; + static char tmpBuffer[128]; + snprintf(tmpBuffer, sizeof(tmpBuffer), "%s%d", prefixRawCode ? "SSL_ERR=" : "", (int)value); + return tmpBuffer; } bool @@ -529,21 +678,14 @@ */ const char *Ssl::ErrorDetail::err_code() const { - static char tmpBuffer[64]; // We can use the GetErrorName but using the detailEntry is faster, // so try it first. - const char *err = detailEntry.name.termedBuf(); + if (const char *err = detailEntry.name.termedBuf()) + return err; // error details not loaded yet or not defined in error_details.txt, // try the GetErrorName... - if (!err) - err = GetErrorName(error_no); - - if (!err) { - snprintf(tmpBuffer, 64, "%d", (int)error_no); - err = tmpBuffer; - } - return err; + return GetErrorName(error_no); } /** diff -u -r -N squid-4.11/src/ssl/ErrorDetail.h squid-4.12/src/ssl/ErrorDetail.h --- squid-4.11/src/ssl/ErrorDetail.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/ssl/ErrorDetail.h 2020-06-08 03:42:16.000000000 +1200 @@ -26,8 +26,9 @@ /// The Security::ErrorCode code of the error described by "name". Security::ErrorCode GetErrorCode(const char *name); -/// The string representation of the TLS error "value" -const char *GetErrorName(Security::ErrorCode value); +/// \return string representation of a known TLS error (or a raw error code) +/// \param prefixRawCode whether to prefix raw codes with "SSL_ERR=" +const char *GetErrorName(Security::ErrorCode value, const bool prefixRawCode = false); /// A short description of the TLS error "value" const char *GetErrorDescr(Security::ErrorCode value); diff -u -r -N squid-4.11/src/ssl/PeekingPeerConnector.cc squid-4.12/src/ssl/PeekingPeerConnector.cc --- squid-4.11/src/ssl/PeekingPeerConnector.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/ssl/PeekingPeerConnector.cc 2020-06-08 03:42:16.000000000 +1200 @@ -276,18 +276,32 @@ BIO *b = SSL_get_rbio(session.get()); Ssl::ServerBio *srvBio = static_cast(BIO_get_data(b)); - // In Peek mode, the ClientHello message sent to the server. If the - // server resuming a previous (spliced) SSL session with the client, - // then probably we are here because local SSL object does not know - // anything about the session being resumed. - // - if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) { - // we currently splice all resumed sessions unconditionally - // if (const bool spliceResumed = true) { - bypassCertValidator(); - checkForPeekAndSpliceMatched(Ssl::bumpSplice); - return; - // } // else fall through to find a matching ssl_bump action (with limited info) + if (srvBio->bumpMode() == Ssl::bumpPeek) { + auto bypassValidator = false; + if (srvBio->encryptedCertificates()) { + // it is pointless to peek at encrypted certificates + // + // we currently splice all sessions with encrypted certificates + // if (const auto spliceEncryptedCertificates = true) { + bypassValidator = true; + // } // else fall through to find a matching ssl_bump action (with limited info) + } else if (srvBio->resumingSession()) { + // In peek mode, the ClientHello message is forwarded to the server. + // If the server is resuming a previous (spliced) SSL session with + // the client, then probably we are here because our local SSL + // object does not know anything about the session being resumed. + // + // we currently splice all resumed sessions + // if (const auto spliceResumed = true) { + bypassValidator = true; + // } // else fall through to find a matching ssl_bump action (with limited info) + } + + if (bypassValidator) { + bypassCertValidator(); + checkForPeekAndSpliceMatched(Ssl::bumpSplice); + return; + } } // If we are in peek-and-splice mode and still we did not write to diff -u -r -N squid-4.11/src/ssl/PeekingPeerConnector.h squid-4.12/src/ssl/PeekingPeerConnector.h --- squid-4.11/src/ssl/PeekingPeerConnector.h 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/ssl/PeekingPeerConnector.h 2020-06-08 03:42:16.000000000 +1200 @@ -30,7 +30,6 @@ Security::PeerConnector(aServerConn, aCallback, alp, timeout), clientConn(aClientConn), splice(false), - resumingSession(false), serverCertificateHandled(false) { request = aRequest; @@ -75,7 +74,6 @@ Comm::ConnectionPointer clientConn; ///< TCP connection to the client AsyncCall::Pointer closeHandler; ///< we call this when the connection closed bool splice; ///< whether we are going to splice or not - bool resumingSession; ///< whether it is an SSL resuming session connection bool serverCertificateHandled; ///< whether handleServerCertificate() succeeded }; diff -u -r -N squid-4.11/src/store/id_rewriters/file/storeid_file_rewrite.8 squid-4.12/src/store/id_rewriters/file/storeid_file_rewrite.8 --- squid-4.11/src/store/id_rewriters/file/storeid_file_rewrite.8 2020-04-20 00:50:36.000000000 +1200 +++ squid-4.12/src/store/id_rewriters/file/storeid_file_rewrite.8 2020-06-09 19:27:17.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "STOREID_FILE_REWRITE 8" -.TH STOREID_FILE_REWRITE 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH STOREID_FILE_REWRITE 8 "2020-06-09" "perl v5.30.3" "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.11/src/store.cc squid-4.12/src/store.cc --- squid-4.11/src/store.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/store.cc 2020-06-08 03:42:16.000000000 +1200 @@ -917,7 +917,6 @@ int non_get; int not_entry_cachable; int wrong_content_length; - int negative_cached; int too_big; int too_small; int private_key; @@ -998,10 +997,6 @@ if (store_status == STORE_OK && EBIT_TEST(flags, ENTRY_BAD_LENGTH)) { debugs(20, 2, "StoreEntry::checkCachable: NO: wrong content-length"); ++store_check_cachable_hist.no.wrong_content_length; - } else if (EBIT_TEST(flags, ENTRY_NEGCACHED)) { - debugs(20, 3, "StoreEntry::checkCachable: NO: negative cached"); - ++store_check_cachable_hist.no.negative_cached; - return 0; /* avoid release call below */ } else if (!mem_obj || !getReply()) { // XXX: In bug 4131, we forgetHit() without mem_obj, so we need // this segfault protection, but how can we get such a HIT? @@ -1053,7 +1048,7 @@ storeAppendPrintf(sentry, "no.wrong_content_length\t%d\n", store_check_cachable_hist.no.wrong_content_length); storeAppendPrintf(sentry, "no.negative_cached\t%d\n", - store_check_cachable_hist.no.negative_cached); + 0); // TODO: Remove this backward compatibility hack. storeAppendPrintf(sentry, "no.missing_parts\t%d\n", store_check_cachable_hist.no.missing_parts); storeAppendPrintf(sentry, "no.too_big\t%d\n", @@ -1412,7 +1407,10 @@ #else expires = squid_curtime; #endif - EBIT_SET(flags, ENTRY_NEGCACHED); + if (expires > squid_curtime) { + EBIT_SET(flags, ENTRY_NEGCACHED); + debugs(20, 6, "expires = " << expires << " +" << (expires-squid_curtime) << ' ' << *this); + } } void diff -u -r -N squid-4.11/src/tests/stub_libanyp.cc squid-4.12/src/tests/stub_libanyp.cc --- squid-4.11/src/tests/stub_libanyp.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/tests/stub_libanyp.cc 2020-06-08 03:42:16.000000000 +1200 @@ -18,6 +18,7 @@ void AnyP::Uri::host(const char *) STUB static SBuf nil; const SBuf &AnyP::Uri::path() const STUB_RETVAL(nil) +void AnyP::Uri::addRelativePath(const char *) STUB const SBuf &AnyP::Uri::SlashPath() { static SBuf slash("/"); @@ -33,11 +34,9 @@ void urlInitialize() STUB const char *urlCanonicalFakeHttps(const HttpRequest *) STUB_RETVAL(nullptr) bool urlIsRelative(const char *) STUB_RETVAL(false) -char *urlMakeAbsolute(const HttpRequest *, const char *)STUB_RETVAL(nullptr) char *urlRInternal(const char *, unsigned short, const char *, const char *) STUB_RETVAL(nullptr) char *urlInternal(const char *, const char *) STUB_RETVAL(nullptr) int matchDomainName(const char *, const char *, uint) STUB_RETVAL(0) int urlCheckRequest(const HttpRequest *) STUB_RETVAL(0) -char *urlHostname(const char *) STUB_RETVAL(nullptr) void urlExtMethodConfigure() STUB diff -u -r -N squid-4.11/src/tests/stub_libsecurity.cc squid-4.12/src/tests/stub_libsecurity.cc --- squid-4.11/src/tests/stub_libsecurity.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/tests/stub_libsecurity.cc 2020-06-08 03:42:16.000000000 +1200 @@ -28,7 +28,7 @@ std::ostream &Security::operator <<(std::ostream &os, const Security::EncryptorAnswer &) STUB_RETVAL(os) #include "security/Handshake.h" -Security::HandshakeParser::HandshakeParser() STUB +Security::HandshakeParser::HandshakeParser(MessageSource) STUB bool Security::HandshakeParser::parseHello(const SBuf &) STUB_RETVAL(false) #include "security/KeyData.h" diff -u -r -N squid-4.11/src/tests/stub_StatHist.cc squid-4.12/src/tests/stub_StatHist.cc --- squid-4.11/src/tests/stub_StatHist.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/tests/stub_StatHist.cc 2020-06-08 03:42:16.000000000 +1200 @@ -16,7 +16,7 @@ void StatHist::dump(StoreEntry * sentry, StatHistBinDumper * bd) const STUB void StatHist::enumInit(unsigned int i) STUB_NOP -void StatHist::count(double d) STUB_NOP +void StatHist::count(double) {/* STUB_NOP */} double statHistDeltaMedian(const StatHist & A, const StatHist & B) STUB_RETVAL(0.0) double statHistDeltaPctile(const StatHist & A, const StatHist & B, double pctile) STUB_RETVAL(0.0) void StatHist::logInit(unsigned int i, double d1, double d2) STUB diff -u -r -N squid-4.11/src/urn.cc squid-4.12/src/urn.cc --- squid-4.11/src/urn.cc 2020-04-20 00:38:51.000000000 +1200 +++ squid-4.12/src/urn.cc 2020-06-08 03:42:16.000000000 +1200 @@ -370,7 +370,6 @@ { char *buf = xstrdup(inbuf); char *token; - char *host; url_entry *list; url_entry *old; int n = 32; @@ -389,24 +388,23 @@ safe_free(old); } - host = urlHostname(token); - - if (NULL == host) + AnyP::Uri uri; + if (!uri.parse(m, SBuf(token)) || !*uri.host()) continue; #if USE_ICMP - list[i].rtt = netdbHostRtt(host); + list[i].rtt = netdbHostRtt(uri.host()); if (0 == list[i].rtt) { - debugs(52, 3, "urnParseReply: Pinging " << host); - netdbPingSite(host); + debugs(52, 3, "Pinging " << uri.host()); + netdbPingSite(uri.host()); } #else list[i].rtt = 0; #endif - list[i].url = xstrdup(token); - list[i].host = xstrdup(host); + list[i].url = xstrdup(uri.absolute().c_str()); + list[i].host = xstrdup(uri.host()); // TODO: Use storeHas() or lock/unlock entry to avoid creating unlocked // ones. list[i].flags.cached = storeGetPublic(list[i].url, m) ? 1 : 0; diff -u -r -N squid-4.11/tools/CharacterSet.cc squid-4.12/tools/CharacterSet.cc --- squid-4.11/tools/CharacterSet.cc 2020-04-20 00:50:38.000000000 +1200 +++ squid-4.12/tools/CharacterSet.cc 2020-06-09 19:27:19.000000000 +1200 @@ -51,6 +51,13 @@ } CharacterSet & +CharacterSet::remove(const unsigned char c) +{ + chars_[static_cast(c)] = 0; + return *this; +} + +CharacterSet & CharacterSet::addRange(unsigned char low, unsigned char high) { //manual loop splitting is needed to cover case where high is 255 diff -u -r -N squid-4.11/tools/helper-mux/helper-mux.8 squid-4.12/tools/helper-mux/helper-mux.8 --- squid-4.11/tools/helper-mux/helper-mux.8 2020-04-20 00:50:38.000000000 +1200 +++ squid-4.12/tools/helper-mux/helper-mux.8 2020-06-09 19:27:19.000000000 +1200 @@ -1,4 +1,4 @@ -.\" Automatically generated by Pod::Man 4.10 (Pod::Simple 3.35) +.\" Automatically generated by Pod::Man 4.11 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== @@ -133,7 +133,7 @@ .\" ======================================================================== .\" .IX Title "HELPER-MUX 8" -.TH HELPER-MUX 8 "2020-04-19" "perl v5.28.1" "User Contributed Perl Documentation" +.TH HELPER-MUX 8 "2020-06-09" "perl v5.30.3" "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