mirror of
https://github.com/haproxy/haproxy.git
synced 2026-05-25 10:42:14 -04:00
Compare commits
38 commits
v3.4-dev13
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32fc35ef09 | ||
|
|
6bb8cb51e6 | ||
|
|
8fe8d5fbe3 | ||
|
|
b78b023d55 | ||
|
|
7d182a2ed5 | ||
|
|
c0e302fe79 | ||
|
|
478e7e52cb | ||
|
|
8e1d33a648 | ||
|
|
49d6306de3 | ||
|
|
01ebb668a4 | ||
|
|
340cc86efb | ||
|
|
f62d020140 | ||
|
|
bbef74fb21 | ||
|
|
608951844e | ||
|
|
f9088a5d75 | ||
|
|
007d5946b4 | ||
|
|
4db85fc53e | ||
|
|
41bb1c24f6 | ||
|
|
9091cfa617 | ||
|
|
57b526e022 | ||
|
|
2644f9ddf9 | ||
|
|
7cab3a3c3a | ||
|
|
04b9215a2e | ||
|
|
75f72c2eb9 | ||
|
|
1ed4ef6659 | ||
|
|
3fab21ea42 | ||
|
|
f9d4d659a4 | ||
|
|
c0aa91a202 | ||
|
|
e2c3cd9eb7 | ||
|
|
6717531053 | ||
|
|
812962d110 | ||
|
|
8fe8f78473 | ||
|
|
cdeb2aa4ef | ||
|
|
9e6e0fd149 | ||
|
|
e98595e4e5 | ||
|
|
413f6f9a1f | ||
|
|
3475a5bb9f | ||
|
|
050e06dd66 |
32 changed files with 220 additions and 106 deletions
|
|
@ -3329,7 +3329,7 @@ setenv <name> <value>
|
||||||
the configuration file sees the new value. See also "presetenv", "resetenv",
|
the configuration file sees the new value. See also "presetenv", "resetenv",
|
||||||
and "unsetenv".
|
and "unsetenv".
|
||||||
|
|
||||||
shm-stats-file <name> [ EXPERIMENTAL ]
|
shm-stats-file <name>
|
||||||
When this directive is set, it enables the use of shared memory for storing
|
When this directive is set, it enables the use of shared memory for storing
|
||||||
stats counters. <name> is used as argument to shm_open() to open the shared
|
stats counters. <name> is used as argument to shm_open() to open the shared
|
||||||
memory at a unique location. It also means that the directive is only
|
memory at a unique location. It also means that the directive is only
|
||||||
|
|
@ -3345,7 +3345,7 @@ shm-stats-file <name> [ EXPERIMENTAL ]
|
||||||
|
|
||||||
See also "guid", "guid-prefix" and "shm-stats-file-max-objects"
|
See also "guid", "guid-prefix" and "shm-stats-file-max-objects"
|
||||||
|
|
||||||
shm-stats-file-max-objects <number> [ EXPERIMENTAL ]
|
shm-stats-file-max-objects <number>
|
||||||
This setting defines the maximum number of objects the shared memory used
|
This setting defines the maximum number of objects the shared memory used
|
||||||
for shared counters will be able to store per thread group. It is directly
|
for shared counters will be able to store per thread group. It is directly
|
||||||
related to the maximum memory size of the shm and is used to "premap" the
|
related to the maximum memory size of the shm and is used to "premap" the
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,8 @@ enum {
|
||||||
/* below we have all handshake flags grouped into one */
|
/* below we have all handshake flags grouped into one */
|
||||||
CO_FL_HANDSHAKE = CO_FL_SEND_PROXY | CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP | CO_FL_SOCKS4_SEND | CO_FL_SOCKS4_RECV,
|
CO_FL_HANDSHAKE = CO_FL_SEND_PROXY | CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP | CO_FL_SOCKS4_SEND | CO_FL_SOCKS4_RECV,
|
||||||
CO_FL_WAIT_XPRT = CO_FL_WAIT_L4_CONN | CO_FL_HANDSHAKE | CO_FL_WAIT_L6_CONN,
|
CO_FL_WAIT_XPRT = CO_FL_WAIT_L4_CONN | CO_FL_HANDSHAKE | CO_FL_WAIT_L6_CONN,
|
||||||
|
/* handshake running on top of a layer6 */
|
||||||
|
CO_FL_WAIT_XPRT_L6 = CO_FL_QMUX_SEND | CO_FL_QMUX_RECV,
|
||||||
|
|
||||||
CO_FL_SSL_WAIT_HS = 0x08000000, /* wait for an SSL handshake to complete */
|
CO_FL_SSL_WAIT_HS = 0x08000000, /* wait for an SSL handshake to complete */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ int conn_reverse(struct connection *conn);
|
||||||
const char *conn_err_code_name(struct connection *c);
|
const char *conn_err_code_name(struct connection *c);
|
||||||
const char *conn_err_code_str(struct connection *c);
|
const char *conn_err_code_str(struct connection *c);
|
||||||
int xprt_add_hs(struct connection *conn);
|
int xprt_add_hs(struct connection *conn);
|
||||||
|
int xprt_add_l6hs(struct connection *conn, int xprt);
|
||||||
void register_mux_proto(struct mux_proto_list *list);
|
void register_mux_proto(struct mux_proto_list *list);
|
||||||
|
|
||||||
static inline void conn_report_term_evt(struct connection *conn, enum term_event_loc loc, unsigned char type);
|
static inline void conn_report_term_evt(struct connection *conn, enum term_event_loc loc, unsigned char type);
|
||||||
|
|
|
||||||
|
|
@ -121,8 +121,8 @@ static inline size_t array_size_or_fail(size_t m, size_t n)
|
||||||
{
|
{
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
if (mulsz_overflow(m, n, &size))
|
if (unlikely(mulsz_overflow(m, n, &size)))
|
||||||
return ~(size_t)0;
|
return DISGUISE(~(size_t)0);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/haproxy/dns-t.h
|
* include/haproxy/resolvers-t.h
|
||||||
* This file provides structures and types for DNS.
|
* This file provides structures and types for DNS.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
||||||
|
|
@ -114,7 +114,7 @@ struct resolv_answer_item {
|
||||||
char name[DNS_MAX_NAME_SIZE+1]; /* answer name */
|
char name[DNS_MAX_NAME_SIZE+1]; /* answer name */
|
||||||
int16_t type; /* question type */
|
int16_t type; /* question type */
|
||||||
int16_t class; /* query class */
|
int16_t class; /* query class */
|
||||||
int32_t ttl; /* response TTL */
|
uint32_t ttl; /* response TTL */
|
||||||
int16_t priority; /* SRV type priority */
|
int16_t priority; /* SRV type priority */
|
||||||
uint16_t weight; /* SRV type weight */
|
uint16_t weight; /* SRV type weight */
|
||||||
uint16_t port; /* SRV type port */
|
uint16_t port; /* SRV type port */
|
||||||
|
|
@ -281,7 +281,7 @@ enum {
|
||||||
* matching preference was found.
|
* matching preference was found.
|
||||||
*/
|
*/
|
||||||
RSLV_UPD_SRVIP_NOT_FOUND, /* provided IP not found
|
RSLV_UPD_SRVIP_NOT_FOUND, /* provided IP not found
|
||||||
* OR provided IP found and preference is not match and an IP
|
* OR provided IP found and preference is not matched and an IP
|
||||||
* matching preference was found.
|
* matching preference was found.
|
||||||
*/
|
*/
|
||||||
RSLV_UPD_NO_IP_FOUND, /* no IP could be found in the response */
|
RSLV_UPD_NO_IP_FOUND, /* no IP could be found in the response */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* include/haproxy/dns.h
|
* include/haproxy/resolvers.h
|
||||||
* This file provides functions related to DNS protocol
|
* This file provides functions related to DNS protocol
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
* Copyright (C) 2014 Baptiste Assmann <bedis9@gmail.com>
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ struct certificate_ocsp {
|
||||||
int refcount_store; /* Number of ckch_store that reference this certificate_ocsp */
|
int refcount_store; /* Number of ckch_store that reference this certificate_ocsp */
|
||||||
int refcount; /* Number of actual references to this certificate_ocsp (SSL_CTXs mostly) */
|
int refcount; /* Number of actual references to this certificate_ocsp (SSL_CTXs mostly) */
|
||||||
struct buffer response;
|
struct buffer response;
|
||||||
long expire;
|
unsigned long expire;
|
||||||
X509 *issuer;
|
X509 *issuer;
|
||||||
STACK_OF(X509) *chain;
|
STACK_OF(X509) *chain;
|
||||||
struct eb64_node next_update; /* Key of items inserted in ocsp_update_tree (sorted by absolute date) */
|
struct eb64_node next_update; /* Key of items inserted in ocsp_update_tree (sorted by absolute date) */
|
||||||
|
|
|
||||||
10
src/acme.c
10
src/acme.c
|
|
@ -1562,6 +1562,16 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
key = ctx->store->data->key;
|
key = ctx->store->data->key;
|
||||||
ctx->store->data->key = NULL;
|
ctx->store->data->key = NULL;
|
||||||
|
|
||||||
|
/* OpenSSL's BIO_new_mem_buf() expects a NUL-terminated string when
|
||||||
|
* passed -1. The httpclient buffer lacks this, so manually terminate
|
||||||
|
* it here to prevent an out-of-bounds heap read during PEM parsing.
|
||||||
|
*/
|
||||||
|
if (b_room(&hc->res.buf) < 1) {
|
||||||
|
memprintf(errmsg, "ACME certificate response has no room for NUL terminator");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
hc->res.buf.area[hc->res.buf.data] = '\0';
|
||||||
|
|
||||||
/* XXX: might need a function dedicated to this, which does not read a private key */
|
/* XXX: might need a function dedicated to this, which does not read a private key */
|
||||||
if (ssl_sock_load_pem_into_ckch(ctx->store->path, hc->res.buf.area, ctx->store->data , errmsg) != 0)
|
if (ssl_sock_load_pem_into_ckch(ctx->store->path, hc->res.buf.area, ctx->store->data , errmsg) != 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
||||||
|
|
@ -539,9 +539,6 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
||||||
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC))
|
if (applet_fl_test(appctx, APPCTX_FL_OUTBLK_ALLOC))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
if (!count)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
if (!appctx_get_buf(appctx, &appctx->outbuf)) {
|
||||||
TRACE_STATE("waiting for appctx outbuf allocation", APPLET_EV_RECV|APPLET_EV_BLK, appctx);
|
TRACE_STATE("waiting for appctx outbuf allocation", APPLET_EV_RECV|APPLET_EV_BLK, appctx);
|
||||||
goto end;
|
goto end;
|
||||||
|
|
@ -550,7 +547,8 @@ size_t appctx_rcv_buf(struct stconn *sc, struct buffer *buf, size_t count, unsig
|
||||||
if (flags & CO_RFL_BUF_FLUSH)
|
if (flags & CO_RFL_BUF_FLUSH)
|
||||||
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
|
applet_fl_set(appctx, APPCTX_FL_FASTFWD);
|
||||||
|
|
||||||
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
if (count)
|
||||||
|
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
||||||
if (ret)
|
if (ret)
|
||||||
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
|
applet_fl_clr(appctx, APPCTX_FL_OUTBLK_FULL);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1818,7 +1818,7 @@ int connect_server(struct stream *s)
|
||||||
{
|
{
|
||||||
struct connection *cli_conn = objt_conn(strm_orig(s));
|
struct connection *cli_conn = objt_conn(strm_orig(s));
|
||||||
struct connection *srv_conn = NULL;
|
struct connection *srv_conn = NULL;
|
||||||
const struct mux_proto_list *mux_proto;
|
const struct mux_proto_list *mux_proto = NULL;
|
||||||
struct server *srv;
|
struct server *srv;
|
||||||
struct ist name = IST_NULL;
|
struct ist name = IST_NULL;
|
||||||
struct sample *name_smp;
|
struct sample *name_smp;
|
||||||
|
|
@ -2139,12 +2139,10 @@ int connect_server(struct stream *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (may_start_mux_now) {
|
if (may_start_mux_now) {
|
||||||
/* Delay QMux MUX init to let xprt_qmux handshake runs first. */
|
/* Delay MUX init if an XPRT handshake is required prior. */
|
||||||
mux_proto = conn_select_mux_be(srv_conn);
|
mux_proto = conn_select_mux_be(srv_conn);
|
||||||
if (mux_proto && mux_proto->init_xprt == XPRT_QMUX) {
|
if (mux_proto && mux_proto->init_xprt)
|
||||||
srv_conn->flags |= (CO_FL_QMUX_RECV|CO_FL_QMUX_SEND);
|
|
||||||
may_start_mux_now = 0;
|
may_start_mux_now = 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
|
#if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation)
|
||||||
|
|
@ -2254,6 +2252,13 @@ int connect_server(struct stream *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (mux_proto && mux_proto->init_xprt) {
|
||||||
|
/* Add handshake layer prior to MUX init if required. Does nothing if SSL layer is active though. */
|
||||||
|
if (xprt_add_l6hs(srv_conn, mux_proto->init_xprt)) {
|
||||||
|
conn_full_close(srv_conn);
|
||||||
|
return SF_ERR_INTERNAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now that the mux may have been created, we can start the xprt.
|
* Now that the mux may have been created, we can start the xprt.
|
||||||
|
|
|
||||||
12
src/cache.c
12
src/cache.c
|
|
@ -2180,7 +2180,17 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
|
||||||
sec_entry = get_secondary_entry(cache_tree, res,
|
sec_entry = get_secondary_entry(cache_tree, res,
|
||||||
s->txn.http->cache_secondary_hash,
|
s->txn.http->cache_secondary_hash,
|
||||||
0);
|
0);
|
||||||
if (sec_entry && sec_entry != res) {
|
if (!sec_entry) {
|
||||||
|
/* Secondary key miss: release the retained primary entry
|
||||||
|
* and reattach the detached row before returning.
|
||||||
|
*/
|
||||||
|
release_entry(cache_tree, res, 0);
|
||||||
|
shctx_wrlock(shctx);
|
||||||
|
if (detached)
|
||||||
|
shctx_row_reattach(shctx, entry_block);
|
||||||
|
shctx_wrunlock(shctx);
|
||||||
|
}
|
||||||
|
else if (sec_entry != res) {
|
||||||
/* The wrong row was added to the hot list. */
|
/* The wrong row was added to the hot list. */
|
||||||
release_entry(cache_tree, res, 0);
|
release_entry(cache_tree, res, 0);
|
||||||
retain_entry(sec_entry);
|
retain_entry(sec_entry);
|
||||||
|
|
|
||||||
|
|
@ -1629,11 +1629,6 @@ static int cfg_parse_global_shm_stats_file(char **args, int section_type,
|
||||||
struct proxy *curpx, const struct proxy *defpx,
|
struct proxy *curpx, const struct proxy *defpx,
|
||||||
const char *file, int line, char **err)
|
const char *file, int line, char **err)
|
||||||
{
|
{
|
||||||
if (!experimental_directives_allowed) {
|
|
||||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global.shm_stats_file != NULL) {
|
if (global.shm_stats_file != NULL) {
|
||||||
memprintf(err, "'%s' already specified.\n", args[0]);
|
memprintf(err, "'%s' already specified.\n", args[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -1644,7 +1639,6 @@ static int cfg_parse_global_shm_stats_file(char **args, int section_type,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
|
||||||
global.shm_stats_file = strdup(args[1]);
|
global.shm_stats_file = strdup(args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1653,11 +1647,6 @@ static int cfg_parse_global_shm_stats_file_max_objects(char **args, int section_
|
||||||
struct proxy *curpx, const struct proxy *defpx,
|
struct proxy *curpx, const struct proxy *defpx,
|
||||||
const char *file, int line, char **err)
|
const char *file, int line, char **err)
|
||||||
{
|
{
|
||||||
if (!experimental_directives_allowed) {
|
|
||||||
memprintf(err, "'%s' directive is experimental, must be allowed via a global 'expose-experimental-directives'", args[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shm_stats_file_max_objects != -1) {
|
if (shm_stats_file_max_objects != -1) {
|
||||||
memprintf(err, "'%s' already specified.\n", args[0]);
|
memprintf(err, "'%s' already specified.\n", args[0]);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -1668,7 +1657,6 @@ static int cfg_parse_global_shm_stats_file_max_objects(char **args, int section_
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_tainted(TAINTED_CONFIG_EXP_KW_DECLARED);
|
|
||||||
shm_stats_file_max_objects = atoi(args[1]);
|
shm_stats_file_max_objects = atoi(args[1]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1151,8 +1151,13 @@ int cli_parse_cmdline(struct appctx *appctx)
|
||||||
*/
|
*/
|
||||||
if (len-1 == strlen(appctx->cli_ctx.payload_pat)) {
|
if (len-1 == strlen(appctx->cli_ctx.payload_pat)) {
|
||||||
if (strncmp(str, appctx->cli_ctx.payload_pat, len-1) == 0) {
|
if (strncmp(str, appctx->cli_ctx.payload_pat, len-1) == 0) {
|
||||||
/* end of payload was reached, rewind before the previous \n and replace it by a \0 */
|
/* end of payload was reached, rewind before the previous \n, if any, and replace it by a \0
|
||||||
b_sub(buf, strlen(appctx->cli_ctx.payload_pat) + 2);
|
* Otherwise, the payload is empty, just
|
||||||
|
*/
|
||||||
|
if (b_data(buf) > len)
|
||||||
|
b_sub(buf, len+1);
|
||||||
|
else
|
||||||
|
b_sub(buf, len);
|
||||||
*b_tail(buf) = '\0';
|
*b_tail(buf) = '\0';
|
||||||
appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
|
appctx->st1 &= ~APPCTX_CLI_ST1_PAYLOAD;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ int conn_notify_mux(struct connection *conn, int old_flags, int forced_wake)
|
||||||
* information to create one, typically from the ALPN. If we're
|
* information to create one, typically from the ALPN. If we're
|
||||||
* done with the handshake, attempt to create one.
|
* done with the handshake, attempt to create one.
|
||||||
*/
|
*/
|
||||||
if (unlikely(!conn->mux) && !(conn->flags & (CO_FL_WAIT_XPRT|CO_FL_QMUX_RECV|CO_FL_QMUX_SEND))) {
|
if (unlikely(!conn->mux) && !(conn->flags & (CO_FL_WAIT_XPRT|CO_FL_WAIT_XPRT_L6))) {
|
||||||
ret = conn_create_mux(conn, NULL);
|
ret = conn_create_mux(conn, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
@ -847,6 +847,43 @@ int xprt_add_hs(struct connection *conn)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Activates an <xprt> layer on top of <conn> connection. This handshake layer
|
||||||
|
* should be designed to work on top of the layer 6. If SSL is active and its
|
||||||
|
* handshake still in progress, this function does nothing.
|
||||||
|
*
|
||||||
|
* Returns 0 on success else a negative error code.
|
||||||
|
*/
|
||||||
|
int xprt_add_l6hs(struct connection *conn, int xprt)
|
||||||
|
{
|
||||||
|
const struct xprt_ops *ops = xprt_get(xprt);
|
||||||
|
void *ops_ctx = NULL;
|
||||||
|
|
||||||
|
/* Only QMux is supported as handshake on top of layer6 for now. */
|
||||||
|
BUG_ON(xprt != XPRT_QMUX);
|
||||||
|
|
||||||
|
if (conn->flags & CO_FL_ERROR)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Do nothing if SSL is in used but handshake still in progress. In
|
||||||
|
* this case, xprt layer will be added on handshake completion.
|
||||||
|
*/
|
||||||
|
if (conn->xprt == xprt_get(XPRT_SSL) &&
|
||||||
|
(conn->flags & CO_FL_WAIT_L6_CONN)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ops->init(conn, &ops_ctx))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ops->add_xprt(conn, ops_ctx, conn->xprt_ctx, conn->xprt, NULL, NULL);
|
||||||
|
conn->xprt = ops;
|
||||||
|
conn->xprt_ctx = ops_ctx;
|
||||||
|
/* Reset XPRT READY flag before the next conn_xprt_start(). */
|
||||||
|
conn->flags &= ~CO_FL_XPRT_READY;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* returns a short name for an error, typically the same as the enum name
|
/* returns a short name for an error, typically the same as the enum name
|
||||||
* without the "CO_ER_" prefix, or an empty string for no error (better eye
|
* without the "CO_ER_" prefix, or an empty string for no error (better eye
|
||||||
* catching in logs). This is more compact for some debug cases.
|
* catching in logs). This is more compact for some debug cases.
|
||||||
|
|
|
||||||
24
src/dict.c
24
src/dict.c
|
|
@ -79,7 +79,7 @@ static struct dict_entry *__dict_lookup(struct dict *d, const char *s)
|
||||||
*/
|
*/
|
||||||
struct dict_entry *dict_insert(struct dict *d, char *s)
|
struct dict_entry *dict_insert(struct dict *d, char *s)
|
||||||
{
|
{
|
||||||
struct dict_entry *de;
|
struct dict_entry *de, *tree_de;
|
||||||
struct ebpt_node *n;
|
struct ebpt_node *n;
|
||||||
|
|
||||||
HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
|
HA_RWLOCK_RDLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
|
@ -97,13 +97,18 @@ struct dict_entry *dict_insert(struct dict *d, char *s)
|
||||||
|
|
||||||
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
||||||
n = ebis_insert(&d->values, &de->value);
|
n = ebis_insert(&d->values, &de->value);
|
||||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
tree_de = container_of(n, struct dict_entry, value);
|
||||||
if (n != &de->value) {
|
if (tree_de == de)
|
||||||
|
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
else {
|
||||||
|
/* another entry was already there, we'll return it, kill
|
||||||
|
* ours and bump the other's refcount before returning it.
|
||||||
|
*/
|
||||||
|
HA_ATOMIC_INC(&tree_de->refcount);
|
||||||
|
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
free_dict_entry(de);
|
free_dict_entry(de);
|
||||||
de = container_of(n, struct dict_entry, value);
|
|
||||||
}
|
}
|
||||||
|
return tree_de;
|
||||||
return de;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -117,10 +122,11 @@ void dict_entry_unref(struct dict *d, struct dict_entry *de)
|
||||||
if (!de)
|
if (!de)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
HA_RWLOCK_WRLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
if (HA_ATOMIC_SUB_FETCH(&de->refcount, 1) != 0) {
|
||||||
|
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
ebpt_delete(&de->value);
|
ebpt_delete(&de->value);
|
||||||
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1926,20 +1926,37 @@ static void dump_registered_keywords(void)
|
||||||
|
|
||||||
/* Generate a random cluster-secret in case the setting is not provided in the
|
/* Generate a random cluster-secret in case the setting is not provided in the
|
||||||
* configuration. This allows to use features which rely on it albeit with some
|
* configuration. This allows to use features which rely on it albeit with some
|
||||||
* limitations.
|
* limitations. The function doesn't (solely) use ha_random64() because this
|
||||||
|
* secret is permanent, and ha_random64() can easily be leaked at various
|
||||||
|
* places.
|
||||||
*/
|
*/
|
||||||
static void generate_random_cluster_secret()
|
static void generate_random_cluster_secret()
|
||||||
{
|
{
|
||||||
/* used as a default random cluster-secret if none defined. */
|
/* used as a default random cluster-secret if none defined. */
|
||||||
uint64_t rand;
|
union {
|
||||||
|
uint64_t by64[2];
|
||||||
|
uint32_t by32[4];
|
||||||
|
uchar by8[16];
|
||||||
|
} rand;
|
||||||
|
|
||||||
/* The caller must not overwrite an already defined secret. */
|
/* The caller must not overwrite an already defined secret. */
|
||||||
BUG_ON(cluster_secret_isset);
|
BUG_ON(cluster_secret_isset);
|
||||||
|
BUG_ON(sizeof(global.cluster_secret) != sizeof(rand));
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
if (RAND_bytes(rand.by8, sizeof(rand.by8)) != 1)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* no SSL or not working, fall back to other sources */
|
||||||
|
rand.by64[0] = ha_random64();
|
||||||
|
rand.by64[1] = ha_random64();
|
||||||
|
rand.by32[0] ^= ((random() & 0x00ffff00) << 8) | ((random() & 0x00ffff00) >> 8);
|
||||||
|
rand.by32[1] ^= ((random() & 0x00ffff00) << 8) | ((random() & 0x00ffff00) >> 8);
|
||||||
|
rand.by32[2] ^= ((random() & 0x00ffff00) << 8) | ((random() & 0x00ffff00) >> 8);
|
||||||
|
rand.by32[3] ^= ((random() & 0x00ffff00) << 8) | ((random() & 0x00ffff00) >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
rand = ha_random64();
|
|
||||||
memcpy(global.cluster_secret, &rand, sizeof(rand));
|
memcpy(global.cluster_secret, &rand, sizeof(rand));
|
||||||
rand = ha_random64();
|
|
||||||
memcpy(global.cluster_secret + sizeof(rand), &rand, sizeof(rand));
|
|
||||||
cluster_secret_isset = 1;
|
cluster_secret_isset = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2949,20 +2949,20 @@ __LJMP static int hlua_socket_receive_yield(struct lua_State *L, int status, lua
|
||||||
|
|
||||||
/* remove final \r\n. */
|
/* remove final \r\n. */
|
||||||
if (nblk == 1) {
|
if (nblk == 1) {
|
||||||
if (blk1[len1-1] == '\n') {
|
if (len1 && blk1[len1-1] == '\n') {
|
||||||
len1--;
|
len1--;
|
||||||
skip_at_end++;
|
skip_at_end++;
|
||||||
if (blk1[len1-1] == '\r') {
|
if (len1 && blk1[len1-1] == '\r') {
|
||||||
len1--;
|
len1--;
|
||||||
skip_at_end++;
|
skip_at_end++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (blk2[len2-1] == '\n') {
|
if (len2 && blk2[len2-1] == '\n') {
|
||||||
len2--;
|
len2--;
|
||||||
skip_at_end++;
|
skip_at_end++;
|
||||||
if (blk2[len2-1] == '\r') {
|
if (len2 && blk2[len2-1] == '\r') {
|
||||||
len2--;
|
len2--;
|
||||||
skip_at_end++;
|
skip_at_end++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3319,7 +3319,7 @@ struct ist *build_log_header(struct log_header hdr, size_t *nbelem)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (metadata && metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN) {
|
else if (metadata && metadata[LOG_META_TIME].len >= LOG_ISOTIME_MINLEN) {
|
||||||
int month;
|
uint month;
|
||||||
char *timestamp = metadata[LOG_META_TIME].ptr;
|
char *timestamp = metadata[LOG_META_TIME].ptr;
|
||||||
|
|
||||||
/* iso time always begins like this: '1970-01-01T00:00:00' */
|
/* iso time always begins like this: '1970-01-01T00:00:00' */
|
||||||
|
|
@ -5499,7 +5499,7 @@ void parse_log_message(char *buf, size_t buflen, int *level, int *facility,
|
||||||
return;
|
return;
|
||||||
fac_level = 10*fac_level + (*p - '0');
|
fac_level = 10*fac_level + (*p - '0');
|
||||||
p++;
|
p++;
|
||||||
if ((p - buf) > buflen)
|
if ((p - buf) >= buflen)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -6743,6 +6743,7 @@ int cfg_parse_log_profile(const char *file, int linenum, char **args, int kwm)
|
||||||
SMP_VAL_FE_LOG_END, &errmsg)) {
|
SMP_VAL_FE_LOG_END, &errmsg)) {
|
||||||
ha_alert("Parsing [%s:%d]: failed to parse logformat: %s.\n",
|
ha_alert("Parsing [%s:%d]: failed to parse logformat: %s.\n",
|
||||||
file, linenum, errmsg);
|
file, linenum, errmsg);
|
||||||
|
lf_expr_deinit(target_lf);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/mux_h2.c
14
src/mux_h2.c
|
|
@ -6236,6 +6236,13 @@ next_frame:
|
||||||
|
|
||||||
/* Skip StreamDep and weight for now (we don't support PRIORITY) */
|
/* Skip StreamDep and weight for now (we don't support PRIORITY) */
|
||||||
if (h2c->dff & H2_F_HEADERS_PRIORITY) {
|
if (h2c->dff & H2_F_HEADERS_PRIORITY) {
|
||||||
|
if (flen < 5) {
|
||||||
|
h2c_report_glitch(h2c, 1, "too short PRIORITY frame");
|
||||||
|
TRACE_STATE("too short PRIORITY frame", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
|
||||||
|
h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (read_n32(hdrs) == h2c->dsi) {
|
if (read_n32(hdrs) == h2c->dsi) {
|
||||||
/* RFC7540#5.3.1 : stream dep may not depend on itself */
|
/* RFC7540#5.3.1 : stream dep may not depend on itself */
|
||||||
h2c_report_glitch(h2c, 1, "PRIORITY frame referencing itself");
|
h2c_report_glitch(h2c, 1, "PRIORITY frame referencing itself");
|
||||||
|
|
@ -6245,13 +6252,6 @@ next_frame:
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flen < 5) {
|
|
||||||
h2c_report_glitch(h2c, 1, "too short PRIORITY frame");
|
|
||||||
TRACE_STATE("too short PRIORITY frame", H2_EV_RX_FRAME|H2_EV_RX_HDR|H2_EV_H2C_ERR|H2_EV_PROTO_ERR, h2c->conn);
|
|
||||||
h2c_error(h2c, H2_ERR_FRAME_SIZE_ERROR);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
hdrs += 5; // stream dep = 4, weight = 1
|
hdrs += 5; // stream dep = 4, weight = 1
|
||||||
flen -= 5;
|
flen -= 5;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -447,8 +447,8 @@ static size_t tcp_fullhdr_find_opt(const struct sample *smp, uint8_t opt)
|
||||||
/* kind1 = NOP and is a single byte, others have a length field */
|
/* kind1 = NOP and is a single byte, others have a length field */
|
||||||
if (smp->data.u.str.area[next] == 1)
|
if (smp->data.u.str.area[next] == 1)
|
||||||
next++;
|
next++;
|
||||||
else if (next + 1 < len)
|
else if (next + 1 < len && smp->data.u.str.area[next + 1] > 1)
|
||||||
next += smp->data.u.str.area[next + 1];
|
next += (uchar)smp->data.u.str.area[next + 1];
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
if (smp->data.u.str.area[curr] == opt && next <= len)
|
if (smp->data.u.str.area[curr] == opt && next <= len)
|
||||||
|
|
@ -605,7 +605,7 @@ static int sample_conv_tcp_options_list(const struct arg *arg_p, struct sample *
|
||||||
/* kind1 = NOP and is a single byte, others have a length field */
|
/* kind1 = NOP and is a single byte, others have a length field */
|
||||||
if (smp->data.u.str.area[ofs] == 1)
|
if (smp->data.u.str.area[ofs] == 1)
|
||||||
ofs++;
|
ofs++;
|
||||||
else if (ofs + 1 < len && smp->data.u.str.area[ofs + 1])
|
else if (ofs + 1 < len && smp->data.u.str.area[ofs + 1] > 1)
|
||||||
ofs += (uchar)smp->data.u.str.area[ofs + 1];
|
ofs += (uchar)smp->data.u.str.area[ofs + 1];
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
|
@ -780,7 +780,7 @@ static int sample_conv_ip_fp(const struct arg *arg_p, struct sample *smp, void *
|
||||||
/* kind1 = NOP and is a single byte, others have a length field */
|
/* kind1 = NOP and is a single byte, others have a length field */
|
||||||
if (smp->data.u.str.area[ofs] == 1)
|
if (smp->data.u.str.area[ofs] == 1)
|
||||||
next = ofs + 1;
|
next = ofs + 1;
|
||||||
else if ((ofs + 1 < tcplen) && smp->data.u.str.area[ofs + 1]) /* optlen 0 will cause an infinite loop */
|
else if ((ofs + 1 < tcplen) && smp->data.u.str.area[ofs + 1] > 1)
|
||||||
next = ofs + (uchar)smp->data.u.str.area[ofs + 1];
|
next = ofs + (uchar)smp->data.u.str.area[ofs + 1];
|
||||||
else
|
else
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
#include <haproxy/uri_auth.h>
|
#include <haproxy/uri_auth.h>
|
||||||
|
|
||||||
/* Lock to ensure multiple backends deletion concurrently is safe */
|
/* Lock to ensure multiple backends deletion concurrently is safe */
|
||||||
static __decl_spinlock(proxies_del_lock);
|
__decl_spinlock(proxies_del_lock);
|
||||||
|
|
||||||
int listeners; /* # of proxy listeners, set by cfgparse */
|
int listeners; /* # of proxy listeners, set by cfgparse */
|
||||||
struct proxy *proxies_list = NULL; /* list of main proxies */
|
struct proxy *proxies_list = NULL; /* list of main proxies */
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,10 @@ static int qmux_parse_frm(struct qcc *qcc, struct buffer *buf)
|
||||||
struct qf_reset_stream *rst_frm = &frm.reset_stream;
|
struct qf_reset_stream *rst_frm = &frm.reset_stream;
|
||||||
qcc_recv_reset_stream(qcc, rst_frm->id, rst_frm->app_error_code, rst_frm->final_size);
|
qcc_recv_reset_stream(qcc, rst_frm->id, rst_frm->app_error_code, rst_frm->final_size);
|
||||||
}
|
}
|
||||||
|
else if (frm.type == QUIC_FT_STOP_SENDING) {
|
||||||
|
struct qf_stop_sending *ss_frm = &frm.stop_sending;
|
||||||
|
qcc_recv_stop_sending(qcc, ss_frm->id, ss_frm->app_error_code);
|
||||||
|
}
|
||||||
else if (frm.type == QUIC_FT_MAX_DATA) {
|
else if (frm.type == QUIC_FT_MAX_DATA) {
|
||||||
struct qf_max_data *md_frm = &frm.max_data;
|
struct qf_max_data *md_frm = &frm.max_data;
|
||||||
qcc_recv_max_data(qcc, md_frm->max_data);
|
qcc_recv_max_data(qcc, md_frm->max_data);
|
||||||
|
|
@ -82,13 +86,26 @@ static int qmux_parse_frm(struct qcc *qcc, struct buffer *buf)
|
||||||
struct qf_max_streams *ms_frm = &frm.max_streams_bidi;
|
struct qf_max_streams *ms_frm = &frm.max_streams_bidi;
|
||||||
qcc_recv_max_streams(qcc, ms_frm->max_streams, 1);
|
qcc_recv_max_streams(qcc, ms_frm->max_streams, 1);
|
||||||
}
|
}
|
||||||
|
else if (frm.type == QUIC_FT_MAX_STREAMS_UNI) {
|
||||||
|
struct qf_max_streams *ms_frm = &frm.max_streams_uni;
|
||||||
|
qcc_recv_max_streams(qcc, ms_frm->max_streams, 0);
|
||||||
|
}
|
||||||
else if (frm.type == QUIC_FT_DATA_BLOCKED ||
|
else if (frm.type == QUIC_FT_DATA_BLOCKED ||
|
||||||
frm.type == QUIC_FT_STREAM_DATA_BLOCKED ||
|
frm.type == QUIC_FT_STREAM_DATA_BLOCKED ||
|
||||||
frm.type == QUIC_FT_STREAMS_BLOCKED_BIDI ||
|
frm.type == QUIC_FT_STREAMS_BLOCKED_BIDI ||
|
||||||
frm.type == QUIC_FT_STREAMS_BLOCKED_UNI) {
|
frm.type == QUIC_FT_STREAMS_BLOCKED_UNI) {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
CHECK_IF("received flow control blocked frame not yet handled in QMux");
|
||||||
|
}
|
||||||
|
else if (frm.type == QUIC_FT_PADDING) {
|
||||||
|
CHECK_IF("received padding frame not yet handled in QMux");
|
||||||
|
}
|
||||||
|
else if (frm.type == QUIC_FT_CONNECTION_CLOSE ||
|
||||||
|
frm.type == QUIC_FT_CONNECTION_CLOSE_APP) {
|
||||||
|
CHECK_IF("received connection_close frame not yet handled in QMux");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
/* qmux_is_frm_valid() must prevent this */
|
||||||
ABORT_NOW();
|
ABORT_NOW();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -378,7 +378,7 @@ int quic_get_cid_tid(const unsigned char *cid, size_t cid_len,
|
||||||
|
|
||||||
tree = &quic_fe_cid_trees[quic_cid_tree_idx(&derive_cid)];
|
tree = &quic_fe_cid_trees[quic_cid_tree_idx(&derive_cid)];
|
||||||
HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
|
HA_RWLOCK_RDLOCK(QC_CID_LOCK, &tree->lock);
|
||||||
node = ebmb_lookup(&tree->root, cid, cid_len);
|
node = ebmb_lookup(&tree->root, derive_cid.data, derive_cid.len);
|
||||||
if (node) {
|
if (node) {
|
||||||
conn_id = ebmb_entry(node, struct quic_connection_id, node);
|
conn_id = ebmb_entry(node, struct quic_connection_id, node);
|
||||||
cid_tid = HA_ATOMIC_LOAD(&conn_id->tid);
|
cid_tid = HA_ATOMIC_LOAD(&conn_id->tid);
|
||||||
|
|
|
||||||
|
|
@ -444,7 +444,7 @@ INITCALL0(STG_REGISTER, regex_register_build_options);
|
||||||
#ifdef USE_PCRE2
|
#ifdef USE_PCRE2
|
||||||
static int init_pcre2_per_thread(void)
|
static int init_pcre2_per_thread(void)
|
||||||
{
|
{
|
||||||
local_pcre2_match = pcre2_match_data_create(MAX_MATCH - 1, NULL);
|
local_pcre2_match = pcre2_match_data_create(MAX_MATCH, NULL);
|
||||||
if (!local_pcre2_match) {
|
if (!local_pcre2_match) {
|
||||||
ha_alert("Failed to allocate PCRE2 match data context for thread %u.\n", tid);
|
ha_alert("Failed to allocate PCRE2 match data context for thread %u.\n", tid);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ struct show_resolvers_ctx {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* returns the currently accepted address families as a combination of
|
/* returns the currently accepted address families as a combination of
|
||||||
* RSLV_ACCEPT_IPV4 and RSLV_ACCEPT_IPV6 only. It will dynamically adapt adapt
|
* RSLV_ACCEPT_IPV4 and RSLV_ACCEPT_IPV6 only. It will dynamically adapt
|
||||||
* the IPv6 status to sock_inet6_seems_reachable if RSLV_AUTO_FAMILY is set,
|
* the IPv6 status to sock_inet6_seems_reachable if RSLV_AUTO_FAMILY is set,
|
||||||
* otherwise returns the relevant bits of resolv_accept_families.
|
* otherwise returns the relevant bits of resolv_accept_families.
|
||||||
*/
|
*/
|
||||||
|
|
@ -509,7 +509,7 @@ resolv_run_resolution(struct resolv_resolution *resolution)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Check if a resolution has already been started for this server return
|
/* Check if a resolution has already been started for this server return
|
||||||
* directly to avoid resolution pill up. */
|
* directly to avoid resolution pile up. */
|
||||||
if (resolution->step != RSLV_STEP_NONE)
|
if (resolution->step != RSLV_STEP_NONE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|
@ -1236,8 +1236,7 @@ static int resolv_validate_dns_response(unsigned char *resp, unsigned char *bufe
|
||||||
if (reader + 4 > bufend)
|
if (reader + 4 > bufend)
|
||||||
goto invalid_resp;
|
goto invalid_resp;
|
||||||
|
|
||||||
answer_record->ttl = reader[0] * 16777216 + reader[1] * 65536
|
answer_record->ttl = read_n32(reader);
|
||||||
+ reader[2] * 256 + reader[3];
|
|
||||||
reader += 4;
|
reader += 4;
|
||||||
|
|
||||||
/* Now reading data len */
|
/* Now reading data len */
|
||||||
|
|
@ -1498,8 +1497,7 @@ static int resolv_validate_dns_response(unsigned char *resp, unsigned char *bufe
|
||||||
if (reader + 4 > bufend)
|
if (reader + 4 > bufend)
|
||||||
goto invalid_resp;
|
goto invalid_resp;
|
||||||
|
|
||||||
answer_record->ttl = reader[0] * 16777216 + reader[1] * 65536
|
answer_record->ttl = read_n32(reader);
|
||||||
+ reader[2] * 256 + reader[3];
|
|
||||||
reader += 4;
|
reader += 4;
|
||||||
|
|
||||||
/* Now reading data len */
|
/* Now reading data len */
|
||||||
|
|
@ -1599,7 +1597,6 @@ static int resolv_validate_dns_response(unsigned char *resp, unsigned char *bufe
|
||||||
tmp_record->ar_item == NULL &&
|
tmp_record->ar_item == NULL &&
|
||||||
memcmp(tmp_record->data.target, answer_record->name, tmp_record->data_len) == 0) {
|
memcmp(tmp_record->data.target, answer_record->name, tmp_record->data_len) == 0) {
|
||||||
/* Always use the received additional record to refresh info */
|
/* Always use the received additional record to refresh info */
|
||||||
pool_free(resolv_answer_item_pool, tmp_record->ar_item);
|
|
||||||
tmp_record->ar_item = answer_record;
|
tmp_record->ar_item = answer_record;
|
||||||
answer_record = NULL;
|
answer_record = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
@ -1855,7 +1852,15 @@ int resolv_dn_label_to_str(const char *dn, int dn_len, char *str, int str_len)
|
||||||
|
|
||||||
ptr = str;
|
ptr = str;
|
||||||
for (i = 0; i < dn_len; ++i) {
|
for (i = 0; i < dn_len; ++i) {
|
||||||
sz = dn[i];
|
sz = (unsigned char)dn[i];
|
||||||
|
|
||||||
|
if (!sz)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Check str_len adding 1 for the dot if (i!=0) and 1 for null terminator */
|
||||||
|
if (str_len < sz+i+(!!i)+1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (i)
|
if (i)
|
||||||
*ptr++ = '.';
|
*ptr++ = '.';
|
||||||
/* copy the string at i+1 to lower case */
|
/* copy the string at i+1 to lower case */
|
||||||
|
|
|
||||||
|
|
@ -2150,11 +2150,11 @@ static int sample_conv_be2hex_check(struct arg *args, struct sample_conv *conv,
|
||||||
*/
|
*/
|
||||||
static int sample_conv_be2hex(const struct arg *args, struct sample *smp, void *private)
|
static int sample_conv_be2hex(const struct arg *args, struct sample *smp, void *private)
|
||||||
{
|
{
|
||||||
struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data);
|
struct buffer *trash = get_trash_chunk_sz(smp->data.u.str.data * 2);
|
||||||
int chunk_size = args[1].data.sint;
|
int chunk_size = args[1].data.sint;
|
||||||
const int last = args[2].data.sint ? smp->data.u.str.data - chunk_size + 1 : smp->data.u.str.data;
|
const int last = args[2].data.sint ? smp->data.u.str.data - chunk_size + 1 : smp->data.u.str.data;
|
||||||
int i;
|
int i;
|
||||||
int max_size;
|
size_t max_size;
|
||||||
int ptr = 0;
|
int ptr = 0;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
|
|
||||||
|
|
@ -2163,7 +2163,9 @@ static int sample_conv_be2hex(const struct arg *args, struct sample *smp, void *
|
||||||
trash->data = 0;
|
trash->data = 0;
|
||||||
if (args[0].data.str.data == 0 && args[2].data.sint == 0)
|
if (args[0].data.str.data == 0 && args[2].data.sint == 0)
|
||||||
chunk_size = smp->data.u.str.data;
|
chunk_size = smp->data.u.str.data;
|
||||||
max_size = trash->size - 2 * chunk_size;
|
if (2 * (size_t)chunk_size > trash->size)
|
||||||
|
return 0;
|
||||||
|
max_size = trash->size - 2 * (size_t)chunk_size;
|
||||||
|
|
||||||
while (ptr < last && trash->data <= max_size) {
|
while (ptr < last && trash->data <= max_size) {
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
|
|
|
||||||
|
|
@ -241,14 +241,17 @@ int session_accept_fd(struct connection *cli_conn)
|
||||||
if (l->bind_conf->options & BC_O_ACC_CIP)
|
if (l->bind_conf->options & BC_O_ACC_CIP)
|
||||||
cli_conn->flags |= CO_FL_ACCEPT_CIP;
|
cli_conn->flags |= CO_FL_ACCEPT_CIP;
|
||||||
|
|
||||||
if (l->bind_conf->mux_proto && l->bind_conf->mux_proto->init_xprt == XPRT_QMUX)
|
|
||||||
cli_conn->flags |= (CO_FL_QMUX_RECV|CO_FL_QMUX_SEND);
|
|
||||||
|
|
||||||
/* Add the handshake pseudo-XPRT */
|
/* Add the handshake pseudo-XPRT */
|
||||||
if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) {
|
if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) {
|
||||||
if (xprt_add_hs(cli_conn) != 0)
|
if (xprt_add_hs(cli_conn) != 0)
|
||||||
goto out_free_conn;
|
goto out_free_conn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add handshake layer prior to MUX init if required. Does nothing if SSL layer is active though. */
|
||||||
|
if (l->bind_conf->mux_proto && l->bind_conf->mux_proto->init_xprt) {
|
||||||
|
if (xprt_add_l6hs(cli_conn, l->bind_conf->mux_proto->init_xprt))
|
||||||
|
goto out_free_conn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reversed conns already have an assigned session, do not recreate it. */
|
/* Reversed conns already have an assigned session, do not recreate it. */
|
||||||
|
|
@ -351,7 +354,7 @@ int session_accept_fd(struct connection *cli_conn)
|
||||||
* v | | |
|
* v | | |
|
||||||
* conn -- owner ---> task <-----+
|
* conn -- owner ---> task <-----+
|
||||||
*/
|
*/
|
||||||
if (cli_conn->flags & (CO_FL_WAIT_XPRT | CO_FL_EARLY_SSL_HS)) {
|
if (cli_conn->flags & (CO_FL_WAIT_XPRT | CO_FL_EARLY_SSL_HS | CO_FL_WAIT_XPRT_L6)) {
|
||||||
int timeout;
|
int timeout;
|
||||||
int clt_tmt = p->timeout.client;
|
int clt_tmt = p->timeout.client;
|
||||||
int hs_tmt = p->timeout.client_hs;
|
int hs_tmt = p->timeout.client_hs;
|
||||||
|
|
|
||||||
|
|
@ -356,8 +356,10 @@ int ssl_sock_generate_certificate(const char *servername, struct bind_conf *bind
|
||||||
ssl_ctx = (SSL_CTX *)lru->data;
|
ssl_ctx = (SSL_CTX *)lru->data;
|
||||||
if (!ssl_ctx && lru) {
|
if (!ssl_ctx && lru) {
|
||||||
ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl);
|
ssl_ctx = ssl_sock_do_create_cert(servername, bind_conf, ssl);
|
||||||
if (!ssl_ctx)
|
if (!ssl_ctx) {
|
||||||
|
HA_RWLOCK_WRUNLOCK(SSL_GEN_CERTS_LOCK, &ssl_ctx_lru_rwlock);
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
|
lru64_commit(lru, ssl_ctx, cacert, 0, (void (*)(void *))SSL_CTX_free);
|
||||||
}
|
}
|
||||||
SSL_set_SSL_CTX(ssl, ssl_ctx);
|
SSL_set_SSL_CTX(ssl, ssl_ctx);
|
||||||
|
|
|
||||||
|
|
@ -290,6 +290,8 @@ int ssl_sock_load_ocsp_response(struct buffer *ocsp_response,
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
#ifdef HAVE_ASN1_TIME_TO_TM
|
#ifdef HAVE_ASN1_TIME_TO_TM
|
||||||
struct tm nextupd_tm = {0};
|
struct tm nextupd_tm = {0};
|
||||||
|
#else
|
||||||
|
long expire = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
resp = d2i_OCSP_RESPONSE(NULL, (const unsigned char **)&p,
|
resp = d2i_OCSP_RESPONSE(NULL, (const unsigned char **)&p,
|
||||||
|
|
@ -391,11 +393,12 @@ int ssl_sock_load_ocsp_response(struct buffer *ocsp_response,
|
||||||
}
|
}
|
||||||
ocsp->expire = my_timegm(&nextupd_tm) - OCSP_MAX_RESPONSE_TIME_SKEW;
|
ocsp->expire = my_timegm(&nextupd_tm) - OCSP_MAX_RESPONSE_TIME_SKEW;
|
||||||
#else
|
#else
|
||||||
ocsp->expire = asn1_generalizedtime_to_epoch(nextupd) - OCSP_MAX_RESPONSE_TIME_SKEW;
|
expire = asn1_generalizedtime_to_epoch(nextupd) - OCSP_MAX_RESPONSE_TIME_SKEW;
|
||||||
if (ocsp->expire < 0) {
|
if (expire < 0) {
|
||||||
memprintf(err, "OCSP single response: Invalid \"Next Update\" time");
|
memprintf(err, "OCSP single response: Invalid \"Next Update\" time");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
ocsp->expire = expire;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ocsp->expire < date.tv_sec) {
|
if (ocsp->expire < date.tv_sec) {
|
||||||
|
|
|
||||||
|
|
@ -6973,12 +6973,8 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
|
||||||
mux = !conn_is_back(conn) ?
|
mux = !conn_is_back(conn) ?
|
||||||
conn_select_mux_fe(conn) : conn_select_mux_be(conn);
|
conn_select_mux_fe(conn) : conn_select_mux_be(conn);
|
||||||
|
|
||||||
if (ctx->conn->flags & (CO_FL_QMUX_RECV|CO_FL_QMUX_SEND) ||
|
if (mux->init_xprt) {
|
||||||
mux->init_xprt == XPRT_QMUX) {
|
ret = xprt_add_l6hs(conn, mux->init_xprt);
|
||||||
const struct xprt_ops *ops = xprt_get(XPRT_QMUX);
|
|
||||||
void *xprt_ctx_hs = NULL;
|
|
||||||
|
|
||||||
ret = ops->init(conn, &xprt_ctx_hs);
|
|
||||||
/* Frontend conn must be freed in case of XPRT init failure. */
|
/* Frontend conn must be freed in case of XPRT init failure. */
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (!conn_is_back(conn)) {
|
if (!conn_is_back(conn)) {
|
||||||
|
|
@ -6990,15 +6986,7 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ops->add_xprt(conn, xprt_ctx_hs,
|
ret = conn_xprt_start(conn);
|
||||||
conn->xprt_ctx, conn->xprt, NULL, NULL);
|
|
||||||
BUG_ON(ret); /* xprt_qmux add_xprt always succeeds */
|
|
||||||
|
|
||||||
conn->xprt = ops;
|
|
||||||
conn->xprt_ctx = xprt_ctx_hs;
|
|
||||||
|
|
||||||
ret = conn->xprt->start(conn, xprt_ctx_hs);
|
|
||||||
BUG_ON(ret);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* TODO MUX selection already performs by conn_select_mux_fe/be().
|
/* TODO MUX selection already performs by conn_select_mux_fe/be().
|
||||||
|
|
|
||||||
|
|
@ -834,6 +834,8 @@ enum tcpcheck_eval_ret tcpcheck_spop_expect_hello(struct check *check, struct tc
|
||||||
goto invalid_frame;
|
goto invalid_frame;
|
||||||
if (decode_varint(&ptr, end, &sz) == -1)
|
if (decode_varint(&ptr, end, &sz) == -1)
|
||||||
goto invalid_frame;
|
goto invalid_frame;
|
||||||
|
if (sz >= SPOP_ERR_ENTRIES)
|
||||||
|
sz = SPOP_ERR_UNKNOWN;
|
||||||
check->code = sz;
|
check->code = sz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -989,7 +991,7 @@ enum tcpcheck_eval_ret tcpcheck_agent_expect_reply(struct check *check, struct t
|
||||||
const char *sc = NULL; /* maxconn */
|
const char *sc = NULL; /* maxconn */
|
||||||
const char *err = NULL; /* first error to report */
|
const char *err = NULL; /* first error to report */
|
||||||
const char *wrn = NULL; /* first warning to report */
|
const char *wrn = NULL; /* first warning to report */
|
||||||
char *cmd, *p;
|
char *cmd, *p, *end;
|
||||||
|
|
||||||
TRACE_ENTER(CHK_EV_TCPCHK_EXP, check);
|
TRACE_ENTER(CHK_EV_TCPCHK_EXP, check);
|
||||||
|
|
||||||
|
|
@ -1018,10 +1020,11 @@ enum tcpcheck_eval_ret tcpcheck_agent_expect_reply(struct check *check, struct t
|
||||||
*/
|
*/
|
||||||
|
|
||||||
p = b_head(&check->bi);
|
p = b_head(&check->bi);
|
||||||
while (*p && *p != '\n' && *p != '\r')
|
end = b_tail(&check->bi);
|
||||||
|
while (p < end && *p && *p != '\n' && *p != '\r')
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
if (!*p) {
|
if (!*p || p == end) {
|
||||||
if (!last_read)
|
if (!last_read)
|
||||||
goto wait_more_data;
|
goto wait_more_data;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@
|
||||||
#include <haproxy/quic_frame.h>
|
#include <haproxy/quic_frame.h>
|
||||||
#include <haproxy/quic_tp-t.h>
|
#include <haproxy/quic_tp-t.h>
|
||||||
|
|
||||||
|
/* Default protocol when not running over SSL layer. */
|
||||||
|
#define XPRT_QMUX_DEFAULT_ALPN "h3"
|
||||||
|
|
||||||
struct xprt_qmux_ctx {
|
struct xprt_qmux_ctx {
|
||||||
struct connection *conn;
|
struct connection *conn;
|
||||||
struct wait_event wait_event;
|
struct wait_event wait_event;
|
||||||
|
|
@ -207,7 +210,7 @@ struct task *xprt_qmux_io_cb(struct task *t, void *context, unsigned int state)
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if ((conn->flags & CO_FL_ERROR) ||
|
if ((conn->flags & CO_FL_ERROR) ||
|
||||||
!(conn->flags & (CO_FL_QMUX_RECV|CO_FL_QMUX_SEND))) {
|
!(conn->flags & CO_FL_WAIT_XPRT_L6)) {
|
||||||
/* XPRT should be unsubscribed when transfer done or on error. */
|
/* XPRT should be unsubscribed when transfer done or on error. */
|
||||||
BUG_ON(ctx->wait_event.events);
|
BUG_ON(ctx->wait_event.events);
|
||||||
|
|
||||||
|
|
@ -332,7 +335,7 @@ static void xprt_qmux_close(struct connection *conn, void *xprt_ctx)
|
||||||
if (ctx->ops_lower && ctx->ops_lower->close)
|
if (ctx->ops_lower && ctx->ops_lower->close)
|
||||||
ctx->ops_lower->close(conn, ctx->ctx_lower);
|
ctx->ops_lower->close(conn, ctx->ctx_lower);
|
||||||
|
|
||||||
conn->flags &= ~(CO_FL_QMUX_RECV|CO_FL_QMUX_SEND);
|
conn->flags &= ~CO_FL_WAIT_XPRT_L6;
|
||||||
|
|
||||||
BUG_ON(conn->xprt_ctx != ctx);
|
BUG_ON(conn->xprt_ctx != ctx);
|
||||||
conn->xprt_ctx = ctx->ctx_lower;
|
conn->xprt_ctx = ctx->ctx_lower;
|
||||||
|
|
@ -346,6 +349,14 @@ static int xprt_qmux_get_alpn(const struct connection *conn, void *xprt_ctx,
|
||||||
const char **str, int *len)
|
const char **str, int *len)
|
||||||
{
|
{
|
||||||
struct xprt_qmux_ctx *ctx = xprt_ctx;
|
struct xprt_qmux_ctx *ctx = xprt_ctx;
|
||||||
|
|
||||||
|
/* Return a the default ALPN if lower layer is not able to negotiate it. */
|
||||||
|
if (!ctx->ops_lower || !ctx->ops_lower->get_alpn) {
|
||||||
|
*str = XPRT_QMUX_DEFAULT_ALPN;
|
||||||
|
*len = strlen(XPRT_QMUX_DEFAULT_ALPN);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return ctx->ops_lower->get_alpn(conn, ctx->ctx_lower, str, len);
|
return ctx->ops_lower->get_alpn(conn, ctx->ctx_lower, str, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue