From 1784615d361ca05b6fc074e6870e945deec3a427 Mon Sep 17 00:00:00 2001 From: Christian Lachner Date: Wed, 19 Jun 2019 14:34:29 +0200 Subject: [PATCH] haproxy: Update HAProxy to v1.8.20 - Update haproxy download URL and hash - Add new patches (see https://www.haproxy.org/bugs/bugs-1.8.20.html) - Make halog use our CFLAGS - Update statically linked LUA to v5.3.5 Signed-off-by: Christian Lachner --- net/haproxy/Makefile | 64 +- net/haproxy/get-latest-patches.sh | 27 + ...tp_req_ctr-only-one-time-per-request.patch | 40 + ...t-SSL_ERROR_SYSCALL-as-unrecovarable.patch | 61 -- ...ion-for-reading-on-SSL_ERROR_SYSCALL.patch | 63 -- ...n-tunnel-mode-as-earlier-as-possible.patch | 69 -- ...le-ssl_bc_-fetch-keywords-are-broken.patch | 103 -- ...-previous-frag-frame-but-len-changed.patch | 83 ++ ...o-pass-frag_ctx-info-during-encoding.patch | 71 ++ ...ity-Typos-and-fix-the-reject-example.patch | 38 + ...header-is-NULL-dont-try-to-strdup-it.patch | 36 + ...-last-changelog-date-in-haproxy-spec.patch | 23 + ...-segfault-during-show-map-acl-on-CLI.patch | 67 ++ ...er-of-consecutive-accepts-is-handled.patch | 79 ++ ...-maxaccept-during-the-config-parsing.patch | 44 + ...r--maxaccept-when-nbproc-is-set-to-1.patch | 34 + ...NOR-threads-Implement-HA_ATOMIC_LOAD.patch | 54 + ...range-Make-the-ring-buffer-lock-free.patch | 116 +++ ...the-smp-direction-for-cookie-and-hdr.patch | 81 ++ ...M-dns-make-the-port-numbers-unsigned.patch | 37 + ...e-the-SPOE-applet-after-releasing-it.patch | 44 + net/haproxy/patches/015-DOC-fix-typos.patch | 925 ++++++++++++++++++ ...mory-leak-when-disabling-compression.patch | 53 + ...l-fix-latest-LibreSSL-reg-test-error.patch | 46 + ...ed-server-is-not-full-on-second-pass.patch | 54 + ...x-http-request-reject-when-not-final.patch | 43 + ...hard-stop-after-perform-a-clean-exit.patch | 71 ++ ...ix-multiple-handshake-polling-issues.patch | 133 +++ ...-is-always-valid-when-accessing-vars.patch | 193 ++++ ...-unset-var-action-support-conditions.patch | 44 + ...the-connection-timeout-is-always-set.patch | 73 ++ ...status-for-deny-in-the-error-message.patch | 34 + ...OR-doc-Remove--Ds-option-in-man-page.patch | 30 + ...oc-add-master-worker-in-the-man-page.patch | 55 ++ ...pt-Encoding-for-compressed-responses.patch | 249 +++++ ...ssl.patch => 029-deprecated-openssl.patch} | 25 +- 36 files changed, 2917 insertions(+), 345 deletions(-) create mode 100755 net/haproxy/get-latest-patches.sh create mode 100644 net/haproxy/patches/000-BUG-MINOR-http-Call-stream_inc_be_http_req_ctr-only-one-time-per-request.patch delete mode 100644 net/haproxy/patches/0001-BUG-MEDIUM-ssl-Dont-always-treat-SSL_ERROR_SYSCALL-as-unrecovarable.patch delete mode 100644 net/haproxy/patches/0002-BUG-MEDIUM-ssl-Shutdown-the-connection-for-reading-on-SSL_ERROR_SYSCALL.patch delete mode 100644 net/haproxy/patches/0003-BUG-MEDIUM-http-Switch-the-HTTP-response-in-tunnel-mode-as-earlier-as-possible.patch delete mode 100644 net/haproxy/patches/0004-BUG-MEDIUM-ssl-sample-ssl_bc_-fetch-keywords-are-broken.patch create mode 100644 net/haproxy/patches/001-BUG-MEDIUM-spoe-arg-len-encoded-in-previous-frag-frame-but-len-changed.patch create mode 100644 net/haproxy/patches/002-MINOR-spoe-Use-the-sample-context-to-pass-frag_ctx-info-during-encoding.patch create mode 100644 net/haproxy/patches/003-DOC-contrib-modsecurity-Typos-and-fix-the-reject-example.patch create mode 100644 net/haproxy/patches/004-BUG-MEDIUM-contrib-modsecurity-If-host-header-is-NULL-dont-try-to-strdup-it.patch create mode 100644 net/haproxy/patches/005-MINOR-examples-Use-right-locale-for-the-last-changelog-date-in-haproxy-spec.patch create mode 100644 net/haproxy/patches/006-BUG-MAJOR-map-acl-real-fix-segfault-during-show-map-acl-on-CLI.patch create mode 100644 net/haproxy/patches/007-BUG-MEDIUM-listener-Fix-how-unlimited-number-of-consecutive-accepts-is-handled.patch create mode 100644 net/haproxy/patches/008-MINOR-config-Test-validity-of-tune-maxaccept-during-the-config-parsing.patch create mode 100644 net/haproxy/patches/009-CLEANUP-config-Dont-alter-listener--maxaccept-when-nbproc-is-set-to-1.patch create mode 100644 net/haproxy/patches/010-MINOR-threads-Implement-HA_ATOMIC_LOAD.patch create mode 100644 net/haproxy/patches/011-BUG-MEDIUM-port_range-Make-the-ring-buffer-lock-free.patch create mode 100644 net/haproxy/patches/012-BUG-MINOR-http_fetch-Rely-on-the-smp-direction-for-cookie-and-hdr.patch create mode 100644 net/haproxy/patches/013-BUG-MEDIUM-dns-make-the-port-numbers-unsigned.patch create mode 100644 net/haproxy/patches/014-BUG-MEDIUM-spoe-Dont-use-the-SPOE-applet-after-releasing-it.patch create mode 100644 net/haproxy/patches/015-DOC-fix-typos.patch create mode 100644 net/haproxy/patches/016-BUG-MINOR-ssl_sock-Fix-memory-leak-when-disabling-compression.patch create mode 100644 net/haproxy/patches/017-BUILD-ssl-fix-latest-LibreSSL-reg-test-error.patch create mode 100644 net/haproxy/patches/018-BUG-MAJOR-lb-threads-make-sure-the-avoided-server-is-not-full-on-second-pass.patch create mode 100644 net/haproxy/patches/019-BUG-MEDIUM-http-fix-http-request-reject-when-not-final.patch create mode 100644 net/haproxy/patches/020-BUG-MINOR-deinit-threads-make-hard-stop-after-perform-a-clean-exit.patch create mode 100644 net/haproxy/patches/021-BUG-MEDIUM-connection-fix-multiple-handshake-polling-issues.patch create mode 100644 net/haproxy/patches/022-BUG-MEDIUM-vars-make-sure-the-scope-is-always-valid-when-accessing-vars.patch create mode 100644 net/haproxy/patches/023-BUG-MEDIUM-vars-make-the-tcp-http-unset-var-action-support-conditions.patch create mode 100644 net/haproxy/patches/024-BUG-MEDIUM-mux-h2-make-sure-the-connection-timeout-is-always-set.patch create mode 100644 net/haproxy/patches/025-BUG-MINOR-http-rules-mention-deny_status-for-deny-in-the-error-message.patch create mode 100644 net/haproxy/patches/026-MINOR-doc-Remove--Ds-option-in-man-page.patch create mode 100644 net/haproxy/patches/027-MINOR-doc-add-master-worker-in-the-man-page.patch create mode 100644 net/haproxy/patches/028-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch rename net/haproxy/patches/{012-deprecated-openssl.patch => 029-deprecated-openssl.patch} (83%) diff --git a/net/haproxy/Makefile b/net/haproxy/Makefile index 9968577a7d..5d10824a02 100644 --- a/net/haproxy/Makefile +++ b/net/haproxy/Makefile @@ -1,6 +1,7 @@ # # Copyright (C) 2010-2016 OpenWrt.org # Copyright (C) 2009-2016 Thomas Heil +# Copyright (C) 2018 Christian Lachner # # This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. @@ -9,16 +10,17 @@ include $(TOPDIR)/rules.mk PKG_NAME:=haproxy -PKG_VERSION:=1.8.4 -PKG_RELEASE:=02 +PKG_VERSION:=1.8.20 +PKG_RELEASE:=1 PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://www.haproxy.org/download/1.8/src/ -PKG_HASH:=e305b0a4e7dec08072841eef6ac6dcd1b5586b1eff09c2d51e152a912e8884a6 +PKG_HASH:=3228f78d5fe1dfbaccf41bf387e36b08eeef6e16330053cafde5fa303e262b16 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION) PKG_LICENSE:=GPL-2.0 -MAINTAINER:=Thomas Heil +MAINTAINER:=Thomas Heil , \ + Christian Lachner include $(INCLUDE_DIR)/package.mk @@ -30,17 +32,17 @@ define Package/haproxy/Default URL:=https://www.haproxy.org/ endef -define Download/lua534 - FILE:=lua-5.3.4.tar.gz +define Download/lua535 + FILE:=lua-5.3.5.tar.gz URL:=https://www.lua.org/ftp/ - HASH:=f681aa518233bc407e23acf0f5887c884f17436f000d453b2491a9f11a52400c + HASH:=0c2eed3f960446e1a3e4b9a1ca2f3ff893b6ce41942cf54d5dd59ab4b3b058ac endef define Build/Prepare $(call Build/Prepare/Default) ifeq ($(ENABLE_LUA),y) - tar -zxvf $(DL_DIR)/lua-5.3.4.tar.gz -C $(PKG_BUILD_DIR) - ln -s $(PKG_BUILD_DIR)/lua-5.3.4 $(PKG_BUILD_DIR)/lua + tar -zxvf $(DL_DIR)/lua-5.3.5.tar.gz -C $(PKG_BUILD_DIR) + ln -s $(PKG_BUILD_DIR)/lua-5.3.5 $(PKG_BUILD_DIR)/lua endif endef @@ -54,7 +56,6 @@ endef define Package/haproxy DEPENDS+= +libpcre +libltdl +zlib +libpthread +libopenssl +libncursesw +libreadline +libatomic +@OPENSSL_WITH_COMPRESSION +@OPENSSL_WITH_DTLS +@OPENSSL_ENGINE_CRYPTO - TITLE+= (with SSL support) VARIANT:=ssl $(call Package/haproxy/Default) @@ -69,11 +70,6 @@ $(call Package/haproxy/Default/description) This package is built with SSL and LUA support. endef -define Package/haproxy/config - select CONFIG_OPENSSL_WITH_DEPRECATED - $(call Package/haproxy/Default/config) -endef - define Package/haproxy-nossl TITLE+= (without SSL support) VARIANT:=nossl @@ -94,22 +90,11 @@ endef ENABLE_LUA:=y ENABLE_REGPARM:=n -ifeq ($(CONFIG_mips),y) - ENABLE_LUA:=n -endif -ifeq ($(CONFIG_mipsel),y) - ENABLE_LUA:=n -endif - ifeq ($(CONFIG_TARGET_x86),y) ENABLE_REGPARM:=y endif -ifeq ($(CONFIG_avr32),y) - LINUX_TARGET:=linux26 -else - LINUX_TARGET:=linux2628 -endif +LINUX_TARGET:=linux2628 ifeq ($(BUILD_VARIANT),ssl) ADDON+=USE_OPENSSL=1 @@ -118,9 +103,9 @@ endif ifeq ($(ENABLE_LUA),y) ADDON+=USE_LUA=1 - ADDON+=LUA_LIB_NAME="lua534" - ADDON+=LUA_INC="$(STAGING_DIR)/lua-5.3.4/include" - ADDON+=LUA_LIB="$(STAGING_DIR)/lua-5.3.4/lib" + ADDON+=LUA_LIB_NAME="lua535" + ADDON+=LUA_INC="$(STAGING_DIR)/lua-5.3.5/include" + ADDON+=LUA_LIB="$(STAGING_DIR)/lua-5.3.5/lib" endif ifeq ($(ENABLE_REGPARM),y) @@ -130,14 +115,14 @@ endif ifeq ($(ENABLE_LUA),y) define Build/Compile/lua $(MAKE) TARGET=$(LINUX_TARGET) -C $(PKG_BUILD_DIR)/lua \ - INSTALL_TOP="$(STAGING_DIR)/lua-5.3.4/" \ + INSTALL_TOP="$(STAGING_DIR)/lua-5.3.5/" \ CC="$(TARGET_CC)" \ CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \ LDFLAGS="$(TARGET_LDFLAGS) -lncurses -lreadline" \ LD="$(TARGET_LD)" \ linux install - mv $(STAGING_DIR)/lua-5.3.4/lib/liblua.a $(STAGING_DIR)/lua-5.3.4/lib/liblua534.a + mv $(STAGING_DIR)/lua-5.3.5/lib/liblua.a $(STAGING_DIR)/lua-5.3.5/lib/liblua535.a endef endif @@ -147,27 +132,28 @@ define Build/Compile DESTDIR="$(PKG_INSTALL_DIR)" \ CC="$(TARGET_CC)" \ PCREDIR="$(STAGING_DIR)/usr/" \ - SMALL_OPTS="-DBUFSIZE=16384 -DMAXREWRITE=1030 -DSYSTEM_MAXCONN=165530 " \ + SMALL_OPTS="-DBUFSIZE=16384 -DMAXREWRITE=1030 -DSYSTEM_MAXCONN=165530" \ USE_LINUX_TPROXY=1 USE_LINUX_SPLICE=1 USE_TFO=1 \ USE_ZLIB=yes USE_PCRE=1 USE_PCRE_JIT=1 USE_GETADDRINFO=1 \ - VERSION="$(PKG_VERSION)-patch$(PKG_RELEASE)" \ + VERSION="$(PKG_VERSION)" SUBVERS="-$(PKG_RELEASE)" \ + VERDATE="$(shell date -d @$(SOURCE_DATE_EPOCH) '+%Y/%m/%d')" IGNOREGIT=1 \ $(ADDON) \ + CFLAGS="$(TARGET_CFLAGS)" \ LD="$(TARGET_CC)" \ - LDFLAGS="$(TARGET_LDFLAGS) -latomic" \ - IGNOREGIT=1 + LDFLAGS="$(TARGET_LDFLAGS) -latomic" $(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR) \ DESTDIR="$(PKG_INSTALL_DIR)" \ LD="$(TARGET_CC)" \ - LDFLAGS="$(TARGET_LDFLAGS)" \ + LDFLAGS="$(TARGET_LDFLAGS)" \ $(MAKE_FLAGS) \ install $(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR)/contrib/halog \ DESTDIR="$(PKG_INSTALL_DIR)" \ $(MAKE_FLAGS) \ + OPTIMIZE="$(TARGET_CFLAGS)" \ ADDLIB="-lcrypto" \ - VERSION="$(PKG_VERSION)-patch$(PKG_RELEASE)" \ halog endef @@ -200,7 +186,7 @@ define Package/halog/install $(INSTALL_BIN) $(PKG_BUILD_DIR)/contrib/halog/halog $(1)/usr/bin/ endef -$(eval $(call Download,lua534)) +$(eval $(call Download,lua535)) $(eval $(call BuildPackage,haproxy)) $(eval $(call BuildPackage,halog)) $(eval $(call BuildPackage,haproxy-nossl)) diff --git a/net/haproxy/get-latest-patches.sh b/net/haproxy/get-latest-patches.sh new file mode 100755 index 0000000000..f4b683ecf0 --- /dev/null +++ b/net/haproxy/get-latest-patches.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +CLONEURL=http://git.haproxy.org/git/haproxy-1.8.git +BASE_TAG=v1.8.20 +TMP_REPODIR=tmprepo +PATCHESDIR=patches + +if test -d "${TMP_REPODIR}"; then rm -rf "${TMP_REPODIR}"; fi + +git clone "${CLONEURL}" "${TMP_REPODIR}" + +printf "Cleaning patches\n" +find ${PATCHESDIR} -type f -name "*.patch" -exec rm -f "{}" \; + +i=0 +for cid in $(git -C "${TMP_REPODIR}" rev-list ${BASE_TAG}..HEAD | tac); do + filename="$(printf "%03d" $i)-$(git -C "${TMP_REPODIR}" log --format=%s -n 1 $cid | sed -e"s/[()']//g" -e's/[^_a-zA-Z0-9+-]\+/-/g' -e's/-$//').patch" + printf "Creating ${filename}\n" + git -C "${TMP_REPODIR}" show $cid > "${PATCHESDIR}/$filename" + git add "${PATCHESDIR}/$filename" + let i++ +done + +rm -rf "${TMP_REPODIR}" + +printf "finished\n" + diff --git a/net/haproxy/patches/000-BUG-MINOR-http-Call-stream_inc_be_http_req_ctr-only-one-time-per-request.patch b/net/haproxy/patches/000-BUG-MINOR-http-Call-stream_inc_be_http_req_ctr-only-one-time-per-request.patch new file mode 100644 index 0000000000..4449df1ccd --- /dev/null +++ b/net/haproxy/patches/000-BUG-MINOR-http-Call-stream_inc_be_http_req_ctr-only-one-time-per-request.patch @@ -0,0 +1,40 @@ +commit cf2f1243373be97249567ffd259e975cc87068b8 +Author: Christopher Faulet +Date: Mon Apr 29 13:12:02 2019 +0200 + + BUG/MINOR: http: Call stream_inc_be_http_req_ctr() only one time per request + + The function stream_inc_be_http_req_ctr() is called at the beginning of the + analysers AN_REQ_HTTP_PROCESS_FE/BE. It as an effect only on the backend. But we + must be careful to call it only once. If the processing of HTTP rules is + interrupted in the middle, when the analyser is resumed, we must not call it + again. Otherwise, the tracked counters of the backend are incremented several + times. + + This bug was reported in github. See issue #74. + + This fix should be backported as far as 1.6. + + (cherry picked from commit 1907ccc2f75b78ace1ee4acdfc60d48a76e3decd) + Signed-off-by: Christopher Faulet + (cherry picked from commit 319921866ea9ecc46215fea5679abc8efdfcbea5) + [cf: HTX part was removed] + Signed-off-by: Christopher Faulet + +diff --git a/src/proto_http.c b/src/proto_http.c +index ccacd6a4..556cabad 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -3420,8 +3420,10 @@ int http_process_req_common(struct stream *s, struct channel *req, int an_bit, s + req->buf->i, + req->analysers); + +- /* just in case we have some per-backend tracking */ +- stream_inc_be_http_req_ctr(s); ++ /* just in case we have some per-backend tracking. Only called the first ++ * execution of the analyser. */ ++ if (!s->current_rule || s->current_rule_list != &px->http_req_rules) ++ stream_inc_be_http_req_ctr(s); + + /* evaluate http-request rules */ + if (!LIST_ISEMPTY(&px->http_req_rules)) { diff --git a/net/haproxy/patches/0001-BUG-MEDIUM-ssl-Dont-always-treat-SSL_ERROR_SYSCALL-as-unrecovarable.patch b/net/haproxy/patches/0001-BUG-MEDIUM-ssl-Dont-always-treat-SSL_ERROR_SYSCALL-as-unrecovarable.patch deleted file mode 100644 index 93b51dc40d..0000000000 --- a/net/haproxy/patches/0001-BUG-MEDIUM-ssl-Dont-always-treat-SSL_ERROR_SYSCALL-as-unrecovarable.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 2fcd544272a5498ffa49544e9f06b51bc93e55d1 Mon Sep 17 00:00:00 2001 -From: Olivier Houchard -Date: Tue, 13 Feb 2018 15:17:23 +0100 -Subject: [PATCH] BUG/MEDIUM: ssl: Don't always treat SSL_ERROR_SYSCALL as - unrecovarable. - -Bart Geesink reported some random errors appearing under the form of -termination flags SD in the logs for connections involving SSL traffic -to reach the servers. - -Tomek Gacek and Mateusz Malek finally narrowed down the problem to commit -c2aae74 ("MEDIUM: ssl: Handle early data with OpenSSL 1.1.1"). It happens -that the special case of SSL_ERROR_SYSCALL isn't handled anymore since -this commit. - -SSL_read() might return <= 0, and SSL_get_erro() return SSL_ERROR_SYSCALL, -without meaning the connection is gone. Before flagging the connection -as in error, check the errno value. - -This should be backported to 1.8. - -(cherry picked from commit 7e2e505006feb8f3b4a7f9e0ac5e89b5a8c4895e) -Signed-off-by: Willy Tarreau ---- - src/ssl_sock.c | 9 ++++++++- - 1 file changed, 8 insertions(+), 1 deletion(-) - -diff --git a/src/ssl_sock.c b/src/ssl_sock.c -index aecf3dd..f118724 100644 ---- a/src/ssl_sock.c -+++ b/src/ssl_sock.c -@@ -5437,6 +5437,12 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun - break; - } else if (ret == SSL_ERROR_ZERO_RETURN) - goto read0; -+ /* For SSL_ERROR_SYSCALL, make sure the error is -+ * unrecoverable before flagging the connection as -+ * in error. -+ */ -+ if (ret == SSL_ERROR_SYSCALL && (!errno || errno == EAGAIN)) -+ goto clear_ssl_error; - /* otherwise it's a real error */ - goto out_error; - } -@@ -5451,11 +5457,12 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun - conn_sock_read0(conn); - goto leave; - out_error: -+ conn->flags |= CO_FL_ERROR; -+clear_ssl_error: - /* Clear openssl global errors stack */ - ssl_sock_dump_errors(conn); - ERR_clear_error(); - -- conn->flags |= CO_FL_ERROR; - goto leave; - } - --- -1.7.10.4 - diff --git a/net/haproxy/patches/0002-BUG-MEDIUM-ssl-Shutdown-the-connection-for-reading-on-SSL_ERROR_SYSCALL.patch b/net/haproxy/patches/0002-BUG-MEDIUM-ssl-Shutdown-the-connection-for-reading-on-SSL_ERROR_SYSCALL.patch deleted file mode 100644 index 22274d3669..0000000000 --- a/net/haproxy/patches/0002-BUG-MEDIUM-ssl-Shutdown-the-connection-for-reading-on-SSL_ERROR_SYSCALL.patch +++ /dev/null @@ -1,63 +0,0 @@ -From f7fa1d461aa71bbc8a6c23fdcfc305f2e52ce5dd Mon Sep 17 00:00:00 2001 -From: Christopher Faulet -Date: Mon, 19 Feb 2018 14:25:15 +0100 -Subject: [PATCH] BUG/MEDIUM: ssl: Shutdown the connection for reading on - SSL_ERROR_SYSCALL - -When SSL_read returns SSL_ERROR_SYSCALL and errno is unset or set to EAGAIN, the -connection must be shut down for reading. Else, the connection loops infinitly, -consuming all the CPU. - -The bug was introduced in the commit 7e2e50500 ("BUG/MEDIUM: ssl: Don't always -treat SSL_ERROR_SYSCALL as unrecovarable."). This patch must be backported in -1.8 too. - -(cherry picked from commit 4ac77a98cda3d0f9b1d9de7bbbda2c91357f0767) -Signed-off-by: Willy Tarreau ---- - src/ssl_sock.c | 14 ++++++++------ - 1 file changed, 8 insertions(+), 6 deletions(-) - -diff --git a/src/ssl_sock.c b/src/ssl_sock.c -index f118724..a065bbb 100644 ---- a/src/ssl_sock.c -+++ b/src/ssl_sock.c -@@ -5437,10 +5437,9 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun - break; - } else if (ret == SSL_ERROR_ZERO_RETURN) - goto read0; -- /* For SSL_ERROR_SYSCALL, make sure the error is -- * unrecoverable before flagging the connection as -- * in error. -- */ -+ /* For SSL_ERROR_SYSCALL, make sure to clear the error -+ * stack before shutting down the connection for -+ * reading. */ - if (ret == SSL_ERROR_SYSCALL && (!errno || errno == EAGAIN)) - goto clear_ssl_error; - /* otherwise it's a real error */ -@@ -5453,16 +5452,19 @@ static int ssl_sock_to_buf(struct connection *conn, struct buffer *buf, int coun - conn_cond_update_sock_polling(conn); - return done; - -+ clear_ssl_error: -+ /* Clear openssl global errors stack */ -+ ssl_sock_dump_errors(conn); -+ ERR_clear_error(); - read0: - conn_sock_read0(conn); - goto leave; -+ - out_error: - conn->flags |= CO_FL_ERROR; --clear_ssl_error: - /* Clear openssl global errors stack */ - ssl_sock_dump_errors(conn); - ERR_clear_error(); -- - goto leave; - } - --- -1.7.10.4 - diff --git a/net/haproxy/patches/0003-BUG-MEDIUM-http-Switch-the-HTTP-response-in-tunnel-mode-as-earlier-as-possible.patch b/net/haproxy/patches/0003-BUG-MEDIUM-http-Switch-the-HTTP-response-in-tunnel-mode-as-earlier-as-possible.patch deleted file mode 100644 index 446a6107db..0000000000 --- a/net/haproxy/patches/0003-BUG-MEDIUM-http-Switch-the-HTTP-response-in-tunnel-mode-as-earlier-as-possible.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 8a5949f2d74c3a3a6c6da25449992c312b183ef3 Mon Sep 17 00:00:00 2001 -From: Christopher Faulet -Date: Fri, 2 Feb 2018 15:54:15 +0100 -Subject: [PATCH] BUG/MEDIUM: http: Switch the HTTP response in tunnel mode as - earlier as possible - -When the body length is undefined (no Content-Length or Transfer-Encoding -headers), The reponse remains in ending mode, waiting the request is done. So, -most of time this is not a problem because the resquest is done before the -response. But when a client sends data to a server that replies without waiting -all the data, it is really not desirable to wait the end of the request to -finish the response. - -This bug was introduced when the tunneling of the request and the reponse was -refactored, in commit 4be980391 ("MINOR: http: Switch requests/responses in -TUNNEL mode only by checking txn flag"). - -This patch should be backported in 1.8 and 1.7. - -(cherry picked from commit fd04fcf5edb0a24cd29ce8f4d4dc2aa3a0e2e82c) -Signed-off-by: Willy Tarreau ---- - src/proto_http.c | 15 +++++---------- - 1 file changed, 5 insertions(+), 10 deletions(-) - -diff --git a/src/proto_http.c b/src/proto_http.c -index 64bd410..29880ea 100644 ---- a/src/proto_http.c -+++ b/src/proto_http.c -@@ -4634,16 +4634,8 @@ int http_sync_res_state(struct stream *s) - * let's enforce it now that we're not expecting any new - * data to come. The caller knows the stream is complete - * once both states are CLOSED. -- * -- * However, there is an exception if the response length -- * is undefined. In this case, we switch in TUNNEL mode. - */ -- if (!(txn->rsp.flags & HTTP_MSGF_XFER_LEN)) { -- channel_auto_read(chn); -- txn->rsp.msg_state = HTTP_MSG_TUNNEL; -- chn->flags |= CF_NEVER_WAIT; -- } -- else if (!(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) { -+ if (!(chn->flags & (CF_SHUTW|CF_SHUTW_NOW))) { - channel_shutr_now(chn); - channel_shutw_now(chn); - } -@@ -6241,6 +6233,8 @@ http_msg_forward_body(struct stream *s, struct http_msg *msg) - /* The server still sending data that should be filtered */ - if (!(chn->flags & CF_SHUTR) && HAS_DATA_FILTERS(s, chn)) - goto missing_data_or_waiting; -+ msg->msg_state = HTTP_MSG_TUNNEL; -+ goto ending; - } - - msg->msg_state = HTTP_MSG_ENDING; -@@ -6262,7 +6256,8 @@ http_msg_forward_body(struct stream *s, struct http_msg *msg) - /* default_ret */ 1, - /* on_error */ goto error, - /* on_wait */ goto waiting); -- msg->msg_state = HTTP_MSG_DONE; -+ if (msg->msg_state == HTTP_MSG_ENDING) -+ msg->msg_state = HTTP_MSG_DONE; - return 1; - - missing_data_or_waiting: --- -1.7.10.4 - diff --git a/net/haproxy/patches/0004-BUG-MEDIUM-ssl-sample-ssl_bc_-fetch-keywords-are-broken.patch b/net/haproxy/patches/0004-BUG-MEDIUM-ssl-sample-ssl_bc_-fetch-keywords-are-broken.patch deleted file mode 100644 index 3e81fca4fa..0000000000 --- a/net/haproxy/patches/0004-BUG-MEDIUM-ssl-sample-ssl_bc_-fetch-keywords-are-broken.patch +++ /dev/null @@ -1,103 +0,0 @@ -From 7ccf7c9791f2b2329f3940d1347618af3a77bebc Mon Sep 17 00:00:00 2001 -From: Emeric Brun -Date: Mon, 19 Feb 2018 15:59:48 +0100 -Subject: [PATCH] BUG/MEDIUM: ssl/sample: ssl_bc_* fetch keywords are broken. - -Since the split between connections and conn-stream objects, this -keywords are broken. - -This patch must be backported in 1.8 - -(cherry picked from commit eb8def9f34c37537d56a69fcd211d4c4c8006bea) -Signed-off-by: Willy Tarreau ---- - src/ssl_sock.c | 31 ++++++++++++++----------------- - 1 file changed, 14 insertions(+), 17 deletions(-) - -diff --git a/src/ssl_sock.c b/src/ssl_sock.c -index 4d0d5db..d832d76 100644 ---- a/src/ssl_sock.c -+++ b/src/ssl_sock.c -@@ -6565,8 +6565,8 @@ smp_fetch_ssl_x_key_alg(const struct arg *args, struct sample *smp, const char * - static int - smp_fetch_ssl_fc(const struct arg *args, struct sample *smp, const char *kw, void *private) - { -- struct connection *conn = objt_conn((kw[4] != 'b') ? smp->sess->origin : -- smp->strm ? smp->strm->si[1].end : NULL); -+ struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) : -+ smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - - smp->data.type = SMP_T_BOOL; - smp->data.u.sint = (conn && conn->xprt == &ssl_sock); -@@ -6610,8 +6610,8 @@ smp_fetch_ssl_fc_is_resumed(const struct arg *args, struct sample *smp, const ch - static int - smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char *kw, void *private) - { -- struct connection *conn = objt_conn((kw[4] != 'b') ? smp->sess->origin : -- smp->strm ? smp->strm->si[1].end : NULL); -+ struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) : -+ smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - - smp->flags = 0; - if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock) -@@ -6636,9 +6636,8 @@ smp_fetch_ssl_fc_cipher(const struct arg *args, struct sample *smp, const char * - static int - smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private) - { -- struct connection *conn = objt_conn((kw[4] != 'b') ? smp->sess->origin : -- smp->strm ? smp->strm->si[1].end : NULL); -- -+ struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) : -+ smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - int sint; - - smp->flags = 0; -@@ -6661,8 +6660,8 @@ smp_fetch_ssl_fc_alg_keysize(const struct arg *args, struct sample *smp, const c - static int - smp_fetch_ssl_fc_use_keysize(const struct arg *args, struct sample *smp, const char *kw, void *private) - { -- struct connection *conn = objt_conn((kw[4] != 'b') ? smp->sess->origin : -- smp->strm ? smp->strm->si[1].end : NULL); -+ struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) : -+ smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - - smp->flags = 0; - if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock) -@@ -6732,8 +6731,8 @@ smp_fetch_ssl_fc_alpn(const struct arg *args, struct sample *smp, const char *kw - static int - smp_fetch_ssl_fc_protocol(const struct arg *args, struct sample *smp, const char *kw, void *private) - { -- struct connection *conn = objt_conn((kw[4] != 'b') ? smp->sess->origin : -- smp->strm ? smp->strm->si[1].end : NULL); -+ struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) : -+ smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - - smp->flags = 0; - if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock) -@@ -6758,9 +6757,8 @@ static int - smp_fetch_ssl_fc_session_id(const struct arg *args, struct sample *smp, const char *kw, void *private) - { - #if OPENSSL_VERSION_NUMBER > 0x0090800fL -- struct connection *conn = objt_conn((kw[4] != 'b') ? smp->sess->origin : -- smp->strm ? smp->strm->si[1].end : NULL); -- -+ struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) : -+ smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - SSL_SESSION *ssl_sess; - - smp->flags = SMP_F_CONST; -@@ -6902,9 +6900,8 @@ static int - smp_fetch_ssl_fc_unique_id(const struct arg *args, struct sample *smp, const char *kw, void *private) - { - #if OPENSSL_VERSION_NUMBER > 0x0090800fL -- struct connection *conn = objt_conn((kw[4] != 'b') ? smp->sess->origin : -- smp->strm ? smp->strm->si[1].end : NULL); -- -+ struct connection *conn = (kw[4] != 'b') ? objt_conn(smp->sess->origin) : -+ smp->strm ? cs_conn(objt_cs(smp->strm->si[1].end)) : NULL; - int finished_len; - struct chunk *finished_trash; - --- -1.7.10.4 - diff --git a/net/haproxy/patches/001-BUG-MEDIUM-spoe-arg-len-encoded-in-previous-frag-frame-but-len-changed.patch b/net/haproxy/patches/001-BUG-MEDIUM-spoe-arg-len-encoded-in-previous-frag-frame-but-len-changed.patch new file mode 100644 index 0000000000..9ef9507652 --- /dev/null +++ b/net/haproxy/patches/001-BUG-MEDIUM-spoe-arg-len-encoded-in-previous-frag-frame-but-len-changed.patch @@ -0,0 +1,83 @@ +commit c1620a52a3def02b4837376385c416c03ca874c4 +Author: Kevin Zhu +Date: Fri Apr 26 14:00:01 2019 +0800 + + BUG/MEDIUM: spoe: arg len encoded in previous frag frame but len changed + + Fragmented arg will do fetch at every encode time, each fetch may get + different result if SMP_F_MAY_CHANGE, for example res.payload, but + the length already encoded in first fragment of the frame, that will + cause SPOA decode failed and waste resources. + + This patch must be backported to 1.9 and 1.8. + + (cherry picked from commit f7f54280c8106e92a55243f5d60f8587e79602d1) + Signed-off-by: Christopher Faulet + (cherry picked from commit 3a838e526cdbc00ded5362e66f1ef3a441abc3c1) + Signed-off-by: Christopher Faulet + +diff --git a/include/proto/spoe.h b/include/proto/spoe.h +index 002cf7d7..2cdca10b 100644 +--- a/include/proto/spoe.h ++++ b/include/proto/spoe.h +@@ -121,7 +121,7 @@ spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len) + * many bytes has been encoded. If <*off> is zero at the end, it means that all + * data has been encoded. */ + static inline int +-spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end) ++spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char **buf, char *end) + { + char *p = *buf; + int ret; +@@ -183,15 +183,16 @@ spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end) + ret = spoe_encode_frag_buffer(chk->str, chk->len, &p, end); + if (ret == -1) + return -1; ++ *len = chk->len; + } + else { + /* The sample has been fragmented, encode remaining data */ +- ret = MIN(chk->len - *off, end - p); ++ ret = MIN(*len - *off, end - p); + memcpy(p, chk->str + *off, ret); + p += ret; + } + /* Now update <*off> */ +- if (ret + *off != chk->len) ++ if (ret + *off != *len) + *off += ret; + else + *off = 0; +diff --git a/include/types/spoe.h b/include/types/spoe.h +index 53e7200c..cfaa42f8 100644 +--- a/include/types/spoe.h ++++ b/include/types/spoe.h +@@ -304,6 +304,7 @@ struct spoe_context { + struct spoe_message *curmsg; /* SPOE message from which to resume encoding */ + struct spoe_arg *curarg; /* SPOE arg in from which to resume encoding */ + unsigned int curoff; /* offset in from which to resume encoding */ ++ unsigned int curlen; /* length of need to be encode, for SMP_F_MAY_CHANGE data */ + unsigned int flags; /* SPOE_FRM_FL_* */ + } frag_ctx; /* Info about fragmented frames, valid on if SPOE_CTX_FL_FRAGMENTED is set */ + }; +diff --git a/src/flt_spoe.c b/src/flt_spoe.c +index f6109778..0c0b3794 100644 +--- a/src/flt_spoe.c ++++ b/src/flt_spoe.c +@@ -2172,6 +2172,7 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx, + list_for_each_entry(arg, &msg->args, list) { + ctx->frag_ctx.curarg = arg; + ctx->frag_ctx.curoff = UINT_MAX; ++ ctx->frag_ctx.curlen = 0; + + encode_argument: + if (ctx->frag_ctx.curoff != UINT_MAX) +@@ -2186,7 +2187,7 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx, + + /* Fetch the arguement value */ + smp = sample_process(s->be, s->sess, s, dir|SMP_OPT_FINAL, arg->expr, NULL); +- ret = spoe_encode_data(smp, &ctx->frag_ctx.curoff, buf, end); ++ ret = spoe_encode_data(&ctx->frag_ctx.curlen, smp, &ctx->frag_ctx.curoff, buf, end); + if (ret == -1 || ctx->frag_ctx.curoff) + goto too_big; + } diff --git a/net/haproxy/patches/002-MINOR-spoe-Use-the-sample-context-to-pass-frag_ctx-info-during-encoding.patch b/net/haproxy/patches/002-MINOR-spoe-Use-the-sample-context-to-pass-frag_ctx-info-during-encoding.patch new file mode 100644 index 0000000000..c26629c816 --- /dev/null +++ b/net/haproxy/patches/002-MINOR-spoe-Use-the-sample-context-to-pass-frag_ctx-info-during-encoding.patch @@ -0,0 +1,71 @@ +commit 72fdff1fdb5b82685dc3d2db23ece042195a0cbd +Author: Christopher Faulet +Date: Fri Apr 26 14:30:15 2019 +0200 + + MINOR: spoe: Use the sample context to pass frag_ctx info during encoding + + This simplifies the API and hide the details in the sample. This way, only + string and binary are aware of these info, because other types cannot be + partially encoded. + + This patch may be backported to 1.9 and 1.8. + + (cherry picked from commit 85db3212b87b33f1a39a688546f4f53a5c4ba4da) + Signed-off-by: Christopher Faulet + (cherry picked from commit b93366e3ee44f5de93f01569fcdcd602f6d0703f) + Signed-off-by: Christopher Faulet + +diff --git a/include/proto/spoe.h b/include/proto/spoe.h +index 2cdca10b..cce13e50 100644 +--- a/include/proto/spoe.h ++++ b/include/proto/spoe.h +@@ -117,11 +117,9 @@ spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len) + * + * If the value is too big to be encoded, depending on its type, then encoding + * failed or the value is partially encoded. Only strings and binaries can be +- * partially encoded. In this case, the offset <*off> is updated to known how +- * many bytes has been encoded. If <*off> is zero at the end, it means that all +- * data has been encoded. */ ++ * partially encoded. */ + static inline int +-spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char **buf, char *end) ++spoe_encode_data(struct sample *smp, char **buf, char *end) + { + char *p = *buf; + int ret; +@@ -164,12 +162,16 @@ spoe_encode_data(unsigned int *len, struct sample *smp, unsigned int *off, char + + case SMP_T_STR: + case SMP_T_BIN: { ++ /* If defined, get length and offset of the sample by reading the sample ++ * context. ctx.a[0] is the pointer to the length and ctx.a[1] is the ++ * pointer to the offset. If the offset is greater than 0, it means the ++ * sample is partially encoded. In this case, we only need to encode the ++ * reamining. When all the sample is encoded, the offset is reset to 0. ++ * So the caller know it can try to encode the next sample. */ + struct chunk *chk = &smp->data.u.str; ++ unsigned int *len = (smp->ctx.a[0] ? smp->ctx.a[0] : 0); ++ unsigned int *off = (smp->ctx.a[1] ? smp->ctx.a[1] : 0); + +- /* Here, we need to know if the sample has already been +- * partially encoded. If yes, we only need to encode the +- * remaining, <*off> reprensenting the number of bytes +- * already encoded. */ + if (!*off) { + /* First evaluation of the sample : encode the + * type (string or binary), the buffer length +diff --git a/src/flt_spoe.c b/src/flt_spoe.c +index 0c0b3794..66d8b045 100644 +--- a/src/flt_spoe.c ++++ b/src/flt_spoe.c +@@ -2187,7 +2187,9 @@ spoe_encode_message(struct stream *s, struct spoe_context *ctx, + + /* Fetch the arguement value */ + smp = sample_process(s->be, s->sess, s, dir|SMP_OPT_FINAL, arg->expr, NULL); +- ret = spoe_encode_data(&ctx->frag_ctx.curlen, smp, &ctx->frag_ctx.curoff, buf, end); ++ smp->ctx.a[0] = &ctx->frag_ctx.curlen; ++ smp->ctx.a[1] = &ctx->frag_ctx.curoff; ++ ret = spoe_encode_data(smp, buf, end); + if (ret == -1 || ctx->frag_ctx.curoff) + goto too_big; + } diff --git a/net/haproxy/patches/003-DOC-contrib-modsecurity-Typos-and-fix-the-reject-example.patch b/net/haproxy/patches/003-DOC-contrib-modsecurity-Typos-and-fix-the-reject-example.patch new file mode 100644 index 0000000000..514c4c568d --- /dev/null +++ b/net/haproxy/patches/003-DOC-contrib-modsecurity-Typos-and-fix-the-reject-example.patch @@ -0,0 +1,38 @@ +commit dfc3718f0a302ea3deb5f1a325d35fce0e4cfa48 +Author: Yann Cézard +Date: Thu Apr 25 14:48:38 2019 +0200 + + DOC: contrib/modsecurity: Typos and fix the reject example + + Thanks to https://www.mail-archive.com/haproxy@formilux.org/msg30056.html + + This patch may be backported to 1.9 and 1.8. + + (cherry picked from commit 494ddbff478d880e48de490f2689607addac70bc) + Signed-off-by: Christopher Faulet + (cherry picked from commit 850896603086877641272d6e4075e66bd91f2e50) + Signed-off-by: Christopher Faulet + +diff --git a/contrib/modsecurity/README b/contrib/modsecurity/README +index e6cb305e..8031389d 100644 +--- a/contrib/modsecurity/README ++++ b/contrib/modsecurity/README +@@ -88,15 +88,15 @@ HAProxy configuration. For example: + balance roundrobin + timeout connect 5s + timeout server 3m +- server iprep1 127.0.0.1:12345 ++ server modsec1 127.0.0.1:12345 + + The modsecurity action is returned in a variable called txn.modsec.code. It + contains the HTTP returned code. If the variable contains 0, the request is + clean. + +- tcp-request content reject if { var(txn.modsec.code) -m int gt 0 } ++ http-request deny if { var(txn.modsec.code) -m int gt 0 } + +-With this rule, all the request not clean are reected. ++With this rule, all the request not clean are rejected. + + + Known bugs, limitations and TODO list diff --git a/net/haproxy/patches/004-BUG-MEDIUM-contrib-modsecurity-If-host-header-is-NULL-dont-try-to-strdup-it.patch b/net/haproxy/patches/004-BUG-MEDIUM-contrib-modsecurity-If-host-header-is-NULL-dont-try-to-strdup-it.patch new file mode 100644 index 0000000000..af49cc2f41 --- /dev/null +++ b/net/haproxy/patches/004-BUG-MEDIUM-contrib-modsecurity-If-host-header-is-NULL-dont-try-to-strdup-it.patch @@ -0,0 +1,36 @@ +commit 95cf225d099dcb49eefcf4f5b648be604414ae0c +Author: Yann Cézard +Date: Thu Apr 25 14:30:23 2019 +0200 + + BUG/MEDIUM: contrib/modsecurity: If host header is NULL, don't try to strdup it + + I discovered this bug when running OWASP regression tests against HAProxy + + modsecurity-spoa (it's a POC to evaluate how it is working). I found out that + modsecurity spoa will crash when the request doesn't have any Host header. + + See the pull request #86 on github for details. + + This patch must be backported to 1.9 and 1.8. + + (cherry picked from commit bf60f6b8033deddc86de5357d6099c7593fe44cc) + Signed-off-by: Christopher Faulet + (cherry picked from commit d988e3dddcbe1f48f3b24d1bb529fc9ecefde180) + Signed-off-by: Christopher Faulet + +diff --git a/contrib/modsecurity/modsec_wrapper.c b/contrib/modsecurity/modsec_wrapper.c +index 271ec15d..2f3987b4 100644 +--- a/contrib/modsecurity/modsec_wrapper.c ++++ b/contrib/modsecurity/modsec_wrapper.c +@@ -325,7 +325,11 @@ int modsecurity_process(struct worker *worker, struct modsecurity_parameters *pa + req->content_type = apr_table_get(req->headers_in, "Content-Type"); + req->content_encoding = apr_table_get(req->headers_in, "Content-Encoding"); + req->hostname = apr_table_get(req->headers_in, "Host"); +- req->parsed_uri.hostname = chunk_strdup(req, req->hostname, strlen(req->hostname)); ++ if (req->hostname != NULL) { ++ req->parsed_uri.hostname = chunk_strdup(req, req->hostname, strlen(req->hostname)); ++ } else { ++ req->parsed_uri.hostname = NULL; ++ } + + lang = apr_table_get(req->headers_in, "Content-Languages"); + if (lang != NULL) { diff --git a/net/haproxy/patches/005-MINOR-examples-Use-right-locale-for-the-last-changelog-date-in-haproxy-spec.patch b/net/haproxy/patches/005-MINOR-examples-Use-right-locale-for-the-last-changelog-date-in-haproxy-spec.patch new file mode 100644 index 0000000000..310dc0f4f4 --- /dev/null +++ b/net/haproxy/patches/005-MINOR-examples-Use-right-locale-for-the-last-changelog-date-in-haproxy-spec.patch @@ -0,0 +1,23 @@ +commit 86860896dc1841eb59cb95832d76a8093e8dc8c5 +Author: Christopher Faulet +Date: Tue Apr 30 10:55:38 2019 +0200 + + MINOR: examples: Use right locale for the last changelog date in haproxy.spec + + The last changelog entry was stamped with the wrong locale. + + No need to backport, it is specific to 1.8 + +diff --git a/examples/haproxy.spec b/examples/haproxy.spec +index f3e0c7e0..fe5215d7 100644 +--- a/examples/haproxy.spec ++++ b/examples/haproxy.spec +@@ -74,7 +74,7 @@ fi + %attr(0755,root,root) %config %{_sysconfdir}/rc.d/init.d/%{name} + + %changelog +-* jeu. avril 25 2019 Christopher Faulet ++* Thu Apr 25 2019 Christopher Faulet + - updated to 1.8.20 + + * Mon Feb 11 2019 Willy Tarreau diff --git a/net/haproxy/patches/006-BUG-MAJOR-map-acl-real-fix-segfault-during-show-map-acl-on-CLI.patch b/net/haproxy/patches/006-BUG-MAJOR-map-acl-real-fix-segfault-during-show-map-acl-on-CLI.patch new file mode 100644 index 0000000000..e961294770 --- /dev/null +++ b/net/haproxy/patches/006-BUG-MAJOR-map-acl-real-fix-segfault-during-show-map-acl-on-CLI.patch @@ -0,0 +1,67 @@ +commit 83af1f6b65806982640679823228976deebf5202 +Author: Willy Tarreau +Date: Tue Apr 30 11:43:43 2019 +0200 + + BUG/MAJOR: map/acl: real fix segfault during show map/acl on CLI + + A previous commit 8d85aa44d ("BUG/MAJOR: map: fix segfault during + 'show map/acl' on cli.") was provided to address a concurrency issue + between "show acl" and "clear acl" on the CLI. Sadly the code placed + there was copy-pasted without changing the element type (which was + struct stream in the original code) and not tested since the crash + is still present. + + The reproducer is simple : load a large ACL file (e.g. geolocation + addresses), issue "show acl #0" in loops in one window and issue a + "clear acl #0" in the other one, haproxy crashes. + + This fix was also tested with threads enabled and looks good since + the locking seems to work correctly in these areas though. It will + have to be backported as far as 1.6 since the commit above went + that far as well... + + (cherry picked from commit 49ee3b2f9a9e5d0b8d394938df527aa645ce72b4) + Signed-off-by: Willy Tarreau + (cherry picked from commit ac4be10f62ef72962d9cf0e6f2619e1e1c370d62) + Signed-off-by: Christopher Faulet + +diff --git a/src/pattern.c b/src/pattern.c +index 7eea9d96..21639569 100644 +--- a/src/pattern.c ++++ b/src/pattern.c +@@ -1651,7 +1651,7 @@ int pat_ref_delete_by_id(struct pat_ref *ref, struct pat_ref_elt *refelt) + LIST_DEL(&bref->users); + LIST_INIT(&bref->users); + if (elt->list.n != &ref->head) +- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users); ++ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users); + bref->ref = elt->list.n; + } + list_for_each_entry(expr, &ref->pat, list) +@@ -1691,7 +1691,7 @@ int pat_ref_delete(struct pat_ref *ref, const char *key) + LIST_DEL(&bref->users); + LIST_INIT(&bref->users); + if (elt->list.n != &ref->head) +- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users); ++ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users); + bref->ref = elt->list.n; + } + list_for_each_entry(expr, &ref->pat, list) +@@ -2086,7 +2086,7 @@ void pat_ref_reload(struct pat_ref *ref, struct pat_ref *replace) + LIST_DEL(&bref->users); + LIST_INIT(&bref->users); + if (elt->list.n != &ref->head) +- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users); ++ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users); + bref->ref = elt->list.n; + } + LIST_DEL(&elt->list); +@@ -2175,7 +2175,7 @@ void pat_ref_prune(struct pat_ref *ref) + LIST_DEL(&bref->users); + LIST_INIT(&bref->users); + if (elt->list.n != &ref->head) +- LIST_ADDQ(&LIST_ELEM(elt->list.n, struct stream *, list)->back_refs, &bref->users); ++ LIST_ADDQ(&LIST_ELEM(elt->list.n, typeof(elt), list)->back_refs, &bref->users); + bref->ref = elt->list.n; + } + LIST_DEL(&elt->list); diff --git a/net/haproxy/patches/007-BUG-MEDIUM-listener-Fix-how-unlimited-number-of-consecutive-accepts-is-handled.patch b/net/haproxy/patches/007-BUG-MEDIUM-listener-Fix-how-unlimited-number-of-consecutive-accepts-is-handled.patch new file mode 100644 index 0000000000..e54c530fbe --- /dev/null +++ b/net/haproxy/patches/007-BUG-MEDIUM-listener-Fix-how-unlimited-number-of-consecutive-accepts-is-handled.patch @@ -0,0 +1,79 @@ +commit 7bd7a8d2b8889f604b807c21190d2e70328d6674 +Author: Christopher Faulet +Date: Tue Apr 30 12:17:13 2019 +0200 + + BUG/MEDIUM: listener: Fix how unlimited number of consecutive accepts is handled + + There is a bug when global.tune.maxaccept is set to -1 (no limit). It is pretty + visible with one process (nbproc sets to 1). The functions listener_accept() and + accept_queue_process() don't expect to handle negative maxaccept values. So + instead of accepting incoming connections without any limit, none are never + accepted and HAProxy loop infinitly in the scheduler. + + When there are 2 or more processes, the bug is a bit more subtile. The limit for + a listener is set to 1. So only one connection is accepted at a time by a given + listener. This happens because the listener's maxaccept value is an unsigned + integer. In check_config_validity(), it is first set to UINT_MAX (-1 casted in + an unsigned integer), and then some calculations on it leads to an integer + overflow. + + To fix the bug, the listener's maxaccept value is now a signed integer. So, if a + negative value is set for global.tune.maxaccept, we keep it untouched for the + listener and no calculation is made on it. Then, in the listener code, this + signed value is casted to a unsigned one. It simplifies all tests instead of + dealing with negative values. So, it limits the number of connections accepted + at a time to UINT_MAX at most. But, honestly, it not an issue. + + This patch must be backported to 1.9 and 1.8. + + (cherry picked from commit 102854cbbaa4d22466dddec9035d411db244082f) + Signed-off-by: Christopher Faulet + (cherry picked from commit bca4fb2d9d7f2966d9f8270fa1796fdc0dfc866d) + Signed-off-by: Christopher Faulet + +diff --git a/include/types/listener.h b/include/types/listener.h +index ea2eadb5..16ef6d7a 100644 +--- a/include/types/listener.h ++++ b/include/types/listener.h +@@ -196,7 +196,7 @@ struct listener { + int nbconn; /* current number of connections on this listener */ + int maxconn; /* maximum connections allowed on this listener */ + unsigned int backlog; /* if set, listen backlog */ +- unsigned int maxaccept; /* if set, max number of connections accepted at once */ ++ int maxaccept; /* if set, max number of connections accepted at once (-1 when disabled) */ + struct list proto_list; /* list in the protocol header */ + int (*accept)(struct listener *l, int fd, struct sockaddr_storage *addr); /* upper layer's accept() */ + enum obj_type *default_target; /* default target to use for accepted sessions or NULL */ +diff --git a/src/listener.c b/src/listener.c +index 821c931a..74990c45 100644 +--- a/src/listener.c ++++ b/src/listener.c +@@ -406,7 +406,7 @@ void listener_accept(int fd) + { + struct listener *l = fdtab[fd].owner; + struct proxy *p; +- int max_accept; ++ unsigned int max_accept; + int next_conn = 0; + int next_feconn = 0; + int next_actconn = 0; +@@ -420,6 +420,10 @@ void listener_accept(int fd) + if (!l) + return; + p = l->bind_conf->frontend; ++ ++ /* if l->maxaccept is -1, then max_accept is UINT_MAX. It is not really ++ * illimited, but it is probably enough. ++ */ + max_accept = l->maxaccept ? l->maxaccept : 1; + + if (!(l->options & LI_O_UNLIMITED) && global.sps_lim) { +@@ -480,7 +484,7 @@ void listener_accept(int fd) + * worst case. If we fail due to system limits or temporary resource + * shortage, we try again 100ms later in the worst case. + */ +- for (; max_accept-- > 0; next_conn = next_feconn = next_actconn = 0) { ++ for (; max_accept; next_conn = next_feconn = next_actconn = 0, max_accept--) { + struct sockaddr_storage addr; + socklen_t laddr = sizeof(addr); + unsigned int count; diff --git a/net/haproxy/patches/008-MINOR-config-Test-validity-of-tune-maxaccept-during-the-config-parsing.patch b/net/haproxy/patches/008-MINOR-config-Test-validity-of-tune-maxaccept-during-the-config-parsing.patch new file mode 100644 index 0000000000..5c5d88967a --- /dev/null +++ b/net/haproxy/patches/008-MINOR-config-Test-validity-of-tune-maxaccept-during-the-config-parsing.patch @@ -0,0 +1,44 @@ +commit 6e580b6e744011e87c337ebe2c082acfd5ca835a +Author: Christopher Faulet +Date: Tue Apr 30 14:03:56 2019 +0200 + + MINOR: config: Test validity of tune.maxaccept during the config parsing + + Only -1 and positive integers from 0 to INT_MAX are accepted. An error is + triggered during the config parsing for any other values. + + This patch may be backported to all supported versions. + + (cherry picked from commit 6b02ab87348090efec73b1dd24f414239669f279) + Signed-off-by: Christopher Faulet + (cherry picked from commit 2bbc40f8bc9a52ba0d03b25270ac0129cca29bba) + Signed-off-by: Christopher Faulet + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index c178538b..8e325416 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -789,6 +789,8 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) + global.tune.maxpollevents = atol(args[1]); + } + else if (!strcmp(args[0], "tune.maxaccept")) { ++ long max; ++ + if (alertif_too_many_args(1, file, linenum, args, &err_code)) + goto out; + if (global.tune.maxaccept != 0) { +@@ -801,7 +803,13 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } +- global.tune.maxaccept = atol(args[1]); ++ max = atol(args[1]); ++ if (/*max < -1 || */max > INT_MAX) { ++ ha_alert("parsing [%s:%d] : '%s' expects -1 or an integer from 0 to INT_MAX.\n", file, linenum, args[0]); ++ err_code |= ERR_ALERT | ERR_FATAL; ++ goto out; ++ } ++ global.tune.maxaccept = max; + } + else if (!strcmp(args[0], "tune.chksize")) { + if (alertif_too_many_args(1, file, linenum, args, &err_code)) diff --git a/net/haproxy/patches/009-CLEANUP-config-Dont-alter-listener--maxaccept-when-nbproc-is-set-to-1.patch b/net/haproxy/patches/009-CLEANUP-config-Dont-alter-listener--maxaccept-when-nbproc-is-set-to-1.patch new file mode 100644 index 0000000000..4bcae444fe --- /dev/null +++ b/net/haproxy/patches/009-CLEANUP-config-Dont-alter-listener--maxaccept-when-nbproc-is-set-to-1.patch @@ -0,0 +1,34 @@ +commit c6e03c1495fa51f9a98ed0bbe3230313c7c7201c +Author: Christopher Faulet +Date: Tue Apr 30 14:08:41 2019 +0200 + + CLEANUP: config: Don't alter listener->maxaccept when nbproc is set to 1 + + This patch only removes a useless calculation on listener->maxaccept when nbproc + is set to 1. Indeed, the following formula has no effet in such case: + + listener->maxaccept = (listener->maxaccept + nbproc - 1) / nbproc; + + This patch may be backported as far as 1.5. + + (cherry picked from commit 02f3cf19ed803d20aff9294ce7cb732489951ff5) + Signed-off-by: Christopher Faulet + (cherry picked from commit 14203e3cf9404e57de5e274b453f0fe4f2174924) + Signed-off-by: Christopher Faulet + +diff --git a/src/cfgparse.c b/src/cfgparse.c +index 8e325416..3f6ea352 100644 +--- a/src/cfgparse.c ++++ b/src/cfgparse.c +@@ -9018,9 +9018,8 @@ out_uri_auth_compat: + * is bound to. Rememeber that maxaccept = -1 must be kept as it is + * used to disable the limit. + */ +- if (listener->maxaccept > 0) { +- if (nbproc > 1) +- listener->maxaccept = (listener->maxaccept + 1) / 2; ++ if (listener->maxaccept > 0 && nbproc > 1) { ++ listener->maxaccept = (listener->maxaccept + 1) / 2; + listener->maxaccept = (listener->maxaccept + nbproc - 1) / nbproc; + } + diff --git a/net/haproxy/patches/010-MINOR-threads-Implement-HA_ATOMIC_LOAD.patch b/net/haproxy/patches/010-MINOR-threads-Implement-HA_ATOMIC_LOAD.patch new file mode 100644 index 0000000000..30e8cd4d72 --- /dev/null +++ b/net/haproxy/patches/010-MINOR-threads-Implement-HA_ATOMIC_LOAD.patch @@ -0,0 +1,54 @@ +commit f95cf6ad70565ee2322cf23bc519b7bb0b3831b2 +Author: Olivier Houchard +Date: Tue Apr 30 13:38:02 2019 +0200 + + MINOR: threads: Implement HA_ATOMIC_LOAD(). + + The same way we have HA_ATOMIC_STORE(), implement HA_ATOMIC_LOAD(). + + This should be backported to 1.8 and 1.9, as we need it for a bug fix + in port ranges. + + (cherry picked from commit 9ce62b5498b27fbf4217d9c25779d5b2ceca23f2) + Signed-off-by: Olivier Houchard + (cherry picked from commit 358c979611370fa2bc3b8e47ed50a325cf9126cf) + Signed-off-by: Christopher Faulet + +diff --git a/include/common/hathreads.h b/include/common/hathreads.h +index 8134839a..11d7cab6 100644 +--- a/include/common/hathreads.h ++++ b/include/common/hathreads.h +@@ -62,6 +62,7 @@ enum { tid = 0 }; + *(val) = new; \ + __old_xchg; \ + }) ++#define HA_ATOMIC_LOAD(val) *(val) + #define HA_ATOMIC_STORE(val, new) ({*(val) = new;}) + #define HA_ATOMIC_UPDATE_MAX(val, new) \ + ({ \ +@@ -203,6 +204,16 @@ static inline unsigned long thread_isolated() + } while (!__sync_bool_compare_and_swap(__val_xchg, __old_xchg, __new_xchg)); \ + __old_xchg; \ + }) ++ ++#define HA_ATOMIC_LOAD(val) \ ++ ({ \ ++ typeof(*(val)) ret; \ ++ __sync_synchronize(); \ ++ ret = *(volatile typeof(val))val; \ ++ __sync_synchronize(); \ ++ ret; \ ++ }) ++ + #define HA_ATOMIC_STORE(val, new) \ + ({ \ + typeof((val)) __val_store = (val); \ +@@ -221,6 +232,8 @@ static inline unsigned long thread_isolated() + #define HA_ATOMIC_OR(val, flags) __atomic_or_fetch(val, flags, __ATOMIC_SEQ_CST) + #define HA_ATOMIC_XCHG(val, new) __atomic_exchange_n(val, new, __ATOMIC_SEQ_CST) + #define HA_ATOMIC_STORE(val, new) __atomic_store_n(val, new, __ATOMIC_SEQ_CST) ++#define HA_ATOMIC_LOAD(val) __atomic_load_n(val, __ATOMIC_SEQ_CST) ++ + #endif + + #define HA_ATOMIC_UPDATE_MAX(val, new) \ diff --git a/net/haproxy/patches/011-BUG-MEDIUM-port_range-Make-the-ring-buffer-lock-free.patch b/net/haproxy/patches/011-BUG-MEDIUM-port_range-Make-the-ring-buffer-lock-free.patch new file mode 100644 index 0000000000..68332fdde4 --- /dev/null +++ b/net/haproxy/patches/011-BUG-MEDIUM-port_range-Make-the-ring-buffer-lock-free.patch @@ -0,0 +1,116 @@ +commit 31470e2ba2aabb4c6340fbc15cb5486ceb8c69c8 +Author: Olivier Houchard +Date: Mon Apr 29 18:52:06 2019 +0200 + + BUG/MEDIUM: port_range: Make the ring buffer lock-free. + + Port range uses a ring buffer, and unfortunately, when making haproxy + multithreaded, it's been overlooked, and the ring buffer is not thread-safe. + When specifying a source range, 2 or more threads could pick the same + port, and of course only one of them could use the port, the others would + always fail the connection. + To fix this, make it a lock-free ring buffer. This is easier than usual + because we know the ring buffer can never be full. + + This should be backported to 1.8 and 1.9. + + (cherry picked from commit 07425de71777b688e77a9c70a7088c13e66e41e9) + Signed-off-by: Olivier Houchard + (cherry picked from commit bffb51147a4a5939e344b3c838628f9a944febef) + Signed-off-by: Christopher Faulet + +diff --git a/include/proto/port_range.h b/include/proto/port_range.h +index 8c63faca..f7e3f1d5 100644 +--- a/include/proto/port_range.h ++++ b/include/proto/port_range.h +@@ -24,18 +24,22 @@ + + #include + ++#define GET_NEXT_OFF(range, off) ((off) == (range)->size - 1 ? 0 : (off) + 1) ++ + /* return an available port from range , or zero if none is left */ + static inline int port_range_alloc_port(struct port_range *range) + { + int ret; ++ int get; ++ int put; + +- if (!range->avail) +- return 0; +- ret = range->ports[range->get]; +- range->get++; +- if (range->get >= range->size) +- range->get = 0; +- range->avail--; ++ get = HA_ATOMIC_LOAD(&range->get); ++ do { ++ put = HA_ATOMIC_LOAD(&range->put_t); ++ if (unlikely(put == get)) ++ return 0; ++ ret = range->ports[get]; ++ } while (!(HA_ATOMIC_CAS(&range->get, &get, GET_NEXT_OFF(range, get)))); + return ret; + } + +@@ -45,14 +49,28 @@ static inline int port_range_alloc_port(struct port_range *range) + */ + static inline void port_range_release_port(struct port_range *range, int port) + { ++ int put; ++ + if (!port || !range) + return; + +- range->ports[range->put] = port; +- range->avail++; +- range->put++; +- if (range->put >= range->size) +- range->put = 0; ++ put = range->put_h; ++ /* put_h is reserved for producers, so that they can each get a ++ * free slot, put_t is what is used by consumers to know if there's ++ * elements available or not ++ */ ++ /* First reserve or slot, we know the ring buffer can't be full, ++ * as we will only ever release port we allocated before ++ */ ++ while (!(HA_ATOMIC_CAS(&range->put_h, &put, GET_NEXT_OFF(range, put)))); ++ HA_ATOMIC_STORE(&range->ports[put], port); ++ /* Wait until all the threads that got a slot before us are done */ ++ while ((volatile int)range->put_t != put) ++ __ha_compiler_barrier(); ++ /* Let the world know we're done, and any potential consumer they ++ * can use that port. ++ */ ++ HA_ATOMIC_STORE(&range->put_t, GET_NEXT_OFF(range, put)); + } + + /* return a new initialized port range of N ports. The ports are not +@@ -62,8 +80,10 @@ static inline struct port_range *port_range_alloc_range(int n) + { + struct port_range *ret; + ret = calloc(1, sizeof(struct port_range) + +- n * sizeof(((struct port_range *)0)->ports[0])); +- ret->size = ret->avail = n; ++ (n + 1) * sizeof(((struct port_range *)0)->ports[0])); ++ ret->size = n + 1; ++ /* Start at the first free element */ ++ ret->put_h = ret->put_t = n; + return ret; + } + +diff --git a/include/types/port_range.h b/include/types/port_range.h +index 1d010f77..33455d2d 100644 +--- a/include/types/port_range.h ++++ b/include/types/port_range.h +@@ -25,8 +25,7 @@ + #include + + struct port_range { +- int size, get, put; /* range size, and get/put positions */ +- int avail; /* number of available ports left */ ++ int size, get, put_h, put_t; /* range size, and get/put positions */ + uint16_t ports[0]; /* array of ports, in host byte order */ + }; + diff --git a/net/haproxy/patches/012-BUG-MINOR-http_fetch-Rely-on-the-smp-direction-for-cookie-and-hdr.patch b/net/haproxy/patches/012-BUG-MINOR-http_fetch-Rely-on-the-smp-direction-for-cookie-and-hdr.patch new file mode 100644 index 0000000000..3b7e268391 --- /dev/null +++ b/net/haproxy/patches/012-BUG-MINOR-http_fetch-Rely-on-the-smp-direction-for-cookie-and-hdr.patch @@ -0,0 +1,81 @@ +commit ef9cafc46c13eea2db65152e452607a6566cbeac +Author: Christopher Faulet +Date: Thu May 16 10:07:30 2019 +0200 + + BUG/MINOR: http_fetch: Rely on the smp direction for "cookie()" and "hdr()" + + A regression was introduced in the commit 89dc49935 ("BUG/MAJOR: http_fetch: Get + the channel depending on the keyword used") on the samples "cookie()" and + "hdr()". Unlike other samples manipulating the HTTP headers, these ones depend + on the sample direction. To fix the bug, these samples use now their own + functions. Depending on the sample direction, they call smp_fetch_cookie() and + smp_fetch_hdr() with the appropriate keyword. + + Thanks to Yves Lafon to report this issue. + + This patch must be backported wherever the commit 89dc49935 was backported. For + now, 1.9 and 1.8. + + (cherry picked from commit c1f40dd4920050ec5a83b2a5d22a3eb4e4be425a) + Signed-off-by: Christopher Faulet + (cherry picked from commit 5eaf770abfce56951202cb1ea55a968f5ec8be71) + Signed-off-by: Christopher Faulet + +diff --git a/src/proto_http.c b/src/proto_http.c +index 556cabad..32aeef2d 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -10218,6 +10218,17 @@ smp_fetch_hdr(const struct arg *args, struct sample *smp, const char *kw, void * + return 0; + } + ++/* Same than smp_fetch_hdr() but only relies on the sample direction to choose ++ * the right channel. So instead of duplicating the code, we just change the ++ * keyword and then fallback on smp_fetch_hdr(). ++ */ ++static int ++smp_fetch_chn_hdr(const struct arg *args, struct sample *smp, const char *kw, void *private) ++{ ++ kw = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ ? "req.hdr" : "res.hdr"); ++ return smp_fetch_hdr(args, smp, kw, private); ++} ++ + /* 6. Check on HTTP header count. The number of occurrences is returned. + * Accepts exactly 1 argument of type string. + */ +@@ -10935,6 +10946,17 @@ int smp_fetch_cookie(const struct arg *args, struct sample *smp, const char *kw, + return found; + } + ++/* Same than smp_fetch_cookie() but only relies on the sample direction to ++ * choose the right channel. So instead of duplicating the code, we just change ++ * the keyword and then fallback on smp_fetch_cookie(). ++ */ ++static int ++smp_fetch_chn_cookie(const struct arg *args, struct sample *smp, const char *kw, void *private) ++{ ++ kw = ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_REQ ? "req.cook" : "res.cook"); ++ return smp_fetch_cookie(args, smp, kw, private); ++} ++ + /* Iterate over all cookies present in a request to count how many occurrences + * match the name in args and args->data.str.len. If is non-null, then + * multiple cookies may be parsed on the same line. The returned sample is of +@@ -12855,7 +12877,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { + * for ACL compatibility only. + */ + { "cook", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV }, +- { "cookie", smp_fetch_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV }, ++ { "cookie", smp_fetch_chn_cookie, ARG1(0,STR), NULL, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV }, + { "cook_cnt", smp_fetch_cookie_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV }, + { "cook_val", smp_fetch_cookie_val, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV }, + +@@ -12863,7 +12885,7 @@ static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, { + * only here to match the ACL's name, are request-only and are used for + * ACL compatibility only. + */ +- { "hdr", smp_fetch_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV }, ++ { "hdr", smp_fetch_chn_hdr, ARG2(0,STR,SINT), val_hdr, SMP_T_STR, SMP_USE_HRQHV|SMP_USE_HRSHV }, + { "hdr_cnt", smp_fetch_hdr_cnt, ARG1(0,STR), NULL, SMP_T_SINT, SMP_USE_HRQHV }, + { "hdr_ip", smp_fetch_hdr_ip, ARG2(0,STR,SINT), val_hdr, SMP_T_IPV4, SMP_USE_HRQHV }, + { "hdr_val", smp_fetch_hdr_val, ARG2(0,STR,SINT), val_hdr, SMP_T_SINT, SMP_USE_HRQHV }, diff --git a/net/haproxy/patches/013-BUG-MEDIUM-dns-make-the-port-numbers-unsigned.patch b/net/haproxy/patches/013-BUG-MEDIUM-dns-make-the-port-numbers-unsigned.patch new file mode 100644 index 0000000000..830c7672a2 --- /dev/null +++ b/net/haproxy/patches/013-BUG-MEDIUM-dns-make-the-port-numbers-unsigned.patch @@ -0,0 +1,37 @@ +commit b50e7fe5e9ae7e8670a467fdd7ece2d08fc02809 +Author: Willy Tarreau +Date: Wed May 22 20:07:45 2019 +0200 + + BUG/MEDIUM: dns: make the port numbers unsigned + + Mustafa Yildirim reported in Discourse that ports >32767 advertised + in SRV records are wrong. Given the high value they definitely + correspond to a sign extension of a negative number. The cause was + indeed that the port is declared as a signed int in the dns_answer_item + structure, and Lukas confirmed in github issue #103 that turning it to + unsigned addresses the issue. + + It is worth noting that there are other such fields in this structure + that don't look right (ttl, priority, class, type) and that someone + should audit this part to be certain they are properly typed. + + This fix must be backported to 1.9 and likely to 1.8 as well. + + (cherry picked from commit d1f56c9a0110805c4a5f3afba2990556cb74ec8b) + Signed-off-by: Christopher Faulet + (cherry picked from commit 01ceb8a9fb0caecb20a12cc6763230cfc9895de5) + Signed-off-by: Christopher Faulet + +diff --git a/include/types/dns.h b/include/types/dns.h +index e8ab9f06..e2d98169 100644 +--- a/include/types/dns.h ++++ b/include/types/dns.h +@@ -144,7 +144,7 @@ struct dns_answer_item { + int32_t ttl; /* response TTL */ + int16_t priority; /* SRV type priority */ + uint16_t weight; /* SRV type weight */ +- int16_t port; /* SRV type port */ ++ uint16_t port; /* SRV type port */ + uint16_t data_len; /* number of bytes in target below */ + struct sockaddr address; /* IPv4 or IPv6, network format */ + char target[DNS_MAX_NAME_SIZE+1]; /* Response data: SRV or CNAME type target */ diff --git a/net/haproxy/patches/014-BUG-MEDIUM-spoe-Dont-use-the-SPOE-applet-after-releasing-it.patch b/net/haproxy/patches/014-BUG-MEDIUM-spoe-Dont-use-the-SPOE-applet-after-releasing-it.patch new file mode 100644 index 0000000000..24a2afead9 --- /dev/null +++ b/net/haproxy/patches/014-BUG-MEDIUM-spoe-Dont-use-the-SPOE-applet-after-releasing-it.patch @@ -0,0 +1,44 @@ +commit 89ff157c3262c8493ed48e6ac48f614791f446f8 +Author: Christopher Faulet +Date: Thu May 23 22:47:48 2019 +0200 + + BUG/MEDIUM: spoe: Don't use the SPOE applet after releasing it + + In spoe_release_appctx(), the SPOE applet may be used after it was released to + get its exit status code. Of course, HAProxy crashes when this happens. + + This patch must be backported to 1.9 and 1.8. + + (cherry picked from commit 55ae8a64e4e1175063463921375b279c31bbc6a4) + Signed-off-by: Christopher Faulet + (cherry picked from commit df29d11f522044217ea7c1373f494c2a36515b31) + Signed-off-by: Christopher Faulet + +diff --git a/src/flt_spoe.c b/src/flt_spoe.c +index 66d8b045..aeb1fde7 100644 +--- a/src/flt_spoe.c ++++ b/src/flt_spoe.c +@@ -1292,11 +1292,6 @@ spoe_release_appctx(struct appctx *appctx) + task_wakeup(ctx->strm->task, TASK_WOKEN_MSG); + } + +- /* Release allocated memory */ +- spoe_release_buffer(&spoe_appctx->buffer, +- &spoe_appctx->buffer_wait); +- pool_free(pool_head_spoe_appctx, spoe_appctx); +- + if (!LIST_ISEMPTY(&agent->rt[tid].applets)) + goto end; + +@@ -1317,6 +1312,11 @@ spoe_release_appctx(struct appctx *appctx) + } + + end: ++ /* Release allocated memory */ ++ spoe_release_buffer(&spoe_appctx->buffer, ++ &spoe_appctx->buffer_wait); ++ pool_free(pool_head_spoe_appctx, spoe_appctx); ++ + /* Update runtinme agent info */ + agent->rt[tid].frame_size = agent->max_frame_size; + list_for_each_entry(spoe_appctx, &agent->rt[tid].applets, list) diff --git a/net/haproxy/patches/015-DOC-fix-typos.patch b/net/haproxy/patches/015-DOC-fix-typos.patch new file mode 100644 index 0000000000..813170bdaa --- /dev/null +++ b/net/haproxy/patches/015-DOC-fix-typos.patch @@ -0,0 +1,925 @@ +commit 5aa7b32a94ad7ac38f465f0de279f09ff6d529d3 +Author: Michael Prokop +Date: Fri May 24 10:25:45 2019 +0200 + + DOC: fix typos + + s/accidently/accidentally/ + s/any ot these messages/any of theses messages/ + s/catched/caught/ + s/completly/completely/ + s/convertor/converter/ + s/desribing/describing/ + s/developper/developer/ + s/eventhough/even though/ + s/exectution/execution/ + s/functionnality/functionality/ + s/If it receive a/If it receives a/ + s/In can even/It can even/ + s/informations/information/ + s/it will be remove /it will be removed / + s/langage/language/ + s/mentionned/mentioned/ + s/negociated/negotiated/ + s/Optionnaly/Optionally/ + s/ouputs/outputs/ + s/outweights/outweighs/ + s/ressources/resources/ + + (cherry picked from commit 4438c6061d5a2ffd5b4251027038181af9b8dc22) + [wt: removed the wurfl+da notes as well as the part on peers/server] + Signed-off-by: Willy Tarreau + (cherry picked from commit a73e4f3d7a617a51551fffd80c5dbddee81e3aaf) + [wt: removed a few other keywords like ssl_bc_alpn and show peers] + Signed-off-by: Willy Tarreau + +diff --git a/doc/DeviceAtlas-device-detection.txt b/doc/DeviceAtlas-device-detection.txt +index 4ecb44a4..144ee318 100644 +--- a/doc/DeviceAtlas-device-detection.txt ++++ b/doc/DeviceAtlas-device-detection.txt +@@ -39,7 +39,7 @@ All HTTP headers via the sample / fetch + + http-request set-header X-DeviceAtlas-Data %[da-csv-fetch(primaryHardwareType,osName,osVersion,browserName,browserVersion,browserRenderingEngine)] + +-Single HTTP header (e.g. User-Agent) via the convertor ++Single HTTP header (e.g. User-Agent) via the converter + + http-request set-header X-DeviceAtlas-Data %[req.fhdr(User-Agent),da-csv-conv(primaryHardwareType,osName,osVersion,browserName,browserVersion,browserRenderingEngine)] + +diff --git a/doc/SPOE.txt b/doc/SPOE.txt +index dd36d43a..9602df95 100644 +--- a/doc/SPOE.txt ++++ b/doc/SPOE.txt +@@ -96,7 +96,7 @@ for several engines. If no name is provided, the SPOE configuration must not + contain any scope directive. + + We use a separate configuration file on purpose. By commenting SPOE filter +-line, you completly disable the feature, including the parsing of sections ++line, you completely disable the feature, including the parsing of sections + reserved to SPOE. This is also a way to keep the HAProxy configuration clean. + + A SPOE configuration file must contains, at least, the SPOA configuration +@@ -272,7 +272,7 @@ option set-on-error + + * 1 a timeout occurred during the event processing. + +- * 2 an error was triggered during the ressources allocation. ++ * 2 an error was triggered during the resources allocation. + + * 3 the frame payload exceeds the frame size and it cannot be + fragmented. +@@ -923,7 +923,7 @@ For more information about known errors, see section "Errors & timeouts" + ------------------------------- + + If an error occurs, at anytime, from the agent size, a AGENT-DISCONNECT frame +-is sent, with information desribing the error. such frame is also sent in reply ++is sent, with information describing the error. such frame is also sent in reply + to a HAPROXY-DISCONNECT. The agent must close the socket just after sending + this frame. + +diff --git a/doc/coding-style.txt b/doc/coding-style.txt +index 5f252ed0..9f1bd79e 100644 +--- a/doc/coding-style.txt ++++ b/doc/coding-style.txt +@@ -520,7 +520,7 @@ Wrong : + | bit = ! ! (~len++ ^ - (unsigned char) * x) ; + + Note that "sizeof" is a unary operator which is sometimes considered as a +-langage keyword, but in no case it is a function. It does not require ++language keyword, but in no case it is a function. It does not require + parenthesis so it is sometimes followed by spaces and sometimes not when + there are no parenthesis. Most people do not really care as long as what + is written is unambiguous. +@@ -814,7 +814,7 @@ common to see such a thing : + This is wrong. The man page says that -1 is returned if an error occurred. It + does not suggest that any other negative value will be an error. It is possible + that a few such issues have been left in existing code. They are bugs for which +-fixes are accepted, eventhough they're currently harmless since open() is not ++fixes are accepted, even though they're currently harmless since open() is not + known for returning negative values at the moment. + + +diff --git a/doc/configuration.txt b/doc/configuration.txt +index 863508f5..e044639a 100644 +--- a/doc/configuration.txt ++++ b/doc/configuration.txt +@@ -3051,7 +3051,7 @@ cookie [ rewrite | insert | prefix ] [ indirect ] [ nocache ] + + already have a cookie that would have permitted it to access this + server. When used without the "preserve" option, if the server +- emits a cookie with the same name, it will be remove before ++ emits a cookie with the same name, it will be removed before + processing. For this reason, this mode can be used to upgrade + existing configurations running in the "rewrite" mode. The cookie + will only be a session cookie and will not be stored on the +@@ -4786,7 +4786,7 @@ http-reuse { never | safe | aggressive | always } + proving that the server correctly supports connection reuse. + It should only be used when it's sure that the client can + retry a failed request once in a while and where the benefit +- of aggressive connection reuse significantly outweights the ++ of aggressive connection reuse significantly outweighs the + downsides of rare connection failures. + + - "always" : this mode is only recommended when the path to the server is +diff --git a/doc/intro.txt b/doc/intro.txt +index 7ad92db0..864fb8d6 100644 +--- a/doc/intro.txt ++++ b/doc/intro.txt +@@ -1481,7 +1481,7 @@ they are mentioned here even if not directly related to HAProxy. + + Apache is the de-facto standard HTTP server. It's a very complete and modular + project supporting both file serving and dynamic contents. It can serve as a +-frontend for some application servers. In can even proxy requests and cache ++frontend for some application servers. It can even proxy requests and cache + responses. In all of these use cases, a front load balancer is commonly needed. + Apache can work in various modes, some being heavier than others. Certain + modules still require the heavier pre-forked model and will prevent Apache from +diff --git a/doc/lua.txt b/doc/lua.txt +index 7b257ad8..2e266b03 100644 +--- a/doc/lua.txt ++++ b/doc/lua.txt +@@ -412,7 +412,7 @@ The max amount of memory is configured with the option: + tune.lua.maxmem + + As many other script languages, Lua uses a garbage collector for reusing its +-memory. The Lua developper can work without memory preoccupation. Usually, the ++memory. The Lua developer can work without memory preoccupation. Usually, the + garbage collector is controlled by the Lua core, but sometimes it will be useful + to run when the user/developer requires. So the garbage collector can be called + from C part or Lua part. +@@ -885,7 +885,7 @@ The task entry point + + The function "core.register_task(fcn)" executes once the function "fcn" when the + scheduler starts. This way is used for executing background task. For example, +-you can use this functionnality for periodically checking the health of another ++you can use this functionality for periodically checking the health of another + service, and giving the result to each proxy needing it. + + The task is started once, if you want periodic actions, you can use the +diff --git a/doc/management.txt b/doc/management.txt +index 1b41558a..8fdea722 100644 +--- a/doc/management.txt ++++ b/doc/management.txt +@@ -1634,7 +1634,7 @@ set rate-limit ssl-sessions global + + set server / addr [port ] + Replace the current IP address of a server by the one provided. +- Optionnaly, the port can be changed using the 'port' parameter. ++ Optionally, the port can be changed using the 'port' parameter. + Note that changing the port also support switching from/to port mapping + (notation with +X or -Y), only if a port is configured for the health check. + +diff --git a/doc/netscaler-client-ip-insertion-protocol.txt b/doc/netscaler-client-ip-insertion-protocol.txt +index 559d98a8..dc64327a 100644 +--- a/doc/netscaler-client-ip-insertion-protocol.txt ++++ b/doc/netscaler-client-ip-insertion-protocol.txt +@@ -1,4 +1,4 @@ +-When NetScaler application switch is used as L3+ switch, informations ++When NetScaler application switch is used as L3+ switch, information + regarding the original IP and TCP headers are lost as a new TCP + connection is created between the NetScaler and the backend server. + +diff --git a/doc/peers-v2.0.txt b/doc/peers-v2.0.txt +index a7f70dcc..02914743 100644 +--- a/doc/peers-v2.0.txt ++++ b/doc/peers-v2.0.txt +@@ -275,11 +275,11 @@ if no available remote peers are found. + + The chosen remote peer will push its all known data ending with a Resync Finished Message or a Resync Partial Message (if it it does not consider itself as full updated). + +-If it receive a Resync Finished Message it will consider itself as fully updated and stops to ask for resync. ++If it receives a Resync Finished Message it will consider itself as fully updated and stops to ask for resync. + +-If it receive a Resync Partial Message, the current peer will be flagged to anymore be requested and any other connected peer will be randomly chosen for a resync request (5s). ++If it receives a Resync Partial Message, the current peer will be flagged to anymore be requested and any other connected peer will be randomly chosen for a resync request (5s). + +-If the session is broken before receiving any ot these messages any other connected peer will be randomly chosen for a resync request (5s). ++If the session is broken before receiving any of these messages any other connected peer will be randomly chosen for a resync request (5s). + + If the timeout expire, the process will consider itself as fully updated + +diff --git a/doc/proxy-protocol.txt b/doc/proxy-protocol.txt +index 4969180a..52d7bc71 100644 +--- a/doc/proxy-protocol.txt ++++ b/doc/proxy-protocol.txt +@@ -561,7 +561,7 @@ Contains the host name value passed by the client, as an UTF8-encoded string. + In case of TLS being used on the client connection, this is the exact copy of + the "server_name" extension as defined by RFC3546 [10], section 3.1, often + referred to as "SNI". There are probably other situations where an authority +-can be mentionned on a connection without TLS being involved at all. ++can be mentioned on a connection without TLS being involved at all. + + + 2.2.3. PP2_TYPE_CRC32C +diff --git a/doc/regression-testing.txt b/doc/regression-testing.txt +new file mode 100644 +index 00000000..320c51cd +--- /dev/null ++++ b/doc/regression-testing.txt +@@ -0,0 +1,706 @@ ++ +---------------------------------------+ ++ | HAProxy regression testing with vtest | ++ +---------------------------------------+ ++ ++ ++The information found in this file are a short starting guide to help you to ++write VTC (Varnish Test Case) scripts (or VTC files) for haproxy regression testing. ++Such VTC files are currently used to test Varnish cache application developed by ++Poul-Henning Kamp. A very big thanks you to him for having helped you to add ++our haproxy C modules to vtest tool. Note that vtest was formally developed for ++varnish cache reg testing and was named varnishtest. vtest is an haproxy specific ++version of varnishtest program which reuses the non varnish cache specific code. ++ ++A lot of general information about how to write VTC files may be found in 'man/vtc.7' ++manual of varnish cache sources directory or directly on the web here: ++ ++ https://varnish-cache.org/docs/trunk/reference/vtc.html ++ ++It is *highly* recommended to read this manual before asking to haproxy ML. This ++documentation only deals with the vtest support for haproxy. ++ ++ ++vtest installation ++------------------------ ++ ++To use vtest you will have to download and compile the recent vtest ++sources found at https://github.com/vtest/VTest. ++ ++To compile vtest: ++ ++ $ cd VTest ++ $ make vtest ++ ++Note that varnishtest may be also compiled but not without the varnish cache ++sources already compiled: ++ ++ $ VARNISH_SRC=<...> make varnishtest ++ ++After having compiled these sources, the vtest executable location is at the ++root of the vtest sources directory. ++ ++ ++vtest execution ++--------------------- ++ ++vtest is able to search for the haproxy executable file it is supposed to ++launch thanks to the PATH environment variable. To force the executable to be used by ++vtest, the HAPROXY_PROGRAM environment variable for vtest may be ++typically set as follows: ++ ++ $ HAPROXY_PROGRAM=~/srcs/haproxy/haproxy vtest ... ++ ++vtest program comes with interesting options. The most interesting are: ++ ++ -t Timeout in seconds to abort the test if some launched program ++ -v By default, vtest does not dump the outputs of processus it launched ++ when the test passes. With this option the outputs are dumped even ++ when the test passes. ++ -L to always keep the temporary VTC directories. ++ -l to keep the temporary VTC directories only when the test fails. ++ ++About haproxy, when launched by vtest, -d option is enabled by default. ++ ++ ++How to write VTC files ++---------------------- ++ ++A VTC file must start with a "varnishtest" or "vtest" command line followed by a ++descriptive line enclosed by double quotes. This is not specific to the VTC files ++for haproxy. ++ ++The VTC files for haproxy must also contain a "feature ignore_unknown_macro" line ++if any macro is used for haproxy in this file. This is due to the fact that ++vtest parser code for haproxy commands generates macros the vtest ++parser code for varnish cache has no knowledge of. This line prevents vtest from ++failing in such cases. As a "cli" macro automatically generated, this ++"feature ignore_unknown_macro" is mandatory for each VTC file for haproxy. ++ ++To make vtest capable of testing haproxy, two new VTC commands have been ++implemented: "haproxy" and "syslog". "haproxy" is used to start haproxy processus. ++"syslog" is used to start syslog servers (at this time, only used by haproxy). ++ ++As haproxy cannot work without configuration file, a VTC file for haproxy must ++embed the configuration files contents for the haproxy instances it declares. ++This may be done using the following intuitive syntax construction: -conf {...}. ++Here -conf is an argument of "haproxy" VTC command to declare the configuration ++file of the haproxy instances it also declares (see "Basic HAProxy test" VTC file ++below). ++ ++As for varnish VTC files, the parser of VTC files for haproxy automatically ++generates macros for the declared frontends to be reused by the clients later ++in the script, so after having written the "haproxy" command sections. ++The syntax "fd@${my_frontend_fd_name}" must be used to bind the frontend ++listeners to localhost address and random ports (see "Environment variables" ++section of haproxy documentation). This is mandatory. ++ ++Each time the haproxy command parser finds a "fd@${xyz}" string in a 'ABC' ++"haproxy" command section, it generates three macros: 'ABC_xyz_addr', 'ABC_xyz_port' ++and 'ABC_xyz_sock', with 'ABC_xyz_sock' being resolved as 'ABC_xyz_addr ++ABC_xyz_port' typically used by clients -connect parameter. ++ ++Each haproxy instance works in their own temporary working directories located ++at '/tmp/vtc..XXXXXXXX/' (with XXXXXXXX ++a random 8 digits hexadecimal integer. This is in this temporary directory that ++the configuration file is temporarily written. ++ ++A 'stats.sock' UNIX socket is also created in this directory. There is no need ++to declare such stats sockets in the -conf {...} section. The name of the parent ++directory of the haproxy instances working directories is stored in 'tmpdir'. In ++fact this is the working directory of the current vtest processus. ++ ++There also exists 'testdir' macro which is the parent directory of the VTC file. ++It may be useful to use other files located in the same directory than the current ++VTC file. ++ ++ ++ ++VTC file examples ++----------------- ++ ++The following first VTC file is a real regression test case file for a bug which has ++been fixed by 84c844e commit. We declare a basic configuration for a 'h1' haproxy ++instance. ++ ++ varnishtest "SPOE bug: missing configuration file" ++ ++ #commit 84c844eb12b250aa86f2aadaff77c42dfc3cb619 ++ #Author: Christopher Faulet ++ #Date: Fri Mar 23 14:37:14 2018 +0100 ++ ++ # BUG/MINOR: spoe: Initialize variables used during conf parsing before any check ++ ++ # Some initializations must be done at the beginning of parse_spoe_flt to avoid ++ # segmentaion fault when first errors are caught, when the "filter spoe" line is ++ # parsed. ++ ++ haproxy h1 -conf-BAD {} { ++ defaults ++ timeout connect 5000ms ++ timeout client 50000ms ++ timeout server 50000ms ++ ++ frontend my-front ++ filter spoe ++ } ++ ++ ++-conf-BAD haproxy command argument is used. Its role it to launch haproxy with ++-c option (configuration file checking) and check that 'h1' exit(3) with 1 as ++status. Here is the output when running this VTC file: ++ ++ ++ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy ++ **** top 0.0 extmacro def localhost=127.0.0.1 ++ **** top 0.0 extmacro def bad_backend=127.0.0.1 39564 ++ **** top 0.0 extmacro def bad_ip=192.0.2.255 ++ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy ++ **** top 0.0 macro def tmpdir=/tmp/vtc.6377.64329194 ++ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc starting ++ ** top 0.0 === varnishtest "SPOE bug: missing configuration file" ++ * top 0.0 TEST SPOE bug: missing configuration file ++ ** top 0.0 === haproxy h1 -conf-BAD {} { ++ **** h1 0.0 conf| global ++ **** h1 0.0 conf|\tstats socket /tmp/vtc.6377.64329194/h1/stats.sock level admin mode 600 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf|\tdefaults ++ **** h1 0.0 conf| timeout connect 5000ms ++ **** h1 0.0 conf| timeout client 50000ms ++ **** h1 0.0 conf| timeout server 50000ms ++ **** h1 0.0 conf| ++ **** h1 0.0 conf|\tfrontend my-front ++ **** h1 0.0 conf|\t\tfilter spoe ++ **** h1 0.0 conf| ++ ** h1 0.0 haproxy_start ++ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 1 ++ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -c -f /tmp/vtc.6377.64329194/h1/cfg ++ **** h1 0.0 XXX 5 @277 ++ *** h1 0.0 PID: 6395 ++ **** h1 0.0 macro def h1_pid=6395 ++ **** h1 0.0 macro def h1_name=/tmp/vtc.6377.64329194/h1 ++ ** h1 0.0 Wait ++ ** h1 0.0 Stop HAproxy pid=6395 ++ **** h1 0.0 STDOUT poll 0x10 ++ ** h1 0.0 WAIT4 pid=6395 status=0x008b (user 0.000000 sys 0.000000) ++ * h1 0.0 Expected exit: 0x1 signal: 0 core: 0 ++ ---- h1 0.0 Bad exit status: 0x008b exit 0x0 signal 11 core 128 ++ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc ++ ** h1 0.0 Reset and free h1 haproxy 6395 ++ ** h1 0.0 Wait ++ ---- h1 0.0 Assert error in haproxy_wait(), vtc_haproxy.c line 326: Condition(*(&h->fds[1]) >= 0) not true. ++ ++ * top 0.0 failure during reset ++ # top TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc FAILED (0.008) exit=2 ++ ++ ++'h1' exited with (128 + 11) status and a core file was produced in ++/tmp/vtc.6377.64329194/h1 directory. ++With the patch provided by 84c844e commit, varnishtest makes this VTC file pass ++as expected (verbose mode execution): ++ ++ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy ++ **** top 0.0 extmacro def localhost=127.0.0.1 ++ **** top 0.0 extmacro def bad_backend=127.0.0.1 42264 ++ **** top 0.0 extmacro def bad_ip=192.0.2.255 ++ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy ++ **** top 0.0 macro def tmpdir=/tmp/vtc.25540.59b6ec5d ++ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc starting ++ ** top 0.0 === varnishtest "SPOE bug: missing configuration file" ++ * top 0.0 TEST SPOE bug: missing configuration file ++ ** top 0.0 === haproxy h1 -conf-BAD {} { ++ **** h1 0.0 conf| global ++ **** h1 0.0 conf|\tstats socket /tmp/vtc.25540.59b6ec5d/h1/stats.sock level admin mode 600 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf|\tdefaults ++ **** h1 0.0 conf| timeout connect 5000ms ++ **** h1 0.0 conf| timeout client 50000ms ++ **** h1 0.0 conf| timeout server 50000ms ++ **** h1 0.0 conf| ++ **** h1 0.0 conf|\tfrontend my-front ++ **** h1 0.0 conf|\t\tfilter spoe ++ **** h1 0.0 conf| ++ ** h1 0.0 haproxy_start ++ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 1 ++ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -c -f /tmp/vtc.25540.59b6ec5d/h1/cfg ++ **** h1 0.0 XXX 5 @277 ++ *** h1 0.0 PID: 25558 ++ **** h1 0.0 macro def h1_pid=25558 ++ **** h1 0.0 macro def h1_name=/tmp/vtc.25540.59b6ec5d/h1 ++ ** h1 0.0 Wait ++ ** h1 0.0 Stop HAproxy pid=25558 ++ *** h1 0.0 debug|[ALERT] 157/135318 (25558) : parsing [/tmp/vtc.25540.59b6ec5d/h1/cfg:10] : 'filter' : ''spoe' : missing config file' ++ *** h1 0.0 debug|[ALERT] 157/135318 (25558) : Error(s) found in configuration file : /tmp/vtc.25540.59b6ec5d/h1/cfg ++ *** h1 0.0 debug|[ALERT] 157/135318 (25558) : Fatal errors found in configuration. ++ **** h1 0.0 STDOUT poll 0x10 ++ ** h1 0.0 WAIT4 pid=25558 status=0x0100 (user 0.000000 sys 0.000000) ++ ** h1 0.0 Found expected '' ++ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc ++ ** h1 0.0 Reset and free h1 haproxy -1 ++ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc completed ++ # top TEST /home/fred/src/varnish-cache-haproxy/spoe_bug.vtc passed (0.004) ++ ++ ++The following VTC file does almost nothing except running a shell to list ++the contents of 'tmpdir' directory after having launched a haproxy instance ++and 's1' HTTP server. This shell also prints the content of 'cfg' 'h1' configuration ++file. ++ ++ varnishtest "List the contents of 'tmpdir'" ++ feature ignore_unknown_macro ++ ++ server s1 { ++ } -start ++ ++ haproxy h1 -conf { ++ defaults ++ mode http ++ timeout connect 5s ++ timeout server 30s ++ timeout client 30s ++ ++ backend be1 ++ server srv1 ${s1_addr}:${s1_port} ++ ++ frontend http1 ++ use_backend be1 ++ bind "fd@${my_frontend_fd}" ++ } -start ++ ++ shell { ++ echo "${tmpdir} working directory content:" ++ ls -lR ${tmpdir} ++ cat ${tmpdir}/h1/cfg ++ } ++ ++We give only the output of the shell to illustrate this example: ++ ++ . ++ . ++ . ++ ** top 0.0 === shell { ++ **** top 0.0 shell_cmd|exec 2>&1 ; ++ **** top 0.0 shell_cmd| echo "tmpdir: /tmp/vtc.32092.479d521e" ++ **** top 0.0 shell_cmd| ls -lR /tmp/vtc.32092.479d521e ++ **** top 0.0 shell_cmd| cat /tmp/vtc.32092.479d521e/h1/cfg ++ . ++ . ++ . ++ **** top 0.0 shell_out|/tmp/vtc.3808.448cbfe0 working directory content: ++ **** top 0.0 shell_out|/tmp/vtc.32092.479d521e: ++ **** top 0.0 shell_out|total 8 ++ **** top 0.0 shell_out|drwxr-xr-x 2 users 4096 Jun 7 11:09 h1 ++ **** top 0.0 shell_out|-rw-r--r-- 1 me users 84 Jun 7 11:09 INFO ++ **** top 0.0 shell_out| ++ **** top 0.0 shell_out|/tmp/vtc.32092.479d521e/h1: ++ **** top 0.0 shell_out|total 4 ++ **** top 0.0 shell_out|-rw-r----- 1 fred users 339 Jun 7 11:09 cfg ++ **** top 0.0 shell_out|srw------- 1 fred users 0 Jun 7 11:09 stats.sock ++ **** top 0.0 shell_out| global ++ **** top 0.0 shell_out|\tstats socket /tmp/vtc.32092.479d521e/h1/stats.sock level admin mode 600 ++ **** top 0.0 shell_out| ++ **** top 0.0 shell_out| defaults ++ **** top 0.0 shell_out| mode http ++ **** top 0.0 shell_out| timeout connect 5s ++ **** top 0.0 shell_out| timeout server 30s ++ **** top 0.0 shell_out| timeout client 30s ++ **** top 0.0 shell_out| ++ **** top 0.0 shell_out| backend be1 ++ **** top 0.0 shell_out| server srv1 127.0.0.1:36984 ++ **** top 0.0 shell_out| ++ **** top 0.0 shell_out| frontend http1 ++ **** top 0.0 shell_out| use_backend be1 ++ **** top 0.0 shell_out| bind "fd@${my_frontend_fd}" ++ **** top 0.0 shell_status = 0x0000 ++ ++ ++The following example illustrate how to run a basic HTTP transaction between 'c1' ++client and 's1' server with 'http1' as haproxy frontend. This frontend listen ++on TCP socket with 'my_frontend_fd' as file descriptor. ++ ++ # Mandatory line ++ varnishtest "Basic HAproxy test" ++ ++ # As some macros for haproxy are used in this file, this line is mandatory. ++ feature ignore_unknown_macro ++ ++ server s1 { ++ rxreq ++ txresp -body "s1 >>> Hello world!" ++ } -start ++ ++ haproxy h1 -conf { ++ # Configuration file of 'h1' haproxy instance. ++ defaults ++ mode http ++ timeout connect 5s ++ timeout server 30s ++ timeout client 30s ++ ++ backend be1 ++ # declare 'srv1' server to point to 's1' server instance declare above. ++ server srv1 ${s1_addr}:${s1_port} ++ ++ frontend http1 ++ use_backend be1 ++ bind "fd@${my_frontend_fd}" ++ } -start ++ ++ client c1 -connect ${h1_my_frontend_fd_sock} { ++ txreq -url "/" ++ rxresp ++ expect resp.status == 200 ++ expect resp.body == "s1 >>> Hello world!" ++ } -run ++ ++ ++It is possible to shorten the previous VTC file haproxy command section as follows: ++ ++ haproxy h1 -conf { ++ # Configuration file of 'h1' haproxy instance. ++ defaults ++ mode http ++ timeout connect 5s ++ timeout server 30s ++ timeout client 30s ++ } ++ ++In this latter example, "backend" and "frontend" sections are automatically ++generated depending on the declarations of server instances. ++ ++ ++Another interesting real regression test case is the following: we declare one ++server 's1', a syslog server 'Slg_1' and a basic haproxy configuration for 'h1' ++haproxy instance. Here we want to check that the syslog message are correctly ++formatted thanks to "expect" "syslog" command (see syslog Slg_1 {...} command) ++below. ++ ++ varnishtest "Wrong ip/port logging" ++ feature ignore_unknown_macro ++ ++ #commit d02286d6c866e5c0a7eb6fbb127fa57f3becaf16 ++ #Author: Willy Tarreau ++ #Date: Fri Jun 23 11:23:43 2017 +0200 ++ # ++ # BUG/MINOR: log: pin the front connection when front ip/ports are logged ++ # ++ # Mathias Weiersmueller reported an interesting issue with logs which Lukas ++ # diagnosed as dating back from commit 9b061e332 (1.5-dev9). When front ++ # connection information (ip, port) are logged in TCP mode and the log is ++ # emitted at the end of the connection (eg: because %B or any log tag ++ # requiring LW_BYTES is set), the log is emitted after the connection is ++ # closed, so the address and ports cannot be retrieved anymore. ++ # ++ # It could be argued that we'd make a special case of these to immediately ++ # retrieve the source and destination addresses from the connection, but it ++ # seems cleaner to simply pin the front connection, marking it "tracked" by ++ # adding the LW_XPRT flag to mention that we'll need some of these elements ++ # at the last moment. Only LW_FRTIP and LW_CLIP are affected. Note that after ++ # this change, LW_FRTIP could simply be removed as it's not used anywhere. ++ ++ # Note that the problem doesn't happen when using %[src] or %[dst] since ++ # all sample expressions set LW_XPRT. ++ ++ ++ server s1 { ++ rxreq ++ txresp ++ } -start ++ ++ syslog Slg_1 -level notice { ++ recv ++ recv ++ recv info ++ expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_port}.*\"ts\":\"cD\",\" ++ } -start ++ ++ haproxy h1 -conf { ++ global ++ log ${Slg_1_addr}:${Slg_1_port} local0 ++ ++ defaults ++ log global ++ timeout connect 3000 ++ timeout client 5 ++ timeout server 10000 ++ ++ frontend fe1 ++ bind "fd@${fe_1}" ++ mode tcp ++ log-format {\"dip\":\"%fi\",\"dport\":\"%fp\",\"c_ip\":\"%ci\",\"c_port\":\"%cp\",\"fe_name\":\"%ft\",\"be_name\":\"%b\",\"s_name\":\"%s\",\"ts\":\"%ts\",\"bytes_read\":\"%B\"} ++ default_backend be_app ++ ++ backend be_app ++ server app1 ${s1_addr}:${s1_port} check ++ } -start ++ ++ client c1 -connect ${h1_fe_1_sock} { ++ txreq -url "/" ++ delay 0.02 ++ } -run ++ ++ syslog Slg_1 -wait ++ ++ ++Here is the output produced by varnishtest with the latter VTC file: ++ ++ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy ++ **** top 0.0 extmacro def localhost=127.0.0.1 ++ **** top 0.0 extmacro def bad_backend=127.0.0.1 40386 ++ **** top 0.0 extmacro def bad_ip=192.0.2.255 ++ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy ++ **** top 0.0 macro def tmpdir=/tmp/vtc.15752.560ca66b ++ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc starting ++ ** top 0.0 === varnishtest "HAPEE bug 2788" ++ * top 0.0 TEST HAPEE bug 2788 ++ ** top 0.0 === feature ignore_unknown_macro ++ ** top 0.0 === server s1 { ++ ** s1 0.0 Starting server ++ **** s1 0.0 macro def s1_addr=127.0.0.1 ++ **** s1 0.0 macro def s1_port=35564 ++ **** s1 0.0 macro def s1_sock=127.0.0.1 35564 ++ * s1 0.0 Listen on 127.0.0.1 35564 ++ ** top 0.0 === syslog Slg_1 -level notice { ++ ** Slg_1 0.0 Starting syslog server ++ ** s1 0.0 Started on 127.0.0.1 35564 ++ **** Slg_1 0.0 macro def Slg_1_addr=127.0.0.1 ++ **** Slg_1 0.0 macro def Slg_1_port=33012 ++ **** Slg_1 0.0 macro def Slg_1_sock=127.0.0.1 33012 ++ * Slg_1 0.0 Bound on 127.0.0.1 33012 ++ ** top 0.0 === haproxy h1 -conf { ++ ** Slg_1 0.0 Started on 127.0.0.1 33012 (level: 5) ++ ** Slg_1 0.0 === recv ++ **** h1 0.0 macro def h1_fe_1_sock=::1 51782 ++ **** h1 0.0 macro def h1_fe_1_addr=::1 ++ **** h1 0.0 macro def h1_fe_1_port=51782 ++ **** h1 0.0 setenv(fe_1, 7) ++ **** h1 0.0 conf| global ++ **** h1 0.0 conf|\tstats socket /tmp/vtc.15752.560ca66b/h1/stats.sock level admin mode 600 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| global ++ **** h1 0.0 conf| log 127.0.0.1:33012 local0 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| defaults ++ **** h1 0.0 conf| log global ++ **** h1 0.0 conf| timeout connect 3000 ++ **** h1 0.0 conf| timeout client 5 ++ **** h1 0.0 conf| timeout server 10000 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| frontend fe1 ++ **** h1 0.0 conf| bind "fd@${fe_1}" ++ **** h1 0.0 conf| mode tcp ++ **** h1 0.0 conf| log-format {\"dip\":\"%fi\",\"dport\":\"%fp\",\"c_ip\":\"%ci\",\"c_port\":\"%cp\",\"fe_name\":\"%ft\",\"be_name\":\"%b\",\"s_name\":\"%s\",\"ts\":\"%ts\",\"bytes_read\":\"%B\"} ++ **** h1 0.0 conf| default_backend be_app ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| backend be_app ++ **** h1 0.0 conf| server app1 127.0.0.1:35564 check ++ ** h1 0.0 haproxy_start ++ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 0 ++ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -d -f /tmp/vtc.15752.560ca66b/h1/cfg ++ **** h1 0.0 XXX 9 @277 ++ *** h1 0.0 PID: 15787 ++ **** h1 0.0 macro def h1_pid=15787 ++ **** h1 0.0 macro def h1_name=/tmp/vtc.15752.560ca66b/h1 ++ ** top 0.0 === client c1 -connect ${h1_fe_1_sock} { ++ ** c1 0.0 Starting client ++ ** c1 0.0 Waiting for client ++ *** c1 0.0 Connect to ::1 51782 ++ *** c1 0.0 connected fd 8 from ::1 46962 to ::1 51782 ++ ** c1 0.0 === txreq -url "/" ++ **** c1 0.0 txreq|GET / HTTP/1.1\r ++ **** c1 0.0 txreq|Host: 127.0.0.1\r ++ **** c1 0.0 txreq|\r ++ ** c1 0.0 === delay 0.02 ++ *** c1 0.0 delaying 0.02 second(s) ++ *** h1 0.0 debug|Note: setting global.maxconn to 2000. ++ *** h1 0.0 debug|Available polling systems : ++ *** h1 0.0 debug| epoll : ++ *** h1 0.0 debug|pref=300, ++ *** h1 0.0 debug| test result OK ++ *** h1 0.0 debug| poll : pref=200, test result OK ++ *** h1 0.0 debug| select : ++ *** h1 0.0 debug|pref=150, test result FAILED ++ *** h1 0.0 debug|Total: 3 (2 usable), will use epoll. ++ *** h1 0.0 debug| ++ *** h1 0.0 debug|Available filters : ++ *** h1 0.0 debug|\t[SPOE] spoe ++ *** h1 0.0 debug|\t[COMP] compression ++ *** h1 0.0 debug|\t[TRACE] trace ++ **** Slg_1 0.0 syslog|<133>Jun 7 14:12:51 haproxy[15787]: Proxy fe1 started. ++ ** Slg_1 0.0 === recv ++ **** Slg_1 0.0 syslog|<133>Jun 7 14:12:51 haproxy[15787]: Proxy be_app started. ++ ** Slg_1 0.0 === recv info ++ *** h1 0.0 debug|00000000:fe1.accept(0007)=000a from [::1:46962] ++ *** s1 0.0 accepted fd 6 127.0.0.1 56770 ++ ** s1 0.0 === rxreq ++ **** s1 0.0 rxhdr|GET / HTTP/1.1\r ++ **** s1 0.0 rxhdr|Host: 127.0.0.1\r ++ **** s1 0.0 rxhdr|\r ++ **** s1 0.0 rxhdrlen = 35 ++ **** s1 0.0 http[ 0] |GET ++ **** s1 0.0 http[ 1] |/ ++ **** s1 0.0 http[ 2] |HTTP/1.1 ++ **** s1 0.0 http[ 3] |Host: 127.0.0.1 ++ **** s1 0.0 bodylen = 0 ++ ** s1 0.0 === txresp ++ **** s1 0.0 txresp|HTTP/1.1 200 OK\r ++ **** s1 0.0 txresp|Content-Length: 0\r ++ **** s1 0.0 txresp|\r ++ *** s1 0.0 shutting fd 6 ++ ** s1 0.0 Ending ++ *** h1 0.0 debug|00000000:be_app.srvcls[000a:000c] ++ *** h1 0.0 debug|00000000:be_app.clicls[000a:000c] ++ *** h1 0.0 debug|00000000:be_app.closed[000a:000c] ++ **** Slg_1 0.0 syslog|<134>Jun 7 14:12:51 haproxy[15787]: {"dip":"","dport":"0","c_ip":"::1","c_port":"46962","fe_name":"fe1","be_name":"be_app","s_name":"app1","ts":"cD","bytes_read":"38"} ++ ** Slg_1 0.0 === expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_p... ++ ---- Slg_1 0.0 EXPECT FAILED ~ "\"dip\":\"::1\",\"dport\":\"51782.*\"ts\":\"cD\",\"" ++ *** c1 0.0 closing fd 8 ++ ** c1 0.0 Ending ++ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/d02286d.vtc ++ ** h1 0.0 Reset and free h1 haproxy 15787 ++ ** h1 0.0 Wait ++ ** h1 0.0 Stop HAproxy pid=15787 ++ **** h1 0.0 Kill(2)=0: Success ++ **** h1 0.0 STDOUT poll 0x10 ++ ** h1 0.1 WAIT4 pid=15787 status=0x0002 (user 0.000000 sys 0.004000) ++ ** s1 0.1 Waiting for server (4/-1) ++ ** Slg_1 0.1 Waiting for syslog server (5) ++ * top 0.1 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc FAILED ++ # top TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc FAILED (0.131) exit=2 ++ ++This test does not pass without the bug fix of d02286d commit. Indeed the third syslog ++message received by 'Slg_1' syslog server does not match the regular expression ++of the "syslog" "expect" command: ++ ++ expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_port}.*\"ts\":\"cD\",\" ++ ++(the IP address and port are missing), contrary to what happens with the correct bug fix: ++ ++ **** top 0.0 extmacro def pwd=/home/fred/src/haproxy ++ **** top 0.0 extmacro def localhost=127.0.0.1 ++ **** top 0.0 extmacro def bad_backend=127.0.0.1 37284 ++ **** top 0.0 extmacro def bad_ip=192.0.2.255 ++ **** top 0.0 macro def testdir=//home/fred/src/varnish-cache-haproxy ++ **** top 0.0 macro def tmpdir=/tmp/vtc.12696.186b28b0 ++ * top 0.0 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc starting ++ ** top 0.0 === varnishtest "HAPEE bug 2788" ++ * top 0.0 TEST HAPEE bug 2788 ++ ** top 0.0 === feature ignore_unknown_macro ++ ** top 0.0 === server s1 { ++ ** s1 0.0 Starting server ++ **** s1 0.0 macro def s1_addr=127.0.0.1 ++ **** s1 0.0 macro def s1_port=53384 ++ **** s1 0.0 macro def s1_sock=127.0.0.1 53384 ++ * s1 0.0 Listen on 127.0.0.1 53384 ++ ** top 0.0 === syslog Slg_1 -level notice { ++ ** Slg_1 0.0 Starting syslog server ++ **** Slg_1 0.0 macro def Slg_1_addr=127.0.0.1 ++ ** s1 0.0 Started on 127.0.0.1 53384 ++ **** Slg_1 0.0 macro def Slg_1_port=36195 ++ **** Slg_1 0.0 macro def Slg_1_sock=127.0.0.1 36195 ++ * Slg_1 0.0 Bound on 127.0.0.1 36195 ++ ** top 0.0 === haproxy h1 -conf { ++ ** Slg_1 0.0 Started on 127.0.0.1 36195 (level: 5) ++ ** Slg_1 0.0 === recv ++ **** h1 0.0 macro def h1_fe_1_sock=::1 39264 ++ **** h1 0.0 macro def h1_fe_1_addr=::1 ++ **** h1 0.0 macro def h1_fe_1_port=39264 ++ **** h1 0.0 setenv(fe_1, 7) ++ **** h1 0.0 conf| global ++ **** h1 0.0 conf|\tstats socket /tmp/vtc.12696.186b28b0/h1/stats.sock level admin mode 600 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| global ++ **** h1 0.0 conf| log 127.0.0.1:36195 local0 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| defaults ++ **** h1 0.0 conf| log global ++ **** h1 0.0 conf| timeout connect 3000 ++ **** h1 0.0 conf| timeout client 5 ++ **** h1 0.0 conf| timeout server 10000 ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| frontend fe1 ++ **** h1 0.0 conf| bind "fd@${fe_1}" ++ **** h1 0.0 conf| mode tcp ++ **** h1 0.0 conf| log-format {\"dip\":\"%fi\",\"dport\":\"%fp\",\"c_ip\":\"%ci\",\"c_port\":\"%cp\",\"fe_name\":\"%ft\",\"be_name\":\"%b\",\"s_name\":\"%s\",\"ts\":\"%ts\",\"bytes_read\":\"%B\"} ++ **** h1 0.0 conf| default_backend be_app ++ **** h1 0.0 conf| ++ **** h1 0.0 conf| backend be_app ++ **** h1 0.0 conf| server app1 127.0.0.1:53384 check ++ ** h1 0.0 haproxy_start ++ **** h1 0.0 opt_worker 0 opt_daemon 0 opt_check_mode 0 ++ **** h1 0.0 argv|exec /home/fred/src/haproxy/haproxy -d -f /tmp/vtc.12696.186b28b0/h1/cfg ++ **** h1 0.0 XXX 9 @277 ++ *** h1 0.0 PID: 12728 ++ **** h1 0.0 macro def h1_pid=12728 ++ **** h1 0.0 macro def h1_name=/tmp/vtc.12696.186b28b0/h1 ++ ** top 0.0 === client c1 -connect ${h1_fe_1_sock} { ++ ** c1 0.0 Starting client ++ ** c1 0.0 Waiting for client ++ *** c1 0.0 Connect to ::1 39264 ++ *** c1 0.0 connected fd 8 from ::1 41245 to ::1 39264 ++ ** c1 0.0 === txreq -url "/" ++ **** c1 0.0 txreq|GET / HTTP/1.1\r ++ **** c1 0.0 txreq|Host: 127.0.0.1\r ++ **** c1 0.0 txreq|\r ++ ** c1 0.0 === delay 0.02 ++ *** c1 0.0 delaying 0.02 second(s) ++ *** h1 0.0 debug|Note: setting global.maxconn to 2000. ++ *** h1 0.0 debug|Available polling systems : ++ *** h1 0.0 debug| epoll : pref=300, ++ *** h1 0.0 debug| test result OK ++ *** h1 0.0 debug| poll : pref=200, test result OK ++ *** h1 0.0 debug| select : pref=150, test result FAILED ++ *** h1 0.0 debug|Total: 3 (2 usable), will use epoll. ++ *** h1 0.0 debug| ++ *** h1 0.0 debug|Available filters : ++ *** h1 0.0 debug|\t[SPOE] spoe ++ *** h1 0.0 debug|\t[COMP] compression ++ *** h1 0.0 debug|\t[TRACE] trace ++ *** h1 0.0 debug|Using epoll() as the polling mechanism. ++ **** Slg_1 0.0 syslog|<133>Jun 7 14:10:18 haproxy[12728]: Proxy fe1 started. ++ ** Slg_1 0.0 === recv ++ **** Slg_1 0.0 syslog|<133>Jun 7 14:10:18 haproxy[12728]: Proxy be_app started. ++ ** Slg_1 0.0 === recv info ++ *** h1 0.0 debug|00000000:fe1.accept(0007)=000c from [::1:41245] ALPN= ++ *** s1 0.0 accepted fd 6 127.0.0.1 49946 ++ ** s1 0.0 === rxreq ++ **** s1 0.0 rxhdr|GET / HTTP/1.1\r ++ **** s1 0.0 rxhdr|Host: 127.0.0.1\r ++ **** s1 0.0 rxhdr|\r ++ **** s1 0.0 rxhdrlen = 35 ++ **** s1 0.0 http[ 0] |GET ++ **** s1 0.0 http[ 1] |/ ++ **** s1 0.0 http[ 2] |HTTP/1.1 ++ **** s1 0.0 http[ 3] |Host: 127.0.0.1 ++ **** s1 0.0 bodylen = 0 ++ ** s1 0.0 === txresp ++ **** s1 0.0 txresp|HTTP/1.1 200 OK\r ++ **** s1 0.0 txresp|Content-Length: 0\r ++ **** s1 0.0 txresp|\r ++ *** s1 0.0 shutting fd 6 ++ ** s1 0.0 Ending ++ *** h1 0.0 debug|00000000:be_app.srvcls[000c:adfd] ++ *** h1 0.0 debug|00000000:be_app.clicls[000c:adfd] ++ *** h1 0.0 debug|00000000:be_app.closed[000c:adfd] ++ **** Slg_1 0.0 syslog|<134>Jun 7 14:10:18 haproxy[12728]: {"dip":"::1","dport":"39264","c_ip":"::1","c_port":"41245","fe_name":"fe1","be_name":"be_app","s_name":"app1","ts":"cD","bytes_read":"38"} ++ ** Slg_1 0.0 === expect ~ \"dip\":\"${h1_fe_1_addr}\",\"dport\":\"${h1_fe_1_p... ++ **** Slg_1 0.0 EXPECT MATCH ~ "\"dip\":\"::1\",\"dport\":\"39264.*\"ts\":\"cD\",\"" ++ *** Slg_1 0.0 shutting fd 5 ++ ** Slg_1 0.0 Ending ++ *** c1 0.0 closing fd 8 ++ ** c1 0.0 Ending ++ ** top 0.0 === syslog Slg_1 -wait ++ ** Slg_1 0.0 Waiting for syslog server (-1) ++ * top 0.0 RESETTING after /home/fred/src/varnish-cache-haproxy/d02286d.vtc ++ ** h1 0.0 Reset and free h1 haproxy 12728 ++ ** h1 0.0 Wait ++ ** h1 0.0 Stop HAproxy pid=12728 ++ **** h1 0.0 Kill(2)=0: Success ++ **** h1 0.0 STDOUT poll 0x10 ++ ** h1 0.1 WAIT4 pid=12728 status=0x0002 (user 0.000000 sys 0.004000) ++ ** s1 0.1 Waiting for server (4/-1) ++ * top 0.1 TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc completed ++ # top TEST /home/fred/src/varnish-cache-haproxy/d02286d.vtc passed (0.128) ++ ++In this latter execution the third syslog message is correct: ++ ++ **** Slg_1 0.0 syslog|<134>Jun 7 14:10:18 haproxy[12728]: {"dip":"::1","dport":"39264","c_ip":"::1","c_port":"41245","fe_name":"fe1","be_name":"be_app","s_name":"app1","ts":"cD","bytes_read":"38"} diff --git a/net/haproxy/patches/016-BUG-MINOR-ssl_sock-Fix-memory-leak-when-disabling-compression.patch b/net/haproxy/patches/016-BUG-MINOR-ssl_sock-Fix-memory-leak-when-disabling-compression.patch new file mode 100644 index 0000000000..dc989f1f8e --- /dev/null +++ b/net/haproxy/patches/016-BUG-MINOR-ssl_sock-Fix-memory-leak-when-disabling-compression.patch @@ -0,0 +1,53 @@ +commit b3dae591a4fb47922d4235cf05ac66bcce443cf4 +Author: Ilya Shipitsin +Date: Sat May 25 03:38:14 2019 +0500 + + BUG/MINOR: ssl_sock: Fix memory leak when disabling compression + + according to manpage: + + sk_TYPE_zero() sets the number of elements in sk to zero. It + does not free sk so after this call sk is still valid. + + so we need to free all elements + + [wt: seems like it has been there forever and should be backported + to all stable branches] + + (cherry picked from commit e242f3dfb8ae2f27de9d10d90a783df05d5c849b) + [wt: adjusted context due to libressl detection] + Signed-off-by: Willy Tarreau + (cherry picked from commit 273c61dfb45d968eb8b677616130cda6586977f0) + [wt: minor adjustments due to version detection and local variables] + Signed-off-by: Willy Tarreau + +diff --git a/src/ssl_sock.c b/src/ssl_sock.c +index fbb7cf2b..3ab63342 100644 +--- a/src/ssl_sock.c ++++ b/src/ssl_sock.c +@@ -8959,11 +8959,10 @@ static void ssl_sock_capture_free_func(void *parent, void *ptr, CRYPTO_EX_DATA * + __attribute__((constructor)) + static void __ssl_sock_init(void) + { ++ STACK_OF(SSL_COMP)* cm; + char *ptr; + int i; + +- STACK_OF(SSL_COMP)* cm; +- + if (global_ssl.listen_default_ciphers) + global_ssl.listen_default_ciphers = strdup(global_ssl.listen_default_ciphers); + if (global_ssl.connect_default_ciphers) +@@ -8978,7 +8977,11 @@ static void __ssl_sock_init(void) + xprt_register(XPRT_SSL, &ssl_sock); + SSL_library_init(); + cm = SSL_COMP_get_compression_methods(); +- sk_SSL_COMP_zero(cm); ++ i = sk_SSL_COMP_num(cm); ++ while (i--) { ++ (void) sk_SSL_COMP_pop(cm); ++ } ++ + #ifdef USE_THREAD + ssl_locking_init(); + #endif diff --git a/net/haproxy/patches/017-BUILD-ssl-fix-latest-LibreSSL-reg-test-error.patch b/net/haproxy/patches/017-BUILD-ssl-fix-latest-LibreSSL-reg-test-error.patch new file mode 100644 index 0000000000..aa8bd61364 --- /dev/null +++ b/net/haproxy/patches/017-BUILD-ssl-fix-latest-LibreSSL-reg-test-error.patch @@ -0,0 +1,46 @@ +commit e834ca5c6914c71a86138362423b9d6e7ce15a78 +Author: Ilya Shipitsin +Date: Sat May 25 19:30:50 2019 +0500 + + BUILD: ssl: fix latest LibreSSL reg-test error + + starting with OpenSSL 1.0.0 recommended way to disable compression is + using SSL_OP_NO_COMPRESSION when creating context. + + manipulations with SSL_COMP_get_compression_methods, sk_SSL_COMP_num + are only required for OpenSSL < 1.0.0 + + (cherry picked from commit 0590f44254da9203a3c9d239836f4703aa6d543b) + Signed-off-by: Willy Tarreau + (cherry picked from commit be086d6dc7029aec9349e54ab5cccc499892bd61) + [wt: context adjustments] + Signed-off-by: Willy Tarreau + +diff --git a/src/ssl_sock.c b/src/ssl_sock.c +index 3ab63342..3436459f 100644 +--- a/src/ssl_sock.c ++++ b/src/ssl_sock.c +@@ -8959,7 +8959,9 @@ static void ssl_sock_capture_free_func(void *parent, void *ptr, CRYPTO_EX_DATA * + __attribute__((constructor)) + static void __ssl_sock_init(void) + { ++#if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION)) + STACK_OF(SSL_COMP)* cm; ++#endif + char *ptr; + int i; + +@@ -8976,11 +8978,13 @@ static void __ssl_sock_init(void) + + xprt_register(XPRT_SSL, &ssl_sock); + SSL_library_init(); ++#if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION)) + cm = SSL_COMP_get_compression_methods(); + i = sk_SSL_COMP_num(cm); + while (i--) { + (void) sk_SSL_COMP_pop(cm); + } ++#endif + + #ifdef USE_THREAD + ssl_locking_init(); diff --git a/net/haproxy/patches/018-BUG-MAJOR-lb-threads-make-sure-the-avoided-server-is-not-full-on-second-pass.patch b/net/haproxy/patches/018-BUG-MAJOR-lb-threads-make-sure-the-avoided-server-is-not-full-on-second-pass.patch new file mode 100644 index 0000000000..0fc5fb1636 --- /dev/null +++ b/net/haproxy/patches/018-BUG-MAJOR-lb-threads-make-sure-the-avoided-server-is-not-full-on-second-pass.patch @@ -0,0 +1,54 @@ +commit 5d60902ec7883bb05927c648638a009eb930acc7 +Author: Willy Tarreau +Date: Mon May 27 10:17:05 2019 +0200 + + BUG/MAJOR: lb/threads: make sure the avoided server is not full on second pass + + In fwrr_get_next_server(), we optionally pass a server to avoid. It + usually points to the current server during a redispatch operation. If + this server is usable, an "avoided" pointer is set and we continue to + look for another server. If in the end no other server is found, then + we fall back to this avoided one, which is still better than nothing. + + The problem that may arise with threads is that in the mean time, this + avoided server might have received extra connections and might not be + usable anymore. This causes it to be queued a second time in the "full" + list and the loop to search for a server again, ending up on this one + again and so on. + + This patch makes sure that we break out of the loop when we have to + pick the avoided server. It's probably what the code intended to do + as the current break statement causes fwrr_update_position() and + fwrr_dequeue_srv() to be called again on the avoided server. + + It must be backported to 1.9 and 1.8, and seems appropriate for older + versions though it's unclear what the impact of this bug might be + there since the race doesn't exist and we're left with the double + update of the server's position. + + (cherry picked from commit b6195ef2a6b0cb3f68bc34735313daa640ab3e92) + Signed-off-by: Willy Tarreau + (cherry picked from commit 7df15f275af90110e6ab4ec75065cbfabdf764ec) + Signed-off-by: Willy Tarreau + +diff --git a/src/lb_fwrr.c b/src/lb_fwrr.c +index cba7db5f..33181b46 100644 +--- a/src/lb_fwrr.c ++++ b/src/lb_fwrr.c +@@ -504,7 +504,7 @@ struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid) + if (switched) { + if (avoided) { + srv = avoided; +- break; ++ goto take_this_one; + } + goto requeue_servers; + } +@@ -534,6 +534,7 @@ struct server *fwrr_get_next_server(struct proxy *p, struct server *srvtoavoid) + full = srv; + } + ++ take_this_one: + /* OK, we got the best server, let's update it */ + fwrr_queue_srv(srv); + diff --git a/net/haproxy/patches/019-BUG-MEDIUM-http-fix-http-request-reject-when-not-final.patch b/net/haproxy/patches/019-BUG-MEDIUM-http-fix-http-request-reject-when-not-final.patch new file mode 100644 index 0000000000..6f008d8a83 --- /dev/null +++ b/net/haproxy/patches/019-BUG-MEDIUM-http-fix-http-request-reject-when-not-final.patch @@ -0,0 +1,43 @@ +commit 339e69400f87c34e28c67eaab6e503dc41b29d48 +Author: Willy Tarreau +Date: Tue May 28 08:26:17 2019 +0200 + + BUG/MEDIUM: http: fix "http-request reject" when not final + + When "http-request reject" was introduced in 1.8 with commit 53275e8b0 + ("MINOR: http: implement the "http-request reject" rule"), it was already + broken. The code mentions "it always returns ACT_RET_STOP" and obviously + a gross copy-paste made it ACT_RET_CONT. If the rule is the last one it + properly blocks, but if not the last one it gets ignored, as can be seen + with this simple configuration : + + frontend f1 + bind :8011 + mode http + http-request reject + http-request redirect location / + + This trivial fix must be backported to 1.9 and 1.8. It is tracked by + github issue #107. + + (cherry picked from commit 11c90fbd92cfaa5695e328481402d62d536456ef) + Signed-off-by: Willy Tarreau + (cherry picked from commit f6d5f2b27634cf3f8591016985b9fb81a1caf01c) + Signed-off-by: Christopher Faulet + + [Cf: The fix was applied in the file src/proto_http.c because, in 1.8, the file + src/http_act.c does not exist.] + +diff --git a/src/proto_http.c b/src/proto_http.c +index 32aeef2d..e5792f8c 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -12157,7 +12157,7 @@ enum act_return http_action_reject(struct act_rule *rule, struct proxy *px, + if (!(s->flags & SF_FINST_MASK)) + s->flags |= SF_FINST_R; + +- return ACT_RET_CONT; ++ return ACT_RET_STOP; + } + + /* parse the "reject" action: diff --git a/net/haproxy/patches/020-BUG-MINOR-deinit-threads-make-hard-stop-after-perform-a-clean-exit.patch b/net/haproxy/patches/020-BUG-MINOR-deinit-threads-make-hard-stop-after-perform-a-clean-exit.patch new file mode 100644 index 0000000000..fd4c549028 --- /dev/null +++ b/net/haproxy/patches/020-BUG-MINOR-deinit-threads-make-hard-stop-after-perform-a-clean-exit.patch @@ -0,0 +1,71 @@ +commit ee60daed3071426242fcacbb1cd9603a825b359e +Author: Willy Tarreau +Date: Sun Jun 2 11:11:29 2019 +0200 + + BUG/MINOR: deinit/threads: make hard-stop-after perform a clean exit + + As reported in GH issue #99, when hard-stop-after triggers and threads + are in use, the chance that any thread releases the resources in use by + the other ones is non-null. Thus no thread should be allowed to deinit() + nor exit by itself. + + Here we take a different approach. We simply use a 3rd possible value + for the "killed" variable so that all threads know they must break out + of the run-poll-loop and immediately stop. + + This patch was tested by commenting the stream_shutdown() calls in + hard_stop() to increase the chances to see a stream use released + resources. With this fix applied, it never crashes anymore. + + This fix should be backported to 1.9 and 1.8. + + (cherry picked from commit 7067b3a92efc9c9a7c3239245fdc96ea7310f46a) + Signed-off-by: Willy Tarreau + (cherry picked from commit daf91d3a5c8d2b47878580a0e0bde654d92ad42a) + Signed-off-by: Christopher Faulet + +diff --git a/include/types/global.h b/include/types/global.h +index bd7761cd..d3721d03 100644 +--- a/include/types/global.h ++++ b/include/types/global.h +@@ -213,7 +213,7 @@ extern const int zero; + extern const int one; + extern const struct linger nolinger; + extern int stopping; /* non zero means stopping in progress */ +-extern int killed; /* non zero means a hard-stop is triggered */ ++extern int killed; /* >0 means a hard-stop is triggered, >1 means hard-stop immediately */ + extern char hostname[MAX_HOSTNAME_LEN]; + extern char localpeer[MAX_HOSTNAME_LEN]; + extern struct list global_listener_queue; /* list of the temporarily limited listeners */ +diff --git a/src/haproxy.c b/src/haproxy.c +index 105cde6f..6ea17a0c 100644 +--- a/src/haproxy.c ++++ b/src/haproxy.c +@@ -2431,6 +2431,10 @@ static void run_poll_loop() + if (tid == 0 && jobs == 0) + THREAD_WANT_SYNC(); + ++ /* also stop if we failed to cleanly stop all tasks */ ++ if (killed > 1) ++ break; ++ + /* expire immediately if events are pending */ + exp = now_ms; + if (fd_cache_mask & tid_bit) +diff --git a/src/proxy.c b/src/proxy.c +index cff6c0aa..ef491aed 100644 +--- a/src/proxy.c ++++ b/src/proxy.c +@@ -942,9 +942,9 @@ struct task *hard_stop(struct task *t) + if (killed) { + ha_warning("Some tasks resisted to hard-stop, exiting now.\n"); + send_log(NULL, LOG_WARNING, "Some tasks resisted to hard-stop, exiting now.\n"); +- /* Do some cleanup and explicitely quit */ +- deinit(); +- exit(0); ++ killed = 2; ++ t->expire = TICK_ETERNITY; ++ return t; + } + + ha_warning("soft-stop running for too long, performing a hard-stop.\n"); diff --git a/net/haproxy/patches/021-BUG-MEDIUM-connection-fix-multiple-handshake-polling-issues.patch b/net/haproxy/patches/021-BUG-MEDIUM-connection-fix-multiple-handshake-polling-issues.patch new file mode 100644 index 0000000000..a6a6042bc2 --- /dev/null +++ b/net/haproxy/patches/021-BUG-MEDIUM-connection-fix-multiple-handshake-polling-issues.patch @@ -0,0 +1,133 @@ +commit 30e228120ebc1caad1086d0d90383f472f710375 +Author: Willy Tarreau +Date: Mon Jun 3 08:17:30 2019 +0200 + + BUG/MEDIUM: connection: fix multiple handshake polling issues + + Connection handshakes were rarely stacked on top of each other, but the + recent experiments consisting in sending PROXY over SOCKS4 revealed a + number of issues in these lower layers. First, each handler waiting for + data MUST subscribe to recv events with __conn_sock_want_recv() and MUST + unsubscribe from send events using __conn_sock_stop_send() to avoid any + wake-up loop in case a previous sender has set this. Second, each handler + waiting for sending MUST subscribe to send events with __conn_sock_want_send() + and MUST unsubscribe from recv events using __conn_sock_stop_recv() to + avoid any wake-up loop in case some data are available on the connection. + + Till now this was done at various random places, and in particular the + cases where the FD was not ready for recv forgot to re-enable reading. + + Second, while senders can happily use conn_sock_send() which automatically + handles EINTR, loops, and marks the FD as not ready with fd_cant_send(), + there is no equivalent for recv so receivers facing EAGAIN MUST call + fd_cant_send() to enable polling. It could be argued that implementing + an equivalent conn_sock_recv() function could be useful and more + long-term proof than the current situation. + + Third, both types of handlers MUST unsubscribe from their respective + events once they managed to do their job, and none may even play with + __conn_xprt_*(). Here again this was lacking, and one surprizing call + to __conn_xprt_stop_recv() was present in the proxy protocol parser + for TCP6 messages! + + Thanks to Alexander Liu for his help on this issue. + + This patch must be backported to 1.9 and possibly some older versions, + though the SOCKS parts should be dropped. + + (cherry picked from commit 6499b9d996ea8f57749021f56ed635c4688a727e) + [wt: dropped SOCKS4] + Signed-off-by: Willy Tarreau + (cherry picked from commit a34d37966ed87ffd9924e2b11f8003dc773e1853) + Signed-off-by: Christopher Faulet + +diff --git a/src/connection.c b/src/connection.c +index f57ef60a..e00c2f81 100644 +--- a/src/connection.c ++++ b/src/connection.c +@@ -404,7 +404,7 @@ int conn_recv_proxy(struct connection *conn, int flag) + goto fail; + + if (!fd_recv_ready(conn->handle.fd)) +- return 0; ++ goto not_ready; + + do { + trash.len = recv(conn->handle.fd, trash.str, trash.size, MSG_PEEK); +@@ -413,7 +413,7 @@ int conn_recv_proxy(struct connection *conn, int flag) + continue; + if (errno == EAGAIN) { + fd_cant_recv(conn->handle.fd); +- return 0; ++ goto not_ready; + } + goto recv_abort; + } +@@ -653,8 +653,14 @@ int conn_recv_proxy(struct connection *conn, int flag) + + conn->flags &= ~flag; + conn->flags |= CO_FL_RCVD_PROXY; ++ __conn_sock_stop_recv(conn); + return 1; + ++ not_ready: ++ __conn_sock_want_recv(conn); ++ __conn_sock_stop_send(conn); ++ return 0; ++ + missing: + /* Missing data. Since we're using MSG_PEEK, we can only poll again if + * we have not read anything. Otherwise we need to fail because we won't +@@ -709,7 +715,7 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag) + goto fail; + + if (!fd_recv_ready(conn->handle.fd)) +- return 0; ++ goto not_ready; + + do { + trash.len = recv(conn->handle.fd, trash.str, trash.size, MSG_PEEK); +@@ -718,7 +724,7 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag) + continue; + if (errno == EAGAIN) { + fd_cant_recv(conn->handle.fd); +- return 0; ++ goto not_ready; + } + goto recv_abort; + } +@@ -849,8 +855,14 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag) + } while (0); + + conn->flags &= ~flag; ++ __conn_sock_stop_recv(conn); + return 1; + ++ not_ready: ++ __conn_sock_want_recv(conn); ++ __conn_sock_stop_send(conn); ++ return 0; ++ + missing: + /* Missing data. Since we're using MSG_PEEK, we can only poll again if + * we have not read anything. Otherwise we need to fail because we won't +diff --git a/src/stream_interface.c b/src/stream_interface.c +index 47a100d7..8e4df70a 100644 +--- a/src/stream_interface.c ++++ b/src/stream_interface.c +@@ -400,6 +400,7 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag) + if (conn->flags & CO_FL_WAIT_L4_CONN) + conn->flags &= ~CO_FL_WAIT_L4_CONN; + conn->flags &= ~flag; ++ __conn_sock_stop_send(conn); + return 1; + + out_error: +@@ -409,6 +410,7 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag) + + out_wait: + __conn_sock_stop_recv(conn); ++ __conn_sock_want_send(conn); + return 0; + } + diff --git a/net/haproxy/patches/022-BUG-MEDIUM-vars-make-sure-the-scope-is-always-valid-when-accessing-vars.patch b/net/haproxy/patches/022-BUG-MEDIUM-vars-make-sure-the-scope-is-always-valid-when-accessing-vars.patch new file mode 100644 index 0000000000..5312464a8d --- /dev/null +++ b/net/haproxy/patches/022-BUG-MEDIUM-vars-make-sure-the-scope-is-always-valid-when-accessing-vars.patch @@ -0,0 +1,193 @@ +commit 47133bd99225554519c1d32293e0e5c3db83db30 +Author: Willy Tarreau +Date: Tue Jun 4 16:27:36 2019 +0200 + + BUG/MEDIUM: vars: make sure the scope is always valid when accessing vars + + Patrick Hemmer reported that a simple tcp rule involving a variable like + this is enough to crash haproxy : + + frontend foo + bind :8001 + tcp-request session set-var(txn.foo) src + + The tests on the variables scopes is not strict enough, it needs to always + verify if the stream is valid when accessing a req/res/txn variable. This + patch does this by adding a new get_vars() function which does the job + instead of open-coding all the lookups everywhere. + + It must be backported to all versions supporting set-var and + "tcp-request session" so at least 1.9 and 1.8. + + (cherry picked from commit f37b140b06b9963dea8adaf5e13b5b57cd219c74) + [wt: s/_HA_/HA_/] + Signed-off-by: Willy Tarreau + (cherry picked from commit 5dcf8515592602ed0d962e365cbb74a3646727c1) + Signed-off-by: Christopher Faulet + +diff --git a/src/vars.c b/src/vars.c +index 566ead6e..c86f612f 100644 +--- a/src/vars.c ++++ b/src/vars.c +@@ -34,6 +34,25 @@ static unsigned int var_reqres_limit = 0; + + __decl_hathreads(HA_RWLOCK_T var_names_rwlock); + ++/* returns the struct vars pointer for a session, stream and scope, or NULL if ++ * it does not exist. ++ */ ++static inline struct vars *get_vars(struct session *sess, struct stream *strm, enum vars_scope scope) ++{ ++ switch (scope) { ++ case SCOPE_PROC: ++ return &global.vars; ++ case SCOPE_SESS: ++ return &sess->vars; ++ case SCOPE_TXN: ++ return strm ? &strm->vars_txn : NULL; ++ case SCOPE_REQ: ++ case SCOPE_RES: ++ default: ++ return strm ? &strm->vars_reqres : NULL; ++ } ++} ++ + /* This function adds or remove memory size from the accounting. The inner + * pointers may be null when setting the outer ones only. + */ +@@ -42,10 +61,12 @@ static void var_accounting_diff(struct vars *vars, struct session *sess, struct + switch (vars->scope) { + case SCOPE_REQ: + case SCOPE_RES: +- HA_ATOMIC_ADD(&strm->vars_reqres.size, size); ++ if (strm) ++ HA_ATOMIC_ADD(&strm->vars_reqres.size, size); + /* fall through */ + case SCOPE_TXN: +- HA_ATOMIC_ADD(&strm->vars_txn.size, size); ++ if (strm) ++ HA_ATOMIC_ADD(&strm->vars_txn.size, size); + /* fall through */ + case SCOPE_SESS: + HA_ATOMIC_ADD(&sess->vars.size, size); +@@ -68,11 +89,11 @@ static int var_accounting_add(struct vars *vars, struct session *sess, struct st + switch (vars->scope) { + case SCOPE_REQ: + case SCOPE_RES: +- if (var_reqres_limit && strm->vars_reqres.size + size > var_reqres_limit) ++ if (var_reqres_limit && strm && strm->vars_reqres.size + size > var_reqres_limit) + return 0; + /* fall through */ + case SCOPE_TXN: +- if (var_txn_limit && strm->vars_txn.size + size > var_txn_limit) ++ if (var_txn_limit && strm && strm->vars_txn.size + size > var_txn_limit) + return 0; + /* fall through */ + case SCOPE_SESS: +@@ -285,27 +306,8 @@ static int smp_fetch_var(const struct arg *args, struct sample *smp, const char + struct vars *vars; + + /* Check the availibity of the variable. */ +- switch (var_desc->scope) { +- case SCOPE_PROC: +- vars = &global.vars; +- break; +- case SCOPE_SESS: +- vars = &smp->sess->vars; +- break; +- case SCOPE_TXN: +- if (!smp->strm) +- return 0; +- vars = &smp->strm->vars_txn; +- break; +- case SCOPE_REQ: +- case SCOPE_RES: +- default: +- if (!smp->strm) +- return 0; +- vars = &smp->strm->vars_reqres; +- break; +- } +- if (vars->scope != var_desc->scope) ++ vars = get_vars(smp->sess, smp->strm, var_desc->scope); ++ if (!vars || vars->scope != var_desc->scope) + return 0; + + HA_RWLOCK_RDLOCK(VARS_LOCK, &vars->rwlock); +@@ -423,15 +425,8 @@ static inline int sample_store_stream(const char *name, enum vars_scope scope, s + struct vars *vars; + int ret; + +- switch (scope) { +- case SCOPE_PROC: vars = &global.vars; break; +- case SCOPE_SESS: vars = &smp->sess->vars; break; +- case SCOPE_TXN: vars = &smp->strm->vars_txn; break; +- case SCOPE_REQ: +- case SCOPE_RES: +- default: vars = &smp->strm->vars_reqres; break; +- } +- if (vars->scope != scope) ++ vars = get_vars(smp->sess, smp->strm, scope); ++ if (!vars || vars->scope != scope) + return 0; + + HA_RWLOCK_WRLOCK(VARS_LOCK, &vars->rwlock); +@@ -447,15 +442,8 @@ static inline int sample_clear_stream(const char *name, enum vars_scope scope, s + struct var *var; + unsigned int size = 0; + +- switch (scope) { +- case SCOPE_PROC: vars = &global.vars; break; +- case SCOPE_SESS: vars = &smp->sess->vars; break; +- case SCOPE_TXN: vars = &smp->strm->vars_txn; break; +- case SCOPE_REQ: +- case SCOPE_RES: +- default: vars = &smp->strm->vars_reqres; break; +- } +- if (vars->scope != scope) ++ vars = get_vars(smp->sess, smp->strm, scope); ++ if (!vars || vars->scope != scope) + return 0; + + /* Look for existing variable name. */ +@@ -586,17 +574,8 @@ int vars_get_by_name(const char *name, size_t len, struct sample *smp) + return 0; + + /* Select "vars" pool according with the scope. */ +- switch (scope) { +- case SCOPE_PROC: vars = &global.vars; break; +- case SCOPE_SESS: vars = &smp->sess->vars; break; +- case SCOPE_TXN: vars = &smp->strm->vars_txn; break; +- case SCOPE_REQ: +- case SCOPE_RES: +- default: vars = &smp->strm->vars_reqres; break; +- } +- +- /* Check if the scope is avalaible a this point of processing. */ +- if (vars->scope != scope) ++ vars = get_vars(smp->sess, smp->strm, scope); ++ if (!vars || vars->scope != scope) + return 0; + + /* Get the variable entry. */ +@@ -620,17 +599,10 @@ int vars_get_by_desc(const struct var_desc *var_desc, struct sample *smp) + struct var *var; + + /* Select "vars" pool according with the scope. */ +- switch (var_desc->scope) { +- case SCOPE_PROC: vars = &global.vars; break; +- case SCOPE_SESS: vars = &smp->sess->vars; break; +- case SCOPE_TXN: vars = &smp->strm->vars_txn; break; +- case SCOPE_REQ: +- case SCOPE_RES: +- default: vars = &smp->strm->vars_reqres; break; +- } ++ vars = get_vars(smp->sess, smp->strm, var_desc->scope); + +- /* Check if the scope is avalaible a this point of processing. */ +- if (vars->scope != var_desc->scope) ++ /* Check if the scope is available a this point of processing. */ ++ if (!vars || vars->scope != var_desc->scope) + return 0; + + /* Get the variable entry. */ diff --git a/net/haproxy/patches/023-BUG-MEDIUM-vars-make-the-tcp-http-unset-var-action-support-conditions.patch b/net/haproxy/patches/023-BUG-MEDIUM-vars-make-the-tcp-http-unset-var-action-support-conditions.patch new file mode 100644 index 0000000000..6c98beb12a --- /dev/null +++ b/net/haproxy/patches/023-BUG-MEDIUM-vars-make-the-tcp-http-unset-var-action-support-conditions.patch @@ -0,0 +1,44 @@ +commit a41ac2d710711f3ab91d92415278a73c358aedca +Author: Willy Tarreau +Date: Tue Jun 4 16:43:29 2019 +0200 + + BUG/MEDIUM: vars: make the tcp/http unset-var() action support conditions + + Patrick Hemmer reported that http-request unset-var(foo) if ... fails to + parse. The reason is that it reuses the same parser as "set-var(foo)" which + makes a special case of the arguments, supposed to be a sample expression + for set-var, but which must not exist for unset-var. Unfortunately the + parser finds "if" or "unless" and believes it's an expression. Let's simply + drop the test so that the outer rule parser deals with potential extraneous + keywords. + + This should be backported to all versions supporting unset-var(). + + (cherry picked from commit 4b7531f48b5aa66d11fcee2836c201644bfb6a71) + Signed-off-by: Willy Tarreau + (cherry picked from commit a47e745276662db361637914b8558984f091306b) + Signed-off-by: Christopher Faulet + +diff --git a/src/vars.c b/src/vars.c +index c86f612f..d69fb838 100644 +--- a/src/vars.c ++++ b/src/vars.c +@@ -684,6 +684,7 @@ static int conv_check_var(struct arg *args, struct sample_conv *conv, + * the format: + * + * set-var() ++ * unset-var() + * + * It returns ACT_RET_PRS_ERR if fails and is filled with an error + * message. Otherwise, it returns ACT_RET_PRS_OK and the variable +@@ -727,10 +728,6 @@ static enum act_parse_ret parse_store(const char **args, int *arg, struct proxy + /* There is no fetch method when variable is unset. Just set the right + * action and return. */ + if (!set_var) { +- if (*args[*arg]) { +- memprintf(err, "fetch method not supported"); +- return ACT_RET_PRS_ERR; +- } + rule->action = ACT_CUSTOM; + rule->action_ptr = action_clear; + return ACT_RET_PRS_OK; diff --git a/net/haproxy/patches/024-BUG-MEDIUM-mux-h2-make-sure-the-connection-timeout-is-always-set.patch b/net/haproxy/patches/024-BUG-MEDIUM-mux-h2-make-sure-the-connection-timeout-is-always-set.patch new file mode 100644 index 0000000000..6c47f2f250 --- /dev/null +++ b/net/haproxy/patches/024-BUG-MEDIUM-mux-h2-make-sure-the-connection-timeout-is-always-set.patch @@ -0,0 +1,73 @@ +commit e7c30a33646f4ec73041ea57bd9fdcdc3e4a80ab +Author: Willy Tarreau +Date: Fri Jun 7 08:20:46 2019 +0200 + + BUG/MEDIUM: mux-h2: make sure the connection timeout is always set + + There seems to be a tricky case in the H2 mux related to stream flow + control versus buffer a full situation : is a large response cannot + be entirely sent to the client due to the stream window being too + small, the stream is paused with the SFCTL flag. Then the upper + layer stream might get bored and expire this stream. It will then + shut it down first. But the shutdown operation might fail if the + mux buffer is full, resulting in the h2s being subscribed to the + deferred_shut event with the stream *not* added to the send_list + since it's blocked in SFCTL. In the mean time the upper layer completely + closes, calling h2_detach(). There we have a send_wait (the pending + shutw), the stream is marked with SFCTL so we orphan it. + + Then if the client finally reads all the data that were clogging the + buffer, the send_list is run again, but our stream is not there. From + this point, the connection's stream list is not empty, the mux buffer + is empty, so the connection's timeout is not set. If the client + disappears without updating the stream's window, nothing will expire + the connection. + + This patch makes sure we always keep the connection timeout updated. + There might be finer solutions, such as checking that there are still + living streams in the connection (i.e. streams not blocked in SFCTL + state), though this is not necessarily trivial nor useful, since the + client timeout is the same for the upper level stream and the connection + anyway. + + This patch needs to be backported to 1.9 and 1.8 after some observation. + + (cherry picked from commit 7348119fb22bf761c33e06e8a092bd006660cc81) + Signed-off-by: Christopher Faulet + (cherry picked from commit e76090f78b6b8c519abf20061bfc5a4423816ea5) + Signed-off-by: Christopher Faulet + +diff --git a/src/mux_h2.c b/src/mux_h2.c +index b2f3096e..985b9742 100644 +--- a/src/mux_h2.c ++++ b/src/mux_h2.c +@@ -2406,12 +2406,8 @@ static int h2_wake(struct connection *conn) + } + + if (h2c->task) { +- if (eb_is_empty(&h2c->streams_by_id) || h2c->mbuf->o) { +- h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout); +- task_queue(h2c->task); +- } +- else +- h2c->task->expire = TICK_ETERNITY; ++ h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout); ++ task_queue(h2c->task); + } + return 0; + } +@@ -2587,12 +2583,8 @@ static void h2_detach(struct conn_stream *cs) + h2_release(h2c->conn); + } + else if (h2c->task) { +- if (eb_is_empty(&h2c->streams_by_id) || h2c->mbuf->o) { +- h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout); +- task_queue(h2c->task); +- } +- else +- h2c->task->expire = TICK_ETERNITY; ++ h2c->task->expire = tick_add(now_ms, h2c->last_sid < 0 ? h2c->timeout : h2c->shut_timeout); ++ task_queue(h2c->task); + } + } + diff --git a/net/haproxy/patches/025-BUG-MINOR-http-rules-mention-deny_status-for-deny-in-the-error-message.patch b/net/haproxy/patches/025-BUG-MINOR-http-rules-mention-deny_status-for-deny-in-the-error-message.patch new file mode 100644 index 0000000000..d907153f34 --- /dev/null +++ b/net/haproxy/patches/025-BUG-MINOR-http-rules-mention-deny_status-for-deny-in-the-error-message.patch @@ -0,0 +1,34 @@ +commit 8a74cad9b7fe8b9e1f5b140d90360ece838a878e +Author: Willy Tarreau +Date: Tue Jun 11 16:01:56 2019 +0200 + + BUG/MINOR: http-rules: mention "deny_status" for "deny" in the error message + + The error message indicating an unknown keyword on an http-request rule + doesn't mention the "deny_status" option which comes with the "deny" rule, + this is particularly confusing. + + This can be backported to all versions supporting this option. + + (cherry picked from commit 5abdc760c99a0011607f2cc97e199ef6ce0e8486) + Signed-off-by: Christopher Faulet + (cherry picked from commit 4e66beaf2a32bd835db9de61a60318648258f649) + Signed-off-by: Christopher Faulet + + [Cf: The fix was applied on src/proto_http.c because, in 1.8, the file + src/http_rules.c does not exist.] + +diff --git a/src/proto_http.c b/src/proto_http.c +index e5792f8c..689e0e31 100644 +--- a/src/proto_http.c ++++ b/src/proto_http.c +@@ -8830,7 +8830,8 @@ struct act_rule *parse_http_req_cond(const char **args, const char *file, int li + rule->cond = cond; + } + else if (*args[cur_arg]) { +- ha_alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth' or" ++ ha_alert("parsing [%s:%d]: 'http-request %s' expects 'realm' for 'auth'," ++ " 'deny_status' for 'deny', or" + " either 'if' or 'unless' followed by a condition but found '%s'.\n", + file, linenum, args[0], args[cur_arg]); + goto out_err; diff --git a/net/haproxy/patches/026-MINOR-doc-Remove--Ds-option-in-man-page.patch b/net/haproxy/patches/026-MINOR-doc-Remove--Ds-option-in-man-page.patch new file mode 100644 index 0000000000..44006f2cdb --- /dev/null +++ b/net/haproxy/patches/026-MINOR-doc-Remove--Ds-option-in-man-page.patch @@ -0,0 +1,30 @@ +commit 8f2772f5c603168ad3f79adc9e17569f510274ca +Author: Kazuo Yagi +Date: Thu Jun 13 17:14:57 2019 +0900 + + MINOR: doc: Remove -Ds option in man page + + Remove -Ds option in man page. + + Should be backported in every version since 1.8. + + (cherry picked from commit 971c3943be1283e9d377d68f95ea467304b3a8da) + Signed-off-by: Christopher Faulet + (cherry picked from commit a5e78ea5150f31190e4c1cd38fa7c1cadbf1ae8a) + Signed-off-by: Christopher Faulet + +diff --git a/doc/haproxy.1 b/doc/haproxy.1 +index 91f58a3b..cfed2cf7 100644 +--- a/doc/haproxy.1 ++++ b/doc/haproxy.1 +@@ -77,10 +77,6 @@ starting up. + \fB\-D\fP + Start in daemon mode. + +-.TP +-\fB\-Ds\fP +-Start in systemd daemon mode, keeping a process in foreground. +- + .TP + \fB\-q\fP + Disable messages on output. diff --git a/net/haproxy/patches/027-MINOR-doc-add-master-worker-in-the-man-page.patch b/net/haproxy/patches/027-MINOR-doc-add-master-worker-in-the-man-page.patch new file mode 100644 index 0000000000..61e8ad0ada --- /dev/null +++ b/net/haproxy/patches/027-MINOR-doc-add-master-worker-in-the-man-page.patch @@ -0,0 +1,55 @@ +commit 4fb0b5fb585e7f697914e935fe1001f752da8470 +Author: William Lallemand +Date: Thu Jun 13 11:51:09 2019 +0200 + + MINOR: doc: add master-worker in the man page + + Add some information about the master-worker in the man page. + + Should be backported in every version since 1.8. + + (cherry picked from commit 95635ddac8c29859d297e8ba33174e71efd5fc47) + Signed-off-by: Christopher Faulet + (cherry picked from commit d7a0c4695f00765dc03d7d6f6e17058726e84951) + Signed-off-by: Christopher Faulet + +diff --git a/doc/haproxy.1 b/doc/haproxy.1 +index cfed2cf7..2a23674f 100644 +--- a/doc/haproxy.1 ++++ b/doc/haproxy.1 +@@ -6,7 +6,7 @@ HAProxy \- fast and reliable http reverse proxy and load balancer + + .SH SYNOPSIS + +-haproxy \-f [\-L\ ] [\-n\ maxconn] [\-N\ maxconn] [\-C\ ] [\-v|\-vv] [\-d] [\-D] [\-q] [\-V] [\-c] [\-p\ ] [\-dk] [\-ds] [\-de] [\-dp] [\-db] [\-dM[]] [\-m\ ] [\-x ] [{\-sf|\-st}\ pidlist...] ++haproxy \-f [\-L\ ] [\-n\ maxconn] [\-N\ maxconn] [\-C\ ] [\-v|\-vv] [\-d] [\-D] [\-W] [\-Ws] [\-q] [\-V] [\-c] [\-p\ ] [\-dk] [\-ds] [\-de] [\-dp] [\-db] [\-dM[]] [\-m\ ] [\-x ] [{\-sf|\-st}\ pidlist...] + + .SH DESCRIPTION + +@@ -77,6 +77,16 @@ starting up. + \fB\-D\fP + Start in daemon mode. + ++.TP ++\fB\-W\fP ++Start in master-worker mode. Could be used either with foreground or daemon ++mode. ++ ++.TP ++\fB\-Ws\fP ++Start in master-worker mode with systemd notify support. It tells systemd when ++the process is ready. This mode forces foreground. ++ + .TP + \fB\-q\fP + Disable messages on output. +@@ -172,6 +182,9 @@ Some signals have a special meaning for the haproxy daemon. Generally, they are + \- \fBSIGUSR1\fP + Tells the daemon to stop all proxies and exit once all sessions are closed. It is often referred to as the "soft-stop" signal. + .TP ++\- \fBSIGUSR2\fP ++In master-worker mode, reloads the configuration and sends a soft-stop signal to old processes. ++.TP + \- \fBSIGTTOU\fP + Tells the daemon to stop listening to all sockets. Used internally by \fB\-sf\fP and \fB\-st\fP. + .TP diff --git a/net/haproxy/patches/028-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch b/net/haproxy/patches/028-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch new file mode 100644 index 0000000000..2c104636de --- /dev/null +++ b/net/haproxy/patches/028-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch @@ -0,0 +1,249 @@ +commit a27131f6e1e6c3e16e056915ba5ec2c560051296 +Author: Tim Duesterhus +Date: Mon Jun 17 16:10:07 2019 +0200 + + BUG/MEDIUM: compression: Set Vary: Accept-Encoding for compressed responses + + Make HAProxy set the `Vary: Accept-Encoding` response header if it compressed + the server response. + + Technically the `Vary` header SHOULD also be set for responses that would + normally be compressed based off the current configuration, but are not due + to a missing or invalid `Accept-Encoding` request header or due to the + maximum compression rate being exceeded. + + Not setting the header in these cases does no real harm, though: An + uncompressed response might be returned by a Cache, even if a compressed + one could be retrieved from HAProxy. This increases the traffic to the end + user if the cache is unable to compress itself, but it saves another + roundtrip to HAProxy. + + see the discussion on the mailing list: https://www.mail-archive.com/haproxy@formilux.org/msg34221.html + Message-ID: 20190617121708.GA2964@1wt.eu + + A small issue remains: The User-Agent is not added to the `Vary` header, + despite being relevant to the response. Adding the User-Agent header would + make responses effectively uncacheable and it's unlikely to see a Mozilla/4 + in the wild in 2019. + + Add a reg-test to ensure the behaviour as described in this commit message. + + see issue #121 + Should be backported to all branches with compression (i.e. 1.6+). + + (cherry picked from commit 721d686bd10dc6993859f9026ad907753d1d2064) + Signed-off-by: Christopher Faulet + (cherry picked from commit eaf650083924a697cde3379703984c5e7a5ebd41) + Signed-off-by: Christopher Faulet + (cherry picked from commit 96942d657ec7f29a328a5759558dbaa26d8e3e53) + Signed-off-by: Christopher Faulet + + [Cf: The patch was updated because there is no HTX in 1.8] + +diff --git a/reg-tests/compression/vary.vtc b/reg-tests/compression/vary.vtc +new file mode 100644 +index 00000000..0a060e4b +--- /dev/null ++++ b/reg-tests/compression/vary.vtc +@@ -0,0 +1,187 @@ ++varnishtest "Compression sets Vary header" ++ ++#REQUIRE_VERSION=1.9 ++#REQUIRE_OPTION=ZLIB|SLZ ++ ++feature ignore_unknown_macro ++ ++server s1 { ++ rxreq ++ expect req.url == "/plain/accept-encoding-gzip" ++ expect req.http.accept-encoding == "gzip" ++ txresp \ ++ -hdr "Content-Type: text/plain" \ ++ -bodylen 100 ++ ++ rxreq ++ expect req.url == "/plain/accept-encoding-invalid" ++ expect req.http.accept-encoding == "invalid" ++ txresp \ ++ -hdr "Content-Type: text/plain" \ ++ -bodylen 100 ++ ++ rxreq ++ expect req.url == "/plain/accept-encoding-null" ++ expect req.http.accept-encoding == "" ++ txresp \ ++ -hdr "Content-Type: text/plain" \ ++ -bodylen 100 ++ ++ rxreq ++ expect req.url == "/html/accept-encoding-gzip" ++ expect req.http.accept-encoding == "gzip" ++ txresp \ ++ -hdr "Content-Type: text/html" \ ++ -bodylen 100 ++ ++ rxreq ++ expect req.url == "/html/accept-encoding-invalid" ++ expect req.http.accept-encoding == "invalid" ++ txresp \ ++ -hdr "Content-Type: text/html" \ ++ -bodylen 100 ++ ++ ++ rxreq ++ expect req.url == "/html/accept-encoding-null" ++ expect req.http.accept-encoding == "" ++ txresp \ ++ -hdr "Content-Type: text/html" \ ++ -bodylen 100 ++ ++ rxreq ++ expect req.url == "/dup-etag/accept-encoding-gzip" ++ expect req.http.accept-encoding == "gzip" ++ txresp \ ++ -hdr "Content-Type: text/plain" \ ++ -hdr "ETag: \"123\"" \ ++ -hdr "ETag: \"123\"" \ ++ -bodylen 100 ++} -repeat 2 -start ++ ++ ++haproxy h1 -conf { ++ defaults ++ mode http ++ ${no-htx} option http-use-htx ++ timeout connect 1s ++ timeout client 1s ++ timeout server 1s ++ ++ frontend fe-gzip ++ bind "fd@${fe_gzip}" ++ default_backend be-gzip ++ ++ backend be-gzip ++ compression algo gzip ++ compression type text/plain ++ server www ${s1_addr}:${s1_port} ++ ++ frontend fe-nothing ++ bind "fd@${fe_nothing}" ++ default_backend be-nothing ++ ++ backend be-nothing ++ server www ${s1_addr}:${s1_port} ++} -start ++ ++client c1 -connect ${h1_fe_gzip_sock} { ++ txreq -url "/plain/accept-encoding-gzip" \ ++ -hdr "Accept-Encoding: gzip" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.content-encoding == "gzip" ++ expect resp.http.vary == "Accept-Encoding" ++ gunzip ++ expect resp.bodylen == 100 ++ ++ txreq -url "/plain/accept-encoding-invalid" \ ++ -hdr "Accept-Encoding: invalid" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/plain/accept-encoding-null" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/html/accept-encoding-gzip" \ ++ -hdr "Accept-Encoding: gzip" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/html/accept-encoding-invalid" \ ++ -hdr "Accept-Encoding: invalid" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/html/accept-encoding-null" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/dup-etag/accept-encoding-gzip" \ ++ -hdr "Accept-Encoding: gzip" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++} -run ++ ++# This Client duplicates c1, against the "nothing" frontend, ensuring no Vary header is ever set. ++client c2 -connect ${h1_fe_nothing_sock} { ++ txreq -url "/plain/accept-encoding-gzip" \ ++ -hdr "Accept-Encoding: gzip" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/plain/accept-encoding-invalid" \ ++ -hdr "Accept-Encoding: invalid" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/plain/accept-encoding-null" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/html/accept-encoding-gzip" \ ++ -hdr "Accept-Encoding: gzip" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/html/accept-encoding-invalid" \ ++ -hdr "Accept-Encoding: invalid" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/html/accept-encoding-null" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++ ++ txreq -url "/dup-etag/accept-encoding-gzip" \ ++ -hdr "Accept-Encoding: gzip" ++ rxresp ++ expect resp.status == 200 ++ expect resp.http.vary == "" ++ expect resp.bodylen == 100 ++} -run +diff --git a/src/flt_http_comp.c b/src/flt_http_comp.c +index b93ff69e..b48a4491 100644 +--- a/src/flt_http_comp.c ++++ b/src/flt_http_comp.c +@@ -555,6 +555,9 @@ select_compression_response_header(struct comp_state *st, struct stream *s, stru + if (!(msg->flags & HTTP_MSGF_TE_CHNK)) + http_header_add_tail2(&txn->rsp, &txn->hdr_idx, "Transfer-Encoding: chunked", 26); + ++ /* add Vary header */ ++ if (http_header_add_tail2(&txn->rsp, &txn->hdr_idx, "Vary: Accept-Encoding", 21) < 0) ++ goto fail; + /* + * Add Content-Encoding header when it's not identity encoding. + * RFC 2616 : Identity encoding: This content-coding is used only in the diff --git a/net/haproxy/patches/012-deprecated-openssl.patch b/net/haproxy/patches/029-deprecated-openssl.patch similarity index 83% rename from net/haproxy/patches/012-deprecated-openssl.patch rename to net/haproxy/patches/029-deprecated-openssl.patch index 1b8216f8a3..70479dfdc3 100644 --- a/net/haproxy/patches/012-deprecated-openssl.patch +++ b/net/haproxy/patches/029-deprecated-openssl.patch @@ -8,7 +8,7 @@ #include #include #include -@@ -61,6 +62,17 @@ +@@ -60,6 +61,17 @@ #include #endif @@ -26,7 +26,7 @@ #include #include -@@ -206,7 +218,7 @@ static struct { +@@ -217,7 +229,7 @@ static struct { .capture_cipherlist = 0, }; @@ -35,7 +35,7 @@ static HA_RWLOCK_T *ssl_rwlocks; -@@ -1675,8 +1687,8 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL +@@ -1716,8 +1728,8 @@ ssl_sock_do_create_cert(const char *servername, struct bind_conf *bind_conf, SSL ASN1_INTEGER_set(X509_get_serialNumber(newcrt), HA_ATOMIC_ADD(&ssl_ctx_serial, 1)); /* Set duration for the certificate */ @@ -46,7 +46,7 @@ goto mkcert_error; /* set public key in the certificate */ -@@ -6226,7 +6238,7 @@ smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char +@@ -6299,7 +6311,7 @@ smp_fetch_ssl_x_notafter(const struct arg *args, struct sample *smp, const char goto out; smp_trash = get_trash_chunk(); @@ -55,7 +55,7 @@ goto out; smp->data.u.str = *smp_trash; -@@ -6326,7 +6338,7 @@ smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char +@@ -6399,7 +6411,7 @@ smp_fetch_ssl_x_notbefore(const struct a goto out; smp_trash = get_trash_chunk(); @@ -64,21 +64,26 @@ goto out; smp->data.u.str = *smp_trash; -@@ -8777,10 +8789,12 @@ static void __ssl_sock_init(void) - global_ssl.connect_default_ciphers = strdup(global_ssl.connect_default_ciphers); +@@ -8977,7 +8989,9 @@ static void __ssl_sock_init(void) + #endif xprt_register(XPRT_SSL, &ssl_sock); +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_library_init(); +#endif + #if (!defined(OPENSSL_NO_COMP) && !defined(SSL_OP_NO_COMPRESSION)) cm = SSL_COMP_get_compression_methods(); - sk_SSL_COMP_zero(cm); + i = sk_SSL_COMP_num(cm); +@@ -8986,7 +9000,7 @@ static void __ssl_sock_init(void) + } + #endif + -#ifdef USE_THREAD +#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L) ssl_locking_init(); #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL && !defined OPENSSL_NO_TLSEXT && !defined OPENSSL_IS_BORINGSSL && !defined LIBRESSL_VERSION_NUMBER) -@@ -8808,8 +8822,8 @@ static void __ssl_sock_init(void) +@@ -9015,8 +9029,8 @@ static void __ssl_sock_init(void) #else /* OPENSSL_IS_BORINGSSL */ OPENSSL_VERSION_TEXT "\nRunning on OpenSSL version : %s%s", @@ -89,7 +94,7 @@ #endif memprintf(&ptr, "%s\nOpenSSL library supports TLS extensions : " #if OPENSSL_VERSION_NUMBER < 0x00907000L -@@ -8900,12 +8914,14 @@ static void __ssl_sock_deinit(void) +@@ -9107,12 +9121,14 @@ static void __ssl_sock_deinit(void) } #endif