diff options
-rw-r--r-- | CHANGELOG | 25 | ||||
-rw-r--r-- | SUBVERS | 2 | ||||
-rw-r--r-- | VERDATE | 4 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | doc/configuration.txt | 3 | ||||
-rw-r--r-- | doc/lua-api/index.rst | 4 | ||||
-rw-r--r-- | include/haproxy/stconn-t.h | 1 | ||||
-rw-r--r-- | include/haproxy/stconn.h | 2 | ||||
-rw-r--r-- | src/applet.c | 7 | ||||
-rw-r--r-- | src/cfgparse.c | 2 | ||||
-rw-r--r-- | src/h1_htx.c | 3 | ||||
-rw-r--r-- | src/hlua.c | 219 | ||||
-rw-r--r-- | src/mux_h1.c | 6 | ||||
-rw-r--r-- | src/mux_quic.c | 11 | ||||
-rw-r--r-- | src/quic_conn.c | 18 | ||||
-rw-r--r-- | src/quic_tx.c | 18 | ||||
-rw-r--r-- | src/ssl_sock.c | 39 | ||||
-rw-r--r-- | src/tcpcheck.c | 2 | ||||
-rw-r--r-- | src/tools.c | 9 |
19 files changed, 292 insertions, 85 deletions
@@ -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 @@ -1,2 +1,2 @@ --5590ada +-471a1b2 @@ -1,2 +1,2 @@ -2024-05-29 14:43:38 +0200 -2024/05/29 +2024-06-10 16:15:30 +0200 +2024/06/10 @@ -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. */ @@ -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; } |