summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG25
-rw-r--r--SUBVERS2
-rw-r--r--VERDATE4
-rw-r--r--VERSION2
-rw-r--r--doc/configuration.txt3
-rw-r--r--doc/lua-api/index.rst4
-rw-r--r--include/haproxy/stconn-t.h1
-rw-r--r--include/haproxy/stconn.h2
-rw-r--r--src/applet.c7
-rw-r--r--src/cfgparse.c2
-rw-r--r--src/h1_htx.c3
-rw-r--r--src/hlua.c219
-rw-r--r--src/mux_h1.c6
-rw-r--r--src/mux_quic.c11
-rw-r--r--src/quic_conn.c18
-rw-r--r--src/quic_tx.c18
-rw-r--r--src/ssl_sock.c39
-rw-r--r--src/tcpcheck.c2
-rw-r--r--src/tools.c9
19 files changed, 292 insertions, 85 deletions
diff --git a/CHANGELOG b/CHANGELOG
index abd27db..626b673 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,31 @@
ChangeLog :
===========
+2024/06/10 : 3.0.1
+ - BUG/MINOR: cfgparse: remove the correct option on httpcheck send-state warning
+ - BUG/MINOR: tcpcheck: report correct error in tcp-check rule parser
+ - BUG/MINOR: tools: fix possible null-deref in env_expand() on out-of-memory
+ - DOC: configuration: add an example for keywords from crt-store
+ - BUG/MINOR: hlua: use CertCache.set() from various hlua contexts
+ - BUG/MEDIUM: h1-htx: Don't state interim responses are bodyless
+ - MEDIUM: stconn: Be able to unblock zero-copy data forwarding from done_fastfwd
+ - BUG/MEDIUM: mux-quic: Unblock zero-copy forwarding if the txbuf can be released
+ - BUG/MINOR: quic: prevent crash on qc_kill_conn()
+ - CLEANUP: hlua: use hlua_pusherror() where relevant
+ - BUG/MINOR: hlua: don't use lua_pushfstring() when we don't expect LJMP
+ - BUG/MINOR: hlua: fix unsafe hlua_pusherror() usage
+ - BUG/MINOR: hlua: prevent LJMP in hlua_traceback()
+ - BUG/MINOR: hlua: fix leak in hlua_ckch_set() error path
+ - CLEANUP: hlua: simplify ambiguous lua_insert() usage in hlua_ctx_resume()
+ - BUG/MEDIUM: mux-quic: Don't unblock zero-copy fwding if blocked during nego
+ - BUG/MEDIUM: ssl: wrong priority whem limiting ECDSA ciphers in ECDSA+RSA configuration
+ - BUG/MEDIUM: ssl: bad auth selection with TLS1.2 and WolfSSL
+ - BUG/MINOR: quic: fix computed length of emitted STREAM frames
+ - BUG/MINOR: quic: ensure Tx buf is always purged
+ - BUG/MEDIUM: stconn/mux-h1: Fix suspect change causing timeouts
+ - BUG/MAJOR: mux-h1: Properly copy chunked input data during zero-copy nego
+ - BUG/MINOR: mux-h1: Use the right variable to set NEGO_FF_FL_EXACT_SIZE flag
+
2024/05/29 : 3.0.0
- MINOR: sample: implement the uptime sample fetch
- CI: scripts: fix build of vtest regarding option -C
diff --git a/SUBVERS b/SUBVERS
index ca94673..ce5dfc4 100644
--- a/SUBVERS
+++ b/SUBVERS
@@ -1,2 +1,2 @@
--5590ada
+-471a1b2
diff --git a/VERDATE b/VERDATE
index 6c911ad..28c5614 100644
--- a/VERDATE
+++ b/VERDATE
@@ -1,2 +1,2 @@
-2024-05-29 14:43:38 +0200
-2024/05/29
+2024-06-10 16:15:30 +0200
+2024/06/10
diff --git a/VERSION b/VERSION
index 4a36342..cb2b00e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.0.0
+3.0.1
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 6a02988..370717f 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -3,7 +3,7 @@
Configuration Manual
----------------------
version 3.0
- 2024/05/29
+ 2024/06/10
This document covers the configuration language as implemented in the version
@@ -16141,6 +16141,7 @@ crt-list <file>
certS.pem [curves X25519:P-256 ciphers ECDHE-ECDSA-AES256-GCM-SHA384] secure.domain.tld
default.pem.rsa *
default.pem.ecdsa *
+ foo.crt [key bar.pem ocsp foo.ocsp ocsp-update on] foo.bar.com
default-crt <cert>
This option does the same as the "crt" option, with the difference that this
diff --git a/doc/lua-api/index.rst b/doc/lua-api/index.rst
index 0d69a2f..cfef26c 100644
--- a/doc/lua-api/index.rst
+++ b/doc/lua-api/index.rst
@@ -4463,6 +4463,10 @@ CertCache class
:param string certificate.issuer: The certificate of the OCSP issuer.
:param string certificate.sctl: An SCTL file.
+ .. Note::
+ This function may be slow. As such, it may only be used during startup
+ (main or init context) or from a yield-capable runtime context.
+
.. code-block:: lua
CertCache.set{filename="certs/localhost9994.pem.rsa", crt=crt}
diff --git a/include/haproxy/stconn-t.h b/include/haproxy/stconn-t.h
index f418e95..c346847 100644
--- a/include/haproxy/stconn-t.h
+++ b/include/haproxy/stconn-t.h
@@ -39,6 +39,7 @@ enum iobuf_flags {
* .done_fastfwd() on consumer side must take care of this flag
*/
IOBUF_FL_EOI = 0x00000010, /* A EOI was encountered on producer side */
+ IOBUF_FL_FF_WANT_ROOM = 0x00000020, /* Producer need more room in the IOBUF to forward data */
};
/* Flags used */
diff --git a/include/haproxy/stconn.h b/include/haproxy/stconn.h
index f60eaa8..e6548a6 100644
--- a/include/haproxy/stconn.h
+++ b/include/haproxy/stconn.h
@@ -474,7 +474,7 @@ static inline size_t se_nego_ff(struct sedesc *se, struct buffer *input, size_t
if (se_fl_test(se, SE_FL_T_MUX)) {
const struct mux_ops *mux = se->conn->mux;
- se->iobuf.flags &= ~IOBUF_FL_FF_BLOCKED;
+ se->iobuf.flags &= ~(IOBUF_FL_FF_BLOCKED|IOBUF_FL_FF_WANT_ROOM);
if (mux->nego_fastfwd && mux->done_fastfwd) {
/* Disable zero-copy forwarding if EOS or an error was reported. */
if (se_fl_test(se, SE_FL_EOS|SE_FL_ERROR|SE_FL_ERR_PENDING)) {
diff --git a/src/applet.c b/src/applet.c
index c528963..2bc3eb5 100644
--- a/src/applet.c
+++ b/src/applet.c
@@ -694,7 +694,7 @@ int appctx_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags)
if (se_fl_test(appctx->sedesc, SE_FL_WANT_ROOM)) {
/* The applet request more room, report the info at the iobuf level */
- sdo->iobuf.flags |= IOBUF_FL_FF_BLOCKED;
+ sdo->iobuf.flags |= (IOBUF_FL_FF_BLOCKED|IOBUF_FL_FF_WANT_ROOM);
TRACE_STATE("waiting for more room", APPLET_EV_RECV|APPLET_EV_BLK, appctx);
}
@@ -716,8 +716,9 @@ int appctx_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags)
/* else */
/* applet_have_more_data(appctx); */
- if (se_done_ff(sdo) != 0) {
- /* Something was forwarding, don't reclaim more room */
+ if (se_done_ff(sdo) != 0 || !(sdo->iobuf.flags & (IOBUF_FL_FF_BLOCKED|IOBUF_FL_FF_WANT_ROOM))) {
+ /* Something was forwarding or the consumer states it is not
+ * blocked anyore, don't reclaim more room */
se_fl_clr(appctx->sedesc, SE_FL_WANT_ROOM);
TRACE_STATE("more room available", APPLET_EV_RECV|APPLET_EV_BLK, appctx);
}
diff --git a/src/cfgparse.c b/src/cfgparse.c
index f5cde50..701a370 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -3053,7 +3053,7 @@ init_proxies_list_stage1:
ha_warning("'%s' will be ignored for %s '%s' (requires 'option httpchk').\n",
"send-state", proxy_type_str(curproxy), curproxy->id);
err_code |= ERR_WARN;
- curproxy->options &= ~PR_O2_CHK_SNDST;
+ curproxy->options2 &= ~PR_O2_CHK_SNDST;
}
}
diff --git a/src/h1_htx.c b/src/h1_htx.c
index f4f13fc..562c0f2 100644
--- a/src/h1_htx.c
+++ b/src/h1_htx.c
@@ -295,7 +295,8 @@ static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx
/* Responses known to have no body. */
h1m->flags |= H1_MF_XFER_LEN;
h1m->curr_len = h1m->body_len = 0;
- flags |= HTX_SL_F_BODYLESS_RESP;
+ if (code >= 200)
+ flags |= HTX_SL_F_BODYLESS_RESP;
}
else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
/* Responses with a known body length. */
diff --git a/src/hlua.c b/src/hlua.c
index 098107f..4bcd60a 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -260,6 +260,70 @@ static const char *hlua_tostring_safe(lua_State *L, int index)
return str;
}
+/* below is an helper function similar to lua_pushvfstring() to push a
+ * formatted string on Lua stack but in a safe way (function may not LJMP).
+ * It can be useful to push allocated strings (ie: error messages) on the
+ * stack and ensure proper cleanup.
+ *
+ * Returns a pointer to the internal copy of the string on success and NULL
+ * on error.
+ *
+ * It is assumed that the calling function is allowed to manipulate <L>
+ */
+__LJMP static int _hlua_pushvfstring_safe(lua_State *L)
+{
+ const char **dst = lua_touserdata(L, 1);
+ const char *fmt = lua_touserdata(L, 2);
+ va_list *argp = lua_touserdata(L, 3);
+
+ *dst = lua_pushvfstring(L, fmt, *argp);
+ return 1;
+}
+static const char *hlua_pushvfstring_safe(lua_State *L, const char *fmt, va_list argp)
+{
+ const char *dst = NULL;
+ va_list cpy_argp; /* required if argp is implemented as array type */
+
+ if (!lua_checkstack(L, 4))
+ return NULL;
+
+ va_copy(cpy_argp, argp);
+
+ /* push our custom _hlua_pushvfstring_safe() function on the stack, then
+ * push our destination string pointer, fmt and arg list
+ */
+ lua_pushcfunction(L, _hlua_pushvfstring_safe);
+ lua_pushlightuserdata(L, &dst); // 1st func argument = dst string pointer
+ lua_pushlightuserdata(L, (void *)fmt); // 2nd func argument = fmt
+ lua_pushlightuserdata(L, &cpy_argp); // 3rd func argument = arg list
+
+ /* call our custom function with proper arguments using pcall() to catch
+ * exceptions (if any)
+ */
+ switch (lua_pcall(L, 3, 1, 0)) {
+ case LUA_OK:
+ break;
+ default:
+ /* error was caught */
+ dst = NULL;
+ }
+ va_end(cpy_argp);
+
+ return dst;
+}
+
+static const char *hlua_pushfstring_safe(lua_State *L, const char *fmt, ...)
+{
+ va_list argp;
+ const char *dst;
+
+ va_start(argp, fmt);
+ dst = hlua_pushvfstring_safe(L, fmt, argp);
+ va_end(argp);
+
+ return dst;
+}
+
#define SET_SAFE_LJMP_L(__L, __HLUA) \
({ \
int ret; \
@@ -784,20 +848,41 @@ void hlua_unref(lua_State *L, int ref)
luaL_unref(L, LUA_REGISTRYINDEX, ref);
}
-__LJMP const char *hlua_traceback(lua_State *L, const char* sep)
+__LJMP static int _hlua_traceback(lua_State *L)
+{
+ lua_Debug *ar = lua_touserdata(L, 1);
+
+ /* Fill fields:
+ * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
+ * 'l': fills in the field currentline;
+ * 'n': fills in the field name and namewhat;
+ * 't': fills in the field istailcall;
+ */
+ return lua_getinfo(L, "Slnt", ar);
+}
+
+
+/* This function cannot fail (output will simply be truncated upon errors) */
+const char *hlua_traceback(lua_State *L, const char* sep)
{
lua_Debug ar;
int level = 0;
struct buffer *msg = get_trash_chunk();
while (lua_getstack(L, level++, &ar)) {
- /* Fill fields:
- * 'S': fills in the fields source, short_src, linedefined, lastlinedefined, and what;
- * 'l': fills in the field currentline;
- * 'n': fills in the field name and namewhat;
- * 't': fills in the field istailcall;
- */
- lua_getinfo(L, "Slnt", &ar);
+ if (!lua_checkstack(L, 2))
+ goto end; // abort
+
+ lua_pushcfunction(L, _hlua_traceback);
+ lua_pushlightuserdata(L, &ar);
+
+ /* safe getinfo */
+ switch (lua_pcall(L, 1, 1, 0)) {
+ case LUA_OK:
+ break;
+ default:
+ goto end; // abort
+ }
/* skip these empty entries, usually they come from deep C functions */
if (ar.currentline < 0 && *ar.what == 'C' && !*ar.namewhat && !ar.name)
@@ -838,6 +923,7 @@ __LJMP const char *hlua_traceback(lua_State *L, const char* sep)
chunk_appendf(msg, " ...");
}
+ end:
return msg->area;
}
@@ -855,16 +941,50 @@ __LJMP static inline void check_args(lua_State *L, int nb, char *fcn)
/* This function pushes an error string prefixed by the file name
* and the line number where the error is encountered.
+ *
+ * It returns 1 on success and 0 on failure (function won't LJMP)
*/
+__LJMP static int _hlua_pusherror(lua_State *L)
+{
+ const char *fmt = lua_touserdata(L, 1);
+ va_list *argp = lua_touserdata(L, 2);
+
+ luaL_where(L, 2);
+ lua_pushvfstring(L, fmt, *argp);
+ lua_concat(L, 2);
+
+ return 1;
+}
static int hlua_pusherror(lua_State *L, const char *fmt, ...)
{
va_list argp;
+ int ret = 1;
+
+ if (!lua_checkstack(L, 3))
+ return 0;
+
va_start(argp, fmt);
- luaL_where(L, 1);
- lua_pushvfstring(L, fmt, argp);
+
+ /* push our custom _hlua_pusherror() function on the stack, then
+ * push fmt and arg list
+ */
+ lua_pushcfunction(L, _hlua_pusherror);
+ lua_pushlightuserdata(L, (void *)fmt); // 1st func argument = fmt
+ lua_pushlightuserdata(L, &argp); // 2nd func argument = arg list
+
+ /* call our custom function with proper arguments using pcall() to catch
+ * exceptions (if any)
+ */
+ switch (lua_pcall(L, 2, 1, 0)) {
+ case LUA_OK:
+ break;
+ default:
+ ret = 0;
+ }
+
va_end(argp);
- lua_concat(L, 2);
- return 1;
+
+ return ret;
}
/* This functions is used with sample fetch and converters. It
@@ -1367,8 +1487,8 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
}
reg = regex_comp(argp[idx].data.str.area, !(argp[idx].type_flags & ARGF_REG_ICASE), 1, &err);
if (!reg) {
- msg = lua_pushfstring(L, "error compiling regex '%s' : '%s'",
- argp[idx].data.str.area, err);
+ msg = hlua_pushfstring_safe(L, "error compiling regex '%s' : '%s'",
+ argp[idx].data.str.area, err);
free(err);
goto error;
}
@@ -1388,7 +1508,8 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
ul = auth_find_userlist(argp[idx].data.str.area);
if (!ul) {
- msg = lua_pushfstring(L, "unable to find userlist '%s'", argp[idx].data.str.area);
+ msg = hlua_pushfstring_safe(L, "unable to find userlist '%s'",
+ argp[idx].data.str.area);
goto error;
}
argp[idx].type = ARGT_USR;
@@ -1412,9 +1533,9 @@ __LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp,
/* Check for type of argument. */
if ((mask & ARGT_MASK) != argp[idx].type) {
- msg = lua_pushfstring(L, "'%s' expected, got '%s'",
- arg_type_names[(mask & ARGT_MASK)],
- arg_type_names[argp[idx].type & ARGT_MASK]);
+ msg = hlua_pushfstring_safe(L, "'%s' expected, got '%s'",
+ arg_type_names[(mask & ARGT_MASK)],
+ arg_type_names[argp[idx].type & ARGT_MASK]);
goto error;
}
@@ -1960,12 +2081,14 @@ resume_execution:
msg = hlua_tostring_safe(lua->T, -1);
trace = hlua_traceback(lua->T, ", ");
if (msg)
- lua_pushfstring(lua->T, "[state-id %d] runtime error: %s from %s", lua->state_id, msg, trace);
+ hlua_pushfstring_safe(lua->T, "[state-id %d] runtime error: %s from %s",
+ lua->state_id, msg, trace);
else
- lua_pushfstring(lua->T, "[state-id %d] unknown runtime error from %s", lua->state_id, trace);
+ hlua_pushfstring_safe(lua->T, "[state-id %d] unknown runtime error from %s",
+ lua->state_id, trace);
- /* Move the error msg at the top and then empty the stack except last msg */
- lua_insert(lua->T, -lua_gettop(lua->T));
+ /* Move the error msg at the bottom and then empty the stack except last msg */
+ lua_insert(lua->T, 1);
lua_settop(lua->T, 1);
ret = HLUA_E_ERRMSG;
break;
@@ -1984,12 +2107,14 @@ resume_execution:
}
msg = hlua_tostring_safe(lua->T, -1);
if (msg)
- lua_pushfstring(lua->T, "[state-id %d] message handler error: %s", lua->state_id, msg);
+ hlua_pushfstring_safe(lua->T, "[state-id %d] message handler error: %s",
+ lua->state_id, msg);
else
- lua_pushfstring(lua->T, "[state-id %d] message handler error", lua->state_id);
+ hlua_pushfstring_safe(lua->T, "[state-id %d] message handler error",
+ lua->state_id);
- /* Move the error msg at the top and then empty the stack except last msg */
- lua_insert(lua->T, -lua_gettop(lua->T));
+ /* Move the error msg at the bottom and then empty the stack except last msg */
+ lua_insert(lua->T, 1);
lua_settop(lua->T, 1);
ret = HLUA_E_ERRMSG;
break;
@@ -2369,9 +2494,7 @@ __LJMP static int hlua_map_new(struct lua_State *L)
/* error case: we can't use luaL_error because we must
* free the err variable.
*/
- luaL_where(L, 1);
- lua_pushfstring(L, "'new': %s.", err);
- lua_concat(L, 2);
+ hlua_pusherror(L, "'new': %s.", err);
free(err);
chunk_destroy(&args[0].data.str);
WILL_LJMP(lua_error(L));
@@ -4702,7 +4825,7 @@ __LJMP static int hlua_run_sample_fetch(lua_State *L)
/* Run the special args checker. */
if (f->val_args && !f->val_args(args, NULL)) {
- lua_pushfstring(L, "error in arguments");
+ hlua_pushfstring_safe(L, "error in arguments");
goto error;
}
@@ -12989,8 +13112,10 @@ __LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext
list_for_each_entry_from(ckchi, &old_ckchs->ckch_inst, by_ckchs) {
struct ckch_inst *new_inst;
- /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances */
- if (y % 10 == 0) {
+ /* it takes a lot of CPU to creates SSL_CTXs, so we yield every 10 CKCH instances
+ * during runtime
+ */
+ if (hlua && (y % 10) == 0) {
*lua_ckchi = ckchi;
@@ -13018,8 +13143,9 @@ __LJMP static int hlua_ckch_commit_yield(lua_State *L, int status, lua_KContext
error:
ckch_store_free(new_ckchs);
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
- WILL_LJMP(luaL_error(L, "%s", err));
+ hlua_pushfstring_safe(L, "%s", err);
free(err);
+ WILL_LJMP(lua_error(L));
return 0;
}
@@ -13053,6 +13179,14 @@ __LJMP static int hlua_ckch_set(lua_State *L)
WILL_LJMP(luaL_error(L, "'CertCache.set' needs a table as argument"));
hlua = hlua_gethlua(L);
+ if (hlua && HLUA_CANT_YIELD(hlua)) {
+ /* using hlua_ckch_set() during runtime from a context that
+ * doesn't allow yielding (e.g.: fetches) is not supported
+ * as it may cause contention.
+ */
+ WILL_LJMP(luaL_error(L, "Cannot use CertCache.set from a "
+ "non-yield capable runtime context"));
+ }
/* FIXME: this should not return an error but should come back later */
if (HA_SPIN_TRYLOCK(CKCH_LOCK, &ckch_lock))
@@ -13135,15 +13269,28 @@ __LJMP static int hlua_ckch_set(lua_State *L)
lua_ckchi = lua_newuserdata(L, sizeof(struct ckch_inst *));
*lua_ckchi = NULL;
- task_wakeup(hlua->task, TASK_WOKEN_MSG);
- MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
+ if (hlua) {
+ /* yield right away to let hlua_ckch_commit_yield() benefit from
+ * a fresh task cycle on next wakeup
+ */
+ task_wakeup(hlua->task, TASK_WOKEN_MSG);
+ MAY_LJMP(hlua_yieldk(L, 0, 0, hlua_ckch_commit_yield, TICK_ETERNITY, 0));
+ } else {
+ /* body/init context: yielding not available, perform the commit as a
+ * 1-shot operation (may be slow, but haproxy process is starting so
+ * it is acceptable)
+ */
+ hlua_ckch_commit_yield(L, LUA_OK, 0);
+ }
end:
HA_SPIN_UNLOCK(CKCH_LOCK, &ckch_lock);
if (errcode & ERR_CODE) {
ckch_store_free(new_ckchs);
- WILL_LJMP(luaL_error(L, "%s", err));
+ hlua_pushfstring_safe(L, "%s", err);
+ free(err);
+ WILL_LJMP(lua_error(L));
}
free(err);
diff --git a/src/mux_h1.c b/src/mux_h1.c
index 6bdaf71..0c17315 100644
--- a/src/mux_h1.c
+++ b/src/mux_h1.c
@@ -4376,7 +4376,7 @@ static void h1_shut(struct stconn *sc, enum se_shut_mode mode, struct se_abort_i
do_shutw:
h1_close(h1c);
- if (mode & SE_SHW_NORMAL)
+ if (!(mode & SE_SHW_NORMAL))
h1c->flags |= H1C_F_SILENT_SHUT;
if (!b_data(&h1c->obuf))
@@ -4724,7 +4724,9 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count,
if (xfer > b_data(input))
xfer = b_data(input);
+ h1c->obuf.head += offset;
h1s->sd->iobuf.data = b_xfer(&h1c->obuf, input, xfer);
+ h1c->obuf.head -= offset;
/* Cannot forward more data, wait for room */
if (b_data(input))
@@ -4860,7 +4862,7 @@ static int h1_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags)
ret = 0;
if (h1m->state == H1_MSG_DATA && (h1m->flags & (H1_MF_CHNK|H1_MF_CLEN)) && count > h1m->curr_len) {
- flags |= NEGO_FF_FL_EXACT_SIZE;
+ nego_flags |= NEGO_FF_FL_EXACT_SIZE;
count = h1m->curr_len;
}
diff --git a/src/mux_quic.c b/src/mux_quic.c
index ae504ee..8272b93 100644
--- a/src/mux_quic.c
+++ b/src/mux_quic.c
@@ -3046,8 +3046,17 @@ static size_t qmux_strm_done_ff(struct stconn *sc)
qcs->flags |= QC_SF_FIN_STREAM;
}
- if (!(qcs->flags & QC_SF_FIN_STREAM) && !sd->iobuf.data)
+ if (!(qcs->flags & QC_SF_FIN_STREAM) && !sd->iobuf.data) {
+ TRACE_STATE("no data sent", QMUX_EV_STRM_SEND, qcs->qcc->conn, qcs);
+
+ /* There is nothing to forward and the SD was blocked after a
+ * successful nego by the producer. We can try to release the
+ * TXBUF to retry. In this case, the TX buf MUST exist.
+ */
+ if ((qcs->sd->iobuf.flags & IOBUF_FL_FF_WANT_ROOM) && !qcc_release_stream_txbuf(qcs))
+ qcs->sd->iobuf.flags &= ~(IOBUF_FL_FF_BLOCKED|IOBUF_FL_FF_WANT_ROOM);
goto end;
+ }
data += sd->iobuf.offset;
total = qcs->qcc->app_ops->done_ff(qcs);
diff --git a/src/quic_conn.c b/src/quic_conn.c
index 6cc1d38..9a3ce29 100644
--- a/src/quic_conn.c
+++ b/src/quic_conn.c
@@ -161,7 +161,9 @@ void qc_kill_conn(struct quic_conn *qc)
TRACE_PROTO("killing the connection", QUIC_EV_CONN_KILL, qc);
qc->flags |= QUIC_FL_CONN_TO_KILL;
qc->flags &= ~QUIC_FL_CONN_RETRANS_NEEDED;
- task_wakeup(qc->idle_timer_task, TASK_WOKEN_OTHER);
+
+ if (!(qc->flags & QUIC_FL_CONN_EXP_TIMER))
+ task_wakeup(qc->idle_timer_task, TASK_WOKEN_OTHER);
qc_notify_err(qc);
@@ -549,11 +551,8 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
{
struct list send_list = LIST_HEAD_INIT(send_list);
struct quic_conn *qc = context;
- struct quic_enc_level *qel;
TRACE_ENTER(QUIC_EV_CONN_IO_CB, qc);
-
- qel = qc->ael;
TRACE_STATE("connection handshake state", QUIC_EV_CONN_IO_CB, qc, &qc->state);
if (qc_test_fd(qc))
@@ -592,11 +591,10 @@ struct task *quic_conn_app_io_cb(struct task *t, void *context, unsigned int sta
goto out;
}
- if (!qel_need_sending(qel, qc))
- goto out;
-
/* XXX TODO: how to limit the list frames to send */
- qel_register_send(&send_list, qel, &qel->pktns->tx.frms);
+ if (qel_need_sending(qc->ael, qc))
+ qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
+
if (!qc_send(qc, 0, &send_list)) {
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
goto out;
@@ -802,10 +800,6 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
qel_register_send(&send_list, qel, &qel->pktns->tx.frms);
}
- /* Skip sending if no QEL with frames to sent. */
- if (LIST_ISEMPTY(&send_list))
- goto out;
-
if (!qc_send(qc, 0, &send_list)) {
TRACE_DEVEL("qc_send() failed", QUIC_EV_CONN_IO_CB, qc);
goto out;
diff --git a/src/quic_tx.c b/src/quic_tx.c
index 6d487eb..39b9176 100644
--- a/src/quic_tx.c
+++ b/src/quic_tx.c
@@ -691,7 +691,7 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
{
struct quic_enc_level *qel, *tmp_qel;
- int ret, status = 0;
+ int ret = 0, status = 0;
struct buffer *buf;
TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
@@ -713,7 +713,7 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
}
/* Prepare and send packets until we could not further prepare packets. */
- do {
+ while (!LIST_ISEMPTY(send_list)) {
/* Buffer must always be empty before qc_prep_pkts() usage.
* qc_send_ppkts() ensures it is cleared on success.
*/
@@ -727,7 +727,12 @@ int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
qc_txb_release(qc);
goto out;
}
- } while (ret > 0 && !LIST_ISEMPTY(send_list));
+
+ if (ret <= 0) {
+ TRACE_DEVEL("stopping on qc_prep_pkts() return", QUIC_EV_CONN_TXPKT, qc);
+ break;
+ }
+ }
qc_txb_release(qc);
if (ret < 0)
@@ -1425,6 +1430,7 @@ static int qc_build_frms(struct list *outlist, struct list *inlist,
ret = 0;
if (*len > room)
goto leave;
+ room -= *len;
/* If we are not probing we must take into an account the congestion
* control window.
@@ -1458,8 +1464,8 @@ static int qc_build_frms(struct list *outlist, struct list *inlist,
QUIC_EV_CONN_BCFRMS, qc, &room, len);
/* Compute the length of this CRYPTO frame header */
hlen = 1 + quic_int_getsize(cf->crypto.offset);
- /* Compute the data length of this CRyPTO frame. */
- dlen = max_stream_data_size(room, *len + hlen, cf->crypto.len);
+ /* Compute the data length of this CRYPTO frame. */
+ dlen = max_stream_data_size(room, hlen, cf->crypto.len);
TRACE_DEVEL(" CRYPTO data length (hlen, crypto.len, dlen)",
QUIC_EV_CONN_BCFRMS, qc, &hlen, &cf->crypto.len, &dlen);
if (!dlen)
@@ -1550,7 +1556,7 @@ static int qc_build_frms(struct list *outlist, struct list *inlist,
hlen = 1 + quic_int_getsize(cf->stream.id) +
((cf->type & QUIC_STREAM_FRAME_TYPE_OFF_BIT) ? quic_int_getsize(cf->stream.offset.key) : 0);
/* Compute the data length of this STREAM frame. */
- avail_room = room - hlen - *len;
+ avail_room = room - hlen;
if ((ssize_t)avail_room <= 0)
continue;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index e6bf3ff..8bd6099 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -2268,10 +2268,14 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
}
if (has_ecdsa_sig) { /* in very rare case: has ecdsa sign but not a ECDSA cipher */
const SSL_CIPHER *cipher;
+ STACK_OF(SSL_CIPHER) *ha_ciphers; /* haproxy side ciphers */
uint32_t cipher_id;
size_t len;
const uint8_t *cipher_suites;
+
+ ha_ciphers = SSL_get_ciphers(ssl);
has_ecdsa_sig = 0;
+
#ifdef OPENSSL_IS_BORINGSSL
len = ctx->cipher_suites_len;
cipher_suites = ctx->cipher_suites;
@@ -2290,6 +2294,10 @@ int ssl_sock_switchctx_cbk(SSL *ssl, int *al, void *arg)
if (!cipher)
continue;
+ /* check if this cipher is available in haproxy configuration */
+ if (sk_SSL_CIPHER_find(ha_ciphers, cipher) == -1)
+ continue;
+
cipher_id = SSL_CIPHER_get_id(cipher);
/* skip the SCSV "fake" signaling ciphersuites because they are NID_auth_any (RFC 7507) */
if (cipher_id == SSL3_CK_SCSV || cipher_id == SSL3_CK_FALLBACK_SCSV)
@@ -2556,6 +2564,10 @@ static int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
return 0;
if (SSL_version(ssl) != TLS1_3_VERSION) {
+
+ /* with TLS <= 1.2, we must use the auth which is provided by the cipher, but we don't need to
+ * consider the auth provided by the signature algorithms */
+
for (idx = 0; idx < suiteSz; idx += 2) {
WOLFSSL_CIPHERSUITE_INFO info;
info = wolfSSL_get_ciphersuite_info(suites[idx], suites[idx+1]);
@@ -2564,23 +2576,22 @@ static int ssl_sock_switchctx_wolfSSL_cbk(WOLFSSL* ssl, void* arg)
else if (info.eccAuth)
has_ecdsa_sig = 1;
}
- }
+ } else {
+ /* with TLS >= 1.3, we must use the auth which is provided by the signature algorithms because
+ * the ciphers does not provide the auth */
- if (hashSigAlgoSz > 0) {
- /* sigalgs extension takes precedence over ciphersuites */
- has_ecdsa_sig = 0;
- has_rsa_sig = 0;
- }
- for (idx = 0; idx < hashSigAlgoSz; idx += 2) {
- int hashAlgo;
- int sigAlgo;
+ for (idx = 0; idx < hashSigAlgoSz; idx += 2) {
+ int hashAlgo;
+ int sigAlgo;
- wolfSSL_get_sigalg_info(hashSigAlgo[idx+0], hashSigAlgo[idx+1], &hashAlgo, &sigAlgo);
+ wolfSSL_get_sigalg_info(hashSigAlgo[idx+0], hashSigAlgo[idx+1], &hashAlgo, &sigAlgo);
- if (sigAlgo == RSAk || sigAlgo == RSAPSSk)
- has_rsa_sig = 1;
- else if (sigAlgo == ECDSAk)
- has_ecdsa_sig = 1;
+ if (sigAlgo == RSAk || sigAlgo == RSAPSSk)
+ has_rsa_sig = 1;
+ else if (sigAlgo == ECDSAk)
+ has_ecdsa_sig = 1;
+
+ }
}
}
diff --git a/src/tcpcheck.c b/src/tcpcheck.c
index b4f9590..e820fdc 100644
--- a/src/tcpcheck.c
+++ b/src/tcpcheck.c
@@ -3434,7 +3434,7 @@ struct tcpcheck_rule *parse_tcpcheck_expect(char **args, int cur_arg, struct pro
px->conf.args.ctx = ARGC_SRV;
lf_expr_init(&chk->expect.hdr.value_fmt);
if (!parse_logformat_string(vpat, px, &chk->expect.hdr.value_fmt, 0, SMP_VAL_BE_CHK_RUL, errmsg)) {
- memprintf(errmsg, "'%s' invalid log-format string (%s).\n", npat, *errmsg);
+ memprintf(errmsg, "'%s' invalid log-format string (%s).\n", vpat, *errmsg);
goto error;
}
}
diff --git a/src/tools.c b/src/tools.c
index 7608e7e..b297d04 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -4627,8 +4627,9 @@ int my_unsetenv(const char *name)
* corresponding value. A variable is identified as a series of alphanumeric
* characters or underscores following a '$' sign. The <in> string must be
* free()able. NULL returns NULL. The resulting string might be reallocated if
- * some expansion is made. Variable names may also be enclosed into braces if
- * needed (eg: to concatenate alphanum characters).
+ * some expansion is made (an NULL will be returned on failure). Variable names
+ * may also be enclosed into braces if needed (eg: to concatenate alphanum
+ * characters).
*/
char *env_expand(char *in)
{
@@ -4683,6 +4684,9 @@ char *env_expand(char *in)
}
out = my_realloc2(out, out_len + (txt_end - txt_beg) + val_len + 1);
+ if (!out)
+ goto leave;
+
if (txt_end > txt_beg) {
memcpy(out + out_len, txt_beg, txt_end - txt_beg);
out_len += txt_end - txt_beg;
@@ -4697,6 +4701,7 @@ char *env_expand(char *in)
/* here we know that <out> was allocated and that we don't need <in> anymore */
free(in);
+leave:
return out;
}