summaryrefslogtreecommitdiffstats
path: root/debian/patches
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:35:12 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:35:12 +0000
commit89057599f4791f03c1ee5de836fbe2b5ea434aa9 (patch)
tree09ef6df146509f94541c1afe9cbd78b7f75e81e7 /debian/patches
parentAdding upstream version 2.6.12. (diff)
downloadhaproxy-89057599f4791f03c1ee5de836fbe2b5ea434aa9.tar.xz
haproxy-89057599f4791f03c1ee5de836fbe2b5ea434aa9.zip
Adding debian version 2.6.12-1+deb12u1.debian/2.6.12-1+deb12u1debian
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian/patches')
-rw-r--r--debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch100
-rw-r--r--debian/patches/BUG-MAJOR-http-reject-any-empty-content-length-heade.patch274
-rw-r--r--debian/patches/BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch118
-rw-r--r--debian/patches/BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch68
-rw-r--r--debian/patches/BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch71
-rw-r--r--debian/patches/DOC-clarify-the-handling-of-URL-fragments-in-request.patch76
-rw-r--r--debian/patches/MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch73
-rw-r--r--debian/patches/MINOR-http-add-new-function-http_path_has_forbidden_.patch56
-rw-r--r--debian/patches/MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch84
-rw-r--r--debian/patches/REGTESTS-http-rules-add-accept-invalid-http-request-.patch44
-rw-r--r--debian/patches/REGTESTS-http-rules-verify-that-we-block-by-default-.patch50
-rw-r--r--debian/patches/REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch109
-rw-r--r--debian/patches/debianize-dconv.patch170
-rw-r--r--debian/patches/haproxy.service-add-documentation.patch23
-rw-r--r--debian/patches/haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch21
-rw-r--r--debian/patches/haproxy.service-start-after-syslog.patch27
-rw-r--r--debian/patches/reproducible.patch13
-rw-r--r--debian/patches/series19
18 files changed, 1396 insertions, 0 deletions
diff --git a/debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch b/debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch
new file mode 100644
index 0000000..11ae6f8
--- /dev/null
+++ b/debian/patches/BUG-MAJOR-h3-reject-header-values-containing-invalid.patch
@@ -0,0 +1,100 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 17:18:27 +0200
+Subject: BUG/MAJOR: h3: reject header values containing invalid chars
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=20a35c4d505475215122d37405ce173075338032
+
+In practice it's exactly the same for h3 as 54f53ef7c ("BUG/MAJOR: h2:
+reject header values containing invalid chars") was for h2: we must
+make sure never to accept NUL/CR/LF in any header value because this
+may be used to construct splitted headers on the backend. Hence we
+apply the same solution. Here pseudo-headers, headers and trailers are
+checked separately, which explains why we have 3 locations instead of
+2 for h2 (+1 for response which we don't have here).
+
+This is marked major for consistency and due to the impact if abused,
+but the reality is that at the time of writing, this problem is limited
+by the scarcity of the tools which would permit to build such a request
+in the first place. But this may change over time.
+
+This must be backported to 2.6. This depends on the following commit
+that exposes the filtering function:
+
+ REORG: http: move has_forbidden_char() from h2.c to http.h
+
+(cherry picked from commit d13a80abb7c1badaa42045c37cfff79f24f05726)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 0404bf14c900d6ac879ec432a198435e0741d835)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit f58b63af68f239464c29e698a34f08ff3eef862f)
+ [ad: no http/3 trailer support in 2.6]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ src/h3.c | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/src/h3.c b/src/h3.c
+index 9b4bc6f096d7..b42d41647e4e 100644
+--- a/src/h3.c
++++ b/src/h3.c
+@@ -401,6 +401,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
+ struct ist scheme = IST_NULL, authority = IST_NULL;
+ int hdr_idx, ret;
+ int cookie = -1, last_cookie = -1, i;
++ const char *ctl;
+
+ /* RFC 9114 4.1.2. Malformed Requests and Responses
+ *
+@@ -464,6 +465,24 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
+ if (!istmatch(list[hdr_idx].n, ist(":")))
+ break;
+
++ /* RFC 9114 10.3 Intermediary-Encapsulation Attacks
++ *
++ * While most values that can be encoded will not alter field
++ * parsing, carriage return (ASCII 0x0d), line feed (ASCII 0x0a),
++ * and the null character (ASCII 0x00) might be exploited by an
++ * attacker if they are translated verbatim. Any request or
++ * response that contains a character not permitted in a field
++ * value MUST be treated as malformed
++ */
++
++ /* look for forbidden control characters in the pseudo-header value */
++ ctl = ist_find_ctl(list[hdr_idx].v);
++ if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) {
++ TRACE_ERROR("control character present in pseudo-header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
++ len = -1;
++ goto out;
++ }
++
+ /* pseudo-header. Malformed name with uppercase character or
+ * invalid token will be rejected in the else clause.
+ */
+@@ -561,6 +580,25 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
+ }
+ }
+
++
++ /* RFC 9114 10.3 Intermediary-Encapsulation Attacks
++ *
++ * While most values that can be encoded will not alter field
++ * parsing, carriage return (ASCII 0x0d), line feed (ASCII 0x0a),
++ * and the null character (ASCII 0x00) might be exploited by an
++ * attacker if they are translated verbatim. Any request or
++ * response that contains a character not permitted in a field
++ * value MUST be treated as malformed
++ */
++
++ /* look for forbidden control characters in the header value */
++ ctl = ist_find_ctl(list[hdr_idx].v);
++ if (unlikely(ctl) && http_header_has_forbidden_char(list[hdr_idx].v, ctl)) {
++ TRACE_ERROR("control character present in header value", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
++ len = -1;
++ goto out;
++ }
++
+ if (isteq(list[hdr_idx].n, ist("cookie"))) {
+ http_cookie_register(list, hdr_idx, &cookie, &last_cookie);
+ ++hdr_idx;
+--
+2.43.0
+
diff --git a/debian/patches/BUG-MAJOR-http-reject-any-empty-content-length-heade.patch b/debian/patches/BUG-MAJOR-http-reject-any-empty-content-length-heade.patch
new file mode 100644
index 0000000..fb8bcb0
--- /dev/null
+++ b/debian/patches/BUG-MAJOR-http-reject-any-empty-content-length-heade.patch
@@ -0,0 +1,274 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Wed, 9 Aug 2023 08:32:48 +0200
+Subject: BUG/MAJOR: http: reject any empty content-length header value
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=d17c50010d591d1c070e1cb0567a06032d8869e9
+Bug-Debian: https://bugs.debian.org/1043502
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2023-40225
+
+The content-length header parser has its dedicated function, in order
+to take extreme care about invalid, unparsable, or conflicting values.
+But there's a corner case in it, by which it stops comparing values
+when reaching the end of the header. This has for a side effect that
+an empty value or a value that ends with a comma does not deserve
+further analysis, and it acts as if the header was absent.
+
+While this is not necessarily a problem for the value ending with a
+comma as it will be cause a header folding and will disappear, it is a
+problem for the first isolated empty header because this one will not
+be recontructed when next ones are seen, and will be passed as-is to the
+backend server. A vulnerable HTTP/1 server hosted behind haproxy that
+would just use this first value as "0" and ignore the valid one would
+then not be protected by haproxy and could be attacked this way, taking
+the payload for an extra request.
+
+In field the risk depends on the server. Most commonly used servers
+already have safe content-length parsers, but users relying on haproxy
+to protect a known-vulnerable server might be at risk (and the risk of
+a bug even in a reputable server should never be dismissed).
+
+A configuration-based work-around consists in adding the following rule
+in the frontend, to explicitly reject requests featuring an empty
+content-length header that would have not be folded into an existing
+one:
+
+ http-request deny if { hdr_len(content-length) 0 }
+
+The real fix consists in adjusting the parser so that it always expects a
+value at the beginning of the header or after a comma. It will now reject
+requests and responses having empty values anywhere in the C-L header.
+
+This needs to be backported to all supported versions. Note that the
+modification was made to functions h1_parse_cont_len_header() and
+http_parse_cont_len_header(). Prior to 2.8 the latter was in
+h2_parse_cont_len_header(). One day the two should be refused but the
+former is also used by Lua.
+
+The HTTP messaging reg-tests were completed to test these cases.
+
+Thanks to Ben Kallus of Dartmouth College and Narf Industries for
+reporting this! (this is in GH #2237).
+
+(cherry picked from commit 6492f1f29d738457ea9f382aca54537f35f9d856)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit a32f99f6f991d123ea3e307bf8aa63220836d365)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 65921ee12d88e9fb1fa9f6cd8198fd64b3a3f37f)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ reg-tests/http-messaging/h1_to_h1.vtc | 26 ++++++++++++
+ reg-tests/http-messaging/h2_to_h1.vtc | 60 +++++++++++++++++++++++++++
+ src/h1.c | 20 +++++++--
+ src/http.c | 20 +++++++--
+ 4 files changed, 120 insertions(+), 6 deletions(-)
+
+diff --git a/reg-tests/http-messaging/h1_to_h1.vtc b/reg-tests/http-messaging/h1_to_h1.vtc
+index 0d6536698608..67aba1440949 100644
+--- a/reg-tests/http-messaging/h1_to_h1.vtc
++++ b/reg-tests/http-messaging/h1_to_h1.vtc
+@@ -273,3 +273,29 @@ client c3h1 -connect ${h1_feh1_sock} {
+ # arrive here.
+ expect_close
+ } -run
++
++client c4h1 -connect ${h1_feh1_sock} {
++ # this request is invalid and advertises an invalid C-L ending with an
++ # empty value, which results in a stream error.
++ txreq \
++ -req "GET" \
++ -url "/test31.html" \
++ -hdr "content-length: 0," \
++ -hdr "connection: close"
++ rxresp
++ expect resp.status == 400
++ expect_close
++} -run
++
++client c5h1 -connect ${h1_feh1_sock} {
++ # this request is invalid and advertises an empty C-L, which results
++ # in a stream error.
++ txreq \
++ -req "GET" \
++ -url "/test41.html" \
++ -hdr "content-length:" \
++ -hdr "connection: close"
++ rxresp
++ expect resp.status == 400
++ expect_close
++} -run
+diff --git a/reg-tests/http-messaging/h2_to_h1.vtc b/reg-tests/http-messaging/h2_to_h1.vtc
+index 852ee4caf9dd..5c8c8214314b 100644
+--- a/reg-tests/http-messaging/h2_to_h1.vtc
++++ b/reg-tests/http-messaging/h2_to_h1.vtc
+@@ -10,6 +10,8 @@ barrier b1 cond 2 -cyclic
+ barrier b2 cond 2 -cyclic
+ barrier b3 cond 2 -cyclic
+ barrier b4 cond 2 -cyclic
++barrier b5 cond 2 -cyclic
++barrier b6 cond 2 -cyclic
+
+ server s1 {
+ rxreq
+@@ -31,6 +33,12 @@ server s1 {
+
+ barrier b4 sync
+ # the next request is never received
++
++ barrier b5 sync
++ # the next request is never received
++
++ barrier b6 sync
++ # the next request is never received
+ } -repeat 2 -start
+
+ haproxy h1 -conf {
+@@ -120,6 +128,32 @@ client c1h2 -connect ${h1_feh2_sock} {
+ txdata -data "this is sent and ignored"
+ rxrst
+ } -run
++
++ # fifth request is invalid and advertises an invalid C-L ending with an
++ # empty value, which results in a stream error.
++ stream 9 {
++ barrier b5 sync
++ txreq \
++ -req "GET" \
++ -scheme "https" \
++ -url "/test5.html" \
++ -hdr "content-length" "0," \
++ -nostrend
++ rxrst
++ } -run
++
++ # sixth request is invalid and advertises an empty C-L, which results
++ # in a stream error.
++ stream 11 {
++ barrier b6 sync
++ txreq \
++ -req "GET" \
++ -scheme "https" \
++ -url "/test6.html" \
++ -hdr "content-length" "" \
++ -nostrend
++ rxrst
++ } -run
+ } -run
+
+ # HEAD requests : don't work well yet
+@@ -262,4 +296,30 @@ client c3h2 -connect ${h1_feh2_sock} {
+ txdata -data "this is sent and ignored"
+ rxrst
+ } -run
++
++ # fifth request is invalid and advertises invalid C-L ending with an
++ # empty value, which results in a stream error.
++ stream 9 {
++ barrier b5 sync
++ txreq \
++ -req "POST" \
++ -scheme "https" \
++ -url "/test25.html" \
++ -hdr "content-length" "0," \
++ -nostrend
++ rxrst
++ } -run
++
++ # sixth request is invalid and advertises an empty C-L, which results
++ # in a stream error.
++ stream 11 {
++ barrier b6 sync
++ txreq \
++ -req "POST" \
++ -scheme "https" \
++ -url "/test26.html" \
++ -hdr "content-length" "" \
++ -nostrend
++ rxrst
++ } -run
+ } -run
+diff --git a/src/h1.c b/src/h1.c
+index 88a54c4a593d..126f23cc7376 100644
+--- a/src/h1.c
++++ b/src/h1.c
+@@ -34,13 +34,20 @@ int h1_parse_cont_len_header(struct h1m *h1m, struct ist *value)
+ int not_first = !!(h1m->flags & H1_MF_CLEN);
+ struct ist word;
+
+- word.ptr = value->ptr - 1; // -1 for next loop's pre-increment
++ word.ptr = value->ptr;
+ e = value->ptr + value->len;
+
+- while (++word.ptr < e) {
++ while (1) {
++ if (word.ptr >= e) {
++ /* empty header or empty value */
++ goto fail;
++ }
++
+ /* skip leading delimiter and blanks */
+- if (unlikely(HTTP_IS_LWS(*word.ptr)))
++ if (unlikely(HTTP_IS_LWS(*word.ptr))) {
++ word.ptr++;
+ continue;
++ }
+
+ /* digits only now */
+ for (cl = 0, n = word.ptr; n < e; n++) {
+@@ -79,6 +86,13 @@ int h1_parse_cont_len_header(struct h1m *h1m, struct ist *value)
+ h1m->flags |= H1_MF_CLEN;
+ h1m->curr_len = h1m->body_len = cl;
+ *value = word;
++
++ /* Now either n==e and we're done, or n points to the comma,
++ * and we skip it and continue.
++ */
++ if (n++ == e)
++ break;
++
+ word.ptr = n;
+ }
+ /* here we've reached the end with a single value or a series of
+diff --git a/src/http.c b/src/http.c
+index edf4744553a2..a33c673c11da 100644
+--- a/src/http.c
++++ b/src/http.c
+@@ -707,13 +707,20 @@ int http_parse_cont_len_header(struct ist *value, unsigned long long *body_len,
+ struct ist word;
+ int check_prev = not_first;
+
+- word.ptr = value->ptr - 1; // -1 for next loop's pre-increment
++ word.ptr = value->ptr;
+ e = value->ptr + value->len;
+
+- while (++word.ptr < e) {
++ while (1) {
++ if (word.ptr >= e) {
++ /* empty header or empty value */
++ goto fail;
++ }
++
+ /* skip leading delimiter and blanks */
+- if (unlikely(HTTP_IS_LWS(*word.ptr)))
++ if (unlikely(HTTP_IS_LWS(*word.ptr))) {
++ word.ptr++;
+ continue;
++ }
+
+ /* digits only now */
+ for (cl = 0, n = word.ptr; n < e; n++) {
+@@ -751,6 +758,13 @@ int http_parse_cont_len_header(struct ist *value, unsigned long long *body_len,
+ /* OK, store this result as the one to be indexed */
+ *body_len = cl;
+ *value = word;
++
++ /* Now either n==e and we're done, or n points to the comma,
++ * and we skip it and continue.
++ */
++ if (n++ == e)
++ break;
++
+ word.ptr = n;
+ check_prev = 1;
+ }
+--
+2.43.0
+
diff --git a/debian/patches/BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch b/debian/patches/BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch
new file mode 100644
index 0000000..02d1e74
--- /dev/null
+++ b/debian/patches/BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch
@@ -0,0 +1,118 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 16:17:22 +0200
+Subject: BUG/MINOR: h1: do not accept '#' as part of the URI component
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=832b672eee54866c7a42a1d46078cc9ae0d544d9
+Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2023-45539
+
+Seth Manesse and Paul Plasil reported that the "path" sample fetch
+function incorrectly accepts '#' as part of the path component. This
+can in some cases lead to misrouted requests for rules that would apply
+on the suffix:
+
+ use_backend static if { path_end .png .jpg .gif .css .js }
+
+Note that this behavior can be selectively configured using
+"normalize-uri fragment-encode" and "normalize-uri fragment-strip".
+
+The problem is that while the RFC says that this '#' must never be
+emitted, as often it doesn't suggest how servers should handle it. A
+diminishing number of servers still do accept it and trim it silently,
+while others are rejecting it, as indicated in the conversation below
+with other implementers:
+
+ https://lists.w3.org/Archives/Public/ietf-http-wg/2023JulSep/0070.html
+
+Looking at logs from publicly exposed servers, such requests appear at
+a rate of roughly 1 per million and only come from attacks or poorly
+written web crawlers incorrectly following links found on various pages.
+
+Thus it looks like the best solution to this problem is to simply reject
+such ambiguous requests by default, and include this in the list of
+controls that can be disabled using "option accept-invalid-http-request".
+
+We're already rejecting URIs containing any control char anyway, so we
+should also reject '#'.
+
+In the H1 parser for the H1_MSG_RQURI state, there is an accelerated
+parser for bytes 0x21..0x7e that has been tightened to 0x24..0x7e (it
+should not impact perf since 0x21..0x23 are not supposed to appear in
+a URI anyway). This way '#' falls through the fine-grained filter and
+we can add the special case for it also conditionned by a check on the
+proxy's option "accept-invalid-http-request", with no overhead for the
+vast majority of valid URIs. Here this information is available through
+h1m->err_pos that's set to -2 when the option is here (so we don't need
+to change the API to expose the proxy). Example with a trivial GET
+through netcat:
+
+ [08/Aug/2023:16:16:52.651] frontend layer1 (#2): invalid request
+ backend <NONE> (#-1), server <NONE> (#-1), event #0, src 127.0.0.1:50812
+ buffer starts at 0 (including 0 out), 16361 free,
+ len 23, wraps at 16336, error at position 7
+ H1 connection flags 0x00000000, H1 stream flags 0x00000810
+ H1 msg state MSG_RQURI(4), H1 msg flags 0x00001400
+ H1 chunk len 0 bytes, H1 body len 0 bytes :
+
+ 00000 GET /aa#bb HTTP/1.0\r\n
+ 00021 \r\n
+
+This should be progressively backported to all stable versions along with
+the following patch:
+
+ REGTESTS: http-rules: add accept-invalid-http-request for normalize-uri tests
+
+Similar fixes for h2 and h3 will come in followup patches.
+
+Thanks to Seth Manesse and Paul Plasil for reporting this problem with
+detailed explanations.
+
+(cherry picked from commit 2eab6d354322932cfec2ed54de261e4347eca9a6)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 9bf75c8e22a8f2537f27c557854a8803087046d0)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 9facd01c9ac85fe9bcb331594b80fa08e7406552)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ src/h1.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/src/h1.c b/src/h1.c
+index 126f23cc7376..92ec96bfe19e 100644
+--- a/src/h1.c
++++ b/src/h1.c
+@@ -565,13 +565,13 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
+ case H1_MSG_RQURI:
+ http_msg_rquri:
+ #ifdef HA_UNALIGNED_LE
+- /* speedup: skip bytes not between 0x21 and 0x7e inclusive */
++ /* speedup: skip bytes not between 0x24 and 0x7e inclusive */
+ while (ptr <= end - sizeof(int)) {
+- int x = *(int *)ptr - 0x21212121;
++ int x = *(int *)ptr - 0x24242424;
+ if (x & 0x80808080)
+ break;
+
+- x -= 0x5e5e5e5e;
++ x -= 0x5b5b5b5b;
+ if (!(x & 0x80808080))
+ break;
+
+@@ -583,8 +583,15 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
+ goto http_msg_ood;
+ }
+ http_msg_rquri2:
+- if (likely((unsigned char)(*ptr - 33) <= 93)) /* 33 to 126 included */
++ if (likely((unsigned char)(*ptr - 33) <= 93)) { /* 33 to 126 included */
++ if (*ptr == '#') {
++ if (h1m->err_pos < -1) /* PR_O2_REQBUG_OK not set */
++ goto invalid_char;
++ if (h1m->err_pos == -1) /* PR_O2_REQBUG_OK set: just log */
++ h1m->err_pos = ptr - start + skip;
++ }
+ EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rquri2, http_msg_ood, state, H1_MSG_RQURI);
++ }
+
+ if (likely(HTTP_IS_SPHT(*ptr))) {
+ sl.rq.u.len = ptr - sl.rq.u.ptr;
+--
+2.43.0
+
diff --git a/debian/patches/BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch b/debian/patches/BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch
new file mode 100644
index 0000000..c5b2b9d
--- /dev/null
+++ b/debian/patches/BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch
@@ -0,0 +1,68 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 15:40:49 +0200
+Subject: BUG/MINOR: h2: reject more chars from the :path pseudo header
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=c8e07f2fd8b5462527f102f7145d6027c0d041da
+
+This is the h2 version of this previous fix:
+
+ BUG/MINOR: h1: do not accept '#' as part of the URI component
+
+In addition to the current NUL/CR/LF, this will also reject all other
+control chars, the space and '#' from the :path pseudo-header, to avoid
+taking the '#' for a part of the path. It's still possible to fall back
+to the previous behavior using "option accept-invalid-http-request".
+
+This patch modifies the request parser to change the ":path" pseudo header
+validation function with a new one that rejects 0x00-0x1F (control chars),
+space and '#'. This way such chars will be dropped early in the chain, and
+the search for '#' doesn't incur a second pass over the header's value.
+
+This should be progressively backported to stable versions, along with the
+following commits it relies on:
+
+ REGTESTS: http-rules: add accept-invalid-http-request for normalize-uri tests
+ REORG: http: move has_forbidden_char() from h2.c to http.h
+ MINOR: ist: add new function ist_find_range() to find a character range
+ MINOR: http: add new function http_path_has_forbidden_char()
+ MINOR: h2: pass accept-invalid-http-request down the request parser
+
+(cherry picked from commit b3119d4fb4588087e2483a80b01d322683719e29)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 462a8600ce9e478573a957e046b446a7dcffd286)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 648e59e30723b8fd4e71aab02cb679f6ea7446e7)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ src/h2.c | 15 +++++++++++----
+ 1 file changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/src/h2.c b/src/h2.c
+index cf42b7a5610e..67a443661c3e 100644
+--- a/src/h2.c
++++ b/src/h2.c
+@@ -337,11 +337,18 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms
+ }
+
+ /* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
+- * rejecting NUL, CR and LF characters.
++ * rejecting NUL, CR and LF characters. For :path we reject all CTL
++ * chars, spaces, and '#'.
+ */
+- ctl = ist_find_ctl(list[idx].v);
+- if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl))
+- goto fail;
++ if (phdr == H2_PHDR_IDX_PATH && !relaxed) {
++ ctl = ist_find_range(list[idx].v, 0, '#');
++ if (unlikely(ctl) && http_path_has_forbidden_char(list[idx].v, ctl))
++ goto fail;
++ } else {
++ ctl = ist_find_ctl(list[idx].v);
++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl))
++ goto fail;
++ }
+
+ if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) {
+ /* insert a pseudo header by its index (in phdr) and value (in value) */
+--
+2.43.0
+
diff --git a/debian/patches/BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch b/debian/patches/BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch
new file mode 100644
index 0000000..cbc086c
--- /dev/null
+++ b/debian/patches/BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch
@@ -0,0 +1,71 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 17:54:26 +0200
+Subject: BUG/MINOR: h3: reject more chars from the :path pseudo header
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=eacaa76e7b0e4182dfd17e1e7ca8c02c1cdab72c
+
+This is the h3 version of this previous fix:
+
+ BUG/MINOR: h2: reject more chars from the :path pseudo header
+
+In addition to the current NUL/CR/LF, this will also reject all other
+control chars, the space and '#' from the :path pseudo-header, to avoid
+taking the '#' for a part of the path. It's still possible to fall back
+to the previous behavior using "option accept-invalid-http-request".
+
+Here the :path header value is scanned a second time to look for
+forbidden chars because we don't know upfront if we're dealing with a
+path header field or another one. This is no big deal anyway for now.
+
+This should be progressively backported to 2.6, along with the
+following commits it relies on (the same as for h2):
+
+ REGTESTS: http-rules: add accept-invalid-http-request for normalize-uri tests
+ REORG: http: move has_forbidden_char() from h2.c to http.h
+ MINOR: ist: add new function ist_find_range() to find a character range
+ MINOR: http: add new function http_path_has_forbidden_char()
+
+(cherry picked from commit 2e97857a845540887a92029a566deb5b51f61d0b)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 96dfea858edab8f1f63fa6e4df43f505b81fdad9)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 97c15782afd9c70281ff0c72971485227494cc12)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ src/h3.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/src/h3.c b/src/h3.c
+index b42d41647e4e..e519fb4432e7 100644
+--- a/src/h3.c
++++ b/src/h3.c
+@@ -402,6 +402,7 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
+ int hdr_idx, ret;
+ int cookie = -1, last_cookie = -1, i;
+ const char *ctl;
++ int relaxed = !!(h3c->qcc->proxy->options2 & PR_O2_REQBUG_OK);
+
+ /* RFC 9114 4.1.2. Malformed Requests and Responses
+ *
+@@ -500,6 +501,19 @@ static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
+ len = -1;
+ goto out;
+ }
++
++ if (!relaxed) {
++ /* we need to reject any control chars or '#' from the path,
++ * unless option accept-invalid-http-request is set.
++ */
++ ctl = ist_find_range(list[hdr_idx].v, 0, '#');
++ if (unlikely(ctl) && http_path_has_forbidden_char(list[hdr_idx].v, ctl)) {
++ TRACE_ERROR("forbidden character in ':path' pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
++ len = -1;
++ goto out;
++ }
++ }
++
+ path = list[hdr_idx].v;
+ }
+ else if (isteq(list[hdr_idx].n, ist(":scheme"))) {
+--
+2.43.0
+
diff --git a/debian/patches/DOC-clarify-the-handling-of-URL-fragments-in-request.patch b/debian/patches/DOC-clarify-the-handling-of-URL-fragments-in-request.patch
new file mode 100644
index 0000000..8730e9a
--- /dev/null
+++ b/debian/patches/DOC-clarify-the-handling-of-URL-fragments-in-request.patch
@@ -0,0 +1,76 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 19:35:25 +0200
+Subject: DOC: clarify the handling of URL fragments in requests
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=c47814a58ec153a526e8e9e822cda6e66cef5cc2
+
+We indicate in path/pathq/url that they may contain '#' if the frontend
+is configured with "option accept-invalid-http-request", and that option
+mentions the fragment as well.
+
+(cherry picked from commit 7ab4949ef107a7088777f954de800fe8cf727796)
+ [ad: backported as a companion to BUG/MINOR: h1: do not accept '#' as
+ part of the URI component]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 965fb74eb180ab4f275ef907e018128e7eee0e69)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit e9903d6073ce9ff0ed8b304700e9d2b435ed8050)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ doc/configuration.txt | 20 +++++++++++++++++---
+ 1 file changed, 17 insertions(+), 3 deletions(-)
+
+diff --git a/doc/configuration.txt b/doc/configuration.txt
+index 7219c489ef9a..c01abb2d0a66 100644
+--- a/doc/configuration.txt
++++ b/doc/configuration.txt
+@@ -8609,6 +8609,8 @@ no option accept-invalid-http-request
+ option also relaxes the test on the HTTP version, it allows HTTP/0.9 requests
+ to pass through (no version specified), as well as different protocol names
+ (e.g. RTSP), and multiple digits for both the major and the minor version.
++ Finally, this option also allows incoming URLs to contain fragment references
++ ('#' after the path).
+
+ This option should never be enabled by default as it hides application bugs
+ and open security breaches. It should only be deployed after a problem has
+@@ -20991,7 +20993,11 @@ path : string
+ information from databases and keep them in caches. Note that with outgoing
+ caches, it would be wiser to use "url" instead. With ACLs, it's typically
+ used to match exact file names (e.g. "/login.php"), or directory parts using
+- the derivative forms. See also the "url" and "base" fetch methods.
++ the derivative forms. See also the "url" and "base" fetch methods. Please
++ note that any fragment reference in the URI ('#' after the path) is strictly
++ forbidden by the HTTP standard and will be rejected. However, if the frontend
++ receiving the request has "option accept-invalid-http-request", then this
++ fragment part will be accepted and will also appear in the path.
+
+ ACL derivatives :
+ path : exact string match
+@@ -21009,7 +21015,11 @@ pathq : string
+ relative URI, excluding the scheme and the authority part, if any. Indeed,
+ while it is the common representation for an HTTP/1.1 request target, in
+ HTTP/2, an absolute URI is often used. This sample fetch will return the same
+- result in both cases.
++ result in both cases. Please note that any fragment reference in the URI ('#'
++ after the path) is strictly forbidden by the HTTP standard and will be
++ rejected. However, if the frontend receiving the request has "option
++ accept-invalid-http-request", then this fragment part will be accepted and
++ will also appear in the path.
+
+ query : string
+ This extracts the request's query string, which starts after the first
+@@ -21242,7 +21252,11 @@ url : string
+ "path" is preferred over using "url", because clients may send a full URL as
+ is normally done with proxies. The only real use is to match "*" which does
+ not match in "path", and for which there is already a predefined ACL. See
+- also "path" and "base".
++ also "path" and "base". Please note that any fragment reference in the URI
++ ('#' after the path) is strictly forbidden by the HTTP standard and will be
++ rejected. However, if the frontend receiving the request has "option
++ accept-invalid-http-request", then this fragment part will be accepted and
++ will also appear in the url.
+
+ ACL derivatives :
+ url : exact string match
+--
+2.43.0
+
diff --git a/debian/patches/MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch b/debian/patches/MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch
new file mode 100644
index 0000000..dac7216
--- /dev/null
+++ b/debian/patches/MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch
@@ -0,0 +1,73 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 15:38:28 +0200
+Subject: MINOR: h2: pass accept-invalid-http-request down the request parser
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=014945a1508f43e88ac4e89950fa9037e4fb0679
+
+We're adding a new argument "relaxed" to h2_make_htx_request() so that
+we can control its level of acceptance of certain invalid requests at
+the proxy level with "option accept-invalid-http-request". The goal
+will be to add deactivable checks that are still desirable to have by
+default. For now no test is subject to it.
+
+(cherry picked from commit d93a00861d714313faa0395ff9e2acb14b0a2fca)
+ [ad: backported for following fix : BUG/MINOR: h2: reject more chars
+ from the :path pseudo header]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit b6be1a4f858eb6602490c192235114c1a163fef9)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 26fa3a285df0748fc79e73e552161268b66fb527)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ include/haproxy/h2.h | 2 +-
+ src/h2.c | 6 +++++-
+ src/mux_h2.c | 3 ++-
+ 3 files changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/include/haproxy/h2.h b/include/haproxy/h2.h
+index 84e4c76fc260..4082b38a80f9 100644
+--- a/include/haproxy/h2.h
++++ b/include/haproxy/h2.h
+@@ -207,7 +207,7 @@ extern struct h2_frame_definition h2_frame_definition[H2_FT_ENTRIES];
+ /* various protocol processing functions */
+
+ int h2_parse_cont_len_header(unsigned int *msgf, struct ist *value, unsigned long long *body_len);
+-int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len);
++int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, int relaxed);
+ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, char *upgrade_protocol);
+ int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx);
+
+diff --git a/src/h2.c b/src/h2.c
+index 76c936783461..cf42b7a5610e 100644
+--- a/src/h2.c
++++ b/src/h2.c
+@@ -296,8 +296,12 @@ static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr,
+ *
+ * The Cookie header will be reassembled at the end, and for this, the <list>
+ * will be used to create a linked list, so its contents may be destroyed.
++ *
++ * When <relaxed> is non-nul, some non-dangerous checks will be ignored. This
++ * is in order to satisfy "option accept-invalid-http-request" for
++ * interoperability purposes.
+ */
+-int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len)
++int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, int relaxed)
+ {
+ struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
+ uint32_t fields; /* bit mask of H2_PHDR_FND_* */
+diff --git a/src/mux_h2.c b/src/mux_h2.c
+index 752f074cac87..9e5ee8a56c34 100644
+--- a/src/mux_h2.c
++++ b/src/mux_h2.c
+@@ -5090,7 +5090,8 @@ static int h2c_decode_headers(struct h2c *h2c, struct buffer *rxbuf, uint32_t *f
+ if (h2c->flags & H2_CF_IS_BACK)
+ outlen = h2_make_htx_response(list, htx, &msgf, body_len, upgrade_protocol);
+ else
+- outlen = h2_make_htx_request(list, htx, &msgf, body_len);
++ outlen = h2_make_htx_request(list, htx, &msgf, body_len,
++ !!(((const struct session *)h2c->conn->owner)->fe->options2 & PR_O2_REQBUG_OK));
+
+ if (outlen < 0 || htx_free_space(htx) < global.tune.maxrewrite) {
+ /* too large headers? this is a stream error only */
+--
+2.43.0
+
diff --git a/debian/patches/MINOR-http-add-new-function-http_path_has_forbidden_.patch b/debian/patches/MINOR-http-add-new-function-http_path_has_forbidden_.patch
new file mode 100644
index 0000000..46cdf99
--- /dev/null
+++ b/debian/patches/MINOR-http-add-new-function-http_path_has_forbidden_.patch
@@ -0,0 +1,56 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 15:24:54 +0200
+Subject: MINOR: http: add new function http_path_has_forbidden_char()
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=c699bb17b7e334c9d56e829422e29e5a204615ec
+
+As its name implies, this function checks if a path component has any
+forbidden headers starting at the designated location. The goal is to
+seek from the result of a successful ist_find_range() for more precise
+chars. Here we're focusing on 0x00-0x1F, 0x20 and 0x23 to make sure
+we're not too strict at this point.
+
+(cherry picked from commit 30f58f4217d585efeac3d85cb1b695ba53b7760b)
+ [ad: backported for following fix : BUG/MINOR: h2: reject more chars
+ from the :path pseudo header]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit b491940181a88bb6c69ab2afc24b93a50adfa67c)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit f7666e5e43ce63e804ebffdf224d92cfd3367282)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ include/haproxy/http.h | 19 +++++++++++++++++++
+ 1 file changed, 19 insertions(+)
+
+diff --git a/include/haproxy/http.h b/include/haproxy/http.h
+index 41eca98a1e87..534b6ec2b2f0 100644
+--- a/include/haproxy/http.h
++++ b/include/haproxy/http.h
+@@ -190,6 +190,25 @@ static inline int http_header_has_forbidden_char(const struct ist ist, const cha
+ return 0;
+ }
+
++/* Looks into <ist> for forbidden characters for :path values (0x00..0x1F,
++ * 0x20, 0x23), starting at pointer <start> which must be within <ist>.
++ * Returns non-zero if such a character is found, 0 otherwise. When run on
++ * unlikely header match, it's recommended to first check for the presence
++ * of control chars using ist_find_ctl().
++ */
++static inline int http_path_has_forbidden_char(const struct ist ist, const char *start)
++{
++ do {
++ if ((uint8_t)*start <= 0x23) {
++ if ((uint8_t)*start < 0x20)
++ return 1;
++ if ((1U << ((uint8_t)*start & 0x1F)) & ((1<<3) | (1<<0)))
++ return 1;
++ }
++ start++;
++ } while (start < istend(ist));
++ return 0;
++}
+
+ #endif /* _HAPROXY_HTTP_H */
+
+--
+2.43.0
+
diff --git a/debian/patches/MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch b/debian/patches/MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch
new file mode 100644
index 0000000..40c3a08
--- /dev/null
+++ b/debian/patches/MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch
@@ -0,0 +1,84 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 15:23:19 +0200
+Subject: MINOR: ist: add new function ist_find_range() to find a character
+ range
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=b375df60341c7f7a4904c2d8041a09c66115c754
+
+This looks up the character range <min>..<max> in the input string and
+returns a pointer to the first one found. It's essentially the equivalent
+of ist_find_ctl() in that it searches by 32 or 64 bits at once, but deals
+with a range.
+
+(cherry picked from commit 197668de975e495f0c0f0e4ff51b96203fa9842d)
+ [ad: backported for following fix : BUG/MINOR: h2: reject more chars
+ from the :path pseudo header]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 451ac6628acc4b9eed3260501a49c60d4e4d4e55)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 3468f7f8e04c9c5ca5c985c7511e05e78fe1eded)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ include/import/ist.h | 47 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 47 insertions(+)
+
+diff --git a/include/import/ist.h b/include/import/ist.h
+index 978fb3c72247..38fe9363c2a1 100644
+--- a/include/import/ist.h
++++ b/include/import/ist.h
+@@ -746,6 +746,53 @@ static inline const char *ist_find_ctl(const struct ist ist)
+ return NULL;
+ }
+
++/* Returns a pointer to the first character found <ist> that belongs to the
++ * range [min:max] inclusive, or NULL if none is present. The function is
++ * optimized for strings having no such chars by processing up to sizeof(long)
++ * bytes at once on architectures supporting efficient unaligned accesses.
++ * Despite this it is not very fast (~0.43 byte/cycle) and should mostly be
++ * used on low match probability when it can save a call to a much slower
++ * function. Will not work for characters 0x80 and above. It's optimized for
++ * min and max to be known at build time.
++ */
++static inline const char *ist_find_range(const struct ist ist, unsigned char min, unsigned char max)
++{
++ const union { unsigned long v; } __attribute__((packed)) *u;
++ const char *curr = (void *)ist.ptr - sizeof(long);
++ const char *last = curr + ist.len;
++ unsigned long l1, l2;
++
++ /* easier with an exclusive boundary */
++ max++;
++
++ do {
++ curr += sizeof(long);
++ if (curr > last)
++ break;
++ u = (void *)curr;
++ /* add 0x<min><min><min><min>..<min> then subtract
++ * 0x<max><max><max><max>..<max> to the value to generate a
++ * carry in the lower byte if the byte contains a lower value.
++ * If we generate a bit 7 that was not there, it means the byte
++ * was min..max.
++ */
++ l2 = u->v;
++ l1 = ~l2 & ((~0UL / 255) * 0x80); /* 0x808080...80 */
++ l2 += (~0UL / 255) * min; /* 0x<min><min>..<min> */
++ l2 -= (~0UL / 255) * max; /* 0x<max><max>..<max> */
++ } while ((l1 & l2) == 0);
++
++ last += sizeof(long);
++ if (__builtin_expect(curr < last, 0)) {
++ do {
++ if ((unsigned char)(*curr - min) < (unsigned char)(max - min))
++ return curr;
++ curr++;
++ } while (curr < last);
++ }
++ return NULL;
++}
++
+ /* looks for first occurrence of character <chr> in string <ist> and returns
+ * the tail of the string starting with this character, or (ist.end,0) if not
+ * found.
+--
+2.43.0
+
diff --git a/debian/patches/REGTESTS-http-rules-add-accept-invalid-http-request-.patch b/debian/patches/REGTESTS-http-rules-add-accept-invalid-http-request-.patch
new file mode 100644
index 0000000..60caf8f
--- /dev/null
+++ b/debian/patches/REGTESTS-http-rules-add-accept-invalid-http-request-.patch
@@ -0,0 +1,44 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 19:52:45 +0200
+Subject: REGTESTS: http-rules: add accept-invalid-http-request for
+ normalize-uri tests
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=65849396fd6f192d9f14e81702c6c3851e580345
+
+We'll soon block the '#' by default so let's prepare the test to continue
+to work.
+
+(cherry picked from commit 069d0e221e58a46119d7c049bb07fa4bcb8d0075)
+ [ad: backported for following fix : BUG/MINOR: h2: reject more chars
+ from the :path pseudo header]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 1660481fab69856a39ac44cf88b76cdbcc0ea954)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 90d0300cea6cda18a4e20369f4dc0b4c4783d6c9)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ reg-tests/http-rules/normalize_uri.vtc | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/reg-tests/http-rules/normalize_uri.vtc b/reg-tests/http-rules/normalize_uri.vtc
+index 82c810718df1..34905eaf93ae 100644
+--- a/reg-tests/http-rules/normalize_uri.vtc
++++ b/reg-tests/http-rules/normalize_uri.vtc
+@@ -127,6 +127,7 @@ haproxy h1 -conf {
+
+ frontend fe_fragment_strip
+ bind "fd@${fe_fragment_strip}"
++ option accept-invalid-http-request
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri fragment-strip
+@@ -139,6 +140,7 @@ haproxy h1 -conf {
+
+ frontend fe_fragment_encode
+ bind "fd@${fe_fragment_encode}"
++ option accept-invalid-http-request
+
+ http-request set-var(txn.before) url
+ http-request normalize-uri fragment-encode
+--
+2.43.0
+
diff --git a/debian/patches/REGTESTS-http-rules-verify-that-we-block-by-default-.patch b/debian/patches/REGTESTS-http-rules-verify-that-we-block-by-default-.patch
new file mode 100644
index 0000000..6703482
--- /dev/null
+++ b/debian/patches/REGTESTS-http-rules-verify-that-we-block-by-default-.patch
@@ -0,0 +1,50 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 19:53:51 +0200
+Subject: REGTESTS: http-rules: verify that we block '#' by default for
+ normalize-uri
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=b6b330eb117d520a890e5b3cd623eaa73479db1b
+
+Since we now block fragments by default, let's add an extra test there
+to confirm that it's blocked even when stripping it.
+
+(cherry picked from commit 4d0175b54b2b4eeb01aa6e31282b0a5b0d7d8ace)
+ [ad: backported to test conformance of BUG/MINOR: h1: do not accept '#'
+ as part of the URI component]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit b3f26043df74c661155566a0abd56103e8116078)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 41d161ccbbfa846b4b17ed0166ff08f6bf0c3ea1)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ reg-tests/http-rules/normalize_uri.vtc | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/reg-tests/http-rules/normalize_uri.vtc b/reg-tests/http-rules/normalize_uri.vtc
+index 34905eaf93ae..ad7b44acfe55 100644
+--- a/reg-tests/http-rules/normalize_uri.vtc
++++ b/reg-tests/http-rules/normalize_uri.vtc
+@@ -151,6 +151,11 @@ haproxy h1 -conf {
+
+ default_backend be
+
++ frontend fe_fragment_block
++ bind "fd@${fe_fragment_block}"
++ http-request normalize-uri fragment-strip
++ default_backend be
++
+ backend be
+ server s1 ${s1_addr}:${s1_port}
+
+@@ -536,3 +541,9 @@ client c10 -connect ${h1_fe_fragment_encode_sock} {
+ expect resp.http.before == "*"
+ expect resp.http.after == "*"
+ } -run
++
++client c11 -connect ${h1_fe_fragment_block_sock} {
++ txreq -url "/#foo"
++ rxresp
++ expect resp.status == 400
++} -run
+--
+2.43.0
+
diff --git a/debian/patches/REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch b/debian/patches/REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch
new file mode 100644
index 0000000..5bf1eef
--- /dev/null
+++ b/debian/patches/REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch
@@ -0,0 +1,109 @@
+From: Willy Tarreau <w@1wt.eu>
+Date: Tue, 8 Aug 2023 17:00:50 +0200
+Subject: REORG: http: move has_forbidden_char() from h2.c to http.h
+Origin: https://git.haproxy.org/?p=haproxy-2.6.git;a=commit;h=4a776fd01560a8dfa7a57b30b4d5249c8da7b12c
+
+This function is not H2 specific but rather generic to HTTP. We'll
+need it in H3 soon, so let's move it to HTTP and rename it to
+http_header_has_forbidden_char().
+
+(cherry picked from commit d4069f3cee0f6e94afaec518b6373dd368073f52)
+ [ad: backported for next patch BUG/MAJOR: h3: reject header values
+ containing invalid chars]
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 21c4ffd025115058994a3e2765c17fc3cee52f90)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+(cherry picked from commit 9c0bc4f201cf58c10706416cb4807c0f4794f8ac)
+Signed-off-by: Amaury Denoyelle <adenoyelle@haproxy.com>
+---
+ include/haproxy/http.h | 18 ++++++++++++++++++
+ src/h2.c | 23 +++--------------------
+ 2 files changed, 21 insertions(+), 20 deletions(-)
+
+diff --git a/include/haproxy/http.h b/include/haproxy/http.h
+index f597ee4cd1dc..41eca98a1e87 100644
+--- a/include/haproxy/http.h
++++ b/include/haproxy/http.h
+@@ -173,6 +173,24 @@ static inline struct http_uri_parser http_uri_parser_init(const struct ist uri)
+ return parser;
+ }
+
++/* Looks into <ist> for forbidden characters for header values (0x00, 0x0A,
++ * 0x0D), starting at pointer <start> which must be within <ist>. Returns
++ * non-zero if such a character is found, 0 otherwise. When run on unlikely
++ * header match, it's recommended to first check for the presence of control
++ * chars using ist_find_ctl().
++ */
++static inline int http_header_has_forbidden_char(const struct ist ist, const char *start)
++{
++ do {
++ if ((uint8_t)*start <= 0x0d &&
++ (1U << (uint8_t)*start) & ((1<<13) | (1<<10) | (1<<0)))
++ return 1;
++ start++;
++ } while (start < istend(ist));
++ return 0;
++}
++
++
+ #endif /* _HAPROXY_HTTP_H */
+
+ /*
+diff --git a/src/h2.c b/src/h2.c
+index f794262ee7af..76c936783461 100644
+--- a/src/h2.c
++++ b/src/h2.c
+@@ -49,23 +49,6 @@ struct h2_frame_definition h2_frame_definition[H2_FT_ENTRIES] = {
+ [H2_FT_CONTINUATION ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 0, .max_len = H2_MAX_FRAME_LEN, },
+ };
+
+-/* Looks into <ist> for forbidden characters for header values (0x00, 0x0A,
+- * 0x0D), starting at pointer <start> which must be within <ist>. Returns
+- * non-zero if such a character is found, 0 otherwise. When run on unlikely
+- * header match, it's recommended to first check for the presence of control
+- * chars using ist_find_ctl().
+- */
+-static int has_forbidden_char(const struct ist ist, const char *start)
+-{
+- do {
+- if ((uint8_t)*start <= 0x0d &&
+- (1U << (uint8_t)*start) & ((1<<13) | (1<<10) | (1<<0)))
+- return 1;
+- start++;
+- } while (start < istend(ist));
+- return 0;
+-}
+-
+ /* Prepare the request line into <htx> from pseudo headers stored in <phdr[]>.
+ * <fields> indicates what was found so far. This should be called once at the
+ * detection of the first general header field or at the end of the request if
+@@ -353,7 +336,7 @@ int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *ms
+ * rejecting NUL, CR and LF characters.
+ */
+ ctl = ist_find_ctl(list[idx].v);
+- if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl))
+ goto fail;
+
+ if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) {
+@@ -638,7 +621,7 @@ int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *m
+ * rejecting NUL, CR and LF characters.
+ */
+ ctl = ist_find_ctl(list[idx].v);
+- if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl))
+ goto fail;
+
+ if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) {
+@@ -797,7 +780,7 @@ int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
+ * rejecting NUL, CR and LF characters.
+ */
+ ctl = ist_find_ctl(list[idx].v);
+- if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
++ if (unlikely(ctl) && http_header_has_forbidden_char(list[idx].v, ctl))
+ goto fail;
+
+ if (!htx_add_trailer(htx, list[idx].n, list[idx].v))
+--
+2.43.0
+
diff --git a/debian/patches/debianize-dconv.patch b/debian/patches/debianize-dconv.patch
new file mode 100644
index 0000000..34710ce
--- /dev/null
+++ b/debian/patches/debianize-dconv.patch
@@ -0,0 +1,170 @@
+From: Apollon Oikonomopoulos <apoikos@debian.org>
+Date: Wed, 29 Apr 2015 13:51:49 +0300
+Subject: [PATCH] dconv: debianize
+
+ - Use Debian bootstrap and jquery packages
+ - Add Debian-related resources to the template
+ - Use the package's version instead of HAProxy's git version
+ - Strip the conversion date from the output to ensure reproducible
+ build.
+ - 2020-01-17: make get_haproxy_debian_version() return a string, for py3
+ compatibility
+
+diff --git a/debian/dconv/haproxy-dconv.py b/debian/dconv/haproxy-dconv.py
+index fe2b96dce325..702eefac6a3b 100755
+--- a/debian/dconv/haproxy-dconv.py
++++ b/debian/dconv/haproxy-dconv.py
+@@ -44,12 +44,11 @@ VERSION = ""
+ HAPROXY_GIT_VERSION = False
+
+ def main():
+- global VERSION, HAPROXY_GIT_VERSION
++ global HAPROXY_GIT_VERSION
+
+ usage="Usage: %prog --infile <infile> --outfile <outfile>"
+
+ optparser = OptionParser(description='Generate HTML Document from HAProxy configuation.txt',
+- version=VERSION,
+ usage=usage)
+ optparser.add_option('--infile', '-i', help='Input file mostly the configuration.txt')
+ optparser.add_option('--outfile','-o', help='Output file')
+@@ -65,11 +64,7 @@ def main():
+
+ os.chdir(os.path.dirname(__file__))
+
+- VERSION = get_git_version()
+- if not VERSION:
+- sys.exit(1)
+-
+- HAPROXY_GIT_VERSION = get_haproxy_git_version(os.path.dirname(option.infile))
++ HAPROXY_GIT_VERSION = get_haproxy_debian_version(os.path.dirname(option.infile))
+
+ convert(option.infile, option.outfile, option.base)
+
+@@ -114,6 +109,15 @@ def get_haproxy_git_version(path):
+ version = re.sub(r'-g.*', '', version)
+ return version
+
++def get_haproxy_debian_version(path):
++ try:
++ version = subprocess.check_output(["dpkg-parsechangelog", "-Sversion"],
++ cwd=os.path.join(path, ".."))
++ except subprocess.CalledProcessError:
++ return False
++
++ return version.decode("utf-8").strip()
++
+ def getTitleDetails(string):
+ array = string.split(".")
+
+@@ -506,7 +510,6 @@ def convert(infile, outfile, base=''):
+ keywords = keywords,
+ keywordsCount = keywordsCount,
+ keyword_conflicts = keyword_conflicts,
+- version = VERSION,
+ date = datetime.datetime.now().strftime("%Y/%m/%d"),
+ )
+ except TopLevelLookupException:
+@@ -524,7 +527,6 @@ def convert(infile, outfile, base=''):
+ keywords = keywords,
+ keywordsCount = keywordsCount,
+ keyword_conflicts = keyword_conflicts,
+- version = VERSION,
+ date = datetime.datetime.now().strftime("%Y/%m/%d"),
+ footer = footer
+ )
+diff --git a/debian/dconv/templates/template.html b/debian/dconv/templates/template.html
+index c72b3558c2dd..9aefa16dd82d 100644
+--- a/debian/dconv/templates/template.html
++++ b/debian/dconv/templates/template.html
+@@ -3,8 +3,8 @@
+ <head>
+ <meta charset="utf-8" />
+ <title>${headers['title']} ${headers['version']} - ${headers['subtitle']}</title>
+- <link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" />
+- <link href="${base}css/page.css?${version}" rel="stylesheet" />
++ <link href="${base}css/bootstrap.min.css" rel="stylesheet" />
++ <link href="${base}css/page.css" rel="stylesheet" />
+ </head>
+ <body>
+ <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
+@@ -15,7 +15,7 @@
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+- <a class="navbar-brand" href="${base}index.html">${headers['title']} <small>${headers['subtitle']}</small></a>
++ <a class="navbar-brand" href="${base}configuration.html">${headers['title']}</a>
+ </div>
+ <!-- /.navbar-header -->
+
+@@ -24,31 +24,16 @@
+ <ul class="nav navbar-nav">
+ <li><a href="http://www.haproxy.org/">HAProxy home page</a></li>
+ <li class="dropdown">
+- <a href="#" class="dropdown-toggle" data-toggle="dropdown">Versions <b class="caret"></b></a>
++ <a href="#" class="dropdown-toggle" data-toggle="dropdown">Debian resources <b class="caret"></b></a>
+ <ul class="dropdown-menu">
+ ## TODO : provide a structure to dynamically generate per version links
+- <li class="dropdown-header">HAProxy 1.4</li>
+- <li><a href="${base}configuration-1.4.html">Configuration Manual <small>(stable)</small></a></li>
+- <li><a href="${base}snapshot/configuration-1.4.html">Configuration Manual <small>(snapshot)</small></a></li>
+- <li><a href="http://git.1wt.eu/git/haproxy-1.4.git/">GIT Repository</a></li>
+- <li><a href="http://www.haproxy.org/git/?p=haproxy-1.4.git">Browse repository</a></li>
+- <li><a href="http://www.haproxy.org/download/1.4/">Browse directory</a></li>
+- <li class="divider"></li>
+- <li class="dropdown-header">HAProxy 1.5</li>
+- <li><a href="${base}configuration-1.5.html">Configuration Manual <small>(stable)</small></a></li>
+- <li><a href="${base}snapshot/configuration-1.5.html">Configuration Manual <small>(snapshot)</small></a></li>
+- <li><a href="http://git.1wt.eu/git/haproxy-1.5.git/">GIT Repository</a></li>
+- <li><a href="http://www.haproxy.org/git/?p=haproxy-1.5.git">Browse repository</a></li>
+- <li><a href="http://www.haproxy.org/download/1.5/">Browse directory</a></li>
+- <li class="divider"></li>
+- <li class="dropdown-header">HAProxy 1.6</li>
+- <li><a href="${base}configuration-1.6.html">Configuration Manual <small>(stable)</small></a></li>
+- <li><a href="${base}snapshot/configuration-1.6.html">Configuration Manual <small>(snapshot)</small></a></li>
+- <li><a href="${base}intro-1.6.html">Starter Guide <small>(stable)</small></a></li>
+- <li><a href="${base}snapshot/intro-1.6.html">Starter Guide <small>(snapshot)</small></a></li>
+- <li><a href="http://git.1wt.eu/git/haproxy.git/">GIT Repository</a></li>
+- <li><a href="http://www.haproxy.org/git/?p=haproxy.git">Browse repository</a></li>
+- <li><a href="http://www.haproxy.org/download/1.6/">Browse directory</a></li>
++ <li><a href="https://bugs.debian.org/src:haproxy">Bug Tracking System</a></li>
++ <li><a href="https://packages.debian.org/haproxy">Package page</a></li>
++ <li><a href="http://tracker.debian.org/pkg/haproxy">Package Tracking System</a></li>
++ <li class="divider"></li>
++ <li><a href="${base}intro.html">Starter Guide</a></li>
++ <li><a href="${base}configuration.html">Configuration Manual</a></li>
++ <li><a href="http://anonscm.debian.org/gitweb/?p=pkg-haproxy/haproxy.git">Package Git Repository</a></li>
+ </ul>
+ </li>
+ </ul>
+@@ -72,7 +57,7 @@
+ The feature is automatically disabled when the search field is focused.
+ </p>
+ <p class="text-right">
+- <small>Converted with <a href="https://github.com/cbonte/haproxy-dconv">haproxy-dconv</a> v<b>${version}</b> on <b>${date}</b></small>
++ <small>Converted with <a href="https://github.com/cbonte/haproxy-dconv">haproxy-dconv</a></small>
+ </p>
+ </div>
+ <!-- /.sidebar -->
+@@ -83,7 +68,7 @@
+ <div class="text-center">
+ <h1>${headers['title']}</h1>
+ <h2>${headers['subtitle']}</h2>
+- <p><strong>${headers['version']}</strong></p>
++ <p><strong>${headers['version']} (Debian)</strong></p>
+ <p>
+ <a href="http://www.haproxy.org/" title="HAProxy Home Page"><img src="${base}img/logo-med.png" /></a><br>
+ ${headers['author']}<br>
+@@ -114,9 +99,9 @@
+ </div>
+ <!-- /#wrapper -->
+
+- <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
+- <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.1/js/bootstrap.min.js"></script>
+- <script src="//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.11.1/typeahead.bundle.min.js"></script>
++ <script src="${base}js/jquery.min.js"></script>
++ <script src="${base}js/bootstrap.min.js"></script>
++ <script src="${base}js/typeahead.bundle.js"></script>
+ <script>
+ /* Keyword search */
+ var searchFocus = false
diff --git a/debian/patches/haproxy.service-add-documentation.patch b/debian/patches/haproxy.service-add-documentation.patch
new file mode 100644
index 0000000..a60b0d1
--- /dev/null
+++ b/debian/patches/haproxy.service-add-documentation.patch
@@ -0,0 +1,23 @@
+From: Debian HAProxy Maintainers
+ <pkg-haproxy-maintainers@lists.alioth.debian.org>
+Date: Sun, 25 Mar 2018 11:31:50 +0200
+Subject: Add documentation field to the systemd unit
+
+Forwarded: no
+Last-Update: 2014-01-03
+---
+ admin/systemd/haproxy.service.in | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/admin/systemd/haproxy.service.in b/admin/systemd/haproxy.service.in
+index 243acf2..ac88c37 100644
+--- a/admin/systemd/haproxy.service.in
++++ b/admin/systemd/haproxy.service.in
+@@ -1,5 +1,7 @@
+ [Unit]
+ Description=HAProxy Load Balancer
++Documentation=man:haproxy(1)
++Documentation=file:/usr/share/doc/haproxy/configuration.txt.gz
+ After=network-online.target rsyslog.service
+ Wants=network-online.target
+
diff --git a/debian/patches/haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch b/debian/patches/haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch
new file mode 100644
index 0000000..666f916
--- /dev/null
+++ b/debian/patches/haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch
@@ -0,0 +1,21 @@
+From: Vincent Bernat <bernat@debian.org>
+Date: Thu, 25 Nov 2021 21:35:48 +0100
+Subject: haproxy.service: make systemd bind /dev/log inside chroot
+
+This enables logging to work without rsyslog being present.
+---
+ admin/systemd/haproxy.service.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/admin/systemd/haproxy.service.in b/admin/systemd/haproxy.service.in
+index 0288568..20824df 100644
+--- a/admin/systemd/haproxy.service.in
++++ b/admin/systemd/haproxy.service.in
+@@ -8,6 +8,7 @@ Wants=network-online.target
+ [Service]
+ EnvironmentFile=-/etc/default/haproxy
+ EnvironmentFile=-/etc/sysconfig/haproxy
++BindReadOnlyPaths=/dev/log:/var/lib/haproxy/dev/log
+ Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid" "EXTRAOPTS=-S /run/haproxy-master.sock"
+ ExecStart=@SBINDIR@/haproxy -Ws -f $CONFIG -p $PIDFILE $EXTRAOPTS
+ ExecReload=@SBINDIR@/haproxy -Ws -f $CONFIG -c -q $EXTRAOPTS
diff --git a/debian/patches/haproxy.service-start-after-syslog.patch b/debian/patches/haproxy.service-start-after-syslog.patch
new file mode 100644
index 0000000..14577bd
--- /dev/null
+++ b/debian/patches/haproxy.service-start-after-syslog.patch
@@ -0,0 +1,27 @@
+From: Apollon Oikonomopoulos <apoikos@debian.org>
+Date: Sun, 25 Mar 2018 11:31:50 +0200
+Subject: Start after rsyslog.service
+
+As HAProxy is running chrooted by default, we rely on an additional syslog
+socket created by rsyslog inside the chroot for logging. As this socket cannot
+trigger syslog activation, we explicitly order HAProxy after rsyslog.service.
+Note that we are not using syslog.service here, since the additional socket is
+rsyslog-specific.
+Forwarded: no
+Last-Update: 2017-12-01
+---
+ admin/systemd/haproxy.service.in | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/admin/systemd/haproxy.service.in b/admin/systemd/haproxy.service.in
+index 74e66e3..243acf2 100644
+--- a/admin/systemd/haproxy.service.in
++++ b/admin/systemd/haproxy.service.in
+@@ -1,6 +1,6 @@
+ [Unit]
+ Description=HAProxy Load Balancer
+-After=network-online.target
++After=network-online.target rsyslog.service
+ Wants=network-online.target
+
+ [Service]
diff --git a/debian/patches/reproducible.patch b/debian/patches/reproducible.patch
new file mode 100644
index 0000000..bbc95b8
--- /dev/null
+++ b/debian/patches/reproducible.patch
@@ -0,0 +1,13 @@
+diff --git a/Makefile b/Makefile
+index 566bdb26a3e7..8603dea25c21 100644
+--- a/Makefile
++++ b/Makefile
+@@ -975,7 +975,7 @@ src/haproxy.o: src/haproxy.c $(DEP)
+ -DBUILD_ARCH='"$(strip $(ARCH))"' \
+ -DBUILD_CPU='"$(strip $(CPU))"' \
+ -DBUILD_CC='"$(strip $(CC))"' \
+- -DBUILD_CFLAGS='"$(strip $(VERBOSE_CFLAGS))"' \
++ -DBUILD_CFLAGS='"$(filter-out -ffile-prefix-map=%,$(strip $(VERBOSE_CFLAGS)))"' \
+ -DBUILD_OPTIONS='"$(strip $(BUILD_OPTIONS))"' \
+ -DBUILD_DEBUG='"$(strip $(DEBUG))"' \
+ -DBUILD_FEATURES='"$(strip $(BUILD_FEATURES))"' \
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..7136a90
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1,19 @@
+haproxy.service-start-after-syslog.patch
+haproxy.service-add-documentation.patch
+haproxy.service-make-systemd-bind-dev-log-inside-chroot.patch
+reproducible.patch
+REORG-http-move-has_forbidden_char-from-h2.c-to-http.patch
+BUG-MAJOR-h3-reject-header-values-containing-invalid.patch
+BUG-MAJOR-http-reject-any-empty-content-length-heade.patch
+MINOR-ist-add-new-function-ist_find_range-to-find-a-.patch
+MINOR-http-add-new-function-http_path_has_forbidden_.patch
+MINOR-h2-pass-accept-invalid-http-request-down-the-r.patch
+REGTESTS-http-rules-add-accept-invalid-http-request-.patch
+BUG-MINOR-h1-do-not-accept-as-part-of-the-URI-compon.patch
+BUG-MINOR-h2-reject-more-chars-from-the-path-pseudo-.patch
+BUG-MINOR-h3-reject-more-chars-from-the-path-pseudo-.patch
+REGTESTS-http-rules-verify-that-we-block-by-default-.patch
+DOC-clarify-the-handling-of-URL-fragments-in-request.patch
+
+# applied during the build process:
+# debianize-dconv.patch