mirror of
https://github.com/haproxy/haproxy.git
synced 2026-05-26 11:20:51 -04:00
Compare commits
71 commits
v3.4-dev13
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c0e633f6b | ||
|
|
b463072032 | ||
|
|
f7130c0f36 | ||
|
|
dfb6daca1f | ||
|
|
e4a5a64198 | ||
|
|
4a8bb2fe5f | ||
|
|
d8460a5339 | ||
|
|
8e77620616 | ||
|
|
433cce7af1 | ||
|
|
4a9ec66fd8 | ||
|
|
73b5f0eed4 | ||
|
|
7ac4d7d69f | ||
|
|
85003563c5 | ||
|
|
f932863484 | ||
|
|
26c3b3f41d | ||
|
|
9b6389c8a0 | ||
|
|
93f9ecbfe6 | ||
|
|
2a47cab7f3 | ||
|
|
c41c731f5e | ||
|
|
2653936510 | ||
|
|
997c99df9c | ||
|
|
076655e18d | ||
|
|
8cb0a0c53d | ||
|
|
e583b38c63 | ||
|
|
ffdc91c4a1 | ||
|
|
4f58fef3d4 | ||
|
|
73472025f2 | ||
|
|
5cb932826d | ||
|
|
8bdcc55163 | ||
|
|
b9aaf3c18a | ||
|
|
635652c5aa | ||
|
|
04811943b5 | ||
|
|
e8c9aabd62 | ||
|
|
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 |
50 changed files with 581 additions and 269 deletions
|
|
@ -303,6 +303,7 @@ static void _51d_init_device_offsets(fiftyoneDegreesDeviceOffsets *offsets) {
|
||||||
|
|
||||||
static void _51d_set_device_offsets(struct sample *smp, fiftyoneDegreesDeviceOffsets *offsets)
|
static void _51d_set_device_offsets(struct sample *smp, fiftyoneDegreesDeviceOffsets *offsets)
|
||||||
{
|
{
|
||||||
|
struct buffer *temp = get_trash_chunk();
|
||||||
struct channel *chn;
|
struct channel *chn;
|
||||||
struct htx *htx;
|
struct htx *htx;
|
||||||
struct http_hdr_ctx ctx;
|
struct http_hdr_ctx ctx;
|
||||||
|
|
@ -324,7 +325,15 @@ static void _51d_set_device_offsets(struct sample *smp, fiftyoneDegreesDeviceOff
|
||||||
|
|
||||||
if (http_find_header(htx, name, &ctx, 1)) {
|
if (http_find_header(htx, name, &ctx, 1)) {
|
||||||
(offsets->firstOffset + offsets->size)->httpHeaderOffset = *(global_51degrees.header_offsets + i);
|
(offsets->firstOffset + offsets->size)->httpHeaderOffset = *(global_51degrees.header_offsets + i);
|
||||||
(offsets->firstOffset + offsets->size)->deviceOffset = fiftyoneDegreesGetDeviceOffset(&global_51degrees.data_set, ctx.value.ptr);
|
/* Copy value into trash and NUL-terminate before passing to the
|
||||||
|
* 51Degrees Trie API, which expects a C string.
|
||||||
|
*/
|
||||||
|
if (ctx.value.len >= temp->size)
|
||||||
|
continue;
|
||||||
|
memcpy(temp->area, ctx.value.ptr, ctx.value.len);
|
||||||
|
temp->area[ctx.value.len] = '\0';
|
||||||
|
temp->data = ctx.value.len + 1;
|
||||||
|
(offsets->firstOffset + offsets->size)->deviceOffset = fiftyoneDegreesGetDeviceOffset(&global_51degrees.data_set, temp->area);
|
||||||
offsets->size++;
|
offsets->size++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -9962,7 +9962,7 @@ no option accept-unsafe-violations-in-http-request
|
||||||
When this option is set, the following rules are observed:
|
When this option is set, the following rules are observed:
|
||||||
|
|
||||||
* In H1 only, invalid characters, including NULL character, in header name
|
* In H1 only, invalid characters, including NULL character, in header name
|
||||||
will be accepted;
|
will not be rejected; however the header will be dropped.
|
||||||
|
|
||||||
* In H1 only, NULL character in header value will be accepted;
|
* In H1 only, NULL character in header value will be accepted;
|
||||||
|
|
||||||
|
|
@ -10027,8 +10027,11 @@ no option accept-unsafe-violations-in-http-response
|
||||||
|
|
||||||
When this option is set, the following rules are observed:
|
When this option is set, the following rules are observed:
|
||||||
|
|
||||||
|
* In H1 only, status codes longer than 3 digits but whose value fits in 16
|
||||||
|
bits are not rejected.
|
||||||
|
|
||||||
* In H1 only, invalid characters, including NULL character, in header name
|
* In H1 only, invalid characters, including NULL character, in header name
|
||||||
will be accepted;
|
will not be rejected; however the header will be dropped.
|
||||||
|
|
||||||
* In H1 only, NULL character in header value will be accepted;
|
* In H1 only, NULL character in header value will be accepted;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) */
|
||||||
|
|
|
||||||
|
|
@ -188,4 +188,12 @@ struct file_name_node {
|
||||||
char name[VAR_ARRAY]; /* storage, used with cebus_*() */
|
char name[VAR_ARRAY]; /* storage, used with cebus_*() */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* a pair of uint64_t. It's purposely arranged in little endian to help
|
||||||
|
* being vectorized on modern processors.
|
||||||
|
*/
|
||||||
|
struct uint64_pair {
|
||||||
|
uint64_t l;
|
||||||
|
uint64_t h;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _HAPROXY_TOOLS_T_H */
|
#endif /* _HAPROXY_TOOLS_T_H */
|
||||||
|
|
|
||||||
|
|
@ -1288,11 +1288,27 @@ static inline void _ha_aligned_free(void *ptr)
|
||||||
int parse_dotted_uints(const char *s, unsigned int **nums, size_t *sz);
|
int parse_dotted_uints(const char *s, unsigned int **nums, size_t *sz);
|
||||||
|
|
||||||
/* PRNG */
|
/* PRNG */
|
||||||
|
struct uint64_pair _ha_random64_pair_hashed(void);
|
||||||
|
|
||||||
void ha_generate_uuid_v4(struct buffer *output);
|
void ha_generate_uuid_v4(struct buffer *output);
|
||||||
void ha_generate_uuid_v7(struct buffer *output);
|
void ha_generate_uuid_v7(struct buffer *output);
|
||||||
void ha_random_seed(const unsigned char *seed, size_t len);
|
void ha_random_seed(const unsigned char *seed, size_t len);
|
||||||
void ha_random_jump96(uint32_t dist);
|
void ha_random_seed_thread(void);
|
||||||
|
void ha_random_jump128(uint32_t dist);
|
||||||
|
void ha_random_jump192(uint32_t dist);
|
||||||
uint64_t ha_random64(void);
|
uint64_t ha_random64(void);
|
||||||
|
uint64_t ha_random64_internal(void);
|
||||||
|
|
||||||
|
/* Returns a pair of uint64_t randoms hashed so as not to disclose the internal
|
||||||
|
* PRNG state.
|
||||||
|
*/
|
||||||
|
static inline void ha_random64_pair_hashed(uint64_t *l, uint64_t *h)
|
||||||
|
{
|
||||||
|
struct uint64_pair ret = _ha_random64_pair_hashed();
|
||||||
|
|
||||||
|
*l = ret.l;
|
||||||
|
*h = ret.h;
|
||||||
|
}
|
||||||
|
|
||||||
static inline uint32_t ha_random32()
|
static inline uint32_t ha_random32()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
24
src/acme.c
24
src/acme.c
|
|
@ -1532,7 +1532,7 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
|
|
||||||
hdrs = hc->res.hdrs;
|
hdrs = hc->res.hdrs;
|
||||||
|
|
||||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
|
||||||
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
||||||
istfree(&ctx->nonce);
|
istfree(&ctx->nonce);
|
||||||
ctx->nonce = istdup(hdr->v);
|
ctx->nonce = istdup(hdr->v);
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -1735,7 +1745,7 @@ int acme_res_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
|
|
||||||
hdrs = hc->res.hdrs;
|
hdrs = hc->res.hdrs;
|
||||||
|
|
||||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
|
||||||
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
||||||
istfree(&ctx->nonce);
|
istfree(&ctx->nonce);
|
||||||
ctx->nonce = istdup(hdr->v);
|
ctx->nonce = istdup(hdr->v);
|
||||||
|
|
@ -1836,7 +1846,7 @@ enum acme_ret acme_res_challenge(struct task *task, struct acme_ctx *ctx, struct
|
||||||
|
|
||||||
TRACE_DATA(__FUNCTION__, ACME_EV_RES, ctx, NULL, &hc->res.buf);
|
TRACE_DATA(__FUNCTION__, ACME_EV_RES, ctx, NULL, &hc->res.buf);
|
||||||
|
|
||||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
|
||||||
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
||||||
istfree(&ctx->nonce);
|
istfree(&ctx->nonce);
|
||||||
ctx->nonce = istdup(hdr->v);
|
ctx->nonce = istdup(hdr->v);
|
||||||
|
|
@ -1963,7 +1973,7 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
|
||||||
|
|
||||||
hdrs = hc->res.hdrs;
|
hdrs = hc->res.hdrs;
|
||||||
|
|
||||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
|
||||||
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
||||||
istfree(&ctx->nonce);
|
istfree(&ctx->nonce);
|
||||||
ctx->nonce = istdup(hdr->v);
|
ctx->nonce = istdup(hdr->v);
|
||||||
|
|
@ -2279,7 +2289,7 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
|
|
||||||
hdrs = hc->res.hdrs;
|
hdrs = hc->res.hdrs;
|
||||||
|
|
||||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
|
||||||
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
||||||
istfree(&ctx->nonce);
|
istfree(&ctx->nonce);
|
||||||
ctx->nonce = istdup(hdr->v);
|
ctx->nonce = istdup(hdr->v);
|
||||||
|
|
@ -2458,7 +2468,7 @@ int acme_res_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch
|
||||||
|
|
||||||
hdrs = hc->res.hdrs;
|
hdrs = hc->res.hdrs;
|
||||||
|
|
||||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
|
||||||
if (isteqi(hdr->n, ist("Location"))) {
|
if (isteqi(hdr->n, ist("Location"))) {
|
||||||
istfree(&ctx->kid);
|
istfree(&ctx->kid);
|
||||||
ctx->kid = istdup(hdr->v);
|
ctx->kid = istdup(hdr->v);
|
||||||
|
|
@ -2525,7 +2535,7 @@ int acme_nonce(struct task *task, struct acme_ctx *ctx, char **errmsg)
|
||||||
|
|
||||||
hdrs = hc->res.hdrs;
|
hdrs = hc->res.hdrs;
|
||||||
|
|
||||||
for (hdr = hdrs; isttest(hdr->v); hdr++) {
|
for (hdr = hdrs; hdrs && isttest(hdr->v); hdr++) {
|
||||||
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
|
||||||
istfree(&ctx->nonce);
|
istfree(&ctx->nonce);
|
||||||
ctx->nonce = istdup(hdr->v);
|
ctx->nonce = istdup(hdr->v);
|
||||||
|
|
|
||||||
|
|
@ -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,6 +547,7 @@ 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);
|
||||||
|
|
||||||
|
if (count)
|
||||||
ret = CALL_APPLET_WITH_RET(appctx->applet, rcv_buf(appctx, buf, count, flags));
|
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);
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@ check_user(struct userlist *ul, const char *user, const char *pass)
|
||||||
fprintf(stderr, ", crypt=%s\n", ((ep) ? ep : ""));
|
fprintf(stderr, ", crypt=%s\n", ((ep) ? ep : ""));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ep && strcmp(ep, u->pass) == 0)
|
if (ep && u->pass && strcmp(ep, u->pass) == 0)
|
||||||
return 1;
|
return 1;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -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,13 +2139,11 @@ 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)
|
||||||
/* if websocket stream, try to update connection ALPN. */
|
/* if websocket stream, try to update connection ALPN. */
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,9 @@ int base64dec(const char *in, size_t ilen, char *out, size_t olen) {
|
||||||
signed char b;
|
signed char b;
|
||||||
int convlen = 0, i = 0, pad = 0;
|
int convlen = 0, i = 0, pad = 0;
|
||||||
|
|
||||||
|
if (!ilen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (ilen % 4)
|
if (ilen % 4)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|
|
||||||
23
src/cache.c
23
src/cache.c
|
|
@ -374,7 +374,7 @@ static int secondary_key_cmp(const char *ref_key, const char *new_key)
|
||||||
* delete_expired==0, write otherwise.
|
* delete_expired==0, write otherwise.
|
||||||
*/
|
*/
|
||||||
struct cache_entry *get_secondary_entry(struct cache_tree *cache, struct cache_entry *entry,
|
struct cache_entry *get_secondary_entry(struct cache_tree *cache, struct cache_entry *entry,
|
||||||
const char *secondary_key, int delete_expired)
|
const char *primary_hash, const char *secondary_key, int delete_expired)
|
||||||
{
|
{
|
||||||
struct eb32_node *node = &entry->eb;
|
struct eb32_node *node = &entry->eb;
|
||||||
|
|
||||||
|
|
@ -395,6 +395,12 @@ struct cache_entry *get_secondary_entry(struct cache_tree *cache, struct cache_e
|
||||||
entry = node ? eb32_entry(node, struct cache_entry, eb) : NULL;
|
entry = node ? eb32_entry(node, struct cache_entry, eb) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now verify the full primary hash matches: eb32 only compares 32 bits so
|
||||||
|
* we could have ended up on a different, unrelated entry.
|
||||||
|
*/
|
||||||
|
if (entry && primary_hash && memcmp(entry->hash, primary_hash, sizeof(entry->hash)))
|
||||||
|
entry = NULL;
|
||||||
|
|
||||||
/* Expired entry */
|
/* Expired entry */
|
||||||
if (entry && entry->expire <= date.tv_sec) {
|
if (entry && entry->expire <= date.tv_sec) {
|
||||||
if (delete_expired) {
|
if (delete_expired) {
|
||||||
|
|
@ -1303,7 +1309,7 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
|
||||||
if (old) {
|
if (old) {
|
||||||
if (vary_signature)
|
if (vary_signature)
|
||||||
old = get_secondary_entry(cache_tree, old,
|
old = get_secondary_entry(cache_tree, old,
|
||||||
txn->cache_secondary_hash, 1);
|
txn->cache_hash, txn->cache_secondary_hash, 1);
|
||||||
if (old) {
|
if (old) {
|
||||||
if (!old->complete) {
|
if (!old->complete) {
|
||||||
/* An entry with the same primary key is already being
|
/* An entry with the same primary key is already being
|
||||||
|
|
@ -2178,9 +2184,20 @@ enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *p
|
||||||
if (!http_request_build_secondary_key(s, res->secondary_key_signature)) {
|
if (!http_request_build_secondary_key(s, res->secondary_key_signature)) {
|
||||||
cache_rdlock(cache_tree);
|
cache_rdlock(cache_tree);
|
||||||
sec_entry = get_secondary_entry(cache_tree, res,
|
sec_entry = get_secondary_entry(cache_tree, res,
|
||||||
|
s->txn.http->cache_hash,
|
||||||
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.
|
||||||
|
|
|
||||||
22
src/dict.c
22
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);
|
||||||
|
tree_de = container_of(n, struct dict_entry, 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);
|
HA_RWLOCK_WRUNLOCK(DICT_LOCK, &d->rwlock);
|
||||||
if (n != &de->value) {
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
||||||
27
src/h1.c
27
src/h1.c
|
|
@ -710,6 +710,16 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
|
||||||
case H1_MSG_RPCODE:
|
case H1_MSG_RPCODE:
|
||||||
http_msg_rpcode:
|
http_msg_rpcode:
|
||||||
if (likely(HTTP_IS_DIGIT(*ptr))) {
|
if (likely(HTTP_IS_DIGIT(*ptr))) {
|
||||||
|
if (ptr - sl.st.c.ptr >= 3) {
|
||||||
|
/* more than 3 digits */
|
||||||
|
if (h1m->err_pos == -1) /* only capture the error pointer */
|
||||||
|
h1m->err_pos = ptr - start + skip;
|
||||||
|
else if (h1m->err_pos < -1 || sl.st.status >= ((uint16_t)~0 - 9) / 10) {
|
||||||
|
/* strict checks or risk of overflow */
|
||||||
|
state = H1_MSG_RPCODE;
|
||||||
|
goto http_msg_invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
sl.st.status = sl.st.status * 10 + *ptr - '0';
|
sl.st.status = sl.st.status * 10 + *ptr - '0';
|
||||||
EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, H1_MSG_RPCODE);
|
EAT_AND_JUMP_OR_RETURN(ptr, end, http_msg_rpcode, http_msg_ood, state, H1_MSG_RPCODE);
|
||||||
}
|
}
|
||||||
|
|
@ -952,6 +962,20 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
|
||||||
goto http_output_full;
|
goto http_output_full;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Skip headers whose names contain forbidden
|
||||||
|
* chars. When any is detected, h1m->err_pos >= 0,
|
||||||
|
* so we recheck the name only when an error was
|
||||||
|
* detected.
|
||||||
|
*/
|
||||||
|
if (unlikely(h1m->err_pos >= 0)) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < n.len && HTTP_IS_TOKEN(n.ptr[i]))
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i < n.len)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (isteqi(n, ist("transfer-encoding"))) {
|
if (isteqi(n, ist("transfer-encoding"))) {
|
||||||
ret = h1_parse_xfer_enc_header(h1m, v);
|
ret = h1_parse_xfer_enc_header(h1m, v);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
@ -1248,9 +1272,10 @@ int h1_headers_to_hdr_list(char *start, const char *stop,
|
||||||
void h1_generate_random_ws_input_key(char key_out[25])
|
void h1_generate_random_ws_input_key(char key_out[25])
|
||||||
{
|
{
|
||||||
/* generate a random websocket key */
|
/* generate a random websocket key */
|
||||||
const uint64_t rand1 = ha_random64(), rand2 = ha_random64();
|
uint64_t rand1, rand2;
|
||||||
char key[16];
|
char key[16];
|
||||||
|
|
||||||
|
ha_random64_pair_hashed(&rand1, &rand2);
|
||||||
memcpy(key, &rand1, 8);
|
memcpy(key, &rand1, 8);
|
||||||
memcpy(&key[8], &rand2, 8);
|
memcpy(&key[8], &rand2, 8);
|
||||||
a2base64(key, 16, key_out, 25);
|
a2base64(key, 16, key_out, 25);
|
||||||
|
|
|
||||||
97
src/h3.c
97
src/h3.c
|
|
@ -212,8 +212,33 @@ static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case H3_UNI_S_T_PUSH:
|
case H3_UNI_S_T_PUSH:
|
||||||
/* TODO not supported for the moment */
|
if (!conn_is_back(qcs->qcc->conn)) {
|
||||||
h3s->type = H3S_T_PUSH;
|
/* RFC 9114 6.2.2. Push Streams
|
||||||
|
*
|
||||||
|
* Only servers can push; if a server receives a client-initiated push
|
||||||
|
* stream, this MUST be treated as a connection error of type
|
||||||
|
* H3_STREAM_CREATION_ERROR.
|
||||||
|
*/
|
||||||
|
TRACE_ERROR("reject push from client", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
|
||||||
|
qcc_set_error(qcs->qcc, H3_ERR_STREAM_CREATION_ERROR, 1,
|
||||||
|
muxc_tevt_type_proto_err);
|
||||||
|
qcc_report_glitch(qcs->qcc, 1);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* RFC 9114 4.6. Server Push
|
||||||
|
*
|
||||||
|
* A client MUST treat receipt of a push stream as a connection
|
||||||
|
* error of type H3_ID_ERROR when no MAX_PUSH_ID frame has been sent or
|
||||||
|
* when the stream references a push ID that is greater than the maximum
|
||||||
|
* push ID.
|
||||||
|
*/
|
||||||
|
TRACE_ERROR("reject push from server outside of MAX_PUSH_ID", H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
|
||||||
|
qcc_set_error(qcs->qcc, H3_ERR_ID_ERROR, 1,
|
||||||
|
muxc_tevt_type_proto_err);
|
||||||
|
qcc_report_glitch(qcs->qcc, 1);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case H3_UNI_S_T_QPACK_DEC:
|
case H3_UNI_S_T_QPACK_DEC:
|
||||||
|
|
@ -365,7 +390,6 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
||||||
|
|
||||||
case H3_FT_CANCEL_PUSH:
|
case H3_FT_CANCEL_PUSH:
|
||||||
case H3_FT_GOAWAY:
|
case H3_FT_GOAWAY:
|
||||||
case H3_FT_MAX_PUSH_ID:
|
|
||||||
/* RFC 9114 7.2.3. CANCEL_PUSH
|
/* RFC 9114 7.2.3. CANCEL_PUSH
|
||||||
*
|
*
|
||||||
* A CANCEL_PUSH frame is sent on the control stream. Receiving a
|
* A CANCEL_PUSH frame is sent on the control stream. Receiving a
|
||||||
|
|
@ -412,16 +436,35 @@ static int h3_check_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype
|
||||||
|
|
||||||
case H3_FT_PUSH_PROMISE:
|
case H3_FT_PUSH_PROMISE:
|
||||||
/* RFC 9114 7.2.5. PUSH_PROMISE
|
/* RFC 9114 7.2.5. PUSH_PROMISE
|
||||||
|
*
|
||||||
|
* If a PUSH_PROMISE frame is received on the control stream, the client
|
||||||
|
* MUST respond with a connection error of type H3_FRAME_UNEXPECTED.
|
||||||
*
|
*
|
||||||
* A client MUST NOT send a PUSH_PROMISE frame. A server MUST treat the
|
* A client MUST NOT send a PUSH_PROMISE frame. A server MUST treat the
|
||||||
* receipt of a PUSH_PROMISE frame as a connection error of type
|
* receipt of a PUSH_PROMISE frame as a connection error of type
|
||||||
* H3_FRAME_UNEXPECTED.
|
* H3_FRAME_UNEXPECTED.
|
||||||
*/
|
*/
|
||||||
|
if (h3s->type == H3S_T_CTRL || !conn_is_back(qcs->qcc->conn))
|
||||||
/* TODO server-side only. */
|
|
||||||
ret = H3_ERR_FRAME_UNEXPECTED;
|
ret = H3_ERR_FRAME_UNEXPECTED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case H3_FT_MAX_PUSH_ID:
|
||||||
|
/* RFC 9114 7.2.7. MAX_PUSH_ID
|
||||||
|
*
|
||||||
|
* The MAX_PUSH_ID frame is always sent on the control stream. Receipt
|
||||||
|
* of a MAX_PUSH_ID frame on any other stream MUST be treated as a
|
||||||
|
* connection error of type H3_FRAME_UNEXPECTED.
|
||||||
|
*
|
||||||
|
* A server MUST NOT send a MAX_PUSH_ID frame. A client MUST treat the
|
||||||
|
* receipt of a MAX_PUSH_ID frame as a connection error of type
|
||||||
|
* H3_FRAME_UNEXPECTED.
|
||||||
|
*/
|
||||||
|
if (h3s->type == H3S_T_CTRL || conn_is_back(qcs->qcc->conn))
|
||||||
|
ret = H3_ERR_FRAME_UNEXPECTED;
|
||||||
|
else if (!(h3c->flags & H3_CF_SETTINGS_RECV))
|
||||||
|
ret = H3_ERR_MISSING_SETTINGS;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* RFC 9114 9. Extensions to HTTP/3
|
/* RFC 9114 9. Extensions to HTTP/3
|
||||||
*
|
*
|
||||||
|
|
@ -1930,6 +1973,25 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
|
||||||
h3s->st_req = H3S_ST_REQ_TRAILERS;
|
h3s->st_req = H3S_ST_REQ_TRAILERS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case H3_FT_CANCEL_PUSH:
|
||||||
|
if (!conn_is_back(qcs->qcc->conn)) {
|
||||||
|
/* RFC 9114 7.2.3. CANCEL_PUSH
|
||||||
|
*
|
||||||
|
* If a server receives a CANCEL_PUSH frame for a push ID
|
||||||
|
* that has not yet been mentioned by a PUSH_PROMISE frame, this MUST be
|
||||||
|
* treated as a connection error of type H3_ID_ERROR.
|
||||||
|
*/
|
||||||
|
TRACE_ERROR("reject CANCEL_PUSH from client", H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
|
||||||
|
qcc_set_error(qcs->qcc, H3_ERR_ID_ERROR, 1,
|
||||||
|
muxc_tevt_type_proto_err);
|
||||||
|
qcc_report_glitch(qcs->qcc, 1);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Not supported */
|
||||||
|
ret = flen;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case H3_FT_GOAWAY:
|
case H3_FT_GOAWAY:
|
||||||
ret = h3_parse_goaway_frm(qcs->qcc->ctx, b, flen);
|
ret = h3_parse_goaway_frm(qcs->qcc->ctx, b, flen);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
@ -1938,12 +2000,6 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case H3_FT_CANCEL_PUSH:
|
|
||||||
case H3_FT_PUSH_PROMISE:
|
|
||||||
case H3_FT_MAX_PUSH_ID:
|
|
||||||
/* Not supported */
|
|
||||||
ret = flen;
|
|
||||||
break;
|
|
||||||
case H3_FT_SETTINGS:
|
case H3_FT_SETTINGS:
|
||||||
ret = h3_parse_settings_frm(qcs->qcc->ctx, b, flen);
|
ret = h3_parse_settings_frm(qcs->qcc->ctx, b, flen);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
@ -1953,6 +2009,25 @@ static ssize_t h3_rcv_buf(struct qcs *qcs, struct buffer *b, int fin)
|
||||||
}
|
}
|
||||||
h3c->flags |= H3_CF_SETTINGS_RECV;
|
h3c->flags |= H3_CF_SETTINGS_RECV;
|
||||||
break;
|
break;
|
||||||
|
case H3_FT_PUSH_PROMISE:
|
||||||
|
/* h3_check_frame_valid() must reject on server side. */
|
||||||
|
BUG_ON(!conn_is_back(qcs->qcc->conn));
|
||||||
|
|
||||||
|
/* RFC 9114 7.2.5. PUSH_PROMISE
|
||||||
|
*
|
||||||
|
* A client MUST treat
|
||||||
|
* receipt of a PUSH_PROMISE frame that contains a larger push ID than
|
||||||
|
* the client has advertised as a connection error of H3_ID_ERROR.
|
||||||
|
*/
|
||||||
|
ret = H3_ERR_ID_ERROR;
|
||||||
|
break;
|
||||||
|
case H3_FT_MAX_PUSH_ID:
|
||||||
|
/* h3_check_frame_valid() must reject on client side. */
|
||||||
|
BUG_ON(conn_is_back(qcs->qcc->conn));
|
||||||
|
|
||||||
|
/* Not supported. */
|
||||||
|
ret = flen;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* RFC 9114 Section 9. Extensions to HTTP/3
|
/* RFC 9114 Section 9. Extensions to HTTP/3
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -1926,20 +1926,30 @@ 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 prefers RAND_bytes() if available, otherwise falls
|
||||||
|
* back to ha_random64_pair_hashed().
|
||||||
*/
|
*/
|
||||||
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];
|
||||||
|
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 */
|
||||||
|
ha_random64_pair_hashed(&rand.by64[0], &rand.by64[1]);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3088,6 +3098,7 @@ void *run_thread_poll_loop(void *data)
|
||||||
ha_set_thread(data);
|
ha_set_thread(data);
|
||||||
set_thread_cpu_affinity();
|
set_thread_cpu_affinity();
|
||||||
clock_set_local_source();
|
clock_set_local_source();
|
||||||
|
ha_random_seed_thread();
|
||||||
|
|
||||||
#ifdef USE_THREAD
|
#ifdef USE_THREAD
|
||||||
ha_thread_info[tid].pth_id = ha_get_pthread_id(tid);
|
ha_thread_info[tid].pth_id = ha_get_pthread_id(tid);
|
||||||
|
|
|
||||||
|
|
@ -788,7 +788,7 @@ static void hstream_parse_uri(struct ist uri, struct hstream *hs)
|
||||||
} while (*next);
|
} while (*next);
|
||||||
|
|
||||||
if (use_rand)
|
if (use_rand)
|
||||||
result = ((long long)ha_random64() * result) / ((long long)RAND_MAX + 1);
|
result = ((long long)statistical_prng() * result) / 0xFFFFFFFFU;
|
||||||
|
|
||||||
switch (*arg) {
|
switch (*arg) {
|
||||||
case 's':
|
case 's':
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@ void haproxy_init_args(int argc, char **argv)
|
||||||
|
|
||||||
/* SSL/TCP binding */
|
/* SSL/TCP binding */
|
||||||
hbuf_appendf(&fbuf, "\tbind %s:%s shards by-thread ssl "
|
hbuf_appendf(&fbuf, "\tbind %s:%s shards by-thread ssl "
|
||||||
"alpn h2,http1.1,http1.0"
|
"alpn h3,h2,http1.1,http1.0"
|
||||||
" crt " HATERM_RSA_CERT_NAME
|
" crt " HATERM_RSA_CERT_NAME
|
||||||
" crt " HATERM_ECDSA_CERT_NAME "%s%s\n",
|
" crt " HATERM_ECDSA_CERT_NAME "%s%s\n",
|
||||||
ip, port2,
|
ip, port2,
|
||||||
|
|
@ -438,6 +438,8 @@ void haproxy_init_args(int argc, char **argv)
|
||||||
}
|
}
|
||||||
hbuf_appendf(&gbuf, "global\n");
|
hbuf_appendf(&gbuf, "global\n");
|
||||||
hbuf_appendf(&gbuf, "\ttune.memory.hot-size 3145728\n");
|
hbuf_appendf(&gbuf, "\ttune.memory.hot-size 3145728\n");
|
||||||
|
if (has_ssl)
|
||||||
|
hbuf_appendf(&gbuf, "\texpose-experimental-directives\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* "global" section */
|
/* "global" section */
|
||||||
|
|
|
||||||
22
src/hlua.c
22
src/hlua.c
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
@ -6709,6 +6709,20 @@ __LJMP static inline int hlua_http_add_hdr(lua_State *L, struct http_msg *msg)
|
||||||
size_t value_len;
|
size_t value_len;
|
||||||
const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
|
const char *value = MAY_LJMP(luaL_checklstring(L, 3, &value_len));
|
||||||
struct htx *htx = htxbuf(&msg->chn->buf);
|
struct htx *htx = htxbuf(&msg->chn->buf);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/* Reject header values containing CR/LF/NUL to prevent HTTP header
|
||||||
|
* injection on HTTP/1 output.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < name_len; i++) {
|
||||||
|
if (name[i] == 0 || name[i] == '\r' || name[i] == '\n')
|
||||||
|
WILL_LJMP(lua_error(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < value_len; i++) {
|
||||||
|
if (value[i] == 0 || value[i] == '\r' || value[i] == '\n')
|
||||||
|
WILL_LJMP(lua_error(L));
|
||||||
|
}
|
||||||
|
|
||||||
lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
|
lua_pushboolean(L, http_add_header(htx, ist2(name, name_len),
|
||||||
ist2(value, value_len), 1));
|
ist2(value, value_len), 1));
|
||||||
|
|
|
||||||
|
|
@ -3996,19 +3996,19 @@ void http_check_response_for_cacheability(struct stream *s, struct channel *res)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isteqi(ctx.value, ist("private")) ||
|
|
||||||
isteqi(ctx.value, ist("no-cache")) ||
|
|
||||||
isteqi(ctx.value, ist("no-store")) ||
|
|
||||||
isteqi(ctx.value, ist("s-maxage=0"))) {
|
|
||||||
txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* We might have a no-cache="set-cookie" form. */
|
/* We might have a no-cache="set-cookie" form. */
|
||||||
if (istmatchi(ctx.value, ist("no-cache=\"set-cookie"))) {
|
if (isteqi(ctx.value, ist("no-cache=\"set-cookie\""))) {
|
||||||
txn->flags &= ~TX_CACHE_COOK;
|
txn->flags &= ~TX_CACHE_COOK;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isteqi(ctx.value, ist("private")) || istmatchi(ctx.value, ist("private=")) ||
|
||||||
|
isteqi(ctx.value, ist("no-cache")) || istmatchi(ctx.value, ist("no-cache=")) ||
|
||||||
|
isteqi(ctx.value, ist("no-store")) || istmatchi(ctx.value, ist("no-store=")) ||
|
||||||
|
isteqi(ctx.value, ist("s-maxage=0"))) {
|
||||||
|
txn->flags &= ~TX_CACHEABLE & ~TX_CACHE_COOK;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (istmatchi(ctx.value, ist("s-maxage"))) {
|
if (istmatchi(ctx.value, ist("s-maxage"))) {
|
||||||
has_freshness_info = 1;
|
has_freshness_info = 1;
|
||||||
has_null_maxage = 0; /* The null max-age is overridden, ignore it */
|
has_null_maxage = 0; /* The null max-age is overridden, ignore it */
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ static int sample_conv_url_dec(const struct arg *args, struct sample *smp, void
|
||||||
* before decoding.
|
* before decoding.
|
||||||
*/
|
*/
|
||||||
if (smp->flags & SMP_F_CONST || smp->data.u.str.size <= smp->data.u.str.data) {
|
if (smp->flags & SMP_F_CONST || smp->data.u.str.size <= smp->data.u.str.data) {
|
||||||
struct buffer *str = get_trash_chunk_sz(smp->data.u.str.data);
|
struct buffer *str = get_trash_chunk_sz(smp->data.u.str.data + 1);
|
||||||
|
|
||||||
if (!str)
|
if (!str)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,7 @@ static inline int http_7239_extract_node(struct ist *input, struct forwarded_hea
|
||||||
if (!quoted)
|
if (!quoted)
|
||||||
return 0; /* not supported */
|
return 0; /* not supported */
|
||||||
*input = istnext(*input);
|
*input = istnext(*input);
|
||||||
if (!http_7239_extract_nodeport(input, nodeport))
|
if (!istlen(*input) || !http_7239_extract_nodeport(input, nodeport))
|
||||||
return 0; /* invalid nodeport */
|
return 0; /* invalid nodeport */
|
||||||
out:
|
out:
|
||||||
/* ok */
|
/* ok */
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ static int get_http_auth(struct sample *smp, struct htx *htx)
|
||||||
|
|
||||||
chunk_initlen(&txn->auth.method_data, p, 0, istend(ctx.value) - p);
|
chunk_initlen(&txn->auth.method_data, p, 0, istend(ctx.value) - p);
|
||||||
|
|
||||||
if (!strncasecmp("Basic", auth_method.area, auth_method.data)) {
|
if (isteqi(ist2(auth_method.area, auth_method.data), ist("Basic"))) {
|
||||||
struct buffer *http_auth = get_trash_chunk();
|
struct buffer *http_auth = get_trash_chunk();
|
||||||
|
|
||||||
len = base64dec(txn->auth.method_data.area,
|
len = base64dec(txn->auth.method_data.area,
|
||||||
|
|
@ -159,7 +159,7 @@ static int get_http_auth(struct sample *smp, struct htx *htx)
|
||||||
|
|
||||||
txn->auth.method = HTTP_AUTH_BASIC;
|
txn->auth.method = HTTP_AUTH_BASIC;
|
||||||
return 1;
|
return 1;
|
||||||
} else if (!strncasecmp("Bearer", auth_method.area, auth_method.data)) {
|
} else if (isteqi(ist2(auth_method.area, auth_method.data), ist("Bearer"))) {
|
||||||
txn->auth.method = HTTP_AUTH_BEARER;
|
txn->auth.method = HTTP_AUTH_BEARER;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1298,7 +1298,7 @@ void mworker_apply_master_worker_mode(void)
|
||||||
|
|
||||||
/* This one must not be exported, it's internal! */
|
/* This one must not be exported, it's internal! */
|
||||||
unsetenv("HAPROXY_MWORKER_REEXEC");
|
unsetenv("HAPROXY_MWORKER_REEXEC");
|
||||||
ha_random_jump96(1);
|
ha_random_jump128(1);
|
||||||
|
|
||||||
list_for_each_entry(child, &proc_list, list) {
|
list_for_each_entry(child, &proc_list, list) {
|
||||||
if ((child->options & PROC_O_TYPE_WORKER) && (child->options & PROC_O_INIT)) {
|
if ((child->options & PROC_O_TYPE_WORKER) && (child->options & PROC_O_INIT)) {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,9 @@ smp_client_hello_parse( struct sample *smp, enum client_hello_type type, unsigne
|
||||||
data += 5; /* enter TLS handshake */
|
data += 5; /* enter TLS handshake */
|
||||||
bleft -= 5;
|
bleft -= 5;
|
||||||
|
|
||||||
|
if (bleft < hs_len)
|
||||||
|
goto too_short;
|
||||||
|
|
||||||
/* Check for a complete client hello starting at <data> */
|
/* Check for a complete client hello starting at <data> */
|
||||||
if (bleft < 1)
|
if (bleft < 1)
|
||||||
goto too_short;
|
goto too_short;
|
||||||
|
|
@ -129,15 +132,18 @@ smp_client_hello_parse( struct sample *smp, enum client_hello_type type, unsigne
|
||||||
if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
|
if (hs_len < 2 + 32 + 1 + 2 + 2 + 1 + 1 + 2 + 2)
|
||||||
goto not_ssl_hello; /* too short to have an extension */
|
goto not_ssl_hello; /* too short to have an extension */
|
||||||
|
|
||||||
|
data += 4;
|
||||||
|
bleft -= 4;
|
||||||
|
|
||||||
/* We want the full handshake here */
|
/* We want the full handshake here */
|
||||||
if (bleft < hs_len)
|
if (bleft < hs_len)
|
||||||
goto too_short;
|
goto too_short;
|
||||||
|
|
||||||
data += 4;
|
|
||||||
/* Start of the ClientHello message */
|
/* Start of the ClientHello message */
|
||||||
if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
|
if (data[0] < 0x03 || data[1] < 0x01) /* TLSv1 minimum */
|
||||||
goto not_ssl_hello;
|
goto not_ssl_hello;
|
||||||
|
|
||||||
|
/* Note: covered by the hs_len test 30 lines above */
|
||||||
ext_len = data[34]; /* session_id_len */
|
ext_len = data[34]; /* session_id_len */
|
||||||
if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
|
if (ext_len > 32 || ext_len > (hs_len - 35)) /* check for correct session_id len */
|
||||||
goto not_ssl_hello;
|
goto not_ssl_hello;
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,11 +188,10 @@ int qcc_qmux_recv(struct qcc *qcc)
|
||||||
buf_rec = b_make(b_orig(buf), b_size(buf),
|
buf_rec = b_make(b_orig(buf), b_size(buf),
|
||||||
b_head_ofs(buf), qcc->rx.rlen);
|
b_head_ofs(buf), qcc->rx.rlen);
|
||||||
frm_ret = qmux_parse_frm(qcc, &buf_rec);
|
frm_ret = qmux_parse_frm(qcc, &buf_rec);
|
||||||
|
|
||||||
BUG_ON(frm_ret < 0); /* TODO handle fatal errors */
|
|
||||||
if (!frm_ret) {
|
if (!frm_ret) {
|
||||||
/* emit FRAME_ENCODING_ERROR */
|
/* TODO implement proper connection closure */
|
||||||
ABORT_NOW();
|
conn->flags |= CO_FL_ERROR;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A frame cannot be bigger than a record thanks to <buf_rec> delimitation. */
|
/* A frame cannot be bigger than a record thanks to <buf_rec> delimitation. */
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,10 @@ int quic_generate_token(unsigned char *token, size_t len,
|
||||||
unsigned char aad[sizeof(struct in6_addr)];
|
unsigned char aad[sizeof(struct in6_addr)];
|
||||||
size_t aadlen;
|
size_t aadlen;
|
||||||
uint32_t ts = (uint32_t)date.tv_sec;
|
uint32_t ts = (uint32_t)date.tv_sec;
|
||||||
uint64_t rand_u64;
|
union {
|
||||||
unsigned char rand[QUIC_TOKEN_RAND_DLEN];
|
uint64_t u64[2];
|
||||||
|
uchar u8[QUIC_TOKEN_RAND_DLEN];
|
||||||
|
} rand;
|
||||||
unsigned char key[16];
|
unsigned char key[16];
|
||||||
unsigned char iv[QUIC_TLS_IV_LEN];
|
unsigned char iv[QUIC_TLS_IV_LEN];
|
||||||
const unsigned char *sec = global.cluster_secret;
|
const unsigned char *sec = global.cluster_secret;
|
||||||
|
|
@ -35,10 +37,7 @@ int quic_generate_token(unsigned char *token, size_t len,
|
||||||
TRACE_ENTER(QUIC_EV_CONN_TXPKT);
|
TRACE_ENTER(QUIC_EV_CONN_TXPKT);
|
||||||
|
|
||||||
/* Generate random data to be used as salt to derive the token secret. */
|
/* Generate random data to be used as salt to derive the token secret. */
|
||||||
rand_u64 = ha_random64();
|
ha_random64_pair_hashed(&rand.u64[0], &rand.u64[1]);
|
||||||
write_u64(rand, rand_u64);
|
|
||||||
rand_u64 = ha_random64();
|
|
||||||
write_u64(rand + sizeof(rand_u64), rand_u64);
|
|
||||||
|
|
||||||
if (len < QUIC_TOKEN_LEN) {
|
if (len < QUIC_TOKEN_LEN) {
|
||||||
TRACE_ERROR("too small buffer", QUIC_EV_CONN_TXPKT);
|
TRACE_ERROR("too small buffer", QUIC_EV_CONN_TXPKT);
|
||||||
|
|
@ -48,7 +47,7 @@ int quic_generate_token(unsigned char *token, size_t len,
|
||||||
/* Generate the AAD. */
|
/* Generate the AAD. */
|
||||||
aadlen = ipaddrcpy(aad, addr);
|
aadlen = ipaddrcpy(aad, addr);
|
||||||
if (!quic_tls_derive_token_secret(EVP_sha256(), key, sizeof key,
|
if (!quic_tls_derive_token_secret(EVP_sha256(), key, sizeof key,
|
||||||
iv, sizeof iv, rand, sizeof(rand),
|
iv, sizeof iv, rand.u8, sizeof(rand.u8),
|
||||||
sec, seclen)) {
|
sec, seclen)) {
|
||||||
TRACE_ERROR("quic_tls_derive_token_secret() failed", QUIC_EV_CONN_TXPKT);
|
TRACE_ERROR("quic_tls_derive_token_secret() failed", QUIC_EV_CONN_TXPKT);
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -71,8 +70,8 @@ int quic_generate_token(unsigned char *token, size_t len,
|
||||||
}
|
}
|
||||||
|
|
||||||
p += QUIC_TLS_TAG_LEN;
|
p += QUIC_TLS_TAG_LEN;
|
||||||
memcpy(p, rand, sizeof(rand));
|
memcpy(p, rand.u8, sizeof(rand.u8));
|
||||||
p += sizeof(rand);
|
p += sizeof(rand.u8);
|
||||||
|
|
||||||
ret = p - token;
|
ret = p - token;
|
||||||
leave:
|
leave:
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ struct list resolv_srvrq_list = LIST_HEAD_INIT(resolv_srvrq_list);
|
||||||
|
|
||||||
static THREAD_LOCAL struct list death_row; /* list of deferred resolutions to kill, local validity only */
|
static THREAD_LOCAL struct list death_row; /* list of deferred resolutions to kill, local validity only */
|
||||||
static THREAD_LOCAL unsigned int recurse = 0; /* counter to track calls to public functions */
|
static THREAD_LOCAL unsigned int recurse = 0; /* counter to track calls to public functions */
|
||||||
static THREAD_LOCAL uint64_t resolv_query_id_seed = 0; /* random seed */
|
|
||||||
struct resolvers *curr_resolvers = NULL;
|
struct resolvers *curr_resolvers = NULL;
|
||||||
|
|
||||||
DECLARE_STATIC_TYPED_POOL(resolv_answer_item_pool, "resolv_answer_item", struct resolv_answer_item);
|
DECLARE_STATIC_TYPED_POOL(resolv_answer_item_pool, "resolv_answer_item", struct resolv_answer_item);
|
||||||
|
|
@ -226,7 +225,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.
|
||||||
*/
|
*/
|
||||||
|
|
@ -365,18 +364,6 @@ struct resolv_answer_item *find_srvrq_answer_record(const struct resolv_requeste
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2 bytes random generator to generate DNS query ID */
|
|
||||||
static inline uint16_t resolv_rnd16(void)
|
|
||||||
{
|
|
||||||
if (!resolv_query_id_seed)
|
|
||||||
resolv_query_id_seed = now_ms;
|
|
||||||
resolv_query_id_seed ^= resolv_query_id_seed << 13;
|
|
||||||
resolv_query_id_seed ^= resolv_query_id_seed >> 7;
|
|
||||||
resolv_query_id_seed ^= resolv_query_id_seed << 17;
|
|
||||||
return resolv_query_id_seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline int resolv_resolution_timeout(struct resolv_resolution *res)
|
static inline int resolv_resolution_timeout(struct resolv_resolution *res)
|
||||||
{
|
{
|
||||||
return (!LIST_ISEMPTY(&res->requesters) ? res->resolvers->timeout.resolve : res->resolvers->hold.valid);
|
return (!LIST_ISEMPTY(&res->requesters) ? res->resolvers->timeout.resolve : res->resolvers->hold.valid);
|
||||||
|
|
@ -509,14 +496,14 @@ 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;
|
||||||
|
|
||||||
/* Generates a new query id. We try at most 100 times to find a free
|
/* Generates a new query id. We try at most 100 times to find a free
|
||||||
* query id */
|
* query id */
|
||||||
for (i = 0; i < 100; ++i) {
|
for (i = 0; i < 100; ++i) {
|
||||||
query_id = resolv_rnd16();
|
query_id = (uint16_t)ha_random32();
|
||||||
if (!eb32_lookup(&resolvers->query_ids, query_id))
|
if (!eb32_lookup(&resolvers->query_ids, query_id))
|
||||||
break;
|
break;
|
||||||
query_id = -1;
|
query_id = -1;
|
||||||
|
|
@ -1236,8 +1223,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 */
|
||||||
|
|
@ -1436,7 +1422,7 @@ static int resolv_validate_dns_response(unsigned char *resp, unsigned char *bufe
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
goto invalid_resp;
|
goto invalid_resp;
|
||||||
|
|
||||||
if (reader + offset + 10 >= bufend)
|
if (reader + offset + 10 > bufend)
|
||||||
goto invalid_resp;
|
goto invalid_resp;
|
||||||
|
|
||||||
reader += offset;
|
reader += offset;
|
||||||
|
|
@ -1450,7 +1436,7 @@ static int resolv_validate_dns_response(unsigned char *resp, unsigned char *bufe
|
||||||
len = reader[0] * 256 + reader[1];
|
len = reader[0] * 256 + reader[1];
|
||||||
reader += 2;
|
reader += 2;
|
||||||
|
|
||||||
if (reader + len >= bufend)
|
if (reader + len > bufend)
|
||||||
goto invalid_resp;
|
goto invalid_resp;
|
||||||
|
|
||||||
reader += len;
|
reader += len;
|
||||||
|
|
@ -1498,8 +1484,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 +1584,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 +1839,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;
|
||||||
|
|
|
||||||
|
|
@ -448,6 +448,7 @@ sni_lookup:
|
||||||
for (i = 0; i < trash.size && i < servername_len; i++)
|
for (i = 0; i < trash.size && i < servername_len; i++)
|
||||||
trash.area[i] = tolower((unsigned char)servername[i]);
|
trash.area[i] = tolower((unsigned char)servername[i]);
|
||||||
trash.area[i] = 0;
|
trash.area[i] = 0;
|
||||||
|
servername = trash.area;
|
||||||
|
|
||||||
HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
|
HA_RWLOCK_RDLOCK(SNI_LOCK, &s->sni_lock);
|
||||||
sni_ctx = ssl_sock_choose_sni_ctx(s, conn, trash.area, has_rsa_sig, has_ecdsa_sig);
|
sni_ctx = ssl_sock_choose_sni_ctx(s, conn, trash.area, has_rsa_sig, has_ecdsa_sig);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
234
src/tools.c
234
src/tools.c
|
|
@ -6235,48 +6235,106 @@ int varint_bytes(uint64_t v)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* secret used for XXH hash involved in PRNG */
|
||||||
|
static char ha_random_xxh_secret[XXH3_SECRET_DEFAULT_SIZE] ALIGNED(64);
|
||||||
|
|
||||||
/* Random number generator state, see below */
|
/* 2^256 sequnce thread-local PRNG state known as "XOSHIRO256**".
|
||||||
static uint64_t ha_random_state[2] ALIGNED(2*sizeof(uint64_t));
|
* See details here:
|
||||||
|
* https://prng.di.unimi.it/
|
||||||
/* This is a thread-safe implementation of xoroshiro128** described below:
|
* https://prng.di.unimi.it/xoshiro256starstar.c
|
||||||
* http://prng.di.unimi.it/
|
* It features a 2^256 long sequence, returns 64 high-quality bits on each call,
|
||||||
* It features a 2^128 long sequence, returns 64 high-quality bits on each call,
|
* supports fast jumps and passes all common quality tests. Supporting 128-bit
|
||||||
* supports fast jumps and passes all common quality tests. It is thread-safe,
|
* jumps, it allows to run thread-local with non-overlapping sequences. It must
|
||||||
* uses a double-cas on 64-bit architectures supporting it, and falls back to a
|
* be seeded otherwise the ratio of zeroes is a bit high initially.
|
||||||
* local lock on other ones.
|
|
||||||
*/
|
*/
|
||||||
uint64_t ha_random64()
|
static THREAD_LOCAL uint64_t ha_random_state[4];
|
||||||
|
|
||||||
|
/* Returns the next 64-bit PRNG number from the thread-local 256-bit state and
|
||||||
|
* makes the internal state progress by one step. This is meant to be used by
|
||||||
|
* other local functions. Since its discloses the PRNG's internal state, it
|
||||||
|
* must not be called to produce externally visible randoms.
|
||||||
|
*/
|
||||||
|
static inline uint64_t _ha_random64_internal(void)
|
||||||
{
|
{
|
||||||
uint64_t old[2] ALIGNED(2*sizeof(uint64_t));
|
const uint64_t result = rotl64(ha_random_state[1] * 5, 7) * 9;
|
||||||
uint64_t new[2] ALIGNED(2*sizeof(uint64_t));
|
const uint64_t t = ha_random_state[1] << 17;
|
||||||
|
|
||||||
#if defined(USE_THREAD) && (!defined(HA_CAS_IS_8B) || !defined(HA_HAVE_CAS_DW))
|
ha_random_state[2] ^= ha_random_state[0];
|
||||||
static HA_SPINLOCK_T rand_lock;
|
ha_random_state[3] ^= ha_random_state[1];
|
||||||
|
ha_random_state[1] ^= ha_random_state[2];
|
||||||
|
ha_random_state[0] ^= ha_random_state[3];
|
||||||
|
ha_random_state[2] ^= t;
|
||||||
|
ha_random_state[3] = rotl64(ha_random_state[3], 45);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
HA_SPIN_LOCK(OTHER_LOCK, &rand_lock);
|
/* Returns the next 64-bit PRNG number from the thread-local 256-bit state and
|
||||||
#endif
|
* makes the internal state progress by one step. Since its discloses the PRNG's
|
||||||
|
* internal state, it must not be called to produce externally visible randoms.
|
||||||
|
*/
|
||||||
|
uint64_t ha_random64_internal(void)
|
||||||
|
{
|
||||||
|
return _ha_random64_internal();
|
||||||
|
}
|
||||||
|
|
||||||
old[0] = ha_random_state[0];
|
/* This function uses a pre-calculated jump table to of 4 uint64_t to perform a
|
||||||
old[1] = ha_random_state[1];
|
* jump equivalent to multiple calls to ha_random_next(). It shouldn't be
|
||||||
|
* used directly but only from the next functions.
|
||||||
|
*/
|
||||||
|
static void _ha_random_jump(const uint64_t *table)
|
||||||
|
{
|
||||||
|
uint64_t s0, s1, s2, s3;
|
||||||
|
uint i, j;
|
||||||
|
|
||||||
#if defined(USE_THREAD) && defined(HA_CAS_IS_8B) && defined(HA_HAVE_CAS_DW)
|
s0 = s1 = s2 = s3 = 0;
|
||||||
do {
|
for (i = 0; i < 4; i++) {
|
||||||
#endif
|
for (j = 0; j < 64; j++) {
|
||||||
new[1] = old[0] ^ old[1];
|
if (table[i] & (1ULL << j)) {
|
||||||
new[0] = rotl64(old[0], 24) ^ new[1] ^ (new[1] << 16); // a, b
|
s0 ^= ha_random_state[0];
|
||||||
new[1] = rotl64(new[1], 37); // c
|
s1 ^= ha_random_state[1];
|
||||||
|
s2 ^= ha_random_state[2];
|
||||||
|
s3 ^= ha_random_state[3];
|
||||||
|
}
|
||||||
|
ha_random64_internal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(USE_THREAD) && defined(HA_CAS_IS_8B) && defined(HA_HAVE_CAS_DW)
|
ha_random_state[0] = s0;
|
||||||
} while (unlikely(!_HA_ATOMIC_DWCAS(ha_random_state, old, new)));
|
ha_random_state[1] = s1;
|
||||||
#else
|
ha_random_state[2] = s2;
|
||||||
ha_random_state[0] = new[0];
|
ha_random_state[3] = s3;
|
||||||
ha_random_state[1] = new[1];
|
}
|
||||||
#if defined(USE_THREAD)
|
|
||||||
HA_SPIN_UNLOCK(OTHER_LOCK, &rand_lock);
|
/* This function is equivalent to calling <dist> times 2^128 calls to
|
||||||
#endif
|
* ha_random_next(). It can be used to generate 2^128 non-overlapping
|
||||||
#endif
|
* sequences. The <dist> argument is the distance to jump to and is used
|
||||||
return rotl64(old[0] * 5, 7) * 9;
|
* in a loop so it rather not be too large if the processing time is a
|
||||||
|
* concern. It only applies to the current thread. Note that <dist> may
|
||||||
|
* not be zero.
|
||||||
|
*/
|
||||||
|
void ha_random_jump128(uint32_t dist)
|
||||||
|
{
|
||||||
|
static const uint64_t table[] = { 0x180ec6d33cfd0aba, 0xd5a61266f0c9392c, 0xa9582618e03fc9aa, 0x39abdc4529b1661c };
|
||||||
|
|
||||||
|
BUG_ON(!dist);
|
||||||
|
while (dist--)
|
||||||
|
_ha_random_jump(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is equivalent to calling <dist> times 2^192 calls to
|
||||||
|
* ha_random_next(). It can be used to generate 2^64 non-overlapping
|
||||||
|
* sequences. The <dist> argument is the distance to jump to and is used
|
||||||
|
* in a loop so it rather not be too large if the processing time is a
|
||||||
|
* concern. It only applies to the current thread. Note that <dist> may
|
||||||
|
* not be zero.
|
||||||
|
*/
|
||||||
|
void ha_random_jump192(uint32_t dist)
|
||||||
|
{
|
||||||
|
static const uint64_t table[] = { 0x76e15d3efefdcbbf, 0xc5004e441c522fb3, 0x77710069854ee241, 0x39109bb02acbe635 };
|
||||||
|
|
||||||
|
BUG_ON(!dist);
|
||||||
|
while (dist--)
|
||||||
|
_ha_random_jump(table);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* seeds the random state using up to <len> bytes from <seed>, starting with
|
/* seeds the random state using up to <len> bytes from <seed>, starting with
|
||||||
|
|
@ -6306,43 +6364,49 @@ void ha_random_seed(const unsigned char *seed, size_t len)
|
||||||
len = sizeof(ha_random_state);
|
len = sizeof(ha_random_state);
|
||||||
|
|
||||||
memcpy(ha_random_state, seed, len);
|
memcpy(ha_random_state, seed, len);
|
||||||
|
|
||||||
|
/* also initialize the secret table used by XXH3 */
|
||||||
|
XXH3_generateSecret(ha_random_xxh_secret, sizeof(ha_random_xxh_secret), seed, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This causes a jump to (dist * 2^96) places in the pseudo-random sequence,
|
/* Seed the PRNG for the current thread */
|
||||||
* and is equivalent to calling ha_random64() as many times. It is used to
|
void ha_random_seed_thread(void)
|
||||||
* provide non-overlapping sequences of 2^96 numbers (~7*10^28) to up to 2^32
|
|
||||||
* different generators (i.e. different processes after a fork). The <dist>
|
|
||||||
* argument is the distance to jump to and is used in a loop so it rather not
|
|
||||||
* be too large if the processing time is a concern.
|
|
||||||
*
|
|
||||||
* BEWARE: this function is NOT thread-safe and must not be called during
|
|
||||||
* concurrent accesses to ha_random64().
|
|
||||||
*/
|
|
||||||
void ha_random_jump96(uint32_t dist)
|
|
||||||
{
|
{
|
||||||
while (dist--) {
|
/* seed already done for first thread, but jump still necessary */
|
||||||
uint64_t s0 = 0;
|
if (tid > 0)
|
||||||
uint64_t s1 = 0;
|
ha_random_seed(boot_seed, sizeof(boot_seed));
|
||||||
int b;
|
ha_random_jump192(tid + 1);
|
||||||
|
}
|
||||||
|
|
||||||
for (b = 0; b < 64; b++) {
|
/* Returns a uint64_t random hashed so as not to disclose the internal PRNG
|
||||||
if ((0xd2a98b26625eee7bULL >> b) & 1) {
|
* state. The function uses a local XXH secret that is created at boot, and
|
||||||
s0 ^= ha_random_state[0];
|
* now_ns as the seed to limit remote analysis.
|
||||||
s1 ^= ha_random_state[1];
|
*/
|
||||||
}
|
uint64_t ha_random64(void)
|
||||||
ha_random64();
|
{
|
||||||
}
|
uint64_t ret;
|
||||||
|
|
||||||
for (b = 0; b < 64; b++) {
|
ret = _ha_random64_internal();
|
||||||
if ((0xdddf9b1090aa7ac1ULL >> b) & 1) {
|
return XXH3_64bits_withSecretandSeed(&ret, sizeof(ret),
|
||||||
s0 ^= ha_random_state[0];
|
ha_random_xxh_secret, sizeof(ha_random_xxh_secret),
|
||||||
s1 ^= ha_random_state[1];
|
now_ns);
|
||||||
}
|
}
|
||||||
ha_random64();
|
|
||||||
}
|
/* Returns a pair of uint64_t randoms hashed so as not to disclose the internal
|
||||||
ha_random_state[0] = s0;
|
* PRNG state. This function shouldn't be used directly, better use the public
|
||||||
ha_random_state[1] = s1;
|
* ha_random64_pair_hashed() which calls it. The function uses a local XXH
|
||||||
}
|
* secret that is created at boot, and now_ns as the seed to limit remote
|
||||||
|
* analysis.
|
||||||
|
*/
|
||||||
|
struct uint64_pair _ha_random64_pair_hashed(void)
|
||||||
|
{
|
||||||
|
XXH128_hash_t ret;
|
||||||
|
ret = XXH3_128bits_withSecretandSeed(ha_random_state, 2*sizeof(uint64_t),
|
||||||
|
ha_random_xxh_secret, sizeof(ha_random_xxh_secret),
|
||||||
|
now_ns);
|
||||||
|
/* update the internal state */
|
||||||
|
_ha_random64_internal();
|
||||||
|
return (struct uint64_pair){ .l = ret.low64, .h = ret.high64 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generates an RFC 9562 version 4 UUID into chunk
|
/* Generates an RFC 9562 version 4 UUID into chunk
|
||||||
|
|
@ -6350,23 +6414,15 @@ void ha_random_jump96(uint32_t dist)
|
||||||
*/
|
*/
|
||||||
void ha_generate_uuid_v4(struct buffer *output)
|
void ha_generate_uuid_v4(struct buffer *output)
|
||||||
{
|
{
|
||||||
uint32_t rnd[4];
|
uint64_t l, h;
|
||||||
uint64_t last;
|
|
||||||
|
|
||||||
last = ha_random64();
|
|
||||||
rnd[0] = last;
|
|
||||||
rnd[1] = last >> 32;
|
|
||||||
|
|
||||||
last = ha_random64();
|
|
||||||
rnd[2] = last;
|
|
||||||
rnd[3] = last >> 32;
|
|
||||||
|
|
||||||
|
ha_random64_pair_hashed(&l, &h);
|
||||||
chunk_printf(output, "%8.8x-%4.4x-%4.4x-%4.4x-%12.12llx",
|
chunk_printf(output, "%8.8x-%4.4x-%4.4x-%4.4x-%12.12llx",
|
||||||
rnd[0],
|
(uint)l,
|
||||||
rnd[1] & 0xFFFF,
|
(uint)(l >> 32) & 0xFFFF,
|
||||||
((rnd[1] >> 16u) & 0xFFF) | 0x4000, // highest 4 bits indicate the uuid version
|
(uint)((l >> 48) & 0xFFF) | 0x4000, // highest 4 bits indicate the uuid version
|
||||||
(rnd[2] & 0x3FFF) | 0x8000, // the highest 2 bits indicate the UUID variant (10),
|
(uint)(h & 0x3FFF) | 0x8000, // the highest 2 bits indicate the UUID variant (10),
|
||||||
(long long)((rnd[2] >> 14u) | ((uint64_t) rnd[3] << 18u)) & 0xFFFFFFFFFFFFull);
|
(long long)(rotl64(h, 50) & 0xFFFFFFFFFFFFull));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generates an RFC 9562 version 7 UUID into chunk
|
/* Generates an RFC 9562 version 7 UUID into chunk
|
||||||
|
|
@ -6374,24 +6430,18 @@ void ha_generate_uuid_v4(struct buffer *output)
|
||||||
*/
|
*/
|
||||||
void ha_generate_uuid_v7(struct buffer *output)
|
void ha_generate_uuid_v7(struct buffer *output)
|
||||||
{
|
{
|
||||||
uint32_t rnd[3];
|
uint64_t l, h;
|
||||||
uint64_t last;
|
|
||||||
uint64_t time;
|
uint64_t time;
|
||||||
|
|
||||||
time = (date.tv_sec * 1000) + (date.tv_usec / 1000);
|
time = (date.tv_sec * 1000) + (date.tv_usec / 1000);
|
||||||
last = ha_random64();
|
|
||||||
rnd[0] = last;
|
|
||||||
rnd[1] = last >> 32;
|
|
||||||
|
|
||||||
last = ha_random64();
|
|
||||||
rnd[2] = last;
|
|
||||||
|
|
||||||
|
ha_random64_pair_hashed(&l, &h);
|
||||||
chunk_printf(output, "%8.8x-%4.4x-%4.4x-%4.4x-%12.12llx",
|
chunk_printf(output, "%8.8x-%4.4x-%4.4x-%4.4x-%12.12llx",
|
||||||
(uint)(time >> 16u),
|
(uint)(time >> 16u),
|
||||||
(uint)(time & 0xFFFF),
|
(uint)(time & 0xFFFF),
|
||||||
((rnd[0] >> 16u) & 0xFFF) | 0x7000, // highest 4 bits indicate the uuid version
|
(uint)((l >> 16) & 0xFFF) | 0x7000, // highest 4 bits indicate the uuid version
|
||||||
(rnd[1] & 0x3FFF) | 0x8000, // the highest 2 bits indicate the UUID variant (10),
|
(uint)(h & 0x3FFF) | 0x8000, // the highest 2 bits indicate the UUID variant (10),
|
||||||
(long long)((rnd[1] >> 14u) | ((uint64_t) rnd[2] << 18u)) & 0xFFFFFFFFFFFFull);
|
(long long)(rotl64(h, 50) & 0xFFFFFFFFFFFFull));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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