Merge ~lucaskanashiro/ubuntu/+source/haproxy:focal-mre into ubuntu/+source/haproxy:ubuntu/focal-devel
- Git
- lp:~lucaskanashiro/ubuntu/+source/haproxy
- focal-mre
- Merge into ubuntu/focal-devel
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | git-ubuntu bot | ||||
Approved revision: | not available | ||||
Merge reported by: | Lucas Kanashiro | ||||
Merged at revision: | 755142d4b5e5d59a7b76565fd3a63e4338bee448 | ||||
Proposed branch: | ~lucaskanashiro/ubuntu/+source/haproxy:focal-mre | ||||
Merge into: | ubuntu/+source/haproxy:ubuntu/focal-devel | ||||
Diff against target: |
3289 lines (+1130/-445) 72 files modified
.github/matrix.py (+6/-3) .github/workflows/cross-zoo.yml (+110/-0) .github/workflows/vtest.yml (+5/-2) .github/workflows/windows.yml (+2/-1) CHANGELOG (+100/-0) Makefile (+5/-1) SUBVERS (+1/-1) VERDATE (+2/-2) VERSION (+1/-1) contrib/prometheus-exporter/service-prometheus.c (+1/-0) contrib/wurfl/wurfl/wurfl.h (+10/-5) debian/changelog (+20/-0) debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch (+0/-2) debian/patches/series (+0/-2) debian/tests/control (+8/-0) debian/tests/proxy-localhost (+5/-9) debian/tests/proxy-ssl-pass-through (+59/-0) debian/tests/proxy-ssl-termination (+48/-0) debian/tests/utils (+58/-0) dev/null (+0/-175) doc/configuration.txt (+99/-41) doc/management.txt (+4/-0) doc/proxy-protocol.txt (+1/-1) include/common/buf.h (+1/-1) include/common/compiler.h (+3/-1) include/common/memory.h (+2/-2) include/common/standard.h (+3/-2) include/proto/server.h (+1/-0) include/proto/ssl_sock.h (+25/-0) include/types/global.h (+1/-0) include/types/listener.h (+11/-2) reg-tests/http-messaging/http_abortonclose.vtc (+27/-5) reg-tests/http-messaging/http_request_buffer.vtc (+29/-4) scripts/announce-release (+12/-11) scripts/make-releases-json (+103/-0) scripts/publish-release (+6/-0) src/backend.c (+0/-5) src/cache.c (+7/-7) src/cfgparse-listen.c (+2/-1) src/cfgparse.c (+40/-12) src/dns.c (+18/-6) src/ev_epoll.c (+2/-2) src/ev_evports.c (+2/-4) src/ev_kqueue.c (+2/-2) src/ev_poll.c (+2/-1) src/flt_spoe.c (+22/-9) src/h1.c (+4/-0) src/haproxy.c (+10/-2) src/hlua.c (+3/-1) src/hlua_fcn.c (+3/-0) src/hpack-dec.c (+9/-0) src/http_fetch.c (+9/-6) src/http_msg.c (+7/-1) src/listener.c (+6/-0) src/log.c (+8/-3) src/memory.c (+6/-6) src/mux_h1.c (+1/-1) src/mux_h2.c (+9/-2) src/mworker.c (+4/-2) src/peers.c (+40/-23) src/proto_http.c (+8/-2) src/proto_htx.c (+1/-0) src/proto_sockpair.c (+1/-1) src/proxy.c (+24/-10) src/sample.c (+2/-1) src/server.c (+4/-5) src/signal.c (+3/-0) src/ssl_sock.c (+50/-27) src/standard.c (+4/-3) src/stick_table.c (+29/-17) src/stream.c (+18/-8) src/stream_interface.c (+1/-1) |
||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andreas Hasenack | Approve | ||
git-ubuntu bot | Approve | ||
Canonical Server Reporter | Pending | ||
Review via email: mp+439428@code.launchpad.net |
Commit message
Description of the change
MRE update to version 2.0.31 (LP: #2012557). Some patches were removed (applied by upstream) and others refreshed.
the proposed package is available in this PPA:
https:/
autopkgtest summary:
autopkgtest [18:17:03]: @@@@@@@
cli PASS
proxy-localhost PASS
Andreas Hasenack (ahasenack) : | # |
Lucas Kanashiro (lucaskanashiro) : | # |
Lucas Kanashiro (lucaskanashiro) wrote : | # |
git-ubuntu bot (git-ubuntu-bot) wrote : | # |
Approvers: lucaskanashiro, ahasenack
Uploaders: lucaskanashiro, ahasenack
MP auto-approved
- fbe702c... by Lucas Kanashiro
-
Backport DEP-8 tests from Lunar
Lucas Kanashiro (lucaskanashiro) wrote : | # |
I backported the DEP-8 tests from Lunar as I did in the Jammy MRE. All tests are still passing:
autopkgtest [17:14:27]: @@@@@@@
cli PASS
proxy-localhost PASS
proxy-ssl-
proxy-ssl-
Could you please re-check this part Andreas?
Andreas Hasenack (ahasenack) wrote : | # |
Looks good, thanks for that
Lucas Kanashiro (lucaskanashiro) wrote : | # |
Thanks Andreas. Package uploaded:
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
Uploading haproxy_
Preview Diff
1 | diff --git a/.github/matrix.py b/.github/matrix.py |
2 | index 2ea3053..3d704ae 100644 |
3 | --- a/.github/matrix.py |
4 | +++ b/.github/matrix.py |
5 | @@ -8,6 +8,7 @@ |
6 | |
7 | import json |
8 | import sys |
9 | +from os import environ |
10 | |
11 | if len(sys.argv) == 2: |
12 | build_type = sys.argv[1] |
13 | @@ -50,7 +51,7 @@ matrix = [] |
14 | |
15 | # Ubuntu |
16 | |
17 | -os = "ubuntu-latest" |
18 | +os = "ubuntu-20.04" |
19 | TARGET = "linux-glibc" |
20 | for CC in ["gcc", "clang"]: |
21 | matrix.append( |
22 | @@ -125,7 +126,7 @@ for CC in ["gcc", "clang"]: |
23 | |
24 | # ASAN |
25 | |
26 | -os = "ubuntu-latest" |
27 | +os = "ubuntu-20.04" |
28 | CC = "clang" |
29 | TARGET = "linux-glibc" |
30 | matrix.append( |
31 | @@ -173,4 +174,6 @@ for CC in ["clang"]: |
32 | |
33 | print(json.dumps(matrix, indent=4, sort_keys=True)) |
34 | |
35 | -print("::set-output name=matrix::{}".format(json.dumps({"include": matrix}))) |
36 | +if environ.get('GITHUB_OUTPUT') is not None: |
37 | + with open(environ.get('GITHUB_OUTPUT'), 'a') as f: |
38 | + print("matrix={}".format(json.dumps({"include": matrix})), file=f) |
39 | diff --git a/.github/workflows/cross-zoo.yml b/.github/workflows/cross-zoo.yml |
40 | new file mode 100644 |
41 | index 0000000..e2a5816 |
42 | --- /dev/null |
43 | +++ b/.github/workflows/cross-zoo.yml |
44 | @@ -0,0 +1,110 @@ |
45 | +# |
46 | +# this is naamed "zoo" after OpenSSL "cross zoo pipeline" |
47 | +# |
48 | +name: Cross Compile |
49 | + |
50 | +on: |
51 | + schedule: |
52 | + - cron: "0 0 21 * *" |
53 | + |
54 | +permissions: |
55 | + contents: read |
56 | + |
57 | +jobs: |
58 | + cross-compilation: |
59 | + strategy: |
60 | + matrix: |
61 | + platform: [ |
62 | + { |
63 | + arch: aarch64-linux-gnu, |
64 | + libs: libc6-dev-arm64-cross, |
65 | + target: linux-aarch64 |
66 | + }, { |
67 | + arch: alpha-linux-gnu, |
68 | + libs: libc6.1-dev-alpha-cross, |
69 | + target: linux-alpha-gcc |
70 | + }, { |
71 | + arch: arm-linux-gnueabi, |
72 | + libs: libc6-dev-armel-cross, |
73 | + target: linux-armv4 |
74 | + }, { |
75 | + arch: arm-linux-gnueabihf, |
76 | + libs: libc6-dev-armhf-cross, |
77 | + target: linux-armv4 |
78 | + }, { |
79 | + arch: hppa-linux-gnu, |
80 | + libs: libc6-dev-hppa-cross, |
81 | + target: -static linux-generic32 |
82 | + }, { |
83 | + arch: m68k-linux-gnu, |
84 | + libs: libc6-dev-m68k-cross, |
85 | + target: -static -m68040 linux-latomic |
86 | + }, { |
87 | + arch: mips-linux-gnu, |
88 | + libs: libc6-dev-mips-cross, |
89 | + target: -static linux-mips32 |
90 | + }, { |
91 | + arch: mips64-linux-gnuabi64, |
92 | + libs: libc6-dev-mips64-cross, |
93 | + target: -static linux64-mips64 |
94 | + }, { |
95 | + arch: mipsel-linux-gnu, |
96 | + libs: libc6-dev-mipsel-cross, |
97 | + target: linux-mips32 |
98 | + }, { |
99 | + arch: powerpc64le-linux-gnu, |
100 | + libs: libc6-dev-ppc64el-cross, |
101 | + target: linux-ppc64le |
102 | + }, { |
103 | + arch: riscv64-linux-gnu, |
104 | + libs: libc6-dev-riscv64-cross, |
105 | + target: linux64-riscv64 |
106 | + }, { |
107 | + arch: s390x-linux-gnu, |
108 | + libs: libc6-dev-s390x-cross, |
109 | + target: linux64-s390x |
110 | + }, { |
111 | + arch: sh4-linux-gnu, |
112 | + libs: libc6-dev-sh4-cross, |
113 | + target: no-async linux-latomic |
114 | + }, { |
115 | + arch: hppa-linux-gnu, |
116 | + libs: libc6-dev-hppa-cross, |
117 | + target: linux-generic32, |
118 | + }, { |
119 | + arch: m68k-linux-gnu, |
120 | + libs: libc6-dev-m68k-cross, |
121 | + target: -mcfv4e linux-latomic |
122 | + }, { |
123 | + arch: mips-linux-gnu, |
124 | + libs: libc6-dev-mips-cross, |
125 | + target: linux-mips32 |
126 | + }, { |
127 | + arch: mips64-linux-gnuabi64, |
128 | + libs: libc6-dev-mips64-cross, |
129 | + target: linux64-mips64 |
130 | + }, { |
131 | + arch: sparc64-linux-gnu, |
132 | + libs: libc6-dev-sparc64-cross, |
133 | + target: linux64-sparcv9 |
134 | + } |
135 | + ] |
136 | + runs-on: ubuntu-latest |
137 | + steps: |
138 | + - name: install packages |
139 | + run: | |
140 | + sudo apt-get update |
141 | + sudo apt-get -yq --force-yes install \ |
142 | + gcc-${{ matrix.platform.arch }} \ |
143 | + ${{ matrix.platform.libs }} |
144 | + - uses: actions/checkout@v2 |
145 | + |
146 | + |
147 | + - name: install quictls |
148 | + run: | |
149 | + QUICTLS_EXTRA_ARGS="--cross-compile-prefix=${{ matrix.platform.arch }}- ${{ matrix.platform.target }}" QUICTLS=yes scripts/build-ssl.sh |
150 | + |
151 | + - name: Build |
152 | + run: | |
153 | + make ERR=1 CC=${{ matrix.platform.arch }}-gcc TARGET=linux-glibc USE_LIBCRYPT= USE_OPENSSL=1 USE_QUIC=1 USE_PROMEX=1 SSL_LIB=${HOME}/opt/lib SSL_INC=${HOME}/opt/include ADDLIB="-Wl,-rpath,${HOME}/opt/lib" |
154 | + |
155 | diff --git a/.github/workflows/vtest.yml b/.github/workflows/vtest.yml |
156 | index 8c838cc..b919418 100644 |
157 | --- a/.github/workflows/vtest.yml |
158 | +++ b/.github/workflows/vtest.yml |
159 | @@ -49,7 +49,7 @@ jobs: |
160 | - name: Generate cache key |
161 | id: generate-cache-key |
162 | run: | |
163 | - echo "::set-output name=key::$(echo ${{ matrix.name }} | sha256sum | awk '{print $1}')" |
164 | + echo "key=$(echo ${{ matrix.name }} | sha256sum | awk '{print $1}')" >> $GITHUB_OUTPUT |
165 | |
166 | - name: Cache SSL libs |
167 | if: ${{ matrix.ssl && matrix.ssl != 'stock' && matrix.ssl != 'BORINGSSL=yes' && matrix.ssl != 'QUICTLS=yes' }} |
168 | @@ -96,6 +96,9 @@ jobs: |
169 | run: make -C contrib/wurfl |
170 | - name: Compile HAProxy with ${{ matrix.CC }} |
171 | run: | |
172 | + echo "::group::Show compiler's version" |
173 | + echo | ${{ matrix.CC }} -v |
174 | + echo "::endgroup::" |
175 | echo "::group::Show platform specific defines" |
176 | echo | ${{ matrix.CC }} -dM -xc -E - |
177 | echo "::endgroup::" |
178 | @@ -119,7 +122,7 @@ jobs: |
179 | fi |
180 | echo "::endgroup::" |
181 | haproxy -vv |
182 | - echo "::set-output name=version::$(haproxy -v |awk 'NR==1{print $3}')" |
183 | + echo "version=$(haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT |
184 | - name: Install problem matcher for VTest |
185 | # This allows one to more easily see which tests fail. |
186 | run: echo "::add-matcher::.github/vtest.json" |
187 | diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml |
188 | index ceac981..0292e09 100644 |
189 | --- a/.github/workflows/windows.yml |
190 | +++ b/.github/workflows/windows.yml |
191 | @@ -55,9 +55,10 @@ jobs: |
192 | ERR=1 \ |
193 | TARGET=${{ matrix.TARGET }} \ |
194 | CC=${{ matrix.CC }} \ |
195 | + DEBUG_CFLAGS="-g -Wno-deprecated-declarations" \ |
196 | ${{ join(matrix.FLAGS, ' ') }} |
197 | - name: Show HAProxy version |
198 | id: show-version |
199 | run: | |
200 | ./haproxy -vv |
201 | - echo "::set-output name=version::$(./haproxy -v |awk 'NR==1{print $3}')" |
202 | + echo "version=$(./haproxy -v |awk 'NR==1{print $3}')" >> $GITHUB_OUTPUT |
203 | diff --git a/CHANGELOG b/CHANGELOG |
204 | index 6ae4bed..4b5713f 100644 |
205 | --- a/CHANGELOG |
206 | +++ b/CHANGELOG |
207 | @@ -1,6 +1,106 @@ |
208 | ChangeLog : |
209 | =========== |
210 | |
211 | +2023/02/14 : 2.0.31 |
212 | + - SCRIPTS: announce-release: add a link to the data plane API |
213 | + - CI: github: change "ubuntu-latest" to "ubuntu-20.04" |
214 | + - BUG/MEDIUM: ssl: Verify error codes can exceed 63 |
215 | + - BUG/MINOR: ssl: Fix potential overflow |
216 | + - BUG/MEDIUM: mworker: fix segv in early failure of mworker mode with peers |
217 | + - BUG/MEDIUM: resolvers: Use tick_first() to update the resolvers task timeout |
218 | + - LICENSE: wurfl: clarify the dummy library license. |
219 | + - BUG/MEDIUM: mux-h2: Refuse interim responses with end-stream flag set |
220 | + - BUG/MINOR: pool/stats: Use ullong to report total pool usage in bytes in stats |
221 | + - BUILD: makefile: build the features list dynamically |
222 | + - BUILD: makefile: sort the features list |
223 | + - BUG/MAJOR: buf: Fix copy of wrapping output data when a buffer is realigned |
224 | + - BUG/MINOR: resolvers: Wait the resolution execution for a do_resolv action |
225 | + - BUG/MINOR: promex: Don't forget to consume the request on error |
226 | + - BUG/MINOR: http-fetch: Don't block HTTP sample fetch eval in HTTP_MSG_ERROR state |
227 | + - BUG/MINOR: http-ana: make set-status also update txn->status |
228 | + - BUG/MEDIUM: ssl: wrong eviction from the session cache tree |
229 | + - BUG/MEDIUM: stick-table: do not leave entries in end of window during purge |
230 | + - BUG/MEDIUM: cache: use the correct time reference when comparing dates |
231 | + - DOC: config: fix option spop-check proxy compatibility |
232 | + - DOC: config: 'http-send-name-header' option may be used in default section |
233 | + - DOC: proxy-protocol: fix wrong byte in provided example |
234 | + - CI: github: don't warn on deprecated openssl functions on windows |
235 | + - BUG/CRITICAL: http: properly reject empty http header field names |
236 | + |
237 | +2022/12/09 : 2.0.30 |
238 | + - CI: determine actual LibreSSL version dynamically |
239 | + - BUILD: fix build warning on solaris based systems with __maybe_unused. |
240 | + - REGTESTS: abortonclose: Fix some race conditions |
241 | + - BUG/MINOR: peers: fix error reporting of "bind" lines |
242 | + - BUG/MEDIUM: http: Properly reject non-HTTP/1.x protocols |
243 | + - BUG/MEDIUM: peers: fix segfault using multiple bind on peers sections |
244 | + - BUG/MEDIUM: peers: prevent unitialized multiple listeners on peers section |
245 | + - BUG/MEDIUM: sample: Fix adjusting size in word converter |
246 | + - SCRIPTS: add make-releases-json to recreate a releases.json file in download dirs |
247 | + - SCRIPTS: make publish-release try to launch make-releases-json |
248 | + - DOC: peers: indicate that some server settings are not usable |
249 | + - DOC: peers: clarify when entry expiration date is renewed. |
250 | + - DOC: peers: fix port number and addresses on new peers section format |
251 | + - BUG/MINOR: conn_stream: do not confirm a connection from the frontend path |
252 | + - REGTESTS: abortonclose: Add a barrier to not mix up log messages |
253 | + - REGTESTS: http_request_buffer: Increase client timeout to wait "slow" clients |
254 | + - BUILD: compiler: implement unreachable for older compilers too |
255 | + - BUG/MINOR: server: do not enable DNS resolution on disabled proxies |
256 | + - BUG/MINOR: http-ana: Set method to HTTP_METH_OTHER when an HTTP txn is created |
257 | + - BUG/MINOR: http-fetch: Use integer value when possible in "method" sample fetch |
258 | + - BUG/MINOR: peers/config: always fill the bind_conf's argument |
259 | + - BUG/MINOR: peers: fix possible NULL dereferences at config parsing |
260 | + - BUG/MINOR: backend: Fallback on RR algo if balance on source is impossible |
261 | + - BUG/MINOR: sockpair: wrong return value for fd_send_uxst() |
262 | + - BUG/MINOR: ssl: free the fields in srv->ssl_ctx |
263 | + - MINOR: peers: Use a dedicated reconnect timeout when stopping the local peer |
264 | + - BUG/MEDIUM: peers: limit reconnect attempts of the old process on reload |
265 | + - BUG/MINOR: peers: Use right channel flag to consider the peer as connected |
266 | + - MINOR: server: Constify source server to copy its settings |
267 | + - REORG: server: Export srv_settings_cpy() function |
268 | + - BUG/MEDIUM: proxy: Perform a custom copy for default server settings |
269 | + - BUILD: http: silence an uninitialized warning affecting gcc-5 |
270 | + - BUG/MEDIUM: mux-h2: do not fiddle with ->dsi to indicate demux is idle |
271 | + - BUG/MINOR: resolvers: return the correct value in resolvers_finalize_config() |
272 | + - DOC: configuration: do-resolve doesn't work with a port in the string |
273 | + - BUG/MEDIUM: spoe: Properly update streams waiting for a ACK in async mode |
274 | + - BUG/MEDIUM: peers: Add connect and server timeut to peers proxy |
275 | + - BUG/MEDIUM: peers: Don't use resync timer when local resync is in progress |
276 | + - BUG/MEDIUM: peers: Don't start resync on reload if local peer is not up-to-date |
277 | + - REGTESTS: http_request_buffer: Add a barrier to not mix up log messages |
278 | + - BUG/MINOR: h1: Support headers case adjustment for TCP proxies |
279 | + - BUG/MINOR: signals/poller: set the poller timeout to 0 when there are signals |
280 | + - BUG/MINOR: signals/poller: ensure wakeup from signals |
281 | + - BUG/MEDIUM: proxy: ensure pause_proxy() and resume_proxy() own PROXY_LOCK |
282 | + - BUG/MEDIUM: captures: free() an error capture out of the proxy lock |
283 | + - SCRIPTS: announce-release: update some URLs to https |
284 | + - BUG/MINOR: log: improper behavior when escaping log data |
285 | + - BUILD: fix compilation for OpenSSL-3.0.0-alpha17 |
286 | + - BUILD: cfgparse: Fix GCC warning about a variable used after realloc |
287 | + - BUG/MEDIUM: lua: handle stick table implicit arguments right. |
288 | + - BUG/MINOR: http-fetch: Update method after a prefetch in smp_fetch_meth() |
289 | + - BUILD: http_fetch: silence an uninitiialized warning with gcc-4/5/6 at -Os |
290 | + - DOC: configuration: missing 'if' in tcp-request content example |
291 | + - BUG/MAJOR: stick-tables: do not try to index a server name for applets |
292 | + - CI: Replace the deprecated `::set-output` command by writing to $GITHUB_OUTPUT in matrix.py |
293 | + - CI: Replace the deprecated `::set-output` command by writing to $GITHUB_OUTPUT in workflow definition |
294 | + - DOC: management: add forgotten "show startup-logs" |
295 | + - BUG/MAJOR: stick-table: don't process store-response rules for applets |
296 | + - BUG/MEDIUM: stick-table: fix a race condition when updating the expiration task |
297 | + - CI: add monthly gcc cross compile jobs |
298 | + - CI: emit the compiler's version in the build reports |
299 | + - BUG/MEDIUM: listener: Fix race condition when updating the global mngmt task |
300 | + - BUG/MINOR: http_ana/txn: don't re-initialize txn and req var lists |
301 | + - BUG/MEDIUM: peers: messages about unkown tables not correctly ignored |
302 | + - BUILD: peers: Remove unused variables |
303 | + - BUILD: listener: fix build warning on global_listener_rwlock without threads |
304 | + - DOC: config: provide some configuration hints for "http-reuse" |
305 | + - DOC: config: clarify the fact that SNI should not be used in HTTP scenarios |
306 | + - DOC: config: explain how default matching method for ACL works |
307 | + - DOC: config: clarify the fact that "retries" is not just for connections |
308 | + - DOC: config: clarify the -m dir and -m dom pattern matching methods |
309 | + - Revert "CI: determine actual LibreSSL version dynamically" |
310 | + |
311 | 2022/05/13 : 2.0.29 |
312 | - BUG/MINOR: tools: fix url2sa return value with IPv4 |
313 | - Revert "BUG/MAJOR: mux-pt: Always destroy the backend connection on detach" |
314 | diff --git a/Makefile b/Makefile |
315 | index 7eddac0..bd1042b 100644 |
316 | --- a/Makefile |
317 | +++ b/Makefile |
318 | @@ -449,7 +449,11 @@ ignore_implicit = $(if $(subst environment,,$(origin $(1))), \ |
319 | # is used to report a list of all flags which were used to build this version. |
320 | # Do not assign anything to it. |
321 | BUILD_OPTIONS := $(foreach opt,$(use_opts),$(call ignore_implicit,$(opt))) |
322 | -BUILD_FEATURES := $(foreach opt,$(patsubst USE_%,%,$(use_opts)),$(if $(USE_$(opt)),+$(opt),-$(opt))) |
323 | + |
324 | +# Make a list of all known features with +/- prepended depending on their |
325 | +# activation status. Must be a macro so that dynamically enabled ones are |
326 | +# evaluated with their current status. |
327 | +BUILD_FEATURES = $(foreach opt,$(patsubst USE_%,%,$(sort $(use_opts))),$(if $(USE_$(opt)),+$(opt),-$(opt))) |
328 | |
329 | # All USE_* options have their equivalent macro defined in the code (some might |
330 | # possibly be unused though) |
331 | diff --git a/SUBVERS b/SUBVERS |
332 | index 50af805..e1824da 100644 |
333 | --- a/SUBVERS |
334 | +++ b/SUBVERS |
335 | @@ -1,2 +1,2 @@ |
336 | --5e15b0f |
337 | +-c8b1c15 |
338 | |
339 | diff --git a/VERDATE b/VERDATE |
340 | index cba5e36..2f36592 100644 |
341 | --- a/VERDATE |
342 | +++ b/VERDATE |
343 | @@ -1,2 +1,2 @@ |
344 | -2022-05-13 17:43:21 +0200 |
345 | -2022/05/13 |
346 | +2023-02-14 16:58:28 +0100 |
347 | +2023/02/14 |
348 | diff --git a/VERSION b/VERSION |
349 | index 3df5a46..e235558 100644 |
350 | --- a/VERSION |
351 | +++ b/VERSION |
352 | @@ -1 +1 @@ |
353 | -2.0.29 |
354 | +2.0.31 |
355 | diff --git a/contrib/prometheus-exporter/service-prometheus.c b/contrib/prometheus-exporter/service-prometheus.c |
356 | index d420cbc..3cc502c 100644 |
357 | --- a/contrib/prometheus-exporter/service-prometheus.c |
358 | +++ b/contrib/prometheus-exporter/service-prometheus.c |
359 | @@ -2465,6 +2465,7 @@ static void promex_appctx_handle_io(struct appctx *appctx) |
360 | res->flags |= CF_READ_NULL; |
361 | si_shutr(si); |
362 | si_shutw(si); |
363 | + goto out; |
364 | } |
365 | |
366 | struct applet promex_applet = { |
367 | diff --git a/contrib/wurfl/wurfl/wurfl.h b/contrib/wurfl/wurfl/wurfl.h |
368 | index ca512da..4e089c2 100644 |
369 | --- a/contrib/wurfl/wurfl/wurfl.h |
370 | +++ b/contrib/wurfl/wurfl/wurfl.h |
371 | @@ -4,11 +4,16 @@ |
372 | * Copyright (c) ScientiaMobile, Inc. |
373 | * http://www.scientiamobile.com |
374 | * |
375 | - * This software package is the property of ScientiaMobile Inc. and is licensed |
376 | - * commercially according to a contract between the Licensee and ScientiaMobile Inc. (Licensor). |
377 | - * If you represent the Licensee, please refer to the licensing agreement which has been signed |
378 | - * between the two parties. If you do not represent the Licensee, you are not authorized to use |
379 | - * this software in any way. |
380 | + * This software package is the property of ScientiaMobile Inc. and is distributed under |
381 | + * a dual licensing scheme: |
382 | + * |
383 | + * 1) commercially according to a contract between the Licensee and ScientiaMobile Inc. (Licensor). |
384 | + * If you represent the Licensee, please refer to the licensing agreement which has been signed |
385 | + * between the two parties. If you do not represent the Licensee, you are not authorized to use |
386 | + * this software in any way. |
387 | + * |
388 | + * 2) LGPL when used in the context of the HAProxy project with the purpose of testing compatibility |
389 | + * of HAProxy with ScientiaMobile software. |
390 | * |
391 | */ |
392 | |
393 | diff --git a/debian/changelog b/debian/changelog |
394 | index 2e61d7f..9980b1d 100644 |
395 | --- a/debian/changelog |
396 | +++ b/debian/changelog |
397 | @@ -1,3 +1,23 @@ |
398 | +haproxy (2.0.31-0ubuntu0.1) focal; urgency=medium |
399 | + |
400 | + * New upstream release (LP: #2012557). |
401 | + - Major and critical bug fixes according to the upstream changelog: |
402 | + + BUG/MAJOR: stick-tables: do not try to index a server name for applets |
403 | + + BUG/MAJOR: stick-table: don't process store-response rules for applets |
404 | + + BUG/MAJOR: buf: Fix copy of wrapping output data when a buffer is |
405 | + realigned |
406 | + + BUG/CRITICAL: http: properly reject empty http header field names |
407 | + - Remove patches applied by upstream in debian/patches: |
408 | + + CVE-2023-0056.patch |
409 | + + CVE-2023-25725.patch |
410 | + - Refresh existing patches in debian/patches: |
411 | + + 0002-Use-dpkg-buildflags-to-build-halog.patch |
412 | + * Backport DEP-8 tests from Lunar: |
413 | + - d/t/proxy-ssl-termination |
414 | + - d/t/proxy-ssl-pass-through |
415 | + |
416 | + -- Lucas Kanashiro <kanashiro@ubuntu.com> Wed, 22 Mar 2023 17:39:46 -0300 |
417 | + |
418 | haproxy (2.0.29-0ubuntu1.3) focal-security; urgency=medium |
419 | |
420 | * SECURITY UPDATE: incorrect handling of empty http header field names |
421 | diff --git a/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch b/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch |
422 | index a039316..94e1fb1 100644 |
423 | --- a/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch |
424 | +++ b/debian/patches/0002-Use-dpkg-buildflags-to-build-halog.patch |
425 | @@ -8,8 +8,6 @@ Last-Update: 2013-07-02 |
426 | contrib/halog/Makefile | 16 +++++----------- |
427 | 1 file changed, 5 insertions(+), 11 deletions(-) |
428 | |
429 | -diff --git a/contrib/halog/Makefile b/contrib/halog/Makefile |
430 | -index 5e687c0..ab34027 100644 |
431 | --- a/contrib/halog/Makefile |
432 | +++ b/contrib/halog/Makefile |
433 | @@ -1,22 +1,16 @@ |
434 | diff --git a/debian/patches/CVE-2023-0056.patch b/debian/patches/CVE-2023-0056.patch |
435 | deleted file mode 100644 |
436 | index a10f21b..0000000 |
437 | --- a/debian/patches/CVE-2023-0056.patch |
438 | +++ /dev/null |
439 | @@ -1,39 +0,0 @@ |
440 | -Backport of: |
441 | - |
442 | -From 827a6299e6995c5c3ba620d8b7cbacdaef67f2c4 Mon Sep 17 00:00:00 2001 |
443 | -From: Christopher Faulet <cfaulet@haproxy.com> |
444 | -Date: Thu, 22 Dec 2022 09:47:01 +0100 |
445 | -Subject: [PATCH] BUG/MEDIUM: mux-h2: Refuse interim responses with end-stream |
446 | - flag set |
447 | - |
448 | -As state in RFC9113#8.1, HEADERS frame with the ES flag set that carries an |
449 | -informational status code is malformed. However, there is no test on this |
450 | -condition. |
451 | - |
452 | -On 2.4 and higher, it is hard to predict consequences of this bug because |
453 | -end of the message is only reported with a flag. But on 2.2 and lower, it |
454 | -leads to a crash because there is an unexpected extra EOM block at the end |
455 | -of an interim response. |
456 | - |
457 | -Now, when a ES flag is detected on a HEADERS frame for an interim message, a |
458 | -stream error is sent (RST_STREAM/PROTOCOL_ERROR). |
459 | - |
460 | -This patch should solve the issue #1972. It should be backported as far as |
461 | -2.0. |
462 | ---- |
463 | - src/mux_h2.c | 5 +++++ |
464 | - 1 file changed, 5 insertions(+) |
465 | - |
466 | ---- a/src/mux_h2.c |
467 | -+++ b/src/mux_h2.c |
468 | -@@ -3935,6 +3935,10 @@ next_frame: |
469 | - *flags |= H2_SF_HEADERS_RCVD; |
470 | - |
471 | - if ((h2c->dff & H2_F_HEADERS_END_STREAM)) { |
472 | -+ if (msgf & H2_MSGF_RSP_1XX) { |
473 | -+ /* RFC9113#8.1 : HEADERS frame with the ES flag set that carries an informational status code is malformed */ |
474 | -+ goto fail; |
475 | -+ } |
476 | - /* Mark the end of message, either using EOM in HTX or with the |
477 | - * trailing CRLF after the end of trailers. Note that DATA_CHNK |
478 | - * is not set during headers with END_STREAM. For HTX trailers, |
479 | diff --git a/debian/patches/CVE-2023-25725.patch b/debian/patches/CVE-2023-25725.patch |
480 | deleted file mode 100644 |
481 | index e57d84b..0000000 |
482 | --- a/debian/patches/CVE-2023-25725.patch |
483 | +++ /dev/null |
484 | @@ -1,175 +0,0 @@ |
485 | -From 7382253d6a3636fa85510063bdcc9f2e8f8f696d Mon Sep 17 00:00:00 2001 |
486 | -From: Willy Tarreau <w@1wt.eu> |
487 | -Date: Thu, 9 Feb 2023 21:36:54 +0100 |
488 | -Subject: BUG/CRITICAL: http: properly reject empty http header field names |
489 | - |
490 | -The HTTP header parsers surprizingly accepts empty header field names, |
491 | -and this is a leftover from the original code that was agnostic to this. |
492 | - |
493 | -When muxes were introduced, for H2 first, the HPACK decompressor needed |
494 | -to feed headers lists, and since empty header names were strictly |
495 | -forbidden by the protocol, the lists of headers were purposely designed |
496 | -to be terminated by an empty header field name (a principle that is |
497 | -similar to H1's empty line termination). This principle was preserved |
498 | -and generalized to other protocols migrated to muxes (H1/FCGI/H3 etc) |
499 | -without anyone ever noticing that the H1 parser was still able to deliver |
500 | -empty header field names to this list. In addition to this it turns out |
501 | -that the HPACK decompressor, despite a comment in the code, may |
502 | -successfully decompress an empty header field name, and this mistake |
503 | -was propagated to the QPACK decompressor as well. |
504 | - |
505 | -The impact is that an empty header field name may be used to truncate |
506 | -the list of headers and thus make some headers disappear. While for |
507 | -H2/H3 the impact is limited as haproxy sees a request with missing |
508 | -headers, and headers are not used to delimit messages, in the case of |
509 | -HTTP/1, the impact is significant because the presence (and sometimes |
510 | -contents) of certain sensitive headers is detected during the parsing. |
511 | -Thus, some of these headers may be seen, marked as present, their value |
512 | -extracted, but never delivered to upper layers and obviously not |
513 | -forwarded to the other side either. This can have for consequence that |
514 | -certain important header fields such as Connection, Upgrade, Host, |
515 | -Content-length, Transfer-Encoding etc are possibly seen as different |
516 | -between what haproxy uses to parse/forward/route and what is observed |
517 | -in http-request rules and of course, forwarded. One direct consequence |
518 | -is that it is possible to exploit this property in HTTP/1 to make |
519 | -affected versions of haproxy forward more data than is advertised on |
520 | -the other side, and bypass some access controls or routing rules by |
521 | -crafting extraneous requests. Note, however, that responses to such |
522 | -requests will normally not be passed back to the client, but this can |
523 | -still cause some harm. |
524 | - |
525 | -This specific risk can be mostly worked around in configuration using |
526 | -the following rule that will rely on the bug's impact to precisely |
527 | -detect the inconsistency between the known body size and the one |
528 | -expected to be advertised to the server (the rule works from 2.0 to |
529 | -2.8-dev): |
530 | - |
531 | - http-request deny if { fc_http_major 1 } !{ req.body_size 0 } !{ req.hdr(content-length) -m found } !{ req.hdr(transfer-encoding) -m found } !{ method CONNECT } |
532 | - |
533 | -This will exclusively block such carefully crafted requests delivered |
534 | -over HTTP/1. HTTP/2 and HTTP/3 do not need content-length, and a body |
535 | -that arrives without being announced with a content-length will be |
536 | -forwarded using transfer-encoding, hence will not cause discrepancies. |
537 | -In HAProxy 2.0 in legacy mode ("no option http-use-htx"), this rule will |
538 | -simply have no effect but will not cause trouble either. |
539 | - |
540 | -A clean solution would consist in modifying the loops iterating over |
541 | -these headers lists to check the header name's pointer instead of its |
542 | -length (since both are zero at the end of the list), but this requires |
543 | -to touch tens of places and it's very easy to miss one. Functions such |
544 | -as htx_add_header(), htx_add_trailer(), htx_add_all_headers() would be |
545 | -good starting points for such a possible future change. |
546 | - |
547 | -Instead the current fix focuses on blocking empty headers where they |
548 | -are first inserted, hence in the H1/HPACK/QPACK decoders. One benefit |
549 | -of the current solution (for H1) is that it allows "show errors" to |
550 | -report a precise diagnostic when facing such invalid HTTP/1 requests, |
551 | -with the exact location of the problem and the originating address: |
552 | - |
553 | - $ printf "GET / HTTP/1.1\r\nHost: localhost\r\n:empty header\r\n\r\n" | nc 0 8001 |
554 | - HTTP/1.1 400 Bad request |
555 | - Content-length: 90 |
556 | - Cache-Control: no-cache |
557 | - Connection: close |
558 | - Content-Type: text/html |
559 | - |
560 | - <html><body><h1>400 Bad request</h1> |
561 | - Your browser sent an invalid request. |
562 | - </body></html> |
563 | - |
564 | - $ socat /var/run/haproxy.stat <<< "show errors" |
565 | - Total events captured on [10/Feb/2023:16:29:37.530] : 1 |
566 | - |
567 | - [10/Feb/2023:16:29:34.155] frontend decrypt (#2): invalid request |
568 | - backend <NONE> (#-1), server <NONE> (#-1), event #0, src 127.0.0.1:31092 |
569 | - buffer starts at 0 (including 0 out), 16334 free, |
570 | - len 50, wraps at 16336, error at position 33 |
571 | - H1 connection flags 0x00000000, H1 stream flags 0x00000810 |
572 | - H1 msg state MSG_HDR_NAME(17), H1 msg flags 0x00001410 |
573 | - H1 chunk len 0 bytes, H1 body len 0 bytes : |
574 | - |
575 | - 00000 GET / HTTP/1.1\r\n |
576 | - 00016 Host: localhost\r\n |
577 | - 00033 :empty header\r\n |
578 | - 00048 \r\n |
579 | - |
580 | -I want to address sincere and warm thanks for their great work to the |
581 | -team composed of the following security researchers who found the issue |
582 | -together and reported it: Bahruz Jabiyev, Anthony Gavazzi, and Engin |
583 | -Kirda from Northeastern University, Kaan Onarlioglu from Akamai |
584 | -Technologies, Adi Peleg and Harvey Tuch from Google. And kudos to Amaury |
585 | -Denoyelle from HAProxy Technologies for spotting that the HPACK and |
586 | -QPACK decoders would let this pass despite the comment explicitly |
587 | -saying otherwise. |
588 | - |
589 | -This fix must be backported as far as 2.0. The QPACK changes can be |
590 | -dropped before 2.6. In 2.0 there is also the equivalent code for legacy |
591 | -mode, which doesn't suffer from the list truncation, but it would better |
592 | -be fixed regardless. |
593 | - |
594 | -CVE-2023-25725 was assigned to this issue. |
595 | - |
596 | ---- |
597 | - src/h1.c | 4 ++++ |
598 | - src/hpack-dec.c | 9 +++++++++ |
599 | - src/http_msg.c | 8 +++++++- |
600 | - 3 files changed, 20 insertions(+), 1 deletion(-) |
601 | - |
602 | -diff --git a/src/h1.c b/src/h1.c |
603 | -index 3839fbe97..69a7cedcb 100644 |
604 | ---- a/src/h1.c |
605 | -+++ b/src/h1.c |
606 | -@@ -672,6 +672,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop, |
607 | - |
608 | - if (likely(*ptr == ':')) { |
609 | - col = ptr - start; |
610 | -+ if (col <= sol) { |
611 | -+ state = H1_MSG_HDR_NAME; |
612 | -+ goto http_msg_invalid; |
613 | -+ } |
614 | - EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP); |
615 | - } |
616 | - |
617 | -diff --git a/src/hpack-dec.c b/src/hpack-dec.c |
618 | -index 7f3e7624b..0fc71ebeb 100644 |
619 | ---- a/src/hpack-dec.c |
620 | -+++ b/src/hpack-dec.c |
621 | -@@ -425,6 +425,15 @@ int hpack_decode_frame(struct hpack_dht *dht, const uint8_t *raw, uint32_t len, |
622 | - /* <name> and <value> are correctly filled here */ |
623 | - } |
624 | - |
625 | -+ /* We must not accept empty header names (forbidden by the spec and used |
626 | -+ * as a list termination). |
627 | -+ */ |
628 | -+ if (!name.len) { |
629 | -+ hpack_debug_printf("##ERR@%d##\n", __LINE__); |
630 | -+ ret = -HPACK_ERR_INVALID_ARGUMENT; |
631 | -+ goto leave; |
632 | -+ } |
633 | -+ |
634 | - /* here's what we have here : |
635 | - * - name.len > 0 |
636 | - * - value is filled with either const data or data allocated from tmp |
637 | -diff --git a/src/http_msg.c b/src/http_msg.c |
638 | -index 067a7f863..e07c81c67 100644 |
639 | ---- a/src/http_msg.c |
640 | -+++ b/src/http_msg.c |
641 | -@@ -1006,8 +1006,14 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx) |
642 | - if (likely(HTTP_IS_TOKEN(*ptr))) |
643 | - EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, HTTP_MSG_HDR_NAME); |
644 | - |
645 | -- if (likely(*ptr == ':')) |
646 | -+ if (likely(*ptr == ':')) { |
647 | -+ if (ptr == input + msg->sol) { |
648 | -+ /* empty header names are not permitted */ |
649 | -+ state = HTTP_MSG_HDR_NAME; |
650 | -+ goto http_msg_invalid; |
651 | -+ } |
652 | - EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, HTTP_MSG_HDR_L1_SP); |
653 | -+ } |
654 | - |
655 | - if (likely(msg->err_pos < -1) || *ptr == '\n') { |
656 | - state = HTTP_MSG_HDR_NAME; |
657 | --- |
658 | -2.35.3 |
659 | - |
660 | diff --git a/debian/patches/series b/debian/patches/series |
661 | index f7b2e27..0945bb0 100644 |
662 | --- a/debian/patches/series |
663 | +++ b/debian/patches/series |
664 | @@ -1,5 +1,3 @@ |
665 | 0002-Use-dpkg-buildflags-to-build-halog.patch |
666 | haproxy.service-start-after-syslog.patch |
667 | haproxy.service-add-documentation.patch |
668 | -CVE-2023-0056.patch |
669 | -CVE-2023-25725.patch |
670 | diff --git a/debian/tests/control b/debian/tests/control |
671 | index 70649e3..ccc2b53 100644 |
672 | --- a/debian/tests/control |
673 | +++ b/debian/tests/control |
674 | @@ -5,3 +5,11 @@ Restrictions: needs-root |
675 | Tests: proxy-localhost |
676 | Depends: haproxy, wget, apache2 |
677 | Restrictions: needs-root, allow-stderr, isolation-container |
678 | + |
679 | +Tests: proxy-ssl-termination |
680 | +Depends: haproxy, wget, apache2, gnutls-bin, ssl-cert |
681 | +Restrictions: needs-root, allow-stderr, isolation-container |
682 | + |
683 | +Tests: proxy-ssl-pass-through |
684 | +Depends: haproxy, wget, apache2, gnutls-bin, ssl-cert |
685 | +Restrictions: needs-root, allow-stderr, isolation-container |
686 | diff --git a/debian/tests/proxy-localhost b/debian/tests/proxy-localhost |
687 | index b1279e8..0736985 100644 |
688 | --- a/debian/tests/proxy-localhost |
689 | +++ b/debian/tests/proxy-localhost |
690 | @@ -2,6 +2,9 @@ |
691 | |
692 | set -eux |
693 | |
694 | +WDIR=$(dirname "$0") |
695 | +. "${WDIR}/utils" |
696 | + |
697 | cat > /etc/haproxy/haproxy.cfg <<EOF |
698 | global |
699 | chroot /var/lib/haproxy |
700 | @@ -34,15 +37,8 @@ backend test-back |
701 | EOF |
702 | |
703 | service haproxy restart |
704 | +sleep 2 # Apache 2 could be still starting... See #976997. |
705 | |
706 | -# index.html is shipped with apache2 |
707 | -# Download it via haproxy and compare |
708 | -if wget -t1 http://localhost:8080 -O- | cmp /var/www/html/index.html -; then |
709 | - echo "OK: index.html downloaded via haproxy matches the source file." |
710 | -else |
711 | - echo "FAIL: downloaded index.html via haproxy is different from the" |
712 | - echo " file delivered by apache." |
713 | - exit 1 |
714 | -fi |
715 | +check_index_file "http://localhost:8080" |
716 | |
717 | exit 0 |
718 | diff --git a/debian/tests/proxy-ssl-pass-through b/debian/tests/proxy-ssl-pass-through |
719 | new file mode 100644 |
720 | index 0000000..aa0bd2c |
721 | --- /dev/null |
722 | +++ b/debian/tests/proxy-ssl-pass-through |
723 | @@ -0,0 +1,59 @@ |
724 | +#!/bin/sh |
725 | + |
726 | +set -eux |
727 | + |
728 | +WDIR=$(dirname "$0") |
729 | +. "${WDIR}/utils" |
730 | + |
731 | +CERT_DIR=/etc/ssl/localhost |
732 | +APACHE2_CONFIG=/etc/apache2/sites-available/default-ssl.conf |
733 | + |
734 | +create_ca |
735 | +create_selfsigned_cert ${CERT_DIR} |
736 | + |
737 | +# Use the self-signed certificate in apache2 config |
738 | +sed -i "s#/etc/ssl/certs/ssl-cert-snakeoil.pem#${CERT_DIR}/localhost_cert.pem#" ${APACHE2_CONFIG} |
739 | +sed -i "s#/etc/ssl/private/ssl-cert-snakeoil.key#${CERT_DIR}/localhost_key.pem#" ${APACHE2_CONFIG} |
740 | + |
741 | +cat > /etc/haproxy/haproxy.cfg <<EOF |
742 | +global |
743 | + chroot /var/lib/haproxy |
744 | + user haproxy |
745 | + group haproxy |
746 | + daemon |
747 | + maxconn 4096 |
748 | + |
749 | +defaults |
750 | + log global |
751 | + option dontlognull |
752 | + option redispatch |
753 | + retries 3 |
754 | + timeout client 50s |
755 | + timeout connect 10s |
756 | + timeout http-request 5s |
757 | + timeout server 50s |
758 | + maxconn 4096 |
759 | + |
760 | +frontend test-front |
761 | + bind *:4433 |
762 | + mode tcp |
763 | + option tcplog |
764 | + default_backend test-back |
765 | + |
766 | +backend test-back |
767 | + mode tcp |
768 | + stick store-request src |
769 | + stick-table type ip size 256k expire 30m |
770 | + option ssl-hello-chk |
771 | + server test-1 localhost:443 check |
772 | +EOF |
773 | + |
774 | +systemctl restart haproxy |
775 | +a2enmod ssl |
776 | +a2ensite default-ssl |
777 | +systemctl restart apache2 |
778 | +sleep 5 # Apache 2 could be still starting... See #976997. It needs some extra seconds because of SSL |
779 | + |
780 | +check_index_file "https://localhost:4433" |
781 | + |
782 | +exit 0 |
783 | diff --git a/debian/tests/proxy-ssl-termination b/debian/tests/proxy-ssl-termination |
784 | new file mode 100644 |
785 | index 0000000..6cc1bcc |
786 | --- /dev/null |
787 | +++ b/debian/tests/proxy-ssl-termination |
788 | @@ -0,0 +1,48 @@ |
789 | +#!/bin/sh |
790 | + |
791 | +set -eux |
792 | + |
793 | +WDIR=$(dirname "$0") |
794 | +. "${WDIR}/utils" |
795 | + |
796 | +CERT_DIR=/etc/ssl/localhost |
797 | +create_ca |
798 | +create_selfsigned_cert ${CERT_DIR} |
799 | + |
800 | +cat > /etc/haproxy/haproxy.cfg <<EOF |
801 | +global |
802 | + chroot /var/lib/haproxy |
803 | + user haproxy |
804 | + group haproxy |
805 | + daemon |
806 | + maxconn 4096 |
807 | + ssl-default-bind-options ssl-min-ver SSLv3 |
808 | + |
809 | +defaults |
810 | + log global |
811 | + option dontlognull |
812 | + option redispatch |
813 | + retries 3 |
814 | + timeout client 50s |
815 | + timeout connect 10s |
816 | + timeout http-request 5s |
817 | + timeout server 50s |
818 | + maxconn 4096 |
819 | + |
820 | +frontend test-front |
821 | + bind *:443 ssl crt ${CERT_DIR}/localhost.pem |
822 | + default_backend test-back |
823 | + |
824 | +backend test-back |
825 | + mode http |
826 | + stick store-request src |
827 | + stick-table type ip size 256k expire 30m |
828 | + server test-1 localhost:80 check |
829 | +EOF |
830 | + |
831 | +systemctl restart haproxy |
832 | +sleep 2 # Apache 2 could be still starting... See #976997. |
833 | + |
834 | +check_index_file "https://localhost" |
835 | + |
836 | +exit 0 |
837 | diff --git a/debian/tests/utils b/debian/tests/utils |
838 | new file mode 100644 |
839 | index 0000000..df11b55 |
840 | --- /dev/null |
841 | +++ b/debian/tests/utils |
842 | @@ -0,0 +1,58 @@ |
843 | + |
844 | +create_ca() { |
845 | + certtool --generate-privkey --bits 4096 --outfile /etc/ssl/private/mycakey.pem |
846 | + |
847 | + cat <<EOF > /etc/ssl/ca.info |
848 | +cn = Example Company |
849 | +ca |
850 | +cert_signing_key |
851 | +expiration_days = 3650 |
852 | +EOF |
853 | + |
854 | + certtool --generate-self-signed \ |
855 | + --load-privkey /etc/ssl/private/mycakey.pem \ |
856 | + --template /etc/ssl/ca.info \ |
857 | + --outfile /usr/local/share/ca-certificates/mycacert.crt |
858 | + |
859 | + update-ca-certificates |
860 | +} |
861 | + |
862 | +create_selfsigned_cert() { |
863 | + dir="$1" |
864 | + mkdir -p "${dir}" |
865 | + |
866 | + certtool --generate-privkey --bits 2048 --outfile "${dir}/localhost_key.pem" |
867 | + |
868 | + cat <<EOF > "${dir}/localhost.info" |
869 | +organization = Example Company |
870 | +cn = localhost |
871 | +tls_www_server |
872 | +encryption_key |
873 | +signing_key |
874 | +expiration_days = 365 |
875 | +EOF |
876 | + |
877 | + certtool --generate-certificate \ |
878 | + --load-privkey "${dir}/localhost_key.pem" \ |
879 | + --load-ca-certificate /etc/ssl/certs/mycacert.pem \ |
880 | + --load-ca-privkey /etc/ssl/private/mycakey.pem \ |
881 | + --template "${dir}/localhost.info" \ |
882 | + --outfile "${dir}/localhost_cert.pem" |
883 | + |
884 | + cat "${dir}/localhost_cert.pem" "${dir}/localhost_key.pem" | tee "${dir}/localhost.pem" |
885 | + chgrp haproxy "${dir}/localhost_key.pem" "${dir}/localhost.pem" |
886 | + chmod 0640 "${dir}/localhost_key.pem" "${dir}/localhost.pem" |
887 | +} |
888 | + |
889 | +check_index_file() { |
890 | + haproxy_url="$1" |
891 | + # index.html is shipped with apache2 |
892 | + # Download it via haproxy and compare |
893 | + if wget -t1 "${haproxy_url}" -O- | cmp /var/www/html/index.html -; then |
894 | + echo "OK: index.html downloaded via haproxy matches the source file." |
895 | + else |
896 | + echo "FAIL: downloaded index.html via haproxy is different from the" |
897 | + echo " file delivered by apache." |
898 | + exit 1 |
899 | + fi |
900 | +} |
901 | diff --git a/doc/configuration.txt b/doc/configuration.txt |
902 | index 4394d07..4c7c59e 100644 |
903 | --- a/doc/configuration.txt |
904 | +++ b/doc/configuration.txt |
905 | @@ -3,7 +3,7 @@ |
906 | Configuration Manual |
907 | ---------------------- |
908 | version 2.0 |
909 | - 2022/05/13 |
910 | + 2023/02/14 |
911 | |
912 | |
913 | This document covers the configuration language as implemented in the version |
914 | @@ -2106,9 +2106,10 @@ default-server [param*] |
915 | Arguments: |
916 | <param*> is a list of parameters for this server. The "default-server" |
917 | keyword accepts an important number of options and has a complete |
918 | - section dedicated to it. Please refer to section 5 for more |
919 | - details. |
920 | - |
921 | + section dedicated to it. In a peers section, the transport |
922 | + parameters of a "default-server" line are supported. Please refer |
923 | + to section 5 for more details, and the "server" keyword below in |
924 | + this section for some of the restrictions. |
925 | |
926 | See also: "server" and section 5 about server options |
927 | |
928 | @@ -2140,12 +2141,16 @@ peer <peername> <ip>:<port> [param*] |
929 | |
930 | server <peername> [<ip>:<port>] [param*] |
931 | As previously mentioned, "peer" keyword may be replaced by "server" keyword |
932 | - with a support for all "server" parameters found in 5.2 paragraph. |
933 | - If the underlying peer is local, <ip>:<port> parameters must not be present. |
934 | - These parameters must be provided on a "bind" line (see "bind" keyword |
935 | - of this "peers" section). |
936 | - Some of these parameters are irrelevant for "peers" sections. |
937 | + with a support for all "server" parameters found in 5.2 paragraph that are |
938 | + related to transport settings. If the underlying peer is local, <ip>:<port> |
939 | + parameters must not be present; these parameters must be provided on a "bind" |
940 | + line (see "bind" keyword of this "peers" section). |
941 | |
942 | + A number of "server" parameters are irrelevant for "peers" sections. Peers by |
943 | + nature do not support dynamic host name resolution nor health checks, hence |
944 | + parameters like "init_addr", "resolvers", "check", "agent-check", or "track" |
945 | + are not supported. Similarly, there is no load balancing nor stickiness, thus |
946 | + parameters such as "weight" or "cookie" have no effect. |
947 | |
948 | Example: |
949 | # The old way. |
950 | @@ -2165,10 +2170,11 @@ server <peername> [<ip>:<port>] [param*] |
951 | |
952 | Example: |
953 | peers mypeers |
954 | - bind 127.0.0.11:10001 ssl crt mycerts/pem |
955 | - default-server ssl verify none |
956 | - server hostA 127.0.0.10:10000 |
957 | - server hostB #local peer |
958 | + bind 192.168.0.1:1024 ssl crt mycerts/pem |
959 | + default-server ssl verify none |
960 | + server haproxy1 #local peer |
961 | + server haproxy2 192.168.0.2:1024 |
962 | + server haproxy3 10.2.0.1:1024 |
963 | |
964 | |
965 | table <tablename> type {ip | integer | string [len <length>] | binary [len <length>]} |
966 | @@ -2433,7 +2439,7 @@ http-check send-state X - X X |
967 | http-request - X X X |
968 | http-response - X X X |
969 | http-reuse X - X X |
970 | -http-send-name-header - - X X |
971 | +http-send-name-header X - X X |
972 | id - X X X |
973 | ignore-persist - - X X |
974 | load-server-state-from-file X - X X |
975 | @@ -2493,7 +2499,7 @@ option socket-stats (*) X X X - |
976 | option splice-auto (*) X X X X |
977 | option splice-request (*) X X X X |
978 | option splice-response (*) X X X X |
979 | -option spop-check - - - X |
980 | +option spop-check X - X X |
981 | option srvtcpka (*) X - X X |
982 | option ssl-hello-chk X - X X |
983 | -- keyword -------------------------- defaults - frontend - listen -- backend - |
984 | @@ -4466,7 +4472,8 @@ http-request do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> : |
985 | based on information found in the request (IE a Host header). |
986 | If this action is used to find the server's IP address (using the |
987 | "set-dst" action), then the server IP address in the backend must be set |
988 | - to 0.0.0.0. |
989 | + to 0.0.0.0. The do-resolve action takes an host-only parameter, any port must |
990 | + be removed from the string. |
991 | |
992 | Example: |
993 | resolvers mydns |
994 | @@ -4481,7 +4488,7 @@ http-request do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr> : |
995 | |
996 | frontend fe |
997 | bind 10.42.0.1:80 |
998 | - http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower |
999 | + http-request do-resolve(txn.myip,mydns,ipv4) hdr(Host),lower,regsub(:[0-9]*$,) |
1000 | http-request capture var(txn.myip) len 40 |
1001 | |
1002 | # return 503 when the variable is not set, |
1003 | @@ -5420,7 +5427,26 @@ http-reuse { never | safe | aggressive | always } |
1004 | because almost no new connection will be established while idle connections |
1005 | remain available. This is particularly true with the "always" strategy. |
1006 | |
1007 | - See also : "option http-keep-alive", "server maxconn" |
1008 | + The rules to decide to keep an idle connection opened or to close it after |
1009 | + processing are also governed by the "tune.pool-low-fd-ratio" (default: 20%) |
1010 | + and "tune.pool-high-fd-ratio" (default: 25%). These correspond to the |
1011 | + percentage of total file descriptors spent in idle connections above which |
1012 | + haproxy will respectively refrain from keeping a connection opened after a |
1013 | + response, and actively kill idle connections. Some setups using a very high |
1014 | + ratio of idle connections, either because of too low a global "maxconn", or |
1015 | + due to a lot of HTTP/2 or HTTP/3 traffic on the frontend (few connections) |
1016 | + but HTTP/1 connections on the backend, may observe a lower reuse rate because |
1017 | + too few connections are kept open. It may be desirable in this case to adjust |
1018 | + such thresholds or simply to increase the global "maxconn" value. |
1019 | + |
1020 | + Similarly, when thread groups are explicitly enabled, it is important to |
1021 | + understand that idle connections are only usable between threads from a same |
1022 | + group. As such it may happen that unfair load between groups leads to more |
1023 | + idle connections being needed, causing a lower reuse rate. The same solution |
1024 | + may then be applied (increase global "maxconn" or increase pool ratios). |
1025 | + |
1026 | + See also : "option http-keep-alive", "server maxconn", "thread-groups", |
1027 | + "tune.pool-high-fd-ratio", "tune.pool-low-fd-ratio" |
1028 | |
1029 | |
1030 | http-send-name-header [<header>] |
1031 | @@ -7490,7 +7516,7 @@ no option splice-response |
1032 | option spop-check |
1033 | Use SPOP health checks for server testing |
1034 | May be used in sections : defaults | frontend | listen | backend |
1035 | - no | no | no | yes |
1036 | + yes | no | yes | yes |
1037 | Arguments : none |
1038 | |
1039 | It is possible to test that the server correctly talks SPOP protocol instead |
1040 | @@ -8333,24 +8359,26 @@ reqitarpit <search> [{if | unless} <cond>] (ignore case) (deprecated) |
1041 | |
1042 | |
1043 | retries <value> |
1044 | - Set the number of retries to perform on a server after a connection failure |
1045 | + Set the number of retries to perform on a server after a failure |
1046 | May be used in sections: defaults | frontend | listen | backend |
1047 | yes | no | yes | yes |
1048 | Arguments : |
1049 | - <value> is the number of times a connection attempt should be retried on |
1050 | - a server when a connection either is refused or times out. The |
1051 | - default value is 3. |
1052 | + <value> is the number of times a request or connection attempt should be |
1053 | + retried on a server after a failure. |
1054 | |
1055 | - It is important to understand that this value applies to the number of |
1056 | - connection attempts, not full requests. When a connection has effectively |
1057 | - been established to a server, there will be no more retry. |
1058 | + By default, retries apply only to new connection attempts. However, when |
1059 | + the "retry-on" directive is used, other conditions might trigger a retry |
1060 | + (e.g. empty response, undesired status code), and each of them will count |
1061 | + one attempt, and when the total number attempts reaches the value here, an |
1062 | + error will be returned. |
1063 | |
1064 | In order to avoid immediate reconnections to a server which is restarting, |
1065 | a turn-around timer of min("timeout connect", one second) is applied before |
1066 | - a retry occurs. |
1067 | + a retry occurs on the same server. |
1068 | |
1069 | - When "option redispatch" is set, the last retry may be performed on another |
1070 | - server even if a cookie references a different server. |
1071 | + When "option redispatch" is set, some retries may be performed on another |
1072 | + server even if a cookie references a different server. By default this will |
1073 | + only be the last retry unless an argument is passed to "option redispatch". |
1074 | |
1075 | See also : "option redispatch" |
1076 | |
1077 | @@ -9607,13 +9635,16 @@ stick-table type {ip | integer | string [len <length>] | binary [len <length>]} |
1078 | belonging to the same unique process. |
1079 | |
1080 | <expire> defines the maximum duration of an entry in the table since it |
1081 | - was last created, refreshed or matched. The expiration delay is |
1082 | + was last created, refreshed using 'track-sc' or matched using |
1083 | + 'stick match' or 'stick on' rule. The expiration delay is |
1084 | defined using the standard time format, similarly as the various |
1085 | timeouts. The maximum duration is slightly above 24 days. See |
1086 | section 2.4 for more information. If this delay is not specified, |
1087 | the session won't automatically expire, but older entries will |
1088 | be removed once full. Be sure not to use the "nopurge" parameter |
1089 | if not expiration delay is specified. |
1090 | + Note: 'table_*' converters performs lookups but won't update touch |
1091 | + expire since they don't require 'track-sc'. |
1092 | |
1093 | <data_type> is used to store additional information in the stick-table. This |
1094 | may be used by ACLs in order to control various criteria related |
1095 | @@ -10448,7 +10479,7 @@ tcp-request content <action> [{if | unless} <condition>] |
1096 | evaluated. |
1097 | |
1098 | Example: |
1099 | - tcp-request content use-service lua.deny { src -f /etc/haproxy/blacklist.lst } |
1100 | + tcp-request content use-service lua.deny if { src -f /etc/haproxy/blacklist.lst } |
1101 | |
1102 | Example: |
1103 | |
1104 | @@ -12880,8 +12911,10 @@ sni <expression> |
1105 | The "sni" parameter evaluates the sample fetch expression, converts it to a |
1106 | string and uses the result as the host name sent in the SNI TLS extension to |
1107 | the server. A typical use case is to send the SNI received from the client in |
1108 | - a bridged HTTPS scenario, using the "ssl_fc_sni" sample fetch for the |
1109 | - expression, though alternatives such as req.hdr(host) can also make sense. If |
1110 | + a bridged TCP/SSL scenario, using the "ssl_fc_sni" sample fetch for the |
1111 | + expression. THIS MUST NOT BE USED FOR HTTPS, where req.hdr(host) should be |
1112 | + used instead, since SNI in HTTPS must always match the Host field and clients |
1113 | + are allowed to use different host names over the same connection). If |
1114 | "verify required" is set (which is the recommended setting), the resulting |
1115 | name will also be matched against the server certificate's names. See the |
1116 | "verify" directive for more details. If you want to set a SNI for health |
1117 | @@ -13520,7 +13553,11 @@ possible to convert the sample to lowercase before matching, like this : |
1118 | All ACL-specific criteria imply a default matching method. Most often, these |
1119 | criteria are composed by concatenating the name of the original sample fetch |
1120 | method and the matching method. For example, "hdr_beg" applies the "beg" match |
1121 | -to samples retrieved using the "hdr" fetch method. Since all ACL-specific |
1122 | +to samples retrieved using the "hdr" fetch method. This matching method is only |
1123 | +usable when the keyword is used alone, without any converter. In case any such |
1124 | +converter were to be applied after such an ACL keyword, the default matching |
1125 | +method from the ACL keyword is simply ignored since what will matter for the |
1126 | +matching is the output type of the last converter. Since all ACL-specific |
1127 | criteria rely on a sample fetch method, it is always possible instead to use |
1128 | the original sample fetch method and the explicit matching method using "-m". |
1129 | |
1130 | @@ -13646,13 +13683,24 @@ different forms : |
1131 | - suffix match (-m end) : the patterns are compared with the end of the |
1132 | extracted string, and the ACL matches if any of them matches. |
1133 | |
1134 | - - subdir match (-m dir) : the patterns are looked up inside the extracted |
1135 | - string, delimited with slashes ("/"), and the ACL matches if any of them |
1136 | - matches. |
1137 | - |
1138 | - - domain match (-m dom) : the patterns are looked up inside the extracted |
1139 | - string, delimited with dots ("."), and the ACL matches if any of them |
1140 | - matches. |
1141 | + - subdir match (-m dir) : the patterns are looked up anywhere inside the |
1142 | + extracted string, delimited with slashes ("/"), the beginning or the end |
1143 | + of the string. The ACL matches if any of them matches. As such, the string |
1144 | + "/images/png/logo/32x32.png", would match "/images", "/images/png", |
1145 | + "images/png", "/png/logo", "logo/32x32.png" or "32x32.png" but not "png" |
1146 | + nor "32x32". |
1147 | + |
1148 | + - domain match (-m dom) : the patterns are looked up anywhere inside the |
1149 | + extracted string, delimited with dots ("."), colons (":"), slashes ("/"), |
1150 | + question marks ("?"), the beginning or the end of the string. This is made |
1151 | + to be used with URLs. Leading and trailing delimiters in the pattern are |
1152 | + ignored. The ACL matches if any of them matches. As such, in the example |
1153 | + string "http://www1.dc-eu.example.com:80/blah", the patterns "http", |
1154 | + "www1", ".www1", "dc-eu", "example", "com", "80", "dc-eu.example", |
1155 | + "blah", ":www1:", "dc-eu.example:80" would match, but not "eu" nor "dc". |
1156 | + Using it to match domain suffixes for filtering or routing is generally |
1157 | + not a good idea, as the routing could easily be fooled by prepending the |
1158 | + matching prefix in front of another domain for example. |
1159 | |
1160 | String matching applies to verbatim strings as they are passed, with the |
1161 | exception of the backslash ("\") which makes it possible to escape some |
1162 | @@ -16168,6 +16216,16 @@ ssl_fc_sni : string |
1163 | requires that the SSL library is built with support for TLS extensions |
1164 | enabled (check haproxy -vv). |
1165 | |
1166 | + CAUTION! Except under very specific conditions, it is normally not correct to |
1167 | + use this field as a substitute for the HTTP "Host" header field. For example, |
1168 | + when forwarding an HTTPS connection to a server, the SNI field must be set |
1169 | + from the HTTP Host header field using "req.hdr(host)" and not from the front |
1170 | + SNI value. The reason is that SNI is solely used to select the certificate |
1171 | + the server side will present, and that clients are then allowed to send |
1172 | + requests with different Host values as long as they match the names in the |
1173 | + certificate. As such, "ssl_fc_sni" should normally not be used as an argument |
1174 | + to the "sni" server keyword, unless the backend works in TCP mode. |
1175 | + |
1176 | ACL derivatives : |
1177 | ssl_fc_sni_end : suffix match |
1178 | ssl_fc_sni_reg : regex match |
1179 | diff --git a/doc/management.txt b/doc/management.txt |
1180 | index 337cc14..f90110b 100644 |
1181 | --- a/doc/management.txt |
1182 | +++ b/doc/management.txt |
1183 | @@ -2458,6 +2458,10 @@ show stat [{<iid>|<proxy>} <type> <sid>] [typed|json] |
1184 | $ echo "show stat json" | socat /var/run/haproxy.sock stdio | \ |
1185 | python -m json.tool |
1186 | |
1187 | +show startup-logs |
1188 | + Dump all messages emitted during the startup of the current haproxy process, |
1189 | + each startup-logs buffer is unique to its haproxy worker. |
1190 | + |
1191 | show table |
1192 | Dump general information on all known stick-tables. Their name is returned |
1193 | (the name of the proxy which holds them), their type (currently zero, always |
1194 | diff --git a/doc/proxy-protocol.txt b/doc/proxy-protocol.txt |
1195 | index ff64c8b..45bafe3 100644 |
1196 | --- a/doc/proxy-protocol.txt |
1197 | +++ b/doc/proxy-protocol.txt |
1198 | @@ -500,7 +500,7 @@ protocol. Identifying the protocol version is easy : |
1199 | - if the incoming byte count is 16 or above and the 13 first bytes match |
1200 | the protocol signature block followed by the protocol version 2 : |
1201 | |
1202 | - \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02 |
1203 | + \x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x20 |
1204 | |
1205 | - otherwise, if the incoming byte count is 8 or above, and the 5 first |
1206 | characters match the US-ASCII representation of "PROXY" then the protocol |
1207 | diff --git a/include/common/buf.h b/include/common/buf.h |
1208 | index 1ee6420..3770b9a 100644 |
1209 | --- a/include/common/buf.h |
1210 | +++ b/include/common/buf.h |
1211 | @@ -469,7 +469,7 @@ static inline void b_slow_realign(struct buffer *b, char *swap, size_t output) |
1212 | |
1213 | /* process output data in two steps to cover wrapping */ |
1214 | if (block1 > b_size(b) - b_head_ofs(b)) { |
1215 | - block2 = b_size(b) - b_head_ofs(b); |
1216 | + block2 = b_peek_ofs(b, block1); |
1217 | block1 -= block2; |
1218 | } |
1219 | memcpy(swap + b_size(b) - output, b_head(b), block1); |
1220 | diff --git a/include/common/compiler.h b/include/common/compiler.h |
1221 | index c023c9d..4b76cec 100644 |
1222 | --- a/include/common/compiler.h |
1223 | +++ b/include/common/compiler.h |
1224 | @@ -77,10 +77,12 @@ |
1225 | #endif |
1226 | #endif |
1227 | |
1228 | +#ifndef __maybe_unused |
1229 | /* silence the "unused" warnings without having to place painful #ifdefs. |
1230 | * For use with variables or functions. |
1231 | */ |
1232 | #define __maybe_unused __attribute__((unused)) |
1233 | +#endif |
1234 | |
1235 | /* This allows gcc to know that some locations are never reached, for example |
1236 | * after a longjmp() in the Lua code, hence that some errors caught by such |
1237 | @@ -91,7 +93,7 @@ |
1238 | #if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) |
1239 | #define my_unreachable() __builtin_unreachable() |
1240 | #else |
1241 | -#define my_unreachable() |
1242 | +#define my_unreachable() do { } while (1) |
1243 | #endif |
1244 | |
1245 | /* This macro may be used to block constant propagation that lets the compiler |
1246 | diff --git a/include/common/memory.h b/include/common/memory.h |
1247 | index 6c0b137..ee3b7f0 100644 |
1248 | --- a/include/common/memory.h |
1249 | +++ b/include/common/memory.h |
1250 | @@ -131,8 +131,8 @@ void create_pool_callback(struct pool_head **ptr, char *name, unsigned int size) |
1251 | void dump_pools_to_trash(); |
1252 | void dump_pools(void); |
1253 | int pool_total_failures(); |
1254 | -unsigned long pool_total_allocated(); |
1255 | -unsigned long pool_total_used(); |
1256 | +unsigned long long pool_total_allocated(); |
1257 | +unsigned long long pool_total_used(); |
1258 | |
1259 | /* |
1260 | * This function frees whatever can be freed in pool <pool>. |
1261 | diff --git a/include/common/standard.h b/include/common/standard.h |
1262 | index 38e2bb7..49b72c8 100644 |
1263 | --- a/include/common/standard.h |
1264 | +++ b/include/common/standard.h |
1265 | @@ -498,7 +498,8 @@ char *encode_chunk(char *start, char *stop, |
1266 | |
1267 | /* |
1268 | * Tries to prefix characters tagged in the <map> with the <escape> |
1269 | - * character. The input <string> must be zero-terminated. The result will |
1270 | + * character. The input <string> is processed until string_stop |
1271 | + * is reached or NULL-byte is encountered. The result will |
1272 | * be stored between <start> (included) and <stop> (excluded). This |
1273 | * function will always try to terminate the resulting string with a '\0' |
1274 | * before <stop>, and will return its position if the conversion |
1275 | @@ -506,7 +507,7 @@ char *encode_chunk(char *start, char *stop, |
1276 | */ |
1277 | char *escape_string(char *start, char *stop, |
1278 | const char escape, const long *map, |
1279 | - const char *string); |
1280 | + const char *string, const char *string_stop); |
1281 | |
1282 | /* |
1283 | * Tries to prefix characters tagged in the <map> with the <escape> |
1284 | diff --git a/include/proto/server.h b/include/proto/server.h |
1285 | index 8934075..7f8c725 100644 |
1286 | --- a/include/proto/server.h |
1287 | +++ b/include/proto/server.h |
1288 | @@ -46,6 +46,7 @@ extern struct list toremove_connections[MAX_THREADS]; |
1289 | int srv_downtime(const struct server *s); |
1290 | int srv_lastsession(const struct server *s); |
1291 | int srv_getinter(const struct check *check); |
1292 | +void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl); |
1293 | int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy, int parse_addr, int in_peers_section, int initial_resolve); |
1294 | int update_server_addr(struct server *s, void *ip, int ip_sin_family, const char *updater); |
1295 | const char *update_server_addr_port(struct server *s, const char *addr, const char *port, char *updater); |
1296 | diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h |
1297 | index d6d01a7..f23cbdc 100644 |
1298 | --- a/include/proto/ssl_sock.h |
1299 | +++ b/include/proto/ssl_sock.h |
1300 | @@ -102,6 +102,31 @@ void ssl_async_fd_free(int fd); |
1301 | |
1302 | #define sh_ssl_sess_tree_lookup(k) (struct sh_ssl_sess_hdr *)ebmb_lookup(sh_ssl_sess_tree, \ |
1303 | (k), SSL_MAX_SSL_SESSION_ID_LENGTH); |
1304 | + |
1305 | +static inline int cert_ignerr_bitfield_get(const unsigned long long *bitfield, int bit_index) |
1306 | +{ |
1307 | + int byte_index = bit_index >> 6; |
1308 | + int val = 0; |
1309 | + |
1310 | + if (byte_index < IGNERR_BF_SIZE) |
1311 | + val = bitfield[byte_index] & (1ULL << (bit_index & 0x3F)); |
1312 | + |
1313 | + return val != 0; |
1314 | +} |
1315 | + |
1316 | +static inline void cert_ignerr_bitfield_set(unsigned long long *bitfield, int bit_index) |
1317 | +{ |
1318 | + int byte_index = bit_index >> 6; |
1319 | + |
1320 | + if (byte_index < IGNERR_BF_SIZE) |
1321 | + bitfield[byte_index] |= (1ULL << (bit_index & 0x3F)); |
1322 | +} |
1323 | + |
1324 | +static inline void cert_ignerr_bitfield_set_all(unsigned long long *bitfield) |
1325 | +{ |
1326 | + memset(bitfield, -1, IGNERR_BF_SIZE*sizeof(*bitfield)); |
1327 | +} |
1328 | + |
1329 | #endif /* USE_OPENSSL */ |
1330 | #endif /* _PROTO_SSL_SOCK_H */ |
1331 | |
1332 | diff --git a/include/types/global.h b/include/types/global.h |
1333 | index eab3345..a505009 100644 |
1334 | --- a/include/types/global.h |
1335 | +++ b/include/types/global.h |
1336 | @@ -240,6 +240,7 @@ extern char hostname[MAX_HOSTNAME_LEN]; |
1337 | extern char localpeer[MAX_HOSTNAME_LEN]; |
1338 | extern struct list global_listener_queue; /* list of the temporarily limited listeners */ |
1339 | extern struct task *global_listener_queue_task; |
1340 | +__decl_hathreads(extern HA_RWLOCK_T global_listener_rwlock); |
1341 | extern unsigned int warned; /* bitfield of a few warnings to emit just once */ |
1342 | extern volatile unsigned long sleeping_thread_mask; |
1343 | extern struct list proc_list; /* list of process in mworker mode */ |
1344 | diff --git a/include/types/listener.h b/include/types/listener.h |
1345 | index def48b0..10464fa 100644 |
1346 | --- a/include/types/listener.h |
1347 | +++ b/include/types/listener.h |
1348 | @@ -139,12 +139,21 @@ struct ssl_bind_conf { |
1349 | #endif |
1350 | }; |
1351 | |
1352 | +/* |
1353 | + * In OpenSSL 3.0.0, the biggest verify error code's value is 94 and on the |
1354 | + * latest 1.1.1 it already reaches 79 so we need to size the ca/crt-ignore-err |
1355 | + * arrays accordingly. If the max error code increases, the arrays might need to |
1356 | + * be resized. |
1357 | + */ |
1358 | +#define SSL_MAX_VFY_ERROR_CODE 94 |
1359 | +#define IGNERR_BF_SIZE ((SSL_MAX_VFY_ERROR_CODE >> 6) + 1) |
1360 | + |
1361 | /* "bind" line settings */ |
1362 | struct bind_conf { |
1363 | #ifdef USE_OPENSSL |
1364 | struct ssl_bind_conf ssl_conf; /* ssl conf for ctx setting */ |
1365 | - unsigned long long ca_ignerr; /* ignored verify errors in handshake if depth > 0 */ |
1366 | - unsigned long long crt_ignerr; /* ignored verify errors in handshake if depth == 0 */ |
1367 | + unsigned long long ca_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth > 0 */ |
1368 | + unsigned long long crt_ignerr_bitfield[IGNERR_BF_SIZE]; /* ignored verify errors in handshake if depth == 0 */ |
1369 | SSL_CTX *initial_ctx; /* SSL context for initial negotiation */ |
1370 | SSL_CTX *default_ctx; /* SSL context of first/default certificate */ |
1371 | struct ssl_bind_conf *default_ssl_conf; /* custom SSL conf of default_ctx */ |
1372 | diff --git a/reg-tests/http-messaging/http_abortonclose.vtc b/reg-tests/http-messaging/http_abortonclose.vtc |
1373 | index 733242b..b6066ba 100644 |
1374 | --- a/reg-tests/http-messaging/http_abortonclose.vtc |
1375 | +++ b/reg-tests/http-messaging/http_abortonclose.vtc |
1376 | @@ -7,10 +7,12 @@ feature ignore_unknown_macro |
1377 | #REQUIRE_VERSION=2.0 |
1378 | #REGTEST_TYPE=slow |
1379 | |
1380 | +# b0 : Wait s1 was detected as DOWN to be sure it is stopped |
1381 | # b1 : Don't send /c4 before /c3 was received by s2 server |
1382 | # b2 : Don't finish c2 before c1 and c3 before c4 (from syslog POV) |
1383 | # b3 : finish c3 before s2 |
1384 | |
1385 | +barrier b0 cond 2 -cyclic |
1386 | barrier b1 cond 2 -cyclic |
1387 | barrier b2 cond 2 -cyclic |
1388 | barrier b3 cond 2 -cyclic |
1389 | @@ -32,12 +34,16 @@ server s2 { |
1390 | } -start |
1391 | |
1392 | syslog S -level info { |
1393 | + recv alert |
1394 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: Server check/srv1 is DOWN.*" |
1395 | + barrier b0 sync |
1396 | + |
1397 | recv |
1398 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - SC-- .* .* \"GET /c1 HTTP/1\\.1\"" |
1399 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1_1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - SC-- .* .* \"GET /c1 HTTP/1\\.1\"" |
1400 | barrier b2 sync |
1401 | recv |
1402 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - CC-- .* .* \"GET /c2 HTTP/1\\.1\"" |
1403 | - |
1404 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1_2/srv1 [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - CC-- .* .* \"GET /c2 HTTP/1\\.1\"" |
1405 | + barrier b2 sync |
1406 | recv |
1407 | expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be2/<NOSRV> [0-9]*/[0-9]*/-1/-1/[0-9]* 503 .* - - CQ-- .* .* \"GET /c4 HTTP/1\\.1\"" |
1408 | barrier b2 sync |
1409 | @@ -60,7 +66,8 @@ haproxy h1 -conf { |
1410 | option httplog |
1411 | log ${S_addr}:${S_port} local0 debug err |
1412 | bind "fd@${fe1}" |
1413 | - use_backend be1 |
1414 | + use_backend be1_1 if { path /c1 } |
1415 | + use_backend be1_2 if { path /c2 } |
1416 | |
1417 | frontend fe2 |
1418 | option httplog |
1419 | @@ -68,13 +75,25 @@ haproxy h1 -conf { |
1420 | bind "fd@${fe2}" |
1421 | use_backend be2 |
1422 | |
1423 | - backend be1 |
1424 | + backend be1_1 |
1425 | + server srv1 ${s1_addr}:${s1_port} |
1426 | + |
1427 | + backend be1_2 |
1428 | + timeout connect 1s |
1429 | + retries 10 |
1430 | server srv1 ${s1_addr}:${s1_port} |
1431 | |
1432 | backend be2 |
1433 | server srv1 ${s2_addr}:${s2_port} maxconn 1 |
1434 | + |
1435 | + backend check |
1436 | + server srv1 ${s1_addr}:${s1_port} check |
1437 | + log ${S_addr}:${S_port} local0 debug alert |
1438 | } -start |
1439 | |
1440 | +# Wait s1 was detected as DOWN |
1441 | +barrier b0 sync |
1442 | + |
1443 | # No server, wait all connection retries : SC-- |
1444 | client c1 -connect ${h1_fe1_sock} { |
1445 | txreq -url /c1 |
1446 | @@ -90,6 +109,9 @@ client c2 -connect ${h1_fe1_sock} { |
1447 | txreq -url /c2 |
1448 | } -run |
1449 | |
1450 | +# Wait c2 log entry |
1451 | +barrier b2 sync |
1452 | + |
1453 | # server with maxconn=1, abort waiting the server reply : CH-- |
1454 | client c3 -connect ${h1_fe2_sock} { |
1455 | txreq -url /c3 |
1456 | diff --git a/reg-tests/http-messaging/http_request_buffer.vtc b/reg-tests/http-messaging/http_request_buffer.vtc |
1457 | index 4fd7bb2..3c47599 100644 |
1458 | --- a/reg-tests/http-messaging/http_request_buffer.vtc |
1459 | +++ b/reg-tests/http-messaging/http_request_buffer.vtc |
1460 | @@ -9,6 +9,8 @@ feature ignore_unknown_macro |
1461 | # thanks to "http-buffer-request". If this was the case, c2 client |
1462 | # could not connect to s1 server and this would lead to make this test fail. |
1463 | |
1464 | +barrier b1 cond 2 -cyclic |
1465 | + |
1466 | server s1 { |
1467 | rxreq |
1468 | expect req.bodylen == 257 |
1469 | @@ -24,12 +26,18 @@ server s1 { |
1470 | syslog S -level info { |
1471 | recv |
1472 | expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 fe1/<NOSRV> .* 408 .* - - cD-- .* .* \"GET /this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url-this-is-a-long-url HTTP/1\\.1\"" |
1473 | + barrier b1 sync |
1474 | + |
1475 | recv |
1476 | expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"GET / HTTP/1\\.1\"" |
1477 | + barrier b1 sync |
1478 | + |
1479 | recv |
1480 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"POST /1 HTTP/1\\.1\"" |
1481 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/srv1 [0-9]*/[0-9]*/[0-9]*/[0-9]*/[0-9]* 200 .* - - ---- .* .* \"POST /1 HTTP/1\\.1\"" |
1482 | + barrier b1 sync |
1483 | + |
1484 | recv |
1485 | - expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe1 be1/<NOSRV> [0-9]*/-1/-1/-1/[0-9]* -1 .* - - CR-- .* .* \"POST /2 HTTP/1\\.1\"" |
1486 | + expect ~ "[^:\\[ ]*\\[[0-9]*\\]: .* .* fe2 be1/<NOSRV> [0-9]*/-1/-1/-1/[0-9]* -1 .* - - CR-- .* .* \"POST /2 HTTP/1\\.1\"" |
1487 | } -start |
1488 | |
1489 | haproxy h1 -conf { |
1490 | @@ -49,6 +57,14 @@ haproxy h1 -conf { |
1491 | log ${S_addr}:${S_port} local0 debug err |
1492 | bind "fd@${fe1}" |
1493 | use_backend be1 |
1494 | + |
1495 | + frontend fe2 |
1496 | + timeout client 10s |
1497 | + option httplog |
1498 | + option http-buffer-request |
1499 | + log ${S_addr}:${S_port} local0 debug err |
1500 | + bind "fd@${fe2}" |
1501 | + use_backend be1 |
1502 | } -start |
1503 | |
1504 | # 1 byte of the payload is missing. |
1505 | @@ -80,6 +96,9 @@ client c1 -connect ${h1_fe1_sock} { |
1506 | expect resp.status == 408 |
1507 | } -run |
1508 | |
1509 | +# Wait matching on log message |
1510 | +barrier b1 sync |
1511 | + |
1512 | # Payload is fully sent |
1513 | # ==> Request must be sent to the server. A 200 must be received |
1514 | client c2 -connect ${h1_fe1_sock} { |
1515 | @@ -88,10 +107,13 @@ client c2 -connect ${h1_fe1_sock} { |
1516 | expect resp.status == 200 |
1517 | } -run |
1518 | |
1519 | +# Wait matching on log message |
1520 | +barrier b1 sync |
1521 | + |
1522 | # Payload is fully sent in 2 steps (with a small delay, smaller than the client |
1523 | # timeout) and splitted on a chunk size. |
1524 | # ==> Request must be sent to the server. A 200 must be received |
1525 | -client c3 -connect ${h1_fe1_sock} { |
1526 | +client c3 -connect ${h1_fe2_sock} { |
1527 | send "POST /1 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1\r\n1\r\n1" |
1528 | delay 0.01 |
1529 | send "\r\n1\r\n0\r\n\r\n" |
1530 | @@ -99,11 +121,14 @@ client c3 -connect ${h1_fe1_sock} { |
1531 | expect resp.status == 200 |
1532 | } -run |
1533 | |
1534 | +# Wait matching on log message |
1535 | +barrier b1 sync |
1536 | + |
1537 | # Last CRLF of the request payload is missing but payload is sent in 2 steps |
1538 | # (with a small delay, smaller than the client timeout) and splitted on a chunk |
1539 | # size. The client aborts before sending the last CRLF. |
1540 | # ==> Request must be handled as an error with 'CR--' termination state. |
1541 | -client c4 -connect ${h1_fe1_sock} { |
1542 | +client c4 -connect ${h1_fe2_sock} { |
1543 | send "POST /2 HTTP/1.1\r\nTransfer-Encoding: chunked\r\n\r\n1\r\n1\r\n1" |
1544 | delay 0.01 |
1545 | send "\r\n1\r\n0\r\n" |
1546 | diff --git a/scripts/announce-release b/scripts/announce-release |
1547 | index a229301..4c75a3b 100755 |
1548 | --- a/scripts/announce-release |
1549 | +++ b/scripts/announce-release |
1550 | @@ -210,20 +210,21 @@ else |
1551 | fi |
1552 | |
1553 | (echo "Please find the usual URLs below :" |
1554 | - echo " Site index : http://www.haproxy.org/" |
1555 | - echo " Documentation : http://docs.haproxy.org/" |
1556 | + echo " Site index : https://www.haproxy.org/" |
1557 | + echo " Documentation : https://docs.haproxy.org/" |
1558 | echo " Wiki : https://github.com/haproxy/wiki/wiki" |
1559 | - echo " Discourse : http://discourse.haproxy.org/" |
1560 | + echo " Discourse : https://discourse.haproxy.org/" |
1561 | echo " Slack channel : https://slack.haproxy.org/" |
1562 | echo " Issue tracker : https://github.com/haproxy/haproxy/issues" |
1563 | - echo " Sources : http://www.haproxy.org/download/${BRANCH}/src/" |
1564 | - echo " Git repository : http://git.haproxy.org/git/${gitdir}/" |
1565 | - echo " Git Web browsing : http://git.haproxy.org/?p=${gitdir}" |
1566 | - echo " Changelog : http://www.haproxy.org/download/${BRANCH}/src/CHANGELOG" |
1567 | - echo " Pending bugs : http://www.haproxy.org/l/pending-bugs" |
1568 | - echo " Reviewed bugs : http://www.haproxy.org/l/reviewed-bugs" |
1569 | - echo " Code reports : http://www.haproxy.org/l/code-reports" |
1570 | - echo " Latest builds : http://www.haproxy.org/l/dev-packages" |
1571 | + echo " Sources : https://www.haproxy.org/download/${BRANCH}/src/" |
1572 | + echo " Git repository : https://git.haproxy.org/git/${gitdir}/" |
1573 | + echo " Git Web browsing : https://git.haproxy.org/?p=${gitdir}" |
1574 | + echo " Changelog : https://www.haproxy.org/download/${BRANCH}/src/CHANGELOG" |
1575 | + echo " Dataplane API : https://github.com/haproxytech/dataplaneapi/releases/latest" |
1576 | + echo " Pending bugs : https://www.haproxy.org/l/pending-bugs" |
1577 | + echo " Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs" |
1578 | + echo " Code reports : https://www.haproxy.org/l/code-reports" |
1579 | + echo " Latest builds : https://www.haproxy.org/l/dev-packages" |
1580 | ) >> "$OUTPUT" |
1581 | |
1582 | # sign |
1583 | diff --git a/scripts/make-releases-json b/scripts/make-releases-json |
1584 | new file mode 100755 |
1585 | index 0000000..38bb2b6 |
1586 | --- /dev/null |
1587 | +++ b/scripts/make-releases-json |
1588 | @@ -0,0 +1,103 @@ |
1589 | +#!/usr/bin/env bash |
1590 | +# |
1591 | +# Scan a branch directory for source tarballs and rebuild the releases.json |
1592 | +# file for that branch. md5 and sha256 are added if present. The highest |
1593 | +# numberred version is referenced as the latest release. |
1594 | +# |
1595 | +# Usage: $0 [-b branch] [-o outfile] /path/to/download/branch |
1596 | +# |
1597 | + |
1598 | +USAGE="Usage: ${0##*/} [-b branch] [-o outfile] DIR" |
1599 | +OUTPUT= |
1600 | +BRANCH= |
1601 | +DIR= |
1602 | + |
1603 | +die() { |
1604 | + [ "$#" -eq 0 ] || echo "$*" >&2 |
1605 | + exit 1 |
1606 | +} |
1607 | + |
1608 | +err() { |
1609 | + echo "$*" >&2 |
1610 | +} |
1611 | + |
1612 | +quit() { |
1613 | + [ "$#" -eq 0 -o -n "$QUIET" ] || echo "$*" |
1614 | + exit 0 |
1615 | +} |
1616 | + |
1617 | +emit_json() { |
1618 | + printf '{\n "branch": "%s",\n' ${BRANCH} |
1619 | + latest="" |
1620 | + for file in $(find "$DIR/src" -name 'haproxy-[0-9]*.gz' -printf "%P\n" |grep -v '[0-9]-patches*' | sort -rV ); do |
1621 | + rel="${file##*haproxy-}" |
1622 | + rel="${rel%%.tar.*}" |
1623 | + if [ -z "$latest" ]; then |
1624 | + latest="$rel"; |
1625 | + printf ' "latest_release": "%s",\n' ${latest} |
1626 | + printf ' "releases": {\n' |
1627 | + else |
1628 | + printf ",\n" |
1629 | + fi |
1630 | + printf ' "%s": {\n' ${rel} |
1631 | + printf ' "file": "%s"' ${file} |
1632 | + if [ -s "$DIR/src/$file.md5" ]; then |
1633 | + printf ',\n "md5": "%s"' $(awk '{print $1}' "$DIR/src/$file.md5") |
1634 | + fi |
1635 | + if [ -s "$DIR/src/$file.sha256" ]; then |
1636 | + printf ',\n "sha256": "%s"' $(awk '{print $1}' "$DIR/src/$file.sha256") |
1637 | + fi |
1638 | + printf '\n }' |
1639 | + done |
1640 | + |
1641 | + if [ -n "$latest" ]; then |
1642 | + printf "\n }" ## "releases" |
1643 | + fi |
1644 | + |
1645 | + printf '\n}\n' |
1646 | +} |
1647 | + |
1648 | + |
1649 | +### main |
1650 | + |
1651 | +while [ -n "$1" -a -z "${1##-*}" ]; do |
1652 | + case "$1" in |
1653 | + -b) BRANCH="$2" ; shift 2 ;; |
1654 | + -o) OUTPUT="$2" ; shift 2 ;; |
1655 | + -h|--help) quit "$USAGE" ;; |
1656 | + *) die "$USAGE" ;; |
1657 | + esac |
1658 | +done |
1659 | + |
1660 | +if [ $# -ne 1 ]; then |
1661 | + die "$USAGE" |
1662 | +fi |
1663 | + |
1664 | +DIR="$1" ; shift |
1665 | +if [ -z "$DIR" ]; then |
1666 | + die "Missing download directory name." |
1667 | +fi |
1668 | + |
1669 | +if [ ! -d "$DIR/." ]; then |
1670 | + die "Download directory doesn't exist : $DIR" |
1671 | +fi |
1672 | + |
1673 | +if [ ! -d "$DIR/src" ]; then |
1674 | + die "Download directory must contain 'src' : $DIR" |
1675 | +fi |
1676 | + |
1677 | +if [ -z "$BRANCH" ]; then |
1678 | + BRANCH=${DIR##*/} |
1679 | + if [ -n "${BRANCH//[0-9.]}" ]; then |
1680 | + die "Couldn't determine branch number from dir name: $BRANCH" |
1681 | + fi |
1682 | +fi |
1683 | + |
1684 | +# echo "debug: DIR=$DIR BRANCH=$BRANCH" |
1685 | +if [ -n "$OUTPUT" ]; then |
1686 | + emit_json > "$OUTPUT.tmp" |
1687 | + mv -f "$OUTPUT.tmp" "$OUTPUT" |
1688 | + rm -f "$OUTPUT.tmp" |
1689 | +else |
1690 | + emit_json |
1691 | +fi |
1692 | diff --git a/scripts/publish-release b/scripts/publish-release |
1693 | index abde56f..d785244 100755 |
1694 | --- a/scripts/publish-release |
1695 | +++ b/scripts/publish-release |
1696 | @@ -17,6 +17,7 @@ BRANCH= |
1697 | DEVEL= |
1698 | QUIET= |
1699 | AUTO= |
1700 | +ARG0="$0" |
1701 | NEW= |
1702 | DIR= |
1703 | DOC=( ) |
1704 | @@ -178,6 +179,11 @@ for i in "${DOC[@]}"; do |
1705 | $CMD_GZIP < "$TARGET_DIR/doc/${i#doc/}" > "$TARGET_DIR/doc/${i#doc/}.gz" |
1706 | done |
1707 | |
1708 | +if [ -x "${ARG0%/*}/make-releases-json" ]; then |
1709 | + # regenerate versions |
1710 | + "${ARG0%/*}/make-releases-json" -o "$TARGET_DIR/src/releases.json" "$TARGET_DIR" |
1711 | +fi |
1712 | + |
1713 | echo "Done : ls -l ${TARGET_DIR}" |
1714 | ( cd "$TARGET_DIR" ; |
1715 | ls -l src/CHANGELOG "src${DEVEL}/haproxy-${NEW}".tar.gz{,.md5,.sha256} $(for i in "${DOC[@]}"; do echo "doc/${i#doc/}"{,.gz}; done) |
1716 | diff --git a/src/backend.c b/src/backend.c |
1717 | index 056e53a..3fe9fdc 100644 |
1718 | --- a/src/backend.c |
1719 | +++ b/src/backend.c |
1720 | @@ -728,11 +728,6 @@ int assign_server(struct stream *s) |
1721 | (void *)&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr, |
1722 | 16, prev_srv); |
1723 | } |
1724 | - else { |
1725 | - /* unknown IP family */ |
1726 | - err = SRV_STATUS_INTERNAL; |
1727 | - goto out; |
1728 | - } |
1729 | break; |
1730 | |
1731 | case BE_LB_HASH_URI: |
1732 | diff --git a/src/cache.c b/src/cache.c |
1733 | index 07c406c..d94a76e 100644 |
1734 | --- a/src/cache.c |
1735 | +++ b/src/cache.c |
1736 | @@ -81,7 +81,7 @@ struct cache_st { |
1737 | |
1738 | struct cache_entry { |
1739 | unsigned int latest_validation; /* latest validation date */ |
1740 | - unsigned int expire; /* expiration date */ |
1741 | + unsigned int expire; /* expiration date (wall clock time) */ |
1742 | unsigned int age; /* Origin server "Age" header value */ |
1743 | unsigned int eoh; /* Origin server end of headers offset. */ // field used in legacy mode only |
1744 | |
1745 | @@ -114,7 +114,7 @@ struct cache_entry *entry_exist(struct cache *cache, char *hash) |
1746 | if (memcmp(entry->hash, hash, sizeof(entry->hash))) |
1747 | return NULL; |
1748 | |
1749 | - if (entry->expire > now.tv_sec) { |
1750 | + if (entry->expire > date.tv_sec) { |
1751 | return entry; |
1752 | } else { |
1753 | eb32_delete(node); |
1754 | @@ -864,8 +864,8 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px, |
1755 | shctx_unlock(shctx); |
1756 | |
1757 | /* store latest value and expiration time */ |
1758 | - object->latest_validation = now.tv_sec; |
1759 | - object->expire = now.tv_sec + http_calc_maxage(s, cconf->c.cache); |
1760 | + object->latest_validation = date.tv_sec; |
1761 | + object->expire = date.tv_sec + http_calc_maxage(s, cconf->c.cache); |
1762 | return ACT_RET_CONT; |
1763 | } |
1764 | |
1765 | @@ -1059,7 +1059,7 @@ static int htx_cache_add_age_hdr(struct appctx *appctx, struct htx *htx) |
1766 | char *end; |
1767 | |
1768 | chunk_reset(&trash); |
1769 | - age = MAX(0, (int)(now.tv_sec - cache_ptr->latest_validation)) + cache_ptr->age; |
1770 | + age = MAX(0, (int)(date.tv_sec - cache_ptr->latest_validation)) + cache_ptr->age; |
1771 | if (unlikely(age > CACHE_ENTRY_MAX_AGE)) |
1772 | age = CACHE_ENTRY_MAX_AGE; |
1773 | end = ultoa_o(age, b_head(&trash), b_size(&trash)); |
1774 | @@ -1877,11 +1877,11 @@ static int cli_io_handler_show_cache(struct appctx *appctx) |
1775 | entry = container_of(node, struct cache_entry, eb); |
1776 | next_key = node->key + 1; |
1777 | |
1778 | - if (entry->expire > now.tv_sec) { |
1779 | + if (entry->expire > date.tv_sec) { |
1780 | chunk_printf(&trash, "%p hash:%u size:%u (%u blocks), refcount:%u, expire:%d\n", |
1781 | entry, (*(unsigned int *)entry->hash), |
1782 | block_ptr(entry)->len, block_ptr(entry)->block_count, |
1783 | - block_ptr(entry)->refcount, entry->expire - (int)now.tv_sec); |
1784 | + block_ptr(entry)->refcount, entry->expire - (int)date.tv_sec); |
1785 | } else { |
1786 | /* time to remove that one */ |
1787 | eb32_delete(&entry->eb); |
1788 | diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c |
1789 | index 8bb85c6..7520620 100644 |
1790 | --- a/src/cfgparse-listen.c |
1791 | +++ b/src/cfgparse-listen.c |
1792 | @@ -381,7 +381,8 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) |
1793 | } |
1794 | |
1795 | /* set default values */ |
1796 | - memcpy(&curproxy->defsrv, &defproxy.defsrv, sizeof(curproxy->defsrv)); |
1797 | + srv_settings_cpy(&curproxy->defsrv, &defproxy.defsrv, 0); |
1798 | + |
1799 | curproxy->defsrv.id = "default-server"; |
1800 | |
1801 | curproxy->state = defproxy.state; |
1802 | diff --git a/src/cfgparse.c b/src/cfgparse.c |
1803 | index 36cb18d..e4a93dd 100644 |
1804 | --- a/src/cfgparse.c |
1805 | +++ b/src/cfgparse.c |
1806 | @@ -540,9 +540,10 @@ static struct bind_conf *bind_conf_uniq_alloc(struct proxy *p, |
1807 | |
1808 | if (!LIST_ISEMPTY(&p->conf.bind)) { |
1809 | bind_conf = LIST_ELEM((&p->conf.bind)->n, typeof(bind_conf), by_fe); |
1810 | - free(bind_conf->file); |
1811 | - bind_conf->file = strdup(file); |
1812 | - bind_conf->line = line; |
1813 | + /* |
1814 | + * We keep bind_conf->file and bind_conf->line unchanged |
1815 | + * to make them available for error messages |
1816 | + */ |
1817 | if (arg) { |
1818 | free(bind_conf->arg); |
1819 | bind_conf->arg = strdup(arg); |
1820 | @@ -627,7 +628,12 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1821 | } |
1822 | |
1823 | bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, |
1824 | - NULL, xprt_get(XPRT_RAW)); |
1825 | + args[1], xprt_get(XPRT_RAW)); |
1826 | + if (!bind_conf) { |
1827 | + ha_alert("parsing [%s:%d] : '%s %s' : cannot allocate memory.\n", file, linenum, args[0], args[1]); |
1828 | + err_code |= ERR_FATAL; |
1829 | + goto out; |
1830 | + } |
1831 | if (*args[0] == 'b') { |
1832 | struct listener *l; |
1833 | |
1834 | @@ -637,6 +643,11 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1835 | goto out; |
1836 | } |
1837 | |
1838 | + if (!LIST_ISEMPTY(&bind_conf->listeners)) { |
1839 | + ha_alert("parsing [%s:%d] : One listener per \"peers\" section is authorized but another is already configured at [%s:%d].\n", file, linenum, bind_conf->file, bind_conf->line); |
1840 | + err_code |= ERR_FATAL; |
1841 | + } |
1842 | + |
1843 | if (!str2listener(args[1], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { |
1844 | if (errmsg && *errmsg) { |
1845 | indent_msg(&errmsg, 2); |
1846 | @@ -644,11 +655,14 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1847 | } |
1848 | else |
1849 | ha_alert("parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s.\n", |
1850 | - file, linenum, args[0], args[1], args[2]); |
1851 | + file, linenum, args[0], args[1], args[1]); |
1852 | err_code |= ERR_FATAL; |
1853 | goto out; |
1854 | } |
1855 | - l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); |
1856 | + /* |
1857 | + * Newly allocated listener is at the end of the list |
1858 | + */ |
1859 | + l = LIST_ELEM(bind_conf->listeners.p, typeof(l), by_bind); |
1860 | l->maxaccept = 1; |
1861 | l->accept = session_accept_fd; |
1862 | l->analysers |= curpeers->peers_fe->fe_req_ana; |
1863 | @@ -848,6 +862,16 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1864 | goto out; |
1865 | |
1866 | bind_conf = bind_conf_uniq_alloc(curpeers->peers_fe, file, linenum, args[2], xprt_get(XPRT_RAW)); |
1867 | + if (!bind_conf) { |
1868 | + ha_alert("parsing [%s:%d] : '%s %s' : Cannot allocate memory.\n", file, linenum, args[0], args[1]); |
1869 | + err_code |= ERR_FATAL; |
1870 | + goto out; |
1871 | + } |
1872 | + |
1873 | + if (!LIST_ISEMPTY(&bind_conf->listeners)) { |
1874 | + ha_alert("parsing [%s:%d] : One listener per \"peers\" section is authorized but another is already configured at [%s:%d].\n", file, linenum, bind_conf->file, bind_conf->line); |
1875 | + err_code |= ERR_FATAL; |
1876 | + } |
1877 | |
1878 | if (!str2listener(args[2], curpeers->peers_fe, bind_conf, file, linenum, &errmsg)) { |
1879 | if (errmsg && *errmsg) { |
1880 | @@ -861,7 +885,10 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) |
1881 | goto out; |
1882 | } |
1883 | |
1884 | - l = LIST_ELEM(bind_conf->listeners.n, typeof(l), by_bind); |
1885 | + /* |
1886 | + * Newly allocated listener is at the end of the list |
1887 | + */ |
1888 | + l = LIST_ELEM(bind_conf->listeners.p, typeof(l), by_bind); |
1889 | l->maxaccept = 1; |
1890 | l->accept = session_accept_fd; |
1891 | l->analysers |= curpeers->peers_fe->fe_req_ana; |
1892 | @@ -2078,6 +2105,7 @@ next_line: |
1893 | |
1894 | /* if not enough space in thisline */ |
1895 | if (newlinesize > linesize) { |
1896 | + uintptr_t thisline_addr = (uintptr_t)thisline; /* Save thisline address to make GCC happy ! */ |
1897 | char *newline; |
1898 | |
1899 | newline = realloc(thisline, newlinesize * sizeof(*thisline)); |
1900 | @@ -2087,20 +2115,20 @@ next_line: |
1901 | goto next_line; /* slip current line */ |
1902 | } |
1903 | /* recompute pointers if realloc returns a new pointer */ |
1904 | - if (newline != thisline) { |
1905 | + if (newline != (char *)thisline_addr) { |
1906 | int i; |
1907 | int diff; |
1908 | |
1909 | for (i = 0; i <= arg; i++) { |
1910 | - diff = args[i] - thisline; |
1911 | + diff = args[i] - (char *)thisline_addr; |
1912 | args[i] = newline + diff; |
1913 | } |
1914 | |
1915 | - diff = var_end - thisline; |
1916 | + diff = var_end - (char *)thisline_addr; |
1917 | var_end = newline + diff; |
1918 | - diff = end - thisline; |
1919 | + diff = end - (char *)thisline_addr; |
1920 | end = newline + diff; |
1921 | - diff = line - thisline; |
1922 | + diff = line - (char *)thisline_addr; |
1923 | line = newline + diff; |
1924 | thisline = newline; |
1925 | } |
1926 | diff --git a/src/dns.c b/src/dns.c |
1927 | index 694f840..de9892b 100644 |
1928 | --- a/src/dns.c |
1929 | +++ b/src/dns.c |
1930 | @@ -175,11 +175,11 @@ static void dns_update_resolvers_timeout(struct dns_resolvers *resolvers) |
1931 | next = tick_add(now_ms, resolvers->timeout.resolve); |
1932 | if (!LIST_ISEMPTY(&resolvers->resolutions.curr)) { |
1933 | res = LIST_NEXT(&resolvers->resolutions.curr, struct dns_resolution *, list); |
1934 | - next = MIN(next, tick_add(res->last_query, resolvers->timeout.retry)); |
1935 | + next = tick_first(next, tick_add(res->last_query, resolvers->timeout.retry)); |
1936 | } |
1937 | |
1938 | list_for_each_entry(res, &resolvers->resolutions.wait, list) |
1939 | - next = MIN(next, tick_add(res->last_resolution, dns_resolution_timeout(res))); |
1940 | + next = tick_first(next, tick_add(res->last_resolution, dns_resolution_timeout(res))); |
1941 | |
1942 | resolvers->t->expire = next; |
1943 | task_queue(resolvers->t); |
1944 | @@ -1990,7 +1990,7 @@ static void dns_deinit(void) |
1945 | |
1946 | /* Finalizes the DNS configuration by allocating required resources and checking |
1947 | * live parameters. |
1948 | - * Returns 0 on success, ERR_* flags otherwise. |
1949 | + * Returns 0 on success, 1 on error. |
1950 | */ |
1951 | static int dns_finalize_config(void) |
1952 | { |
1953 | @@ -2058,6 +2058,13 @@ static int dns_finalize_config(void) |
1954 | for (px = proxies_list; px; px = px->next) { |
1955 | struct server *srv; |
1956 | |
1957 | + if (px->state == PR_STSTOPPED) { |
1958 | + /* must not run and will not work anyway since |
1959 | + * nothing in the proxy is initialized. |
1960 | + */ |
1961 | + continue; |
1962 | + } |
1963 | + |
1964 | for (srv = px->srv; srv; srv = srv->next) { |
1965 | struct dns_resolvers *resolvers; |
1966 | |
1967 | @@ -2093,10 +2100,10 @@ static int dns_finalize_config(void) |
1968 | if (err_code & (ERR_ALERT|ERR_ABORT)) |
1969 | goto err; |
1970 | |
1971 | - return err_code; |
1972 | + return 0; |
1973 | err: |
1974 | dns_deinit(); |
1975 | - return err_code; |
1976 | + return 1; |
1977 | |
1978 | } |
1979 | |
1980 | @@ -2262,7 +2269,12 @@ enum act_return dns_action_do_resolve(struct act_rule *rule, struct proxy *px, |
1981 | if (resolution->step == RSLV_STEP_RUNNING) |
1982 | goto yield; |
1983 | if (resolution->step == RSLV_STEP_NONE) { |
1984 | - /* We update the variable only if we have a valid response. */ |
1985 | + /* We update the variable only if we have a valid |
1986 | + * response. If the response was not received yet, we |
1987 | + * must yield. |
1988 | + */ |
1989 | + if (resolution->status == RSLV_STATUS_NONE) |
1990 | + goto yield; |
1991 | if (resolution->status == RSLV_STATUS_VALID) { |
1992 | struct sample smp; |
1993 | short ip_sin_family = 0; |
1994 | diff --git a/src/ev_epoll.c b/src/ev_epoll.c |
1995 | index 6c09c04..d836306 100644 |
1996 | --- a/src/ev_epoll.c |
1997 | +++ b/src/ev_epoll.c |
1998 | @@ -146,7 +146,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
1999 | |
2000 | thread_harmless_now(); |
2001 | |
2002 | - /* now let's wait for polled events */ |
2003 | + /* Now let's wait for polled events. */ |
2004 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
2005 | tv_entering_poll(); |
2006 | activity_count_runtime(); |
2007 | @@ -160,7 +160,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
2008 | break; |
2009 | if (timeout || !wait_time) |
2010 | break; |
2011 | - if (signal_queue_len || wake) |
2012 | + if (wake) |
2013 | break; |
2014 | if (tick_isset(exp) && tick_is_expired(exp, now_ms)) |
2015 | break; |
2016 | diff --git a/src/ev_evports.c b/src/ev_evports.c |
2017 | index eae72d0..2442579 100644 |
2018 | --- a/src/ev_evports.c |
2019 | +++ b/src/ev_evports.c |
2020 | @@ -141,9 +141,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
2021 | |
2022 | thread_harmless_now(); |
2023 | |
2024 | - /* |
2025 | - * Determine how long to wait for events to materialise on the port. |
2026 | - */ |
2027 | + /* Now let's wait for polled events. */ |
2028 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
2029 | tv_entering_poll(); |
2030 | activity_count_runtime(); |
2031 | @@ -183,7 +181,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
2032 | break; |
2033 | if (timeout || !wait_time) |
2034 | break; |
2035 | - if (signal_queue_len || wake) |
2036 | + if (wake) |
2037 | break; |
2038 | if (tick_isset(exp) && tick_is_expired(exp, now_ms)) |
2039 | break; |
2040 | diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c |
2041 | index 56e7147..47f4647 100644 |
2042 | --- a/src/ev_kqueue.c |
2043 | +++ b/src/ev_kqueue.c |
2044 | @@ -131,7 +131,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
2045 | } |
2046 | fd_nbupdt = 0; |
2047 | |
2048 | - /* now let's wait for events */ |
2049 | + /* Now let's wait for polled events. */ |
2050 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
2051 | fd = global.tune.maxpollevents; |
2052 | tv_entering_poll(); |
2053 | @@ -155,7 +155,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
2054 | break; |
2055 | if (timeout || !wait_time) |
2056 | break; |
2057 | - if (signal_queue_len || wake) |
2058 | + if (wake) |
2059 | break; |
2060 | if (tick_isset(exp) && tick_is_expired(exp, now_ms)) |
2061 | break; |
2062 | diff --git a/src/ev_poll.c b/src/ev_poll.c |
2063 | index 86bf8e8..39e5fd9 100644 |
2064 | --- a/src/ev_poll.c |
2065 | +++ b/src/ev_poll.c |
2066 | @@ -24,6 +24,7 @@ |
2067 | #include <common/time.h> |
2068 | |
2069 | #include <types/global.h> |
2070 | +#include <types/signal.h> |
2071 | |
2072 | #include <proto/activity.h> |
2073 | #include <proto/fd.h> |
2074 | @@ -193,7 +194,7 @@ REGPRM3 static void _do_poll(struct poller *p, int exp, int wake) |
2075 | } |
2076 | } |
2077 | |
2078 | - /* now let's wait for events */ |
2079 | + /* Now let's wait for polled events. */ |
2080 | wait_time = wake ? 0 : compute_poll_timeout(exp); |
2081 | tv_entering_poll(); |
2082 | activity_count_runtime(); |
2083 | diff --git a/src/flt_spoe.c b/src/flt_spoe.c |
2084 | index 16b5d6f..128461b 100644 |
2085 | --- a/src/flt_spoe.c |
2086 | +++ b/src/flt_spoe.c |
2087 | @@ -1290,7 +1290,7 @@ spoe_release_appctx(struct appctx *appctx) |
2088 | /* Destroy the task attached to this applet */ |
2089 | task_destroy(spoe_appctx->task); |
2090 | |
2091 | - /* Notify all waiting streams */ |
2092 | + /* Report an error to all streams in the appctx waiting queue */ |
2093 | list_for_each_entry_safe(ctx, back, &spoe_appctx->waiting_queue, list) { |
2094 | LIST_DEL(&ctx->list); |
2095 | LIST_INIT(&ctx->list); |
2096 | @@ -1302,8 +1302,8 @@ spoe_release_appctx(struct appctx *appctx) |
2097 | task_wakeup(ctx->strm->task, TASK_WOKEN_MSG); |
2098 | } |
2099 | |
2100 | - /* If the applet was processing a fragmented frame, notify the |
2101 | - * corresponding stream. */ |
2102 | + /* If the applet was processing a fragmented frame, report an error to |
2103 | + * the corresponding stream. */ |
2104 | if (spoe_appctx->frag_ctx.ctx) { |
2105 | ctx = spoe_appctx->frag_ctx.ctx; |
2106 | ctx->spoe_appctx = NULL; |
2107 | @@ -1312,7 +1312,11 @@ spoe_release_appctx(struct appctx *appctx) |
2108 | task_wakeup(ctx->strm->task, TASK_WOKEN_MSG); |
2109 | } |
2110 | |
2111 | - if (!LIST_ISEMPTY(&agent->rt[tid].waiting_queue)) { |
2112 | + if (!LIST_ISEMPTY(&agent->rt[tid].applets)) { |
2113 | + /* If there are still some running applets, remove reference on |
2114 | + * the current one from streams in the async waiting queue. In |
2115 | + * async mode, the ACK may be received from another appctx. |
2116 | + */ |
2117 | list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) { |
2118 | if (ctx->spoe_appctx == spoe_appctx) |
2119 | ctx->spoe_appctx = NULL; |
2120 | @@ -1320,16 +1324,25 @@ spoe_release_appctx(struct appctx *appctx) |
2121 | goto end; |
2122 | } |
2123 | else { |
2124 | - /* It is the last running applet and the sending and waiting |
2125 | - * queues are not empty. Try to start a new one if HAproxy is |
2126 | - * not stopping. |
2127 | + /* It is the last running applet and the sending and async |
2128 | + * waiting queues are not empty. So try to start a new applet if |
2129 | + * HAproxy is not stopping. On success, we remove reference on |
2130 | + * the current appctx from streams in the async waiting queue. |
2131 | + * In async mode, the ACK may be received from another appctx. |
2132 | */ |
2133 | if (!stopping && |
2134 | (!LIST_ISEMPTY(&agent->rt[tid].sending_queue) || !LIST_ISEMPTY(&agent->rt[tid].waiting_queue)) && |
2135 | - spoe_create_appctx(agent->spoe_conf)) |
2136 | + spoe_create_appctx(agent->spoe_conf)) { |
2137 | + list_for_each_entry_safe(ctx, back, &agent->rt[tid].waiting_queue, list) { |
2138 | + if (ctx->spoe_appctx == spoe_appctx) |
2139 | + ctx->spoe_appctx = NULL; |
2140 | + } |
2141 | goto end; |
2142 | + } |
2143 | |
2144 | - /* otherwise, notify all waiting streams */ |
2145 | + /* Otherwise, report an error to all streams in the sending and |
2146 | + * async waiting queues. |
2147 | + */ |
2148 | list_for_each_entry_safe(ctx, back, &agent->rt[tid].sending_queue, list) { |
2149 | LIST_DEL(&ctx->list); |
2150 | LIST_INIT(&ctx->list); |
2151 | diff --git a/src/h1.c b/src/h1.c |
2152 | index 3839fbe..69a7ced 100644 |
2153 | --- a/src/h1.c |
2154 | +++ b/src/h1.c |
2155 | @@ -672,6 +672,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop, |
2156 | |
2157 | if (likely(*ptr == ':')) { |
2158 | col = ptr - start; |
2159 | + if (col <= sol) { |
2160 | + state = H1_MSG_HDR_NAME; |
2161 | + goto http_msg_invalid; |
2162 | + } |
2163 | EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, H1_MSG_HDR_L1_SP); |
2164 | } |
2165 | |
2166 | diff --git a/src/haproxy.c b/src/haproxy.c |
2167 | index aa37504..f6166d4 100644 |
2168 | --- a/src/haproxy.c |
2169 | +++ b/src/haproxy.c |
2170 | @@ -1,6 +1,6 @@ |
2171 | /* |
2172 | * HA-Proxy : High Availability-enabled HTTP/TCP proxy |
2173 | - * Copyright 2000-2022 Willy Tarreau <willy@haproxy.org>. |
2174 | + * Copyright 2000-2023 Willy Tarreau <willy@haproxy.org>. |
2175 | * |
2176 | * This program is free software; you can redistribute it and/or |
2177 | * modify it under the terms of the GNU General Public License |
2178 | @@ -242,6 +242,7 @@ struct mworker_proc *proc_self = NULL; |
2179 | /* list of the temporarily limited listeners because of lack of resource */ |
2180 | struct list global_listener_queue = LIST_HEAD_INIT(global_listener_queue); |
2181 | struct task *global_listener_queue_task; |
2182 | +__decl_hathreads(HA_RWLOCK_T global_listener_rwlock); |
2183 | static struct task *manage_global_listener_queue(struct task *t, void *context, unsigned short state); |
2184 | |
2185 | static void *run_thread_poll_loop(void *data); |
2186 | @@ -2071,6 +2072,7 @@ static void init(int argc, char **argv) |
2187 | /* very simple initialization, users will queue the task if needed */ |
2188 | global_listener_queue_task->context = NULL; /* not even a context! */ |
2189 | global_listener_queue_task->process = manage_global_listener_queue; |
2190 | + HA_RWLOCK_INIT(&global_listener_rwlock); |
2191 | |
2192 | /* now we know the buffer size, we can initialize the channels and buffers */ |
2193 | init_buffer(); |
2194 | @@ -2778,7 +2780,7 @@ static void run_poll_loop() |
2195 | if (killed > 1) |
2196 | break; |
2197 | |
2198 | - /* expire immediately if events are pending */ |
2199 | + /* expire immediately if events or signals are pending */ |
2200 | wake = 1; |
2201 | if (fd_cache_mask & tid_bit) |
2202 | activity[tid].wake_cache++; |
2203 | @@ -2792,6 +2794,10 @@ static void run_poll_loop() |
2204 | if (global_tasks_mask & tid_bit) { |
2205 | activity[tid].wake_tasks++; |
2206 | _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit); |
2207 | + } else if (signal_queue_len) { |
2208 | + /* this check is required to avoid |
2209 | + * a race with wakeup on signals using wake_threads() */ |
2210 | + _HA_ATOMIC_AND(&sleeping_thread_mask, ~tid_bit); |
2211 | } else |
2212 | wake = 0; |
2213 | } |
2214 | @@ -2946,7 +2952,9 @@ static struct task *manage_global_listener_queue(struct task *t, void *context, |
2215 | dequeue_all_listeners(&global_listener_queue); |
2216 | |
2217 | out: |
2218 | + HA_RWLOCK_WRLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2219 | t->expire = next; |
2220 | + HA_RWLOCK_WRUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2221 | task_queue(t); |
2222 | return t; |
2223 | } |
2224 | diff --git a/src/hlua.c b/src/hlua.c |
2225 | index 888890f..bd8a679 100644 |
2226 | --- a/src/hlua.c |
2227 | +++ b/src/hlua.c |
2228 | @@ -649,7 +649,9 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp, |
2229 | break; |
2230 | |
2231 | case ARGT_TAB: |
2232 | - argp[idx].data.prx = p; |
2233 | + if (!p->table) |
2234 | + WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected")); |
2235 | + argp[idx].data.t = p->table; |
2236 | argp[idx].type = ARGT_TAB; |
2237 | argp[idx+1].type = ARGT_STOP; |
2238 | break; |
2239 | diff --git a/src/hlua_fcn.c b/src/hlua_fcn.c |
2240 | index 955a1ce..c42a60a 100644 |
2241 | --- a/src/hlua_fcn.c |
2242 | +++ b/src/hlua_fcn.c |
2243 | @@ -1298,6 +1298,7 @@ int hlua_proxy_pause(lua_State *L) |
2244 | struct proxy *px; |
2245 | |
2246 | px = hlua_check_proxy(L, 1); |
2247 | + /* safe to call without PROXY_LOCK - pause_proxy takes it */ |
2248 | pause_proxy(px); |
2249 | return 0; |
2250 | } |
2251 | @@ -1307,6 +1308,7 @@ int hlua_proxy_resume(lua_State *L) |
2252 | struct proxy *px; |
2253 | |
2254 | px = hlua_check_proxy(L, 1); |
2255 | + /* safe to call without PROXY_LOCK - resume_proxy takes it */ |
2256 | resume_proxy(px); |
2257 | return 0; |
2258 | } |
2259 | @@ -1316,6 +1318,7 @@ int hlua_proxy_stop(lua_State *L) |
2260 | struct proxy *px; |
2261 | |
2262 | px = hlua_check_proxy(L, 1); |
2263 | + /* safe to call without PROXY_LOCK - stop_proxy takes it */ |
2264 | stop_proxy(px); |
2265 | return 0; |
2266 | } |
2267 | diff --git a/src/hpack-dec.c b/src/hpack-dec.c |
2268 | index 7f3e762..0fc71eb 100644 |
2269 | --- a/src/hpack-dec.c |
2270 | +++ b/src/hpack-dec.c |
2271 | @@ -425,6 +425,15 @@ int hpack_decode_frame(struct hpack_dht *dht, const uint8_t *raw, uint32_t len, |
2272 | /* <name> and <value> are correctly filled here */ |
2273 | } |
2274 | |
2275 | + /* We must not accept empty header names (forbidden by the spec and used |
2276 | + * as a list termination). |
2277 | + */ |
2278 | + if (!name.len) { |
2279 | + hpack_debug_printf("##ERR@%d##\n", __LINE__); |
2280 | + ret = -HPACK_ERR_INVALID_ARGUMENT; |
2281 | + goto leave; |
2282 | + } |
2283 | + |
2284 | /* here's what we have here : |
2285 | * - name.len > 0 |
2286 | * - value is filled with either const data or data allocated from tmp |
2287 | diff --git a/src/http_fetch.c b/src/http_fetch.c |
2288 | index d40bc1d..ea87a52 100644 |
2289 | --- a/src/http_fetch.c |
2290 | +++ b/src/http_fetch.c |
2291 | @@ -244,7 +244,7 @@ struct htx *smp_prefetch_htx(struct sample *smp, struct channel *chn, int vol) |
2292 | if (IS_HTX_STRM(s)) { |
2293 | htx = htxbuf(&chn->buf); |
2294 | |
2295 | - if (msg->msg_state == HTTP_MSG_ERROR || (htx->flags & HTX_FL_PARSING_ERROR)) |
2296 | + if (htx->flags & HTX_FL_PARSING_ERROR) |
2297 | return NULL; |
2298 | |
2299 | if (msg->msg_state < HTTP_MSG_BODY) { |
2300 | @@ -460,6 +460,7 @@ static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char |
2301 | struct channel *chn = SMP_REQ_CHN(smp); |
2302 | int meth; |
2303 | struct http_txn *txn; |
2304 | + struct htx *htx = NULL; |
2305 | |
2306 | if (smp->px->options2 & PR_O2_USE_HTX) { |
2307 | /* HTX version */ |
2308 | @@ -468,15 +469,17 @@ static int smp_fetch_meth(const struct arg *args, struct sample *smp, const char |
2309 | return 0; |
2310 | |
2311 | meth = txn->meth; |
2312 | - smp->data.type = SMP_T_METH; |
2313 | - smp->data.u.meth.meth = meth; |
2314 | if (meth == HTTP_METH_OTHER) { |
2315 | - struct htx *htx; |
2316 | - struct htx_sl *sl; |
2317 | - |
2318 | htx = smp_prefetch_htx(smp, chn, 1); |
2319 | if (!htx) |
2320 | return 0; |
2321 | + meth = txn->meth; |
2322 | + } |
2323 | + |
2324 | + smp->data.type = SMP_T_METH; |
2325 | + smp->data.u.meth.meth = meth; |
2326 | + if (meth == HTTP_METH_OTHER) { |
2327 | + struct htx_sl *sl; |
2328 | |
2329 | if ((smp->opt & SMP_OPT_DIR) == SMP_OPT_DIR_RES) { |
2330 | /* ensure the indexes are not affected */ |
2331 | diff --git a/src/http_msg.c b/src/http_msg.c |
2332 | index 067a7f8..e07c81c 100644 |
2333 | --- a/src/http_msg.c |
2334 | +++ b/src/http_msg.c |
2335 | @@ -1006,8 +1006,14 @@ void http_msg_analyzer(struct http_msg *msg, struct hdr_idx *idx) |
2336 | if (likely(HTTP_IS_TOKEN(*ptr))) |
2337 | EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_name, http_msg_ood, state, HTTP_MSG_HDR_NAME); |
2338 | |
2339 | - if (likely(*ptr == ':')) |
2340 | + if (likely(*ptr == ':')) { |
2341 | + if (ptr == input + msg->sol) { |
2342 | + /* empty header names are not permitted */ |
2343 | + state = HTTP_MSG_HDR_NAME; |
2344 | + goto http_msg_invalid; |
2345 | + } |
2346 | EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_hdr_l1_sp, http_msg_ood, state, HTTP_MSG_HDR_L1_SP); |
2347 | + } |
2348 | |
2349 | if (likely(msg->err_pos < -1) || *ptr == '\n') { |
2350 | state = HTTP_MSG_HDR_NAME; |
2351 | diff --git a/src/listener.c b/src/listener.c |
2352 | index 2141017..0ba2ee1 100644 |
2353 | --- a/src/listener.c |
2354 | +++ b/src/listener.c |
2355 | @@ -766,7 +766,9 @@ void listener_accept(int fd) |
2356 | */ |
2357 | next_actconn = 0; |
2358 | limit_listener(l, &global_listener_queue); |
2359 | + HA_RWLOCK_RDLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2360 | task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */ |
2361 | + HA_RWLOCK_RDUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2362 | goto end; |
2363 | } |
2364 | next_actconn = count + 1; |
2365 | @@ -870,7 +872,9 @@ void listener_accept(int fd) |
2366 | p->id); |
2367 | close(cfd); |
2368 | limit_listener(l, &global_listener_queue); |
2369 | + HA_RWLOCK_RDLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2370 | task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */ |
2371 | + HA_RWLOCK_RDUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2372 | goto end; |
2373 | } |
2374 | |
2375 | @@ -1038,7 +1042,9 @@ void listener_accept(int fd) |
2376 | wait_expire: |
2377 | /* switch the listener to LI_LIMITED and wait until up to <expire> in the global queue */ |
2378 | limit_listener(l, &global_listener_queue); |
2379 | + HA_RWLOCK_RDLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2380 | task_schedule(global_listener_queue_task, tick_first(expire, global_listener_queue_task->expire)); |
2381 | + HA_RWLOCK_RDUNLOCK(LISTENER_LOCK, &global_listener_rwlock); |
2382 | end: |
2383 | if (next_conn) |
2384 | _HA_ATOMIC_SUB(&l->nbconn, 1); |
2385 | diff --git a/src/log.c b/src/log.c |
2386 | index e1c47ff..a63ba61 100644 |
2387 | --- a/src/log.c |
2388 | +++ b/src/log.c |
2389 | @@ -1262,17 +1262,21 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str |
2390 | } |
2391 | |
2392 | if (src && len) { |
2393 | - if (++len > size) |
2394 | - len = size; |
2395 | + /* escape_string and strlcpy2 will both try to add terminating NULL-byte |
2396 | + * to dst, so we need to make sure that extra byte will fit into dst |
2397 | + * before calling them |
2398 | + */ |
2399 | if (node->options & LOG_OPT_ESC) { |
2400 | char *ret; |
2401 | |
2402 | - ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src); |
2403 | + ret = escape_string(dst, (dst + size - 1), '\\', rfc5424_escape_map, src, src + len); |
2404 | if (ret == NULL || *ret != '\0') |
2405 | return NULL; |
2406 | len = ret - dst; |
2407 | } |
2408 | else { |
2409 | + if (++len > size) |
2410 | + len = size; |
2411 | len = strlcpy2(dst, src, len); |
2412 | } |
2413 | |
2414 | @@ -1283,6 +1287,7 @@ char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const str |
2415 | if (size < 2) |
2416 | return NULL; |
2417 | *(dst++) = '-'; |
2418 | + size -= 1; |
2419 | } |
2420 | |
2421 | if (node->options & LOG_OPT_QUOTE) { |
2422 | diff --git a/src/memory.c b/src/memory.c |
2423 | index 242264c..bf19df3 100644 |
2424 | --- a/src/memory.c |
2425 | +++ b/src/memory.c |
2426 | @@ -531,24 +531,24 @@ int pool_total_failures() |
2427 | } |
2428 | |
2429 | /* This function returns the total amount of memory allocated in pools (in bytes) */ |
2430 | -unsigned long pool_total_allocated() |
2431 | +unsigned long long pool_total_allocated() |
2432 | { |
2433 | struct pool_head *entry; |
2434 | - unsigned long allocated = 0; |
2435 | + unsigned long long allocated = 0; |
2436 | |
2437 | list_for_each_entry(entry, &pools, list) |
2438 | - allocated += entry->allocated * entry->size; |
2439 | + allocated += entry->allocated * (unsigned long long)entry->size; |
2440 | return allocated; |
2441 | } |
2442 | |
2443 | /* This function returns the total amount of memory used in pools (in bytes) */ |
2444 | -unsigned long pool_total_used() |
2445 | +unsigned long long pool_total_used() |
2446 | { |
2447 | struct pool_head *entry; |
2448 | - unsigned long used = 0; |
2449 | + unsigned long long used = 0; |
2450 | |
2451 | list_for_each_entry(entry, &pools, list) |
2452 | - used += entry->used * entry->size; |
2453 | + used += entry->used * (unsigned long long)entry->size; |
2454 | return used; |
2455 | } |
2456 | |
2457 | diff --git a/src/mux_h1.c b/src/mux_h1.c |
2458 | index 560632a..4c91672 100644 |
2459 | --- a/src/mux_h1.c |
2460 | +++ b/src/mux_h1.c |
2461 | @@ -623,7 +623,7 @@ static int h1_process_req_vsn(struct h1s *h1s, struct h1m *h1m, union h1_sl sl) |
2462 | if (sl.rq.v.len != 8) |
2463 | return 0; |
2464 | |
2465 | - if (*(sl.rq.v.ptr + 4) != '/' || |
2466 | + if (!istnmatch(sl.rq.v, ist("HTTP/"), 5) || |
2467 | !isdigit((unsigned char)*(sl.rq.v.ptr + 5)) || |
2468 | *(sl.rq.v.ptr + 6) != '.' || |
2469 | !isdigit((unsigned char)*(sl.rq.v.ptr + 7))) |
2470 | diff --git a/src/mux_h2.c b/src/mux_h2.c |
2471 | index 09f8fa5..3141b36 100644 |
2472 | --- a/src/mux_h2.c |
2473 | +++ b/src/mux_h2.c |
2474 | @@ -60,6 +60,7 @@ static const struct h2s *h2_idle_stream; |
2475 | // (SHORT_READ is also excluded) |
2476 | |
2477 | #define H2_CF_DEM_SHORT_READ 0x00000200 // demux blocked on incomplete frame |
2478 | +#define H2_CF_DEM_IN_PROGRESS 0x00000400 // demux in progress (dsi,dfl,dft are valid) |
2479 | |
2480 | /* other flags */ |
2481 | #define H2_CF_GOAWAY_SENT 0x00001000 // a GOAWAY frame was successfully sent |
2482 | @@ -310,7 +311,6 @@ static struct task *h2_deferred_shut(struct task *t, void *ctx, unsigned short s |
2483 | static struct h2s *h2c_bck_stream_new(struct h2c *h2c, struct conn_stream *cs, struct session *sess); |
2484 | static void h2s_alert(struct h2s *h2s); |
2485 | |
2486 | - |
2487 | /* Detect a pending read0 for a H2 connection. It happens if a read0 was |
2488 | * already reported on a previous xprt->rcvbuf() AND a frame parser failed |
2489 | * to parse pending data, confirming no more progress is possible because |
2490 | @@ -2546,6 +2546,7 @@ static void h2_process_demux(struct h2c *h2c) |
2491 | h2c->dft = hdr.ft; |
2492 | h2c->dff = hdr.ff; |
2493 | h2c->dpl = padlen; |
2494 | + h2c->flags |= H2_CF_DEM_IN_PROGRESS; |
2495 | h2c->st0 = H2_CS_FRAME_P; |
2496 | |
2497 | /* check for minimum basic frame format validity */ |
2498 | @@ -2821,8 +2822,10 @@ static void h2_process_demux(struct h2c *h2c) |
2499 | ret = MIN(b_data(&h2c->dbuf), h2c->dfl); |
2500 | b_del(&h2c->dbuf, ret); |
2501 | h2c->dfl -= ret; |
2502 | - if (!h2c->dfl) |
2503 | + if (!h2c->dfl) { |
2504 | + h2c->flags &= ~H2_CF_DEM_IN_PROGRESS; |
2505 | h2c->st0 = H2_CS_FRAME_H; |
2506 | + } |
2507 | } |
2508 | } |
2509 | |
2510 | @@ -3935,6 +3938,10 @@ next_frame: |
2511 | *flags |= H2_SF_HEADERS_RCVD; |
2512 | |
2513 | if ((h2c->dff & H2_F_HEADERS_END_STREAM)) { |
2514 | + if (msgf & H2_MSGF_RSP_1XX) { |
2515 | + /* RFC9113#8.1 : HEADERS frame with the ES flag set that carries an informational status code is malformed */ |
2516 | + goto fail; |
2517 | + } |
2518 | /* Mark the end of message, either using EOM in HTX or with the |
2519 | * trailing CRLF after the end of trailers. Note that DATA_CHNK |
2520 | * is not set during headers with END_STREAM. For HTX trailers, |
2521 | diff --git a/src/mworker.c b/src/mworker.c |
2522 | index 5ff1ef9..487d071 100644 |
2523 | --- a/src/mworker.c |
2524 | +++ b/src/mworker.c |
2525 | @@ -417,8 +417,10 @@ void mworker_cleanlisteners() |
2526 | |
2527 | stop_proxy(curpeers->peers_fe); |
2528 | /* disable this peer section so that it kills itself */ |
2529 | - signal_unregister_handler(curpeers->sighandler); |
2530 | - task_destroy(curpeers->sync_task); |
2531 | + if (curpeers->sighandler) |
2532 | + signal_unregister_handler(curpeers->sighandler); |
2533 | + if (curpeers->sync_task) |
2534 | + task_destroy(curpeers->sync_task); |
2535 | curpeers->sync_task = NULL; |
2536 | task_destroy(curpeers->peers_fe->task); |
2537 | curpeers->peers_fe->task = NULL; |
2538 | diff --git a/src/peers.c b/src/peers.c |
2539 | index ec8de36..a206d9f 100644 |
2540 | --- a/src/peers.c |
2541 | +++ b/src/peers.c |
2542 | @@ -105,6 +105,7 @@ |
2543 | |
2544 | #define PEER_RESYNC_TIMEOUT 5000 /* 5 seconds */ |
2545 | #define PEER_RECONNECT_TIMEOUT 5000 /* 5 seconds */ |
2546 | +#define PEER_LOCAL_RECONNECT_TIMEOUT 500 /* 500ms */ |
2547 | #define PEER_HEARTBEAT_TIMEOUT 3000 /* 3 seconds */ |
2548 | |
2549 | /*****************************/ |
2550 | @@ -1369,7 +1370,6 @@ static inline int peer_send_teach_stage2_msgs(struct appctx *appctx, struct peer |
2551 | static int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, int exp, |
2552 | char **msg_cur, char *msg_end, int msg_len, int totl) |
2553 | { |
2554 | - struct stream_interface *si = appctx->owner; |
2555 | struct shared_table *st = p->remote_table; |
2556 | struct stksess *ts, *newts; |
2557 | uint32_t update; |
2558 | @@ -1565,12 +1565,9 @@ static int peer_treat_updatemsg(struct appctx *appctx, struct peer *p, int updt, |
2559 | |
2560 | HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); |
2561 | stktable_touch_remote(st->table, ts, 1); |
2562 | - return 1; |
2563 | |
2564 | ignore_msg: |
2565 | - /* skip consumed message */ |
2566 | - co_skip(si_oc(si), totl); |
2567 | - return 0; |
2568 | + return 1; |
2569 | |
2570 | malformed_unlock: |
2571 | /* malformed message */ |
2572 | @@ -1671,7 +1668,6 @@ static inline int peer_treat_switchmsg(struct appctx *appctx, struct peer *p, |
2573 | static inline int peer_treat_definemsg(struct appctx *appctx, struct peer *p, |
2574 | char **msg_cur, char *msg_end, int totl) |
2575 | { |
2576 | - struct stream_interface *si = appctx->owner; |
2577 | int table_id_len; |
2578 | struct shared_table *st; |
2579 | int table_type; |
2580 | @@ -1728,11 +1724,9 @@ static inline int peer_treat_definemsg(struct appctx *appctx, struct peer *p, |
2581 | |
2582 | p->remote_table->remote_data = table_data; |
2583 | p->remote_table->remote_id = table_id; |
2584 | - return 1; |
2585 | |
2586 | ignore_msg: |
2587 | - co_skip(si_oc(si), totl); |
2588 | - return 0; |
2589 | + return 1; |
2590 | |
2591 | malformed_exit: |
2592 | /* malformed message */ |
2593 | @@ -2413,7 +2407,7 @@ switchstate: |
2594 | } |
2595 | } |
2596 | |
2597 | - if (si_ic(si)->flags & CF_WRITE_PARTIAL) |
2598 | + if (si_ic(si)->flags & CF_WROTE_DATA) |
2599 | curpeer->statuscode = PEER_SESS_SC_CONNECTEDCODE; |
2600 | |
2601 | reql = peer_getline(appctx); |
2602 | @@ -2593,7 +2587,9 @@ void peers_setup_frontend(struct proxy *fe) |
2603 | fe->cap = PR_CAP_FE | PR_CAP_BE; |
2604 | fe->maxconn = 0; |
2605 | fe->conn_retries = CONN_RETRIES; |
2606 | + fe->timeout.connect = MS_TO_TICKS(1000); |
2607 | fe->timeout.client = MS_TO_TICKS(5000); |
2608 | + fe->timeout.server = MS_TO_TICKS(5000); |
2609 | fe->accept = frontend_accept; |
2610 | fe->default_target = &peer_applet.obj_type; |
2611 | fe->options2 |= PR_O2_INDEPSTR | PR_O2_SMARTCON | PR_O2_SMARTACC; |
2612 | @@ -2613,7 +2609,7 @@ static struct appctx *peer_session_create(struct peers *peers, struct peer *peer |
2613 | struct conn_stream *cs; |
2614 | |
2615 | peer->new_conn++; |
2616 | - peer->reconnect = tick_add(now_ms, MS_TO_TICKS(PEER_RECONNECT_TIMEOUT)); |
2617 | + peer->reconnect = tick_add(now_ms, (stopping ? MS_TO_TICKS(PEER_LOCAL_RECONNECT_TIMEOUT) : MS_TO_TICKS(PEER_RECONNECT_TIMEOUT))); |
2618 | peer->heartbeat = TICK_ETERNITY; |
2619 | peer->statuscode = PEER_SESS_SC_CONNECTCODE; |
2620 | s = NULL; |
2621 | @@ -2888,6 +2884,10 @@ static struct task *process_peer_sync(struct task * task, void *context, unsigne |
2622 | peer_session_forceshutdown(ps); |
2623 | } |
2624 | } |
2625 | + |
2626 | + /* Set resync timeout for the local peer and request a immediate reconnect */ |
2627 | + peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(PEER_RESYNC_TIMEOUT)); |
2628 | + peers->local->reconnect = now_ms; |
2629 | } |
2630 | } |
2631 | |
2632 | @@ -2902,19 +2902,33 @@ static struct task *process_peer_sync(struct task * task, void *context, unsigne |
2633 | } |
2634 | } |
2635 | else if (!ps->appctx) { |
2636 | + /* Re-arm resync timeout if necessary */ |
2637 | + if (!tick_isset(peers->resync_timeout)) |
2638 | + peers->resync_timeout = tick_add(now_ms, MS_TO_TICKS(PEER_RESYNC_TIMEOUT)); |
2639 | + |
2640 | /* If there's no active peer connection */ |
2641 | - if (ps->statuscode == 0 || |
2642 | - ps->statuscode == PEER_SESS_SC_SUCCESSCODE || |
2643 | - ps->statuscode == PEER_SESS_SC_CONNECTEDCODE || |
2644 | - ps->statuscode == PEER_SESS_SC_TRYAGAIN) { |
2645 | - /* connection never tried |
2646 | - * or previous peer connection was successfully established |
2647 | - * or previous tcp connect succeeded but init state incomplete |
2648 | - * or during previous connect, peer replies a try again statuscode */ |
2649 | - |
2650 | - /* connect to the local peer if we must push a local sync */ |
2651 | - if (peers->flags & PEERS_F_DONOTSTOP) { |
2652 | - peer_session_create(peers, ps); |
2653 | + if ((peers->flags & PEERS_RESYNC_STATEMASK) == PEERS_RESYNC_FINISHED && |
2654 | + !tick_is_expired(peers->resync_timeout, now_ms) && |
2655 | + (ps->statuscode == 0 || |
2656 | + ps->statuscode == PEER_SESS_SC_SUCCESSCODE || |
2657 | + ps->statuscode == PEER_SESS_SC_CONNECTEDCODE || |
2658 | + ps->statuscode == PEER_SESS_SC_TRYAGAIN)) { |
2659 | + /* The resync is finished for the local peer and |
2660 | + * the resync timeout is not expired and |
2661 | + * connection never tried |
2662 | + * or previous peer connection was successfully established |
2663 | + * or previous tcp connect succeeded but init state incomplete |
2664 | + * or during previous connect, peer replies a try again statuscode */ |
2665 | + |
2666 | + if (!tick_is_expired(ps->reconnect, now_ms)) { |
2667 | + /* reconnection timer is not expired. reschedule task for reconnect */ |
2668 | + task->expire = tick_first(task->expire, ps->reconnect); |
2669 | + } |
2670 | + else { |
2671 | + /* connect to the local peer if we must push a local sync */ |
2672 | + if (peers->flags & PEERS_F_DONOTSTOP) { |
2673 | + peer_session_create(peers, ps); |
2674 | + } |
2675 | } |
2676 | } |
2677 | else { |
2678 | @@ -2929,6 +2943,9 @@ static struct task *process_peer_sync(struct task * task, void *context, unsigne |
2679 | } |
2680 | } |
2681 | else if (ps->statuscode == PEER_SESS_SC_SUCCESSCODE ) { |
2682 | + /* Reset resync timeout during a resync */ |
2683 | + peers->resync_timeout = TICK_ETERNITY; |
2684 | + |
2685 | /* current peer connection is active and established |
2686 | * wake up all peer handlers to push remaining local updates */ |
2687 | for (st = ps->tables; st ; st = st->next) { |
2688 | diff --git a/src/proto_http.c b/src/proto_http.c |
2689 | index bdc97de..8fb2294 100644 |
2690 | --- a/src/proto_http.c |
2691 | +++ b/src/proto_http.c |
2692 | @@ -7240,6 +7240,7 @@ void http_init_txn(struct stream *s) |
2693 | struct proxy *fe = strm_fe(s); |
2694 | struct conn_stream *cs = objt_cs(s->si[0].end); |
2695 | |
2696 | + txn->meth = HTTP_METH_OTHER; |
2697 | txn->flags = ((cs && cs->flags & CS_FL_NOT_FIRST) |
2698 | ? (TX_NOT_FIRST|TX_WAIT_NEXT_RQ) |
2699 | : 0); |
2700 | @@ -7268,8 +7269,10 @@ void http_init_txn(struct stream *s) |
2701 | if (txn->hdr_idx.v) |
2702 | hdr_idx_init(&txn->hdr_idx); |
2703 | |
2704 | - vars_init(&s->vars_txn, SCOPE_TXN); |
2705 | - vars_init(&s->vars_reqres, SCOPE_REQ); |
2706 | + /* here we don't want to re-initialize s->vars_txn and s->vars_reqres |
2707 | + * variable lists, because they were already initialized upon stream |
2708 | + * creation in stream_new(), and thus may already contain some variables |
2709 | + */ |
2710 | } |
2711 | |
2712 | /* to be used at the end of a transaction */ |
2713 | @@ -7300,6 +7303,9 @@ void http_reset_txn(struct stream *s) |
2714 | http_end_txn(s); |
2715 | http_init_txn(s); |
2716 | |
2717 | + vars_init(&s->vars_txn, SCOPE_TXN); |
2718 | + vars_init(&s->vars_reqres, SCOPE_REQ); |
2719 | + |
2720 | /* reinitialise the current rule list pointer to NULL. We are sure that |
2721 | * any rulelist match the NULL pointer. |
2722 | */ |
2723 | diff --git a/src/proto_htx.c b/src/proto_htx.c |
2724 | index f79d495..51fdd47 100644 |
2725 | --- a/src/proto_htx.c |
2726 | +++ b/src/proto_htx.c |
2727 | @@ -2808,6 +2808,7 @@ void htx_res_set_status(unsigned int status, const char *reason, struct stream * |
2728 | |
2729 | if (http_replace_res_status(htx, ist2(trash.area, trash.data))) |
2730 | http_replace_res_reason(htx, ist2(reason, strlen(reason))); |
2731 | + s->txn->status = status; |
2732 | } |
2733 | |
2734 | /* Executes the http-request rules <rules> for stream <s>, proxy <px> and |
2735 | diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c |
2736 | index 602cb6c..d3aeb4e 100644 |
2737 | --- a/src/proto_sockpair.c |
2738 | +++ b/src/proto_sockpair.c |
2739 | @@ -209,7 +209,7 @@ int send_fd_uxst(int fd, int send_fd) |
2740 | |
2741 | if (sendmsg(fd, &msghdr, 0) != sizeof(iobuf)) { |
2742 | ha_warning("Failed to transfer socket\n"); |
2743 | - return 1; |
2744 | + return -1; |
2745 | } |
2746 | |
2747 | return 0; |
2748 | diff --git a/src/proxy.c b/src/proxy.c |
2749 | index 92db68f..cb5f8e1 100644 |
2750 | --- a/src/proxy.c |
2751 | +++ b/src/proxy.c |
2752 | @@ -112,8 +112,8 @@ const struct cfg_opt cfg_opts2[] = |
2753 | { "http-pretend-keepalive", PR_O2_FAKE_KA, PR_CAP_BE, 0, PR_MODE_HTTP }, |
2754 | { "http-no-delay", PR_O2_NODELAY, PR_CAP_FE|PR_CAP_BE, 0, PR_MODE_HTTP }, |
2755 | { "http-use-htx", PR_O2_USE_HTX, PR_CAP_FE|PR_CAP_BE, 0, 0 }, |
2756 | - {"h1-case-adjust-bogus-client", PR_O2_H1_ADJ_BUGCLI, PR_CAP_FE, 0, PR_MODE_HTTP }, |
2757 | - {"h1-case-adjust-bogus-server", PR_O2_H1_ADJ_BUGSRV, PR_CAP_BE, 0, PR_MODE_HTTP }, |
2758 | + {"h1-case-adjust-bogus-client", PR_O2_H1_ADJ_BUGCLI, PR_CAP_FE, 0, 0 }, |
2759 | + {"h1-case-adjust-bogus-server", PR_O2_H1_ADJ_BUGSRV, PR_CAP_BE, 0, 0 }, |
2760 | {"disable-h2-upgrade", PR_O2_NO_H2_UPGRADE, PR_CAP_FE, 0, PR_MODE_HTTP }, |
2761 | { NULL, 0, 0, 0 } |
2762 | }; |
2763 | @@ -1209,14 +1209,18 @@ void soft_stop(void) |
2764 | * listener returns an error, then the proxy state is set to PR_STERROR |
2765 | * because we don't know how to resume from this. The function returns 0 |
2766 | * if it fails, or non-zero on success. |
2767 | + * The function takes the proxy's lock so it's safe to |
2768 | + * call from multiple places. |
2769 | */ |
2770 | int pause_proxy(struct proxy *p) |
2771 | { |
2772 | struct listener *l; |
2773 | |
2774 | + HA_SPIN_LOCK(PROXY_LOCK, &p->lock); |
2775 | + |
2776 | if (!(p->cap & PR_CAP_FE) || p->state == PR_STERROR || |
2777 | p->state == PR_STSTOPPED || p->state == PR_STPAUSED) |
2778 | - return 1; |
2779 | + goto end; |
2780 | |
2781 | ha_warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); |
2782 | send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); |
2783 | @@ -1229,10 +1233,13 @@ int pause_proxy(struct proxy *p) |
2784 | if (p->state == PR_STERROR) { |
2785 | ha_warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); |
2786 | send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); |
2787 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2788 | return 0; |
2789 | } |
2790 | |
2791 | p->state = PR_STPAUSED; |
2792 | +end: |
2793 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2794 | return 1; |
2795 | } |
2796 | |
2797 | @@ -1279,7 +1286,8 @@ void zombify_proxy(struct proxy *p) |
2798 | * to be called when going down in order to release the ports so that another |
2799 | * process may bind to them. It must also be called on disabled proxies at the |
2800 | * end of start-up. If all listeners are closed, the proxy is set to the |
2801 | - * PR_STSTOPPED state. The function takes the proxy's lock so it's safe to |
2802 | + * PR_STSTOPPED state. |
2803 | + * The function takes the proxy's lock so it's safe to |
2804 | * call from multiple places. |
2805 | */ |
2806 | void stop_proxy(struct proxy *p) |
2807 | @@ -1314,14 +1322,18 @@ void stop_proxy(struct proxy *p) |
2808 | * listeners and tries to enable them all. If any of them fails, the proxy is |
2809 | * put back to the paused state. It returns 1 upon success, or zero if an error |
2810 | * is encountered. |
2811 | + * The function takes the proxy's lock so it's safe to |
2812 | + * call from multiple places. |
2813 | */ |
2814 | int resume_proxy(struct proxy *p) |
2815 | { |
2816 | struct listener *l; |
2817 | int fail; |
2818 | |
2819 | + HA_SPIN_LOCK(PROXY_LOCK, &p->lock); |
2820 | + |
2821 | if (p->state != PR_STPAUSED) |
2822 | - return 1; |
2823 | + goto end; |
2824 | |
2825 | ha_warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); |
2826 | send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); |
2827 | @@ -1353,9 +1365,13 @@ int resume_proxy(struct proxy *p) |
2828 | |
2829 | p->state = PR_STREADY; |
2830 | if (fail) { |
2831 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2832 | + /* pause_proxy will take PROXY_LOCK */ |
2833 | pause_proxy(p); |
2834 | return 0; |
2835 | } |
2836 | +end: |
2837 | + HA_SPIN_UNLOCK(PROXY_LOCK, &p->lock); |
2838 | return 1; |
2839 | } |
2840 | |
2841 | @@ -1648,8 +1664,8 @@ void proxy_capture_error(struct proxy *proxy, int is_back, |
2842 | } else { |
2843 | es = HA_ATOMIC_XCHG(&proxy->invalid_req, es); |
2844 | } |
2845 | - free(es); |
2846 | HA_SPIN_UNLOCK(PROXY_LOCK, &proxy->lock); |
2847 | + free(es); |
2848 | } |
2849 | |
2850 | /* Configure all proxies which lack a maxconn setting to use the global one by |
2851 | @@ -2199,9 +2215,8 @@ static int cli_parse_disable_frontend(char **args, char *payload, struct appctx |
2852 | return 1; |
2853 | } |
2854 | |
2855 | - HA_SPIN_LOCK(PROXY_LOCK, &px->lock); |
2856 | + /* pause_proxy will take PROXY_LOCK */ |
2857 | ret = pause_proxy(px); |
2858 | - HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock); |
2859 | |
2860 | if (!ret) { |
2861 | appctx->ctx.cli.severity = LOG_ERR; |
2862 | @@ -2242,9 +2257,8 @@ static int cli_parse_enable_frontend(char **args, char *payload, struct appctx * |
2863 | return 1; |
2864 | } |
2865 | |
2866 | - HA_SPIN_LOCK(PROXY_LOCK, &px->lock); |
2867 | + /* resume_proxy will take PROXY_LOCK */ |
2868 | ret = resume_proxy(px); |
2869 | - HA_SPIN_UNLOCK(PROXY_LOCK, &px->lock); |
2870 | |
2871 | if (!ret) { |
2872 | appctx->ctx.cli.severity = LOG_ERR; |
2873 | diff --git a/src/sample.c b/src/sample.c |
2874 | index 61e7097..e713f29 100644 |
2875 | --- a/src/sample.c |
2876 | +++ b/src/sample.c |
2877 | @@ -2196,13 +2196,14 @@ found: |
2878 | if (!smp->data.u.str.data) |
2879 | return 1; |
2880 | |
2881 | - smp->data.u.str.area = start; |
2882 | |
2883 | /* Compute remaining size if needed |
2884 | Note: smp->data.u.str.size cannot be set to 0 */ |
2885 | if (smp->data.u.str.size) |
2886 | smp->data.u.str.size -= start - smp->data.u.str.area; |
2887 | |
2888 | + smp->data.u.str.area = start; |
2889 | + |
2890 | return 1; |
2891 | } |
2892 | |
2893 | diff --git a/src/server.c b/src/server.c |
2894 | index 81639b7..bef825d 100644 |
2895 | --- a/src/server.c |
2896 | +++ b/src/server.c |
2897 | @@ -1582,8 +1582,7 @@ static void display_parser_err(const char *file, int linenum, char **args, int c |
2898 | file, linenum, args[0], args[1], args[cur_arg]); |
2899 | } |
2900 | |
2901 | -static void srv_conn_src_sport_range_cpy(struct server *srv, |
2902 | - struct server *src) |
2903 | +static void srv_conn_src_sport_range_cpy(struct server *srv, const struct server *src) |
2904 | { |
2905 | int range_sz; |
2906 | |
2907 | @@ -1604,7 +1603,7 @@ static void srv_conn_src_sport_range_cpy(struct server *srv, |
2908 | /* |
2909 | * Copy <src> server connection source settings to <srv> server everything needed. |
2910 | */ |
2911 | -static void srv_conn_src_cpy(struct server *srv, struct server *src) |
2912 | +static void srv_conn_src_cpy(struct server *srv, const struct server *src) |
2913 | { |
2914 | srv->conn_src.opts = src->conn_src.opts; |
2915 | srv->conn_src.source_addr = src->conn_src.source_addr; |
2916 | @@ -1630,7 +1629,7 @@ static void srv_conn_src_cpy(struct server *srv, struct server *src) |
2917 | * everything needed. |
2918 | */ |
2919 | #if defined(USE_OPENSSL) |
2920 | -static void srv_ssl_settings_cpy(struct server *srv, struct server *src) |
2921 | +static void srv_ssl_settings_cpy(struct server *srv, const struct server *src) |
2922 | { |
2923 | if (src->ssl_ctx.ca_file != NULL) |
2924 | srv->ssl_ctx.ca_file = strdup(src->ssl_ctx.ca_file); |
2925 | @@ -1732,7 +1731,7 @@ static int srv_prepare_for_resolution(struct server *srv, const char *hostname) |
2926 | * <srv_tmpl> distinguishes these two cases (must be 1 if <srv> is a template, |
2927 | * 0 if not). |
2928 | */ |
2929 | -static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmpl) |
2930 | +void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl) |
2931 | { |
2932 | /* Connection source settings copy */ |
2933 | srv_conn_src_cpy(srv, src); |
2934 | diff --git a/src/signal.c b/src/signal.c |
2935 | index 288ef00..58c1710 100644 |
2936 | --- a/src/signal.c |
2937 | +++ b/src/signal.c |
2938 | @@ -58,6 +58,9 @@ void signal_handler(int sig) |
2939 | signal_state[sig].count++; |
2940 | if (sig) |
2941 | signal(sig, signal_handler); /* re-arm signal */ |
2942 | + |
2943 | + /* If the thread is TH_FL_SLEEPING we need to wake it */ |
2944 | + wake_thread(tid); |
2945 | } |
2946 | |
2947 | /* Call handlers of all pending signals and clear counts and queue length. The |
2948 | diff --git a/src/ssl_sock.c b/src/ssl_sock.c |
2949 | index 7ffcefc..b33580f 100644 |
2950 | --- a/src/ssl_sock.c |
2951 | +++ b/src/ssl_sock.c |
2952 | @@ -105,16 +105,20 @@ |
2953 | #define SSL_SOCK_SEND_UNLIMITED 0x00000004 |
2954 | #define SSL_SOCK_RECV_HEARTBEAT 0x00000008 |
2955 | |
2956 | -/* bits 0xFFFF0000 are reserved to store verify errors */ |
2957 | +/* bits 0xFFFFFF00 are reserved to store verify errors. |
2958 | + * The CA en CRT error codes will be stored on 7 bits each |
2959 | + * (since the max verify error code does not exceed 127) |
2960 | + * and the CA error depth will be stored on 4 bits. |
2961 | + */ |
2962 | |
2963 | /* Verify errors macros */ |
2964 | -#define SSL_SOCK_CA_ERROR_TO_ST(e) (((e > 63) ? 63 : e) << (16)) |
2965 | -#define SSL_SOCK_CAEDEPTH_TO_ST(d) (((d > 15) ? 15 : d) << (6+16)) |
2966 | -#define SSL_SOCK_CRTERROR_TO_ST(e) (((e > 63) ? 63 : e) << (4+6+16)) |
2967 | +#define SSL_SOCK_CA_ERROR_TO_ST(e) (((e > 127) ? 127 : e) << (8)) |
2968 | +#define SSL_SOCK_CAEDEPTH_TO_ST(d) (((d > 15) ? 15 : d) << (7+8)) |
2969 | +#define SSL_SOCK_CRTERROR_TO_ST(e) (((e > 127) ? 127 : e) << (4+7+8)) |
2970 | |
2971 | -#define SSL_SOCK_ST_TO_CA_ERROR(s) ((s >> (16)) & 63) |
2972 | -#define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (6+16)) & 15) |
2973 | -#define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+6+16)) & 63) |
2974 | +#define SSL_SOCK_ST_TO_CA_ERROR(s) ((s >> (8)) & 127) |
2975 | +#define SSL_SOCK_ST_TO_CAEDEPTH(s) ((s >> (7+8)) & 15) |
2976 | +#define SSL_SOCK_ST_TO_CRTERROR(s) ((s >> (4+7+8)) & 127) |
2977 | |
2978 | /* ssl_methods flags for ssl options */ |
2979 | #define MC_SSL_O_ALL 0x0000 |
2980 | @@ -1606,7 +1610,8 @@ int ssl_sock_bind_verifycbk(int ok, X509_STORE_CTX *x_store) |
2981 | ctx->xprt_st |= SSL_SOCK_CAEDEPTH_TO_ST(depth); |
2982 | } |
2983 | |
2984 | - if (err < 64 && __objt_listener(conn->target)->bind_conf->ca_ignerr & (1ULL << err)) { |
2985 | + if (err <= SSL_MAX_VFY_ERROR_CODE && |
2986 | + cert_ignerr_bitfield_get(__objt_listener(conn->target)->bind_conf->ca_ignerr_bitfield, err)) { |
2987 | ssl_sock_dump_errors(conn); |
2988 | ERR_clear_error(); |
2989 | return 1; |
2990 | @@ -1620,7 +1625,8 @@ int ssl_sock_bind_verifycbk(int ok, X509_STORE_CTX *x_store) |
2991 | ctx->xprt_st |= SSL_SOCK_CRTERROR_TO_ST(err); |
2992 | |
2993 | /* check if certificate error needs to be ignored */ |
2994 | - if (err < 64 && __objt_listener(conn->target)->bind_conf->crt_ignerr & (1ULL << err)) { |
2995 | + if (err <= SSL_MAX_VFY_ERROR_CODE && |
2996 | + cert_ignerr_bitfield_get(__objt_listener(conn->target)->bind_conf->crt_ignerr_bitfield, err)) { |
2997 | ssl_sock_dump_errors(conn); |
2998 | ERR_clear_error(); |
2999 | return 1; |
3000 | @@ -2175,13 +2181,13 @@ static void ssl_set_TLSv12_func(SSL *ssl, set_context_func c) { |
3001 | : SSL_set_min_proto_version(ssl, TLS1_2_VERSION); |
3002 | } |
3003 | static void ctx_set_TLSv13_func(SSL_CTX *ctx, set_context_func c) { |
3004 | -#if SSL_OP_NO_TLSv1_3 |
3005 | +#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L) |
3006 | c == SET_MAX ? SSL_CTX_set_max_proto_version(ctx, TLS1_3_VERSION) |
3007 | : SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); |
3008 | #endif |
3009 | } |
3010 | static void ssl_set_TLSv13_func(SSL *ssl, set_context_func c) { |
3011 | -#if SSL_OP_NO_TLSv1_3 |
3012 | +#if (HA_OPENSSL_VERSION_NUMBER >= 0x10101000L) |
3013 | c == SET_MAX ? SSL_set_max_proto_version(ssl, TLS1_3_VERSION) |
3014 | : SSL_set_min_proto_version(ssl, TLS1_3_VERSION); |
3015 | #endif |
3016 | @@ -4113,6 +4119,7 @@ static int sh_ssl_sess_store(unsigned char *s_id, unsigned char *data, int data_ |
3017 | if (oldsh_ssl_sess != sh_ssl_sess) { |
3018 | /* NOTE: Row couldn't be in use because we lock read & write function */ |
3019 | /* release the reserved row */ |
3020 | + first->len = 0; /* the len must be liberated in order not to call the release callback on it */ |
3021 | shctx_row_dec_hot(ssl_shctx, first); |
3022 | /* replace the previous session already in the tree */ |
3023 | sh_ssl_sess = oldsh_ssl_sess; |
3024 | @@ -5069,20 +5076,17 @@ int ssl_sock_prepare_bind_conf(struct bind_conf *bind_conf) |
3025 | return -err; |
3026 | } |
3027 | |
3028 | -/* release ssl context allocated for servers. */ |
3029 | +/* release ssl context allocated for servers. Most of the field free here |
3030 | + * must also be allocated in srv_ssl_settings_cpy() */ |
3031 | void ssl_sock_free_srv_ctx(struct server *srv) |
3032 | { |
3033 | #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation |
3034 | - if (srv->ssl_ctx.alpn_str) { |
3035 | - free(srv->ssl_ctx.alpn_str); |
3036 | - srv->ssl_ctx.alpn_str = NULL; |
3037 | - } |
3038 | + free(srv->ssl_ctx.alpn_str); |
3039 | + srv->ssl_ctx.alpn_str = NULL; |
3040 | #endif |
3041 | #ifdef OPENSSL_NPN_NEGOTIATED |
3042 | - if (srv->ssl_ctx.npn_str) { |
3043 | - free(srv->ssl_ctx.npn_str); |
3044 | - srv->ssl_ctx.npn_str = NULL; |
3045 | - } |
3046 | + free(srv->ssl_ctx.npn_str); |
3047 | + srv->ssl_ctx.npn_str = NULL; |
3048 | #endif |
3049 | if (srv->ssl_ctx.reused_sess) { |
3050 | int i; |
3051 | @@ -5101,6 +5105,25 @@ void ssl_sock_free_srv_ctx(struct server *srv) |
3052 | SSL_CTX_free(srv->ssl_ctx.ctx); |
3053 | srv->ssl_ctx.ctx = NULL; |
3054 | } |
3055 | + |
3056 | + free(srv->ssl_ctx.ca_file); |
3057 | + srv->ssl_ctx.ca_file = NULL; |
3058 | + free(srv->ssl_ctx.crl_file); |
3059 | + srv->ssl_ctx.crl_file = NULL; |
3060 | + free(srv->ssl_ctx.client_crt); |
3061 | + srv->ssl_ctx.client_crt = NULL; |
3062 | + free(srv->ssl_ctx.verify_host); |
3063 | + srv->ssl_ctx.verify_host = NULL; |
3064 | +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
3065 | + free(srv->sni_expr); |
3066 | + srv->sni_expr = NULL; |
3067 | +#endif |
3068 | + free(srv->ssl_ctx.ciphers); |
3069 | + srv->ssl_ctx.ciphers = NULL; |
3070 | +#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES |
3071 | + free(srv->ssl_ctx.ciphersuites); |
3072 | + srv->ssl_ctx.ciphersuites = NULL; |
3073 | +#endif |
3074 | } |
3075 | |
3076 | /* Walks down the two trees in bind_conf and frees all the certs. The pointer may |
3077 | @@ -8083,7 +8106,7 @@ static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, str |
3078 | { |
3079 | int code; |
3080 | char *p = args[cur_arg + 1]; |
3081 | - unsigned long long *ignerr = &conf->crt_ignerr; |
3082 | + unsigned long long *ignerr = conf->crt_ignerr_bitfield; |
3083 | |
3084 | if (!*p) { |
3085 | if (err) |
3086 | @@ -8092,22 +8115,22 @@ static int bind_parse_ignore_err(char **args, int cur_arg, struct proxy *px, str |
3087 | } |
3088 | |
3089 | if (strcmp(args[cur_arg], "ca-ignore-err") == 0) |
3090 | - ignerr = &conf->ca_ignerr; |
3091 | + ignerr = conf->ca_ignerr_bitfield; |
3092 | |
3093 | if (strcmp(p, "all") == 0) { |
3094 | - *ignerr = ~0ULL; |
3095 | + cert_ignerr_bitfield_set_all(ignerr); |
3096 | return 0; |
3097 | } |
3098 | |
3099 | while (p) { |
3100 | code = atoi(p); |
3101 | - if ((code <= 0) || (code > 63)) { |
3102 | + if ((code <= 0) || (code > SSL_MAX_VFY_ERROR_CODE)) { |
3103 | if (err) |
3104 | - memprintf(err, "'%s' : ID '%d' out of range (1..63) in error IDs list '%s'", |
3105 | - args[cur_arg], code, args[cur_arg + 1]); |
3106 | + memprintf(err, "'%s' : ID '%d' out of range (1..%d) in error IDs list '%s'", |
3107 | + args[cur_arg], code, SSL_MAX_VFY_ERROR_CODE, args[cur_arg + 1]); |
3108 | return ERR_ALERT | ERR_FATAL; |
3109 | } |
3110 | - *ignerr |= 1ULL << code; |
3111 | + cert_ignerr_bitfield_set(ignerr, code); |
3112 | p = strchr(p, ','); |
3113 | if (p) |
3114 | p++; |
3115 | diff --git a/src/standard.c b/src/standard.c |
3116 | index 3dd3d6d..e941627 100644 |
3117 | --- a/src/standard.c |
3118 | +++ b/src/standard.c |
3119 | @@ -1613,7 +1613,8 @@ char *encode_chunk(char *start, char *stop, |
3120 | |
3121 | /* |
3122 | * Tries to prefix characters tagged in the <map> with the <escape> |
3123 | - * character. The input <string> must be zero-terminated. The result will |
3124 | + * character. The input <string> is processed until string_stop |
3125 | + * is reached or NULL-byte is encountered. The result will |
3126 | * be stored between <start> (included) and <stop> (excluded). This |
3127 | * function will always try to terminate the resulting string with a '\0' |
3128 | * before <stop>, and will return its position if the conversion |
3129 | @@ -1621,11 +1622,11 @@ char *encode_chunk(char *start, char *stop, |
3130 | */ |
3131 | char *escape_string(char *start, char *stop, |
3132 | const char escape, const long *map, |
3133 | - const char *string) |
3134 | + const char *string, const char *string_stop) |
3135 | { |
3136 | if (start < stop) { |
3137 | stop--; /* reserve one byte for the final '\0' */ |
3138 | - while (start < stop && *string != '\0') { |
3139 | + while (start < stop && string < string_stop && *string != '\0') { |
3140 | if (!ha_bit_test((unsigned char)(*string), map)) |
3141 | *start++ = *string; |
3142 | else { |
3143 | diff --git a/src/stick_table.c b/src/stick_table.c |
3144 | index 015463b..a3d63f3 100644 |
3145 | --- a/src/stick_table.c |
3146 | +++ b/src/stick_table.c |
3147 | @@ -215,7 +215,18 @@ int __stktable_trash_oldest(struct stktable *t, int to_batch) |
3148 | ts->exp.key = ts->expire; |
3149 | eb32_insert(&t->exps, &ts->exp); |
3150 | |
3151 | - if (!eb || eb->key > ts->exp.key) |
3152 | + /* the update might have jumped beyond the next element, |
3153 | + * possibly causing a wrapping. We need to check whether |
3154 | + * the next element should be used instead. If the next |
3155 | + * element doesn't exist it means we're on the right |
3156 | + * side and have to check the first one then. If it |
3157 | + * exists and is closer, we must use it, otherwise we |
3158 | + * use the current one. |
3159 | + */ |
3160 | + if (!eb) |
3161 | + eb = eb32_first(&t->exps); |
3162 | + |
3163 | + if (!eb || tick_is_lt(ts->exp.key, eb->key)) |
3164 | eb = &ts->exp; |
3165 | |
3166 | continue; |
3167 | @@ -547,11 +558,12 @@ struct stksess *stktable_set_entry(struct stktable *table, struct stksess *nts) |
3168 | return ts; |
3169 | } |
3170 | /* |
3171 | - * Trash expired sticky sessions from table <t>. The next expiration date is |
3172 | - * returned. |
3173 | + * Task processing function to trash expired sticky sessions. A pointer to the |
3174 | + * task itself is returned since it never dies. |
3175 | */ |
3176 | -static int stktable_trash_expired(struct stktable *t) |
3177 | +struct task *process_table_expire(struct task *task, void *context, unsigned short state) |
3178 | { |
3179 | + struct stktable *t = context; |
3180 | struct stksess *ts; |
3181 | struct eb32_node *eb; |
3182 | int looped = 0; |
3183 | @@ -597,7 +609,18 @@ static int stktable_trash_expired(struct stktable *t) |
3184 | ts->exp.key = ts->expire; |
3185 | eb32_insert(&t->exps, &ts->exp); |
3186 | |
3187 | - if (!eb || eb->key > ts->exp.key) |
3188 | + /* the update might have jumped beyond the next element, |
3189 | + * possibly causing a wrapping. We need to check whether |
3190 | + * the next element should be used instead. If the next |
3191 | + * element doesn't exist it means we're on the right |
3192 | + * side and have to check the first one then. If it |
3193 | + * exists and is closer, we must use it, otherwise we |
3194 | + * use the current one. |
3195 | + */ |
3196 | + if (!eb) |
3197 | + eb = eb32_first(&t->exps); |
3198 | + |
3199 | + if (!eb || tick_is_lt(ts->exp.key, eb->key)) |
3200 | eb = &ts->exp; |
3201 | continue; |
3202 | } |
3203 | @@ -611,19 +634,8 @@ static int stktable_trash_expired(struct stktable *t) |
3204 | /* We have found no task to expire in any tree */ |
3205 | t->exp_next = TICK_ETERNITY; |
3206 | out_unlock: |
3207 | + task->expire = t->exp_next; |
3208 | HA_SPIN_UNLOCK(STK_TABLE_LOCK, &t->lock); |
3209 | - return t->exp_next; |
3210 | -} |
3211 | - |
3212 | -/* |
3213 | - * Task processing function to trash expired sticky sessions. A pointer to the |
3214 | - * task itself is returned since it never dies. |
3215 | - */ |
3216 | -static struct task *process_table_expire(struct task *task, void *context, unsigned short state) |
3217 | -{ |
3218 | - struct stktable *t = context; |
3219 | - |
3220 | - task->expire = stktable_trash_expired(t); |
3221 | return task; |
3222 | } |
3223 | |
3224 | diff --git a/src/stream.c b/src/stream.c |
3225 | index 96bdce7..01f5ed5 100644 |
3226 | --- a/src/stream.c |
3227 | +++ b/src/stream.c |
3228 | @@ -228,8 +228,17 @@ struct stream *stream_new(struct session *sess, enum obj_type *origin) |
3229 | s->req_cap = NULL; |
3230 | s->res_cap = NULL; |
3231 | |
3232 | - /* Initialise all the variables contexts even if not used. |
3233 | + /* Initialize all the variables contexts even if not used. |
3234 | * This permits to prune these contexts without errors. |
3235 | + * |
3236 | + * We need to make sure that those lists are not re-initialized |
3237 | + * by stream-dependant underlying code because we could lose |
3238 | + * track of already defined variables, leading to data inconsistency |
3239 | + * and memory leaks... |
3240 | + * |
3241 | + * For reference: we had a very old bug caused by vars_txn and |
3242 | + * vars_reqres being accidentally re-initialized in http_create_txn() |
3243 | + * (https://github.com/haproxy/haproxy/issues/1935) |
3244 | */ |
3245 | vars_init(&s->vars_txn, SCOPE_TXN); |
3246 | vars_init(&s->vars_reqres, SCOPE_REQ); |
3247 | @@ -1708,7 +1717,7 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit |
3248 | void *ptr; |
3249 | struct dict_entry *de; |
3250 | |
3251 | - if (objt_server(s->target) && objt_server(s->target)->flags & SRV_F_NON_STICK) { |
3252 | + if (!objt_server(s->target) || (__objt_server(s->target)->flags & SRV_F_NON_STICK)) { |
3253 | stksess_free(s->store[i].table, s->store[i].ts); |
3254 | s->store[i].ts = NULL; |
3255 | continue; |
3256 | @@ -1724,14 +1733,15 @@ static int process_store_rules(struct stream *s, struct channel *rep, int an_bit |
3257 | HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); |
3258 | ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_ID); |
3259 | stktable_data_cast(ptr, server_id) = __objt_server(s->target)->puid; |
3260 | - HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); |
3261 | |
3262 | - HA_RWLOCK_WRLOCK(STK_SESS_LOCK, &ts->lock); |
3263 | - de = dict_insert(&server_name_dict, __objt_server(s->target)->id); |
3264 | - if (de) { |
3265 | - ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_NAME); |
3266 | - stktable_data_cast(ptr, server_name) = de; |
3267 | + if (__objt_server(s->target)->id) { |
3268 | + de = dict_insert(&server_name_dict, __objt_server(s->target)->id); |
3269 | + if (de) { |
3270 | + ptr = __stktable_data_ptr(s->store[i].table, ts, STKTABLE_DT_SERVER_NAME); |
3271 | + stktable_data_cast(ptr, server_name) = de; |
3272 | + } |
3273 | } |
3274 | + |
3275 | HA_RWLOCK_WRUNLOCK(STK_SESS_LOCK, &ts->lock); |
3276 | |
3277 | stktable_touch_local(s->store[i].table, ts, 1); |
3278 | diff --git a/src/stream_interface.c b/src/stream_interface.c |
3279 | index ab5c574..1adecf3 100644 |
3280 | --- a/src/stream_interface.c |
3281 | +++ b/src/stream_interface.c |
3282 | @@ -1149,7 +1149,7 @@ static void stream_int_chk_snd_conn(struct stream_interface *si) |
3283 | struct channel *oc = si_oc(si); |
3284 | struct conn_stream *cs = __objt_cs(si->end); |
3285 | |
3286 | - if (unlikely(!si_state_in(si->state, SI_SB_CON|SI_SB_RDY|SI_SB_EST) || |
3287 | + if (unlikely(!si_state_in(si->state, SI_SB_RDY|SI_SB_EST) || |
3288 | (oc->flags & CF_SHUTW))) |
3289 | return; |
3290 |
Fixed. Up for review again.