From 01ec3b49a5d2033f1ccc73b6935aff03e2868152 Mon Sep 17 00:00:00 2001 From: Christian Lachner Date: Mon, 24 Jun 2019 23:08:52 +0200 Subject: [PATCH] haproxy: Update HAProxy to v2.0.0 (LTS) - Update haproxy download URL and hash - Add new patches - Add several CFLAGS (derived from haproxy Makefile) to make the build work with v1.9+ - Update default configuration - Add check-command (for config) to init-script - Add prometheus-service from contribs by default - Add support for uclibc to haproxy with libcrypt disabled - Minor cleanups I have been running v2.0 for some time now and it feels as stable as v1.8. v2.0 is the new LTS release. Signed-off-by: Christian Lachner --- net/haproxy/Makefile | 27 +- net/haproxy/files/haproxy.cfg | 17 +- net/haproxy/files/haproxy.hotplug | 1 - net/haproxy/files/haproxy.init | 8 +- net/haproxy/get-latest-patches.sh | 4 +- ...he-HTX-when-the-cookie-list-is-built.patch | 32 +++ ...tp_req_ctr-only-one-time-per-request.patch | 40 --- ...-previous-frag-frame-but-len-changed.patch | 83 ------ ...-req_req_-and-txn-res_rep_-HTX-aware.patch | 32 +++ ...n-in-lower-case-in-outgoing-messages.patch | 29 ++ ...o-pass-frag_ctx-info-during-encoding.patch | 71 ----- ...pt-Encoding-for-compressed-responses.patch | 253 ++++++++++++++++++ ...ity-Typos-and-fix-the-reject-example.patch | 38 --- ...header-is-NULL-dont-try-to-strdup-it.patch | 36 --- ...he-function-htx_change_blk_value_len.patch | 66 +++++ ...sage-when-the-block-value-is-changed.patch | 133 +++++++++ ...-last-changelog-date-in-haproxy-spec.patch | 23 -- ...-segfault-during-show-map-acl-on-CLI.patch | 67 ----- ...padlen-when-several-frames-are-demux.patch | 27 ++ ...er-of-consecutive-accepts-is-handled.patch | 79 ------ ...th-when-a-DATA-frame-size-is-checked.patch | 30 +++ ...ervers-lb_tree-from-outside-the-lock.patch | 39 +++ ...-maxaccept-during-the-config-parsing.patch | 44 --- ...e-parsing-in-if-unless-ACL-condition.patch | 40 +++ ...r--maxaccept-when-nbproc-is-set-to-1.patch | 34 --- ...NOR-threads-Implement-HA_ATOMIC_LOAD.patch | 54 ---- .../patches/010-add-uclibc-support.patch | 18 ++ ...range-Make-the-ring-buffer-lock-free.patch | 116 -------- .../patches/012-deprecated-openssl.patch | 107 -------- 29 files changed, 736 insertions(+), 812 deletions(-) create mode 100644 net/haproxy/patches/000-BUG-MEDIUM-h2-htx-Update-data-length-of-the-HTX-when-the-cookie-list-is-built.patch delete 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/001-BUG-MEDIUM-spoe-arg-len-encoded-in-previous-frag-frame-but-len-changed.patch create mode 100644 net/haproxy/patches/001-BUG-MINOR-lua-htx-Make-txn-req_req_-and-txn-res_rep_-HTX-aware.patch create mode 100644 net/haproxy/patches/002-BUG-MINOR-mux-h1-Add-the-header-connection-in-lower-case-in-outgoing-messages.patch delete 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-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch delete mode 100644 net/haproxy/patches/003-DOC-contrib-modsecurity-Typos-and-fix-the-reject-example.patch delete 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/004-MINOR-htx-Add-the-function-htx_change_blk_value_len.patch create mode 100644 net/haproxy/patches/005-BUG-MEDIUM-htx-Fully-update-HTX-message-when-the-block-value-is-changed.patch delete mode 100644 net/haproxy/patches/005-MINOR-examples-Use-right-locale-for-the-last-changelog-date-in-haproxy-spec.patch delete 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/006-BUG-MEDIUM-mux-h2-Reset-padlen-when-several-frames-are-demux.patch delete 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/007-BUG-MEDIUM-mux-h2-Remove-the-padding-length-when-a-DATA-frame-size-is-checked.patch create mode 100644 net/haproxy/patches/008-BUG-MEDIUM-lb_fwlc-Dont-test-the-servers-lb_tree-from-outside-the-lock.patch delete 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-BUG-MAJOR-sample-Wrong-stick-table-name-parsing-in-if-unless-ACL-condition.patch delete mode 100644 net/haproxy/patches/009-CLEANUP-config-Dont-alter-listener--maxaccept-when-nbproc-is-set-to-1.patch delete mode 100644 net/haproxy/patches/010-MINOR-threads-Implement-HA_ATOMIC_LOAD.patch create mode 100644 net/haproxy/patches/010-add-uclibc-support.patch delete mode 100644 net/haproxy/patches/011-BUG-MEDIUM-port_range-Make-the-ring-buffer-lock-free.patch delete mode 100644 net/haproxy/patches/012-deprecated-openssl.patch diff --git a/net/haproxy/Makefile b/net/haproxy/Makefile index b42bc59583..272f0075e4 100644 --- a/net/haproxy/Makefile +++ b/net/haproxy/Makefile @@ -10,12 +10,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=haproxy -PKG_VERSION:=1.8.20 -PKG_RELEASE:=1 +PKG_VERSION:=2.0.0 +PKG_RELEASE:=2 PKG_SOURCE:=haproxy-$(PKG_VERSION).tar.gz -PKG_SOURCE_URL:=https://www.haproxy.org/download/1.8/src/ -PKG_HASH:=3228f78d5fe1dfbaccf41bf387e36b08eeef6e16330053cafde5fa303e262b16 +PKG_SOURCE_URL:=https://www.haproxy.org/download/2.0/src/ +PKG_HASH:=fe0a0d69e1091066a91b8d39199c19af8748e0e872961c6fc43c91ec7a28ff20 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION) PKG_LICENSE:=GPL-2.0 @@ -91,10 +91,14 @@ ENABLE_LUA:=y ENABLE_REGPARM:=n ifeq ($(CONFIG_TARGET_x86),y) - ENABLE_REGPARM:=y + ENABLE_REGPARM:=y endif -LINUX_TARGET:=linux2628 +ifeq ($(CONFIG_USE_UCLIBC),y) + LINUX_TARGET:=linux-uclibc +else + LINUX_TARGET:=linux-glibc +endif ifeq ($(BUILD_VARIANT),ssl) ADDON+=USE_OPENSSL=1 @@ -133,14 +137,16 @@ define Build/Compile CC="$(TARGET_CC)" \ PCREDIR="$(STAGING_DIR)/usr/" \ 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 \ + USE_LINUX_TPROXY=1 USE_LINUX_SPLICE=1 USE_TFO=1 USE_NS=1 \ + USE_ZLIB=1 USE_PCRE=1 USE_PCRE_JIT=1 USE_GETADDRINFO=1 \ + USE_THREAD=1 USE_PTHREAD_PSHARED=1 \ VERSION="$(PKG_VERSION)" SUBVERS="-$(PKG_RELEASE)" \ VERDATE="$(shell date -d @$(SOURCE_DATE_EPOCH) '+%Y/%m/%d')" IGNOREGIT=1 \ $(ADDON) \ - CFLAGS="$(TARGET_CFLAGS)" \ + CFLAGS="$(TARGET_CFLAGS) -fno-strict-aliasing -Wdeclaration-after-statement -fwrapv -Wno-format-truncation -Wno-unused-label -Wno-sign-compare -Wno-unused-parameter -Wno-old-style-declaration -Wno-ignored-qualifiers -Wno-clobbered -Wno-missing-field-initializers -Wno-implicit-fallthrough -Wno-stringop-overflow -Wno-cast-function-type -Wtype-limits -Wshift-negative-value -Wshift-overflow=2 -Wduplicated-cond -Wnull-dereference" \ LD="$(TARGET_CC)" \ - LDFLAGS="$(TARGET_LDFLAGS) -latomic" + LDFLAGS="$(TARGET_LDFLAGS) -latomic" \ + EXTRA_OBJS="contrib/prometheus-exporter/service-prometheus.o" $(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR) \ DESTDIR="$(PKG_INSTALL_DIR)" \ @@ -152,6 +158,7 @@ define Build/Compile $(MAKE_VARS) $(MAKE) -C $(PKG_BUILD_DIR)/contrib/halog \ DESTDIR="$(PKG_INSTALL_DIR)" \ $(MAKE_FLAGS) \ + OPTIMIZE="$(TARGET_CFLAGS)" \ ADDLIB="-lcrypto" \ halog endef diff --git a/net/haproxy/files/haproxy.cfg b/net/haproxy/files/haproxy.cfg index a54f5f5ddb..ffe5949ca0 100644 --- a/net/haproxy/files/haproxy.cfg +++ b/net/haproxy/files/haproxy.cfg @@ -1,6 +1,6 @@ -# Example configuration file for HAProxy 1.3, refer to the url below for +# Example configuration file for HAProxy 2.0, refer to the url below for # a full documentation and examples for configuration: -# http://haproxy.1wt.eu/download/1.3/doc/configuration.txt +# https://cbonte.github.io/haproxy-dconv/2.0/configuration.html # Global parameters @@ -38,6 +38,13 @@ global # limits like number of open file descriptors. Default is 1. #nbproc 2 +# Default parameters +defaults + # Default timeouts + timeout connect 5000ms + timeout client 50000ms + timeout server 50000ms + # Example HTTP proxy listener listen my_http_proxy @@ -78,9 +85,9 @@ listen my_smtp_proxy # Round robin load balancing over two servers on port 123 forcing # the address 192.168.1.1 and port 25 as source. balance roundrobin - #use next line for transparent proxy, so the servers can see the - #original ip-address and remove source keyword in server definition - #source 0.0.0.0 usesrc clientip + #use next line for transparent proxy, so the servers can see the + #original ip-address and remove source keyword in server definition + #source 0.0.0.0 usesrc clientip server server01 192.168.1.10:123 source 192.168.1.1:25 server server02 192.168.1.20:123 source 192.168.1.1:25 diff --git a/net/haproxy/files/haproxy.hotplug b/net/haproxy/files/haproxy.hotplug index d14b5bf3f4..bfb5d6da12 100644 --- a/net/haproxy/files/haproxy.hotplug +++ b/net/haproxy/files/haproxy.hotplug @@ -1,7 +1,6 @@ #!/bin/sh if [ "$ACTION" = add ]; then - /etc/init.d/haproxy enabled && \ /etc/init.d/haproxy start fi diff --git a/net/haproxy/files/haproxy.init b/net/haproxy/files/haproxy.init index edda9a3a78..52bc126ac2 100644 --- a/net/haproxy/files/haproxy.init +++ b/net/haproxy/files/haproxy.init @@ -5,6 +5,7 @@ START=99 STOP=80 SERVICE_USE_PID=1 +EXTRA_COMMANDS="check" HAPROXY_BIN="/usr/sbin/haproxy" HAPROXY_CONFIG="/etc/haproxy.cfg" @@ -20,6 +21,9 @@ stop() { } reload() { - $HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID | tr "\n" " ") - #$HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID) + $HAPROXY_BIN -D -q -f $HAPROXY_CONFIG -p $HAPROXY_PID -sf $(cat $HAPROXY_PID) +} + +check() { + $HAPROXY_BIN -c -q -V -f $HAPROXY_CONFIG } diff --git a/net/haproxy/get-latest-patches.sh b/net/haproxy/get-latest-patches.sh index f4b683ecf0..a60529e64d 100755 --- a/net/haproxy/get-latest-patches.sh +++ b/net/haproxy/get-latest-patches.sh @@ -1,7 +1,7 @@ #!/bin/bash -CLONEURL=http://git.haproxy.org/git/haproxy-1.8.git -BASE_TAG=v1.8.20 +CLONEURL=http://git.haproxy.org/git/haproxy-2.0.git +BASE_TAG=v2.0.0 TMP_REPODIR=tmprepo PATCHESDIR=patches diff --git a/net/haproxy/patches/000-BUG-MEDIUM-h2-htx-Update-data-length-of-the-HTX-when-the-cookie-list-is-built.patch b/net/haproxy/patches/000-BUG-MEDIUM-h2-htx-Update-data-length-of-the-HTX-when-the-cookie-list-is-built.patch new file mode 100644 index 0000000000..6d79bf8e6f --- /dev/null +++ b/net/haproxy/patches/000-BUG-MEDIUM-h2-htx-Update-data-length-of-the-HTX-when-the-cookie-list-is-built.patch @@ -0,0 +1,32 @@ +commit 032cff38c24d8359dc575423a94d19b6ad8bf848 +Author: Christopher Faulet +Date: Mon Jun 17 11:44:47 2019 +0200 + + BUG/MEDIUM: h2/htx: Update data length of the HTX when the cookie list is built + + When an H2 request is converted into an HTX message, All cookie headers are + grouped into one, each value separated by a semicolon (;). To do so, we add the + header "cookie" with the first value and then we update the value by appending + other cookies. But during this operation, only the size of the HTX block is + updated. And not the data length of the whole HTX message. + + It is an old bug and it seems to work by chance till now. But it may lead to + undefined behaviour by time to time. + + This patch must be backported to 2.0 and 1.9 + + (cherry picked from commit 0c6de00d7c842a682bba7586ef34fb10f69ec63c) + Signed-off-by: Christopher Faulet + +diff --git a/src/h2.c b/src/h2.c +index 9681aca5..32c1ef16 100644 +--- a/src/h2.c ++++ b/src/h2.c +@@ -737,6 +737,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms + goto fail; + + htx_set_blk_value_len(blk, tl); ++ htx->data += vl+2; + *(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';'; + *(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' '; + memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl); 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 deleted file mode 100644 index 4449df1ccd..0000000000 --- a/net/haproxy/patches/000-BUG-MINOR-http-Call-stream_inc_be_http_req_ctr-only-one-time-per-request.patch +++ /dev/null @@ -1,40 +0,0 @@ -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/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 deleted file mode 100644 index 9ef9507652..0000000000 --- a/net/haproxy/patches/001-BUG-MEDIUM-spoe-arg-len-encoded-in-previous-frag-frame-but-len-changed.patch +++ /dev/null @@ -1,83 +0,0 @@ -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/001-BUG-MINOR-lua-htx-Make-txn-req_req_-and-txn-res_rep_-HTX-aware.patch b/net/haproxy/patches/001-BUG-MINOR-lua-htx-Make-txn-req_req_-and-txn-res_rep_-HTX-aware.patch new file mode 100644 index 0000000000..693dd64ac4 --- /dev/null +++ b/net/haproxy/patches/001-BUG-MINOR-lua-htx-Make-txn-req_req_-and-txn-res_rep_-HTX-aware.patch @@ -0,0 +1,32 @@ +commit 5a8549e68225070d0b79cbbb9c5f791e103685e7 +Author: Christopher Faulet +Date: Mon Jun 17 13:36:06 2019 +0200 + + BUG/MINOR: lua/htx: Make txn.req_req_* and txn.res_rep_* HTX aware + + These bindings were not updated to support HTX streams. + + This patch must be backported to 2.0 and 1.9. It fixes the issue #124. + + (cherry picked from commit ea418748dd22331e9798cfd8f5e25b436cd577e3) + Signed-off-by: Christopher Faulet + +diff --git a/src/hlua.c b/src/hlua.c +index 28abd083..32f0e8db 100644 +--- a/src/hlua.c ++++ b/src/hlua.c +@@ -5375,7 +5375,13 @@ __LJMP static inline int hlua_http_rep_hdr(lua_State *L, struct hlua_txn *htxn, + if (!(re = regex_comp(reg, 1, 1, NULL))) + WILL_LJMP(luaL_argerror(L, 3, "invalid regex")); + +- http_transform_header_str(htxn->s, msg, name, name_len, value, re, action); ++ if (IS_HTX_STRM(htxn->s)) { ++ struct htx *htx = htxbuf(&msg->chn->buf); ++ ++ htx_transform_header_str(htxn->s, msg->chn, htx, ist2(name, name_len), value, re, action); ++ } ++ else ++ http_transform_header_str(htxn->s, msg, name, name_len, value, re, action); + regex_free(re); + return 0; + } diff --git a/net/haproxy/patches/002-BUG-MINOR-mux-h1-Add-the-header-connection-in-lower-case-in-outgoing-messages.patch b/net/haproxy/patches/002-BUG-MINOR-mux-h1-Add-the-header-connection-in-lower-case-in-outgoing-messages.patch new file mode 100644 index 0000000000..73983b434d --- /dev/null +++ b/net/haproxy/patches/002-BUG-MINOR-mux-h1-Add-the-header-connection-in-lower-case-in-outgoing-messages.patch @@ -0,0 +1,29 @@ +commit 661bfc3d0e1b7756db59d00d86e316f694cae3c6 +Author: Christopher Faulet +Date: Mon Jun 17 14:07:46 2019 +0200 + + BUG/MINOR: mux-h1: Add the header connection in lower case in outgoing messages + + When necessary, this header is directly added in outgoing messages by the H1 + multiplexer. Because there is no HTX conversion first, the header name is not + converserted to its lower case version. So, it must be added in lower case by + the multiplexer. + + This patch must be backported to 2.0 and 1.9. + + (cherry picked from commit a110ecbd843e156dd01c6ac581c735be5e240d5b) + Signed-off-by: Christopher Faulet + +diff --git a/src/mux_h1.c b/src/mux_h1.c +index 317f1a55..21deb354 100644 +--- a/src/mux_h1.c ++++ b/src/mux_h1.c +@@ -1642,7 +1642,7 @@ static size_t h1_process_output(struct h1c *h1c, struct buffer *buf, size_t coun + /* There is no "Connection:" header and + * it the conn_mode must be + * processed. So do it */ +- n = ist("Connection"); ++ n = ist("connection"); + v = ist(""); + h1_process_output_conn_mode(h1s, h1m, &v); + if (v.len) { 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 deleted file mode 100644 index c26629c816..0000000000 --- a/net/haproxy/patches/002-MINOR-spoe-Use-the-sample-context-to-pass-frag_ctx-info-during-encoding.patch +++ /dev/null @@ -1,71 +0,0 @@ -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-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch b/net/haproxy/patches/003-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch new file mode 100644 index 0000000000..b71741cce1 --- /dev/null +++ b/net/haproxy/patches/003-BUG-MEDIUM-compression-Set-Vary-Accept-Encoding-for-compressed-responses.patch @@ -0,0 +1,253 @@ +commit eaf650083924a697cde3379703984c5e7a5ebd41 +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 + +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 b04dcd14..37f237fe 100644 +--- a/src/flt_http_comp.c ++++ b/src/flt_http_comp.c +@@ -523,6 +523,9 @@ http_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *m + } + } + ++ if (http_header_add_tail2(msg, &txn->hdr_idx, "Vary: Accept-Encoding", 21) < 0) ++ goto error; ++ + return 1; + + error: +@@ -577,6 +580,9 @@ htx_set_comp_reshdr(struct comp_state *st, struct stream *s, struct http_msg *ms + } + } + ++ if (!http_add_header(htx, ist("Vary"), ist("Accept-Encoding"))) ++ goto error; ++ + return 1; + + error: 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 deleted file mode 100644 index 514c4c568d..0000000000 --- a/net/haproxy/patches/003-DOC-contrib-modsecurity-Typos-and-fix-the-reject-example.patch +++ /dev/null @@ -1,38 +0,0 @@ -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 deleted file mode 100644 index af49cc2f41..0000000000 --- a/net/haproxy/patches/004-BUG-MEDIUM-contrib-modsecurity-If-host-header-is-NULL-dont-try-to-strdup-it.patch +++ /dev/null @@ -1,36 +0,0 @@ -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/004-MINOR-htx-Add-the-function-htx_change_blk_value_len.patch b/net/haproxy/patches/004-MINOR-htx-Add-the-function-htx_change_blk_value_len.patch new file mode 100644 index 0000000000..7c308f7620 --- /dev/null +++ b/net/haproxy/patches/004-MINOR-htx-Add-the-function-htx_change_blk_value_len.patch @@ -0,0 +1,66 @@ +commit 8d09dc21dc913d1540d07d1019a51c430317eae1 +Author: Christopher Faulet +Date: Tue Jun 18 09:37:00 2019 +0200 + + MINOR: htx: Add the function htx_change_blk_value_len() + + As its name suggest, this function change the value length of a block. But it + also update the HTX message accordingly. It simplifies the HTX API. The function + htx_set_blk_value_len() is still available and must be used with caution because + this one does not update the HTX message. It just updates the HTX block. It + should be considered as an internal function. When possible, + htx_change_blk_value_len() should be used instead. + + This function is used to fix a bug affecting the 2.0. So, this patch must be + backported to 2.0. + + (cherry picked from commit bb0efcdd293de33607a6eba075971b49857375e2) + Signed-off-by: Christopher Faulet + +diff --git a/include/common/htx.h b/include/common/htx.h +index 9631c618..7d15365a 100644 +--- a/include/common/htx.h ++++ b/include/common/htx.h +@@ -470,7 +470,41 @@ static inline struct htx_blk *htx_get_next_blk(const struct htx *htx, + } + + /* Changes the size of the value. It is the caller responsibility to change the +- * value itself, make sure there is enough space and update allocated value. ++ * value itself, make sure there is enough space and update allocated ++ * value. This function updates the HTX message accordingly. ++ */ ++static inline void htx_change_blk_value_len(struct htx *htx, struct htx_blk *blk, uint32_t newlen) ++{ ++ enum htx_blk_type type = htx_get_blk_type(blk); ++ uint32_t oldlen, sz; ++ int32_t delta; ++ ++ sz = htx_get_blksz(blk); ++ switch (type) { ++ case HTX_BLK_HDR: ++ case HTX_BLK_TLR: ++ oldlen = (blk->info >> 8) & 0xfffff; ++ blk->info = (type << 28) + (newlen << 8) + (blk->info & 0xff); ++ break; ++ default: ++ oldlen = blk->info & 0xfffffff; ++ blk->info = (type << 28) + newlen; ++ break; ++ } ++ ++ /* Update HTTP message */ ++ delta = (newlen - oldlen); ++ htx->data += delta; ++ if (blk->addr+sz == htx->tail_addr) ++ htx->tail_addr += delta; ++ else if (blk->addr+sz == htx->head_addr) ++ htx->head_addr += delta; ++} ++ ++/* Changes the size of the value. It is the caller responsibility to change the ++ * value itself, make sure there is enough space and update allocated ++ * value. Unlike the function htx_change_blk_value_len(), this one does not ++ * update the HTX message. So it should be used with caution. + */ + static inline void htx_set_blk_value_len(struct htx_blk *blk, uint32_t vlen) + { diff --git a/net/haproxy/patches/005-BUG-MEDIUM-htx-Fully-update-HTX-message-when-the-block-value-is-changed.patch b/net/haproxy/patches/005-BUG-MEDIUM-htx-Fully-update-HTX-message-when-the-block-value-is-changed.patch new file mode 100644 index 0000000000..5a9fda464c --- /dev/null +++ b/net/haproxy/patches/005-BUG-MEDIUM-htx-Fully-update-HTX-message-when-the-block-value-is-changed.patch @@ -0,0 +1,133 @@ +commit 41dc8432f87622145390dc1b1467a5ee14ba184c +Author: Christopher Faulet +Date: Tue Jun 18 09:49:16 2019 +0200 + + BUG/MEDIUM: htx: Fully update HTX message when the block value is changed + + Everywhere the value length of a block is changed, calling the function + htx_set_blk_value_len(), the HTX message must be updated. But at many places, + because of the recent changes in the HTX structure, this update was only + partially done. tail_addr and head_addr values were not systematically updated. + + In fact, the function htx_set_blk_value_len() was designed as an internal + function to the HTX API. And we used it from outside by convenience. But it is + really painfull and error prone to let the caller update the HTX message. So + now, we use the function htx_change_blk_value_len() wherever is possible. It + changes the value length of a block and updates the HTX message accordingly. + + This patch must be backported to 2.0. + + (cherry picked from commit 3e2638ee04407a1d9e9376f0c518f67fca7deaa4) + Signed-off-by: Christopher Faulet + +diff --git a/src/h2.c b/src/h2.c +index 32c1ef16..990d602b 100644 +--- a/src/h2.c ++++ b/src/h2.c +@@ -736,8 +736,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms + if (tl > fs) + goto fail; + +- htx_set_blk_value_len(blk, tl); +- htx->data += vl+2; ++ htx_change_blk_value_len(htx, blk, tl); + *(char *)(htx_get_blk_ptr(htx, blk) + bs + 0) = ';'; + *(char *)(htx_get_blk_ptr(htx, blk) + bs + 1) = ' '; + memcpy(htx_get_blk_ptr(htx, blk) + bs + 2, list[ck].v.ptr, vl); +diff --git a/src/http_htx.c b/src/http_htx.c +index 7322b337..bc26e5ba 100644 +--- a/src/http_htx.c ++++ b/src/http_htx.c +@@ -461,10 +461,7 @@ int http_remove_header(struct htx *htx, struct http_hdr_ctx *ctx) + } + /* Update the block content and its len */ + memmove(start, start+len, v.len-len); +- htx_set_blk_value_len(blk, v.len-len); +- +- /* Update HTX msg */ +- htx->data -= len; ++ htx_change_blk_value_len(htx, blk, v.len-len); + + /* Finally update the ctx */ + ctx->value.ptr = start; +diff --git a/src/htx.c b/src/htx.c +index bfd136f4..81492598 100644 +--- a/src/htx.c ++++ b/src/htx.c +@@ -406,15 +406,8 @@ void htx_truncate(struct htx *htx, uint32_t offset) + offset -= sz; + continue; + } +- if (type == HTX_BLK_DATA) { +- htx_set_blk_value_len(blk, offset); +- htx->data -= (sz - offset); +- +- if (blk->addr+sz == htx->tail_addr) +- htx->tail_addr -= offset; +- else if (blk->addr+sz == htx->head_addr) +- htx->head_addr -= offset; +- } ++ if (type == HTX_BLK_DATA) ++ htx_change_blk_value_len(htx, blk, offset); + offset = 0; + } + while (blk) +@@ -522,14 +515,7 @@ struct htx_blk *htx_add_data_atonce(struct htx *htx, struct ist data) + /* Append data and update the block itself */ + ptr = htx_get_blk_ptr(htx, tailblk); + memcpy(ptr+sz, data.ptr, len); +- htx_set_blk_value_len(tailblk, sz+len); +- +- /* Update HTTP message */ +- htx->data += len; +- if (tailblk->addr+sz == htx->tail_addr) +- htx->tail_addr += len; +- else if (tailblk->addr+sz == htx->head_addr) +- htx->head_addr += len; ++ htx_change_blk_value_len(htx, tailblk, sz+len); + + if (data.len == len) { + blk = tailblk; +@@ -988,14 +974,7 @@ size_t htx_add_data(struct htx *htx, const struct ist data) + /* Append data and update the block itself */ + ptr = htx_get_blk_ptr(htx, tailblk); + memcpy(ptr + sz, data.ptr, len); +- htx_set_blk_value_len(tailblk, sz + len); +- +- /* Update HTTP message */ +- htx->data += len; +- if (tailblk->addr+sz == htx->tail_addr) +- htx->tail_addr += len; +- else if (tailblk->addr+sz == htx->head_addr) +- htx->head_addr += len; ++ htx_change_blk_value_len(htx, tailblk, sz+len); + + BUG_ON((int32_t)htx->tail_addr < 0); + BUG_ON((int32_t)htx->head_addr < 0); +diff --git a/src/proto_htx.c b/src/proto_htx.c +index 7f501366..d821e38c 100644 +--- a/src/proto_htx.c ++++ b/src/proto_htx.c +@@ -4314,10 +4314,8 @@ static void htx_manage_client_side_cookies(struct stream *s, struct channel *req + hdr_end = (preserve_hdr ? del_from : hdr_beg); + } + if ((hdr_end - hdr_beg) != ctx.value.len) { +- if (hdr_beg != hdr_end) { +- htx_set_blk_value_len(ctx.blk, hdr_end - hdr_beg); +- htx->data -= ctx.value.len - (hdr_end - hdr_beg); +- } ++ if (hdr_beg != hdr_end) ++ htx_change_blk_value_len(htx, ctx.blk, hdr_end - hdr_beg); + else + http_remove_header(htx, &ctx); + } +@@ -4495,8 +4493,7 @@ static void htx_manage_server_side_cookies(struct stream *s, struct channel *res + next += stripped_before; + hdr_end += stripped_before; + +- htx_set_blk_value_len(ctx.blk, hdr_end - hdr_beg); +- htx->data -= ctx.value.len - (hdr_end - hdr_beg); ++ htx_change_blk_value_len(htx, ctx.blk, hdr_end - hdr_beg); + ctx.value.len = hdr_end - hdr_beg; + } + 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 deleted file mode 100644 index 310dc0f4f4..0000000000 --- a/net/haproxy/patches/005-MINOR-examples-Use-right-locale-for-the-last-changelog-date-in-haproxy-spec.patch +++ /dev/null @@ -1,23 +0,0 @@ -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 deleted file mode 100644 index e961294770..0000000000 --- a/net/haproxy/patches/006-BUG-MAJOR-map-acl-real-fix-segfault-during-show-map-acl-on-CLI.patch +++ /dev/null @@ -1,67 +0,0 @@ -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/006-BUG-MEDIUM-mux-h2-Reset-padlen-when-several-frames-are-demux.patch b/net/haproxy/patches/006-BUG-MEDIUM-mux-h2-Reset-padlen-when-several-frames-are-demux.patch new file mode 100644 index 0000000000..3a18eeeb8e --- /dev/null +++ b/net/haproxy/patches/006-BUG-MEDIUM-mux-h2-Reset-padlen-when-several-frames-are-demux.patch @@ -0,0 +1,27 @@ +commit 3d574a587dc3704e93bcd29b16d54d96069667b4 +Author: Christopher Faulet +Date: Tue Jun 18 12:22:38 2019 +0200 + + BUG/MEDIUM: mux-h2: Reset padlen when several frames are demux + + In the function h2_process_demux(), if several frames are parsed, the padding + length must be reset between each frame. Otherwise we may wrongly think a frame + has a padding block because the previous one was padded. + + This patch must be backported to 2.0 and 1.9. + + (cherry picked from commit dd2a5620d594523cd515a629e105a9a2b64345bb) + Signed-off-by: Christopher Faulet + +diff --git a/src/mux_h2.c b/src/mux_h2.c +index d02168df..c06d5d68 100644 +--- a/src/mux_h2.c ++++ b/src/mux_h2.c +@@ -2316,6 +2316,7 @@ static void h2_process_demux(struct h2c *h2c) + break; + } + ++ padlen = 0; + if (h2_ft_bit(hdr.ft) & H2_FT_PADDED_MASK && hdr.ff & H2_F_PADDED) { + /* If the frame is padded (HEADERS, PUSH_PROMISE or DATA), + * we read the pad length and drop it from the remaining 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 deleted file mode 100644 index e54c530fbe..0000000000 --- a/net/haproxy/patches/007-BUG-MEDIUM-listener-Fix-how-unlimited-number-of-consecutive-accepts-is-handled.patch +++ /dev/null @@ -1,79 +0,0 @@ -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/007-BUG-MEDIUM-mux-h2-Remove-the-padding-length-when-a-DATA-frame-size-is-checked.patch b/net/haproxy/patches/007-BUG-MEDIUM-mux-h2-Remove-the-padding-length-when-a-DATA-frame-size-is-checked.patch new file mode 100644 index 0000000000..d23f66fc30 --- /dev/null +++ b/net/haproxy/patches/007-BUG-MEDIUM-mux-h2-Remove-the-padding-length-when-a-DATA-frame-size-is-checked.patch @@ -0,0 +1,30 @@ +commit 4fb65f421b4d650711e5d8b9dbcbf4bf589d26cc +Author: Christopher Faulet +Date: Wed Jun 19 09:25:58 2019 +0200 + + BUG/MEDIUM: mux-h2: Remove the padding length when a DATA frame size is checked + + When a DATA frame is processed for a message with a content-length, we first + take care to not have a frame size that exceeds the remaining to + read. Otherwise, an error is triggered. But we must remove the padding length + from the frame size because the padding is not included in the announced + content-length. + + This patch must be backported to 2.0 and 1.9. + + (cherry picked from commit 4f09ec812adbd9336cddc054660a7fb5cd54b459) + Signed-off-by: Christopher Faulet + +diff --git a/src/mux_h2.c b/src/mux_h2.c +index c06d5d68..5bb85181 100644 +--- a/src/mux_h2.c ++++ b/src/mux_h2.c +@@ -2177,7 +2177,7 @@ static int h2c_frt_handle_data(struct h2c *h2c, struct h2s *h2s) + goto strm_err; + } + +- if ((h2s->flags & H2_SF_DATA_CLEN) && h2c->dfl > h2s->body_len) { ++ if ((h2s->flags & H2_SF_DATA_CLEN) && (h2c->dfl - h2c->dpl) > h2s->body_len) { + /* RFC7540#8.1.2 */ + error = H2_ERR_PROTOCOL_ERROR; + goto strm_err; diff --git a/net/haproxy/patches/008-BUG-MEDIUM-lb_fwlc-Dont-test-the-servers-lb_tree-from-outside-the-lock.patch b/net/haproxy/patches/008-BUG-MEDIUM-lb_fwlc-Dont-test-the-servers-lb_tree-from-outside-the-lock.patch new file mode 100644 index 0000000000..129c0b7d48 --- /dev/null +++ b/net/haproxy/patches/008-BUG-MEDIUM-lb_fwlc-Dont-test-the-servers-lb_tree-from-outside-the-lock.patch @@ -0,0 +1,39 @@ +commit 3f0b1de623d09f8668db34c1be696f7245de7d50 +Author: Christopher Faulet +Date: Wed Jun 19 10:50:38 2019 +0200 + + BUG/MEDIUM: lb_fwlc: Don't test the server's lb_tree from outside the lock + + In the function fwlc_srv_reposition(), the server's lb_tree is tested from + outside the lock. So it is possible to remove it after the test and then call + eb32_insert() in fwlc_queue_srv() with a NULL root pointer, which is + invalid. Moving the test in the scope of the lock fixes the bug. + + This issue was reported on Github, issue #126. + + This patch must be backported to 2.0, 1.9 and 1.8. + + (cherry picked from commit 1ae2a8878170ded922f2c4d32b6704af7689bbfd) + Signed-off-by: Christopher Faulet + +diff --git a/src/lb_fwlc.c b/src/lb_fwlc.c +index 174dc67e..5fa81739 100644 +--- a/src/lb_fwlc.c ++++ b/src/lb_fwlc.c +@@ -66,12 +66,11 @@ static inline void fwlc_queue_srv(struct server *s) + */ + static void fwlc_srv_reposition(struct server *s) + { +- if (!s->lb_tree) +- return; +- + HA_SPIN_LOCK(LBPRM_LOCK, &s->proxy->lbprm.lock); +- fwlc_dequeue_srv(s); +- fwlc_queue_srv(s); ++ if (s->lb_tree) { ++ fwlc_dequeue_srv(s); ++ fwlc_queue_srv(s); ++ } + HA_SPIN_UNLOCK(LBPRM_LOCK, &s->proxy->lbprm.lock); + } + 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 deleted file mode 100644 index 5c5d88967a..0000000000 --- a/net/haproxy/patches/008-MINOR-config-Test-validity-of-tune-maxaccept-during-the-config-parsing.patch +++ /dev/null @@ -1,44 +0,0 @@ -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-BUG-MAJOR-sample-Wrong-stick-table-name-parsing-in-if-unless-ACL-condition.patch b/net/haproxy/patches/009-BUG-MAJOR-sample-Wrong-stick-table-name-parsing-in-if-unless-ACL-condition.patch new file mode 100644 index 0000000000..66b5f1aec9 --- /dev/null +++ b/net/haproxy/patches/009-BUG-MAJOR-sample-Wrong-stick-table-name-parsing-in-if-unless-ACL-condition.patch @@ -0,0 +1,40 @@ +commit 9eae8935663bc0b27c23018e8cc24ae9a3e31732 +Author: Frédéric Lécaille +Date: Thu Jun 20 09:31:04 2019 +0200 + + BUG/MAJOR: sample: Wrong stick-table name parsing in "if/unless" ACL condition. + + This bug was introduced by 1b8e68e commit which supposed the stick-table was always + stored in struct arg at parsing time. This is never the case with the usage of + "if/unless" conditions in stick-table declared as backends. In this case, this is + the name of the proxy which must be considered as the stick-table name. + + This must be backported to 2.0. + + (cherry picked from commit 9417f4534ad742eda35c4cc3d1ccb390f75ea4b1) + Signed-off-by: Willy Tarreau + +diff --git a/src/sample.c b/src/sample.c +index 67f59e84..77ec9b1e 100644 +--- a/src/sample.c ++++ b/src/sample.c +@@ -1245,15 +1245,11 @@ int smp_resolve_args(struct proxy *p) + break; + + case ARGT_TAB: +- if (!arg->data.str.data) { +- ha_alert("parsing [%s:%d] : missing table name in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n", +- cur->file, cur->line, +- cur->arg_pos + 1, conv_pre, conv_ctx, conv_pos, ctx, cur->kw, where, p->id); +- cfgerr++; +- continue; +- } ++ if (arg->data.str.data) ++ stktname = arg->data.str.area; ++ else ++ stktname = px->id; + +- stktname = arg->data.str.area; + t = stktable_find_by_name(stktname); + if (!t) { + ha_alert("parsing [%s:%d] : unable to find table '%s' referenced in arg %d of %s%s%s%s '%s' %s proxy '%s'.\n", 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 deleted file mode 100644 index 4bcae444fe..0000000000 --- a/net/haproxy/patches/009-CLEANUP-config-Dont-alter-listener--maxaccept-when-nbproc-is-set-to-1.patch +++ /dev/null @@ -1,34 +0,0 @@ -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 deleted file mode 100644 index 30e8cd4d72..0000000000 --- a/net/haproxy/patches/010-MINOR-threads-Implement-HA_ATOMIC_LOAD.patch +++ /dev/null @@ -1,54 +0,0 @@ -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/010-add-uclibc-support.patch b/net/haproxy/patches/010-add-uclibc-support.patch new file mode 100644 index 0000000000..275702522b --- /dev/null +++ b/net/haproxy/patches/010-add-uclibc-support.patch @@ -0,0 +1,18 @@ +--- a/Makefile ++++ b/Makefile +@@ -327,6 +327,15 @@ ifeq ($(TARGET),linux-glibc) + USE_GETADDRINFO) + endif + ++# For linux >= 2.6.28 and uclibc ++ifeq ($(TARGET),linux-uclibc) ++ set_target_defaults = $(call default_opts, \ ++ USE_POLL USE_TPROXY USE_DL USE_RT USE_NETFILTER \ ++ USE_CPU_AFFINITY USE_THREAD USE_EPOLL USE_FUTEX USE_LINUX_TPROXY \ ++ USE_ACCEPT4 USE_LINUX_SPLICE USE_PRCTL USE_THREAD_DUMP USE_NS USE_TFO \ ++ USE_GETADDRINFO) ++endif ++ + # Solaris 8 and above + ifeq ($(TARGET),solaris) + # We also enable getaddrinfo() which works since solaris 8. 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 deleted file mode 100644 index 68332fdde4..0000000000 --- a/net/haproxy/patches/011-BUG-MEDIUM-port_range-Make-the-ring-buffer-lock-free.patch +++ /dev/null @@ -1,116 +0,0 @@ -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-deprecated-openssl.patch b/net/haproxy/patches/012-deprecated-openssl.patch deleted file mode 100644 index 8dd011e419..0000000000 --- a/net/haproxy/patches/012-deprecated-openssl.patch +++ /dev/null @@ -1,107 +0,0 @@ ---- a/src/ssl_sock.c -+++ b/src/ssl_sock.c -@@ -39,6 +39,7 @@ - #include - #include - -+#include - #include - #include - #include -@@ -60,6 +61,17 @@ - #include - #endif - -+#ifndef OPENSSL_VERSION -+#define OPENSSL_VERSION SSLEAY_VERSION -+#define OpenSSL_version(x) SSLeay_version(x) -+#define OpenSSL_version_num SSLeay -+#endif -+ -+#if OPENSSL_VERSION_NUMBER < 0x10100000L -+#define X509_getm_notBefore X509_get_notBefore -+#define X509_getm_notAfter X509_get_notAfter -+#endif -+ - #include - #include - -@@ -217,7 +229,7 @@ static struct { - .capture_cipherlist = 0, - }; - --#ifdef USE_THREAD -+#if defined(USE_THREAD) && (OPENSSL_VERSION_NUMBER < 0x10100000L) - - static HA_RWLOCK_T *ssl_rwlocks; - -@@ -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 */ -- if (!X509_gmtime_adj(X509_get_notBefore(newcrt), (long)-60*60*24) || -- !X509_gmtime_adj(X509_get_notAfter(newcrt),(long)60*60*24*365)) -+ if (!X509_gmtime_adj(X509_getm_notBefore(newcrt), (long)-60*60*24) || -+ !X509_gmtime_adj(X509_getm_notAfter(newcrt),(long)60*60*24*365)) - goto mkcert_error; - - /* set public key in the certificate */ -@@ -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(); -- if (ssl_sock_get_time(X509_get_notAfter(crt), smp_trash) <= 0) -+ if (ssl_sock_get_time(X509_getm_notAfter(crt), smp_trash) <= 0) - goto out; - - smp->data.u.str = *smp_trash; -@@ -6399,7 +6411,7 @@ smp_fetch_ssl_x_notbefore(const struct arg *args, struct sample *smp, const char - goto out; - - smp_trash = get_trash_chunk(); -- if (ssl_sock_get_time(X509_get_notBefore(crt), smp_trash) <= 0) -+ if (ssl_sock_get_time(X509_getm_notBefore(crt), smp_trash) <= 0) - goto out; - - smp->data.u.str = *smp_trash; -@@ -8976,10 +8988,12 @@ static void __ssl_sock_init(void) - #endif - - xprt_register(XPRT_SSL, &ssl_sock); -+#if OPENSSL_VERSION_NUMBER < 0x10100000L - SSL_library_init(); -+#endif - cm = SSL_COMP_get_compression_methods(); - sk_SSL_COMP_zero(cm); --#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) -@@ -9008,8 +9022,8 @@ static void __ssl_sock_init(void) - #else /* OPENSSL_IS_BORINGSSL */ - OPENSSL_VERSION_TEXT - "\nRunning on OpenSSL version : %s%s", -- SSLeay_version(SSLEAY_VERSION), -- ((OPENSSL_VERSION_NUMBER ^ SSLeay()) >> 8) ? " (VERSIONS DIFFER!)" : ""); -+ OpenSSL_version(OPENSSL_VERSION), -+ ((OPENSSL_VERSION_NUMBER ^ OpenSSL_version_num()) >> 8) ? " (VERSIONS DIFFER!)" : ""); - #endif - memprintf(&ptr, "%s\nOpenSSL library supports TLS extensions : " - #if OPENSSL_VERSION_NUMBER < 0x00907000L -@@ -9100,12 +9114,14 @@ static void __ssl_sock_deinit(void) - } - #endif - -+#if OPENSSL_VERSION_NUMBER < 0x10100000L - ERR_remove_state(0); - ERR_free_strings(); - - EVP_cleanup(); -+#endif - --#if OPENSSL_VERSION_NUMBER >= 0x00907000L -+#if OPENSSL_VERSION_NUMBER >= 0x00907000L && OPENSSL_VERSION_NUMBER < 0x10100000L - CRYPTO_cleanup_all_ex_data(); - #endif - } -- 2.30.2