mirror of
https://github.com/nginx/nginx.git
synced 2025-08-06 06:46:16 +08:00
Moved all QUIC code into ngx_event_quic.c
Introduced ngx_quic_input() and ngx_quic_output() as interface between nginx and protocol. They are the only functions that are exported. While there, added copyrights.
This commit is contained in:
parent
8993721298
commit
b20ed8f7f1
@ -90,328 +90,6 @@ static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
static void ngx_openssl_exit(ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
#if NGX_OPENSSL_QUIC
|
||||
|
||||
static int
|
||||
quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, const uint8_t *read_secret,
|
||||
const uint8_t *write_secret, size_t secret_len)
|
||||
{
|
||||
u_char *name;
|
||||
ngx_uint_t i;
|
||||
const EVP_MD *digest;
|
||||
const EVP_CIPHER *cipher;
|
||||
ngx_connection_t *c;
|
||||
ngx_quic_secret_t *client, *server;
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
|
||||
ngx_ssl_handshake_log(c);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
u_char buf[64];
|
||||
size_t m;
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) read_secret, secret_len) - buf;
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"set_encryption_secrets: read %*s, len: %uz, level:%d",
|
||||
m, buf, secret_len, (int) level);
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) write_secret, secret_len) - buf;
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"set_encryption_secrets: write %*s, len: %uz, level:%d",
|
||||
m, buf, secret_len, (int) level);
|
||||
}
|
||||
#endif
|
||||
|
||||
name = (u_char *) SSL_get_cipher(ssl_conn);
|
||||
|
||||
if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0
|
||||
|| ngx_strcasecmp(name, (u_char *) "(NONE)") == 0)
|
||||
{
|
||||
cipher = EVP_aes_128_gcm();
|
||||
digest = EVP_sha256();
|
||||
|
||||
} else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) {
|
||||
cipher = EVP_aes_256_gcm();
|
||||
digest = EVP_sha384();
|
||||
|
||||
} else {
|
||||
ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher");
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (level) {
|
||||
|
||||
case ssl_encryption_handshake:
|
||||
client = &c->quic->client_hs;
|
||||
server = &c->quic->server_hs;
|
||||
|
||||
break;
|
||||
|
||||
case ssl_encryption_application:
|
||||
client = &c->quic->client_ad;
|
||||
server = &c->quic->server_ad;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
client->key.len = EVP_CIPHER_key_length(cipher);
|
||||
server->key.len = EVP_CIPHER_key_length(cipher);
|
||||
|
||||
client->iv.len = EVP_CIPHER_iv_length(cipher);
|
||||
server->iv.len = EVP_CIPHER_iv_length(cipher);
|
||||
|
||||
client->hp.len = EVP_CIPHER_key_length(cipher);
|
||||
server->hp.len = EVP_CIPHER_key_length(cipher);
|
||||
|
||||
struct {
|
||||
ngx_str_t label;
|
||||
ngx_str_t *key;
|
||||
const uint8_t *secret;
|
||||
} seq[] = {
|
||||
{ ngx_string("tls13 quic key"), &client->key, read_secret },
|
||||
{ ngx_string("tls13 quic iv"), &client->iv, read_secret },
|
||||
{ ngx_string("tls13 quic hp"), &client->hp, read_secret },
|
||||
{ ngx_string("tls13 quic key"), &server->key, write_secret },
|
||||
{ ngx_string("tls13 quic iv"), &server->iv, write_secret },
|
||||
{ ngx_string("tls13 quic hp"), &server->hp, write_secret },
|
||||
};
|
||||
|
||||
for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) {
|
||||
|
||||
if (ngx_quic_hkdf_expand(c, digest, seq[i].key, &seq[i].label,
|
||||
seq[i].secret, secret_len)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
|
||||
enum ssl_encryption_level_t level, const uint8_t *data, size_t len)
|
||||
{
|
||||
u_char *p, *pnp, *name, *nonce, *sample;
|
||||
ngx_int_t m;
|
||||
ngx_str_t in, out, ad;
|
||||
static int pn;
|
||||
const EVP_CIPHER *cipher;
|
||||
ngx_connection_t *c;
|
||||
ngx_quic_secret_t *secret;
|
||||
ngx_quic_connection_t *qc;
|
||||
u_char buf[2048], mask[16];
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
qc = c->quic;
|
||||
|
||||
ngx_ssl_handshake_log(c);
|
||||
|
||||
switch (level) {
|
||||
|
||||
case ssl_encryption_initial:
|
||||
secret = &qc->server_in;
|
||||
break;
|
||||
|
||||
case ssl_encryption_handshake:
|
||||
secret = &qc->server_hs;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) data, ngx_min(len, 1024)) - buf;
|
||||
ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data: %*s%s, len: %uz, level:%d",
|
||||
m, buf, len < 2048 ? "" : "...", len, (int) level);
|
||||
|
||||
in.data = ngx_alloc(4 + len + 5 /*minimal ACK*/, c->log);
|
||||
if (in.data == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = in.data;
|
||||
ngx_quic_build_int(&p, 6); // crypto frame
|
||||
ngx_quic_build_int(&p, 0);
|
||||
ngx_quic_build_int(&p, len);
|
||||
p = ngx_cpymem(p, data, len);
|
||||
|
||||
if (level == ssl_encryption_initial) {
|
||||
ngx_quic_build_int(&p, 2); // ack frame
|
||||
ngx_quic_build_int(&p, 0);
|
||||
ngx_quic_build_int(&p, 0);
|
||||
ngx_quic_build_int(&p, 0);
|
||||
ngx_quic_build_int(&p, 0);
|
||||
}
|
||||
|
||||
in.len = p - in.data;
|
||||
out.len = in.len + EVP_GCM_TLS_TAG_LEN;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data: clear_len:%uz, ciphertext_len:%uz",
|
||||
in.len, out.len);
|
||||
|
||||
ad.data = ngx_alloc(346 /*max header*/, c->log);
|
||||
if (ad.data == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = ad.data;
|
||||
if (level == ssl_encryption_initial) {
|
||||
*p++ = 0xc0; // initial, packet number len
|
||||
} else if (level == ssl_encryption_handshake) {
|
||||
*p++ = 0xe0; // handshake, packet number len
|
||||
}
|
||||
p = ngx_quic_write_uint32(p, quic_version);
|
||||
*p++ = qc->scid.len;
|
||||
p = ngx_cpymem(p, qc->scid.data, qc->scid.len);
|
||||
*p++ = qc->dcid.len;
|
||||
p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len);
|
||||
if (level == ssl_encryption_initial) {
|
||||
ngx_quic_build_int(&p, 0); // token length
|
||||
}
|
||||
ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl)
|
||||
pnp = p;
|
||||
|
||||
if (level == ssl_encryption_initial) {
|
||||
*p++ = 0; // packet number 0
|
||||
|
||||
} else if (level == ssl_encryption_handshake) {
|
||||
*p++ = pn++;
|
||||
}
|
||||
|
||||
ad.len = p - ad.data;
|
||||
|
||||
m = ngx_hex_dump(buf, ad.data, ad.len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data ad: %*s, len: %uz",
|
||||
m, buf, ad.len);
|
||||
|
||||
|
||||
name = (u_char *) SSL_get_cipher(ssl_conn);
|
||||
|
||||
if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0
|
||||
|| ngx_strcasecmp(name, (u_char *) "(NONE)") == 0)
|
||||
{
|
||||
cipher = EVP_aes_128_gcm();
|
||||
|
||||
} else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) {
|
||||
cipher = EVP_aes_256_gcm();
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nonce = ngx_pstrdup(c->pool, &secret->iv);
|
||||
if (level == ssl_encryption_handshake) {
|
||||
nonce[11] ^= (pn - 1);
|
||||
}
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) secret->iv.data, 12) - buf;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data sample: server_iv %*s",
|
||||
m, buf);
|
||||
m = ngx_hex_dump(buf, (u_char *) nonce, 12) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data sample: n=%d nonce %*s",
|
||||
pn - 1, m, buf);
|
||||
|
||||
if (ngx_quic_tls_seal(c, cipher, secret, &out, nonce, &in, &ad) != NGX_OK)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
sample = &out.data[3]; // pnl=0
|
||||
if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), secret, mask, sample) != NGX_OK) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) sample, 16) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data sample: %*s, len: %uz",
|
||||
m, buf, 16);
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) mask, 16) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data mask: %*s, len: %uz",
|
||||
m, buf, 16);
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) secret->hp.data, 16) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data hp_key: %*s, len: %uz",
|
||||
m, buf, 16);
|
||||
|
||||
// header protection, pnl = 0
|
||||
ad.data[0] ^= mask[0] & 0x0f;
|
||||
*pnp ^= mask[1];
|
||||
|
||||
u_char *packet = ngx_alloc(ad.len + out.len, c->log);
|
||||
if (packet == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = ngx_cpymem(packet, ad.data, ad.len);
|
||||
p = ngx_cpymem(p, out.data, out.len);
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) packet, ngx_min(1024, p - packet)) - buf;
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data packet: %*s%s, len: %uz",
|
||||
m, buf, len < 2048 ? "" : "...", p - packet);
|
||||
|
||||
c->send(c, packet, p - packet);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
quic_flush_flight(ngx_ssl_conn_t *ssl_conn)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "quic_flush_flight()");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level,
|
||||
uint8_t alert)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_send_alert(), lvl=%d, alert=%d",
|
||||
(int) level, (int) alert);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static SSL_QUIC_METHOD quic_method = {
|
||||
quic_set_encryption_secrets,
|
||||
quic_add_handshake_data,
|
||||
quic_flush_flight,
|
||||
quic_send_alert,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_command_t ngx_openssl_commands[] = {
|
||||
|
||||
{ ngx_string("ssl_engine"),
|
||||
@ -1790,7 +1468,7 @@ ngx_ssl_quic(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable)
|
||||
|
||||
#if NGX_OPENSSL_QUIC
|
||||
|
||||
SSL_CTX_set_quic_method(ssl->ctx, &quic_method);
|
||||
ngx_quic_init_ssl_methods(ssl->ctx);
|
||||
return NGX_OK;
|
||||
|
||||
#else
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
|
||||
/*
|
||||
*
|
||||
* Copyright (C) Nginx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
@ -10,95 +10,11 @@
|
||||
|
||||
#include <ngx_event_openssl.h>
|
||||
|
||||
#define quic_version 0xff000018
|
||||
/* TODO: get rid somehow of ssl argument? */
|
||||
ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b);
|
||||
ngx_int_t ngx_quic_output(ngx_connection_t *c);
|
||||
|
||||
void ngx_quic_init_ssl_methods(SSL_CTX* ctx);
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t secret;
|
||||
ngx_str_t key;
|
||||
ngx_str_t iv;
|
||||
ngx_str_t hp;
|
||||
} ngx_quic_secret_t;
|
||||
|
||||
|
||||
struct ngx_quic_connection_s {
|
||||
ngx_str_t scid;
|
||||
ngx_str_t dcid;
|
||||
ngx_str_t token;
|
||||
|
||||
ngx_quic_secret_t client_in;
|
||||
ngx_quic_secret_t client_hs;
|
||||
ngx_quic_secret_t client_ad;
|
||||
ngx_quic_secret_t server_in;
|
||||
ngx_quic_secret_t server_hs;
|
||||
ngx_quic_secret_t server_ad;
|
||||
};
|
||||
|
||||
|
||||
uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask);
|
||||
uint64_t ngx_quic_parse_int(u_char **pos);
|
||||
void ngx_quic_build_int(u_char **pos, uint64_t value);
|
||||
|
||||
ngx_int_t ngx_hkdf_extract(u_char *out_key, size_t *out_len,
|
||||
const EVP_MD *digest, const u_char *secret, size_t secret_len,
|
||||
const u_char *salt, size_t salt_len);
|
||||
ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len,
|
||||
const EVP_MD *digest, const u_char *prk, size_t prk_len,
|
||||
const u_char *info, size_t info_len);
|
||||
|
||||
ngx_int_t ngx_quic_hkdf_expand(ngx_connection_t *c, const EVP_MD *digest,
|
||||
ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len);
|
||||
|
||||
ngx_int_t ngx_quic_tls_open(ngx_connection_t *c,
|
||||
const EVP_CIPHER *cipher, ngx_quic_secret_t *s, ngx_str_t *out,
|
||||
u_char *nonce, ngx_str_t *in, ngx_str_t *ad);
|
||||
ngx_int_t ngx_quic_tls_seal(ngx_connection_t *c,
|
||||
const EVP_CIPHER *cipher, ngx_quic_secret_t *s, ngx_str_t *out,
|
||||
u_char *nonce, ngx_str_t *in, ngx_str_t *ad);
|
||||
|
||||
ngx_int_t
|
||||
ngx_quic_tls_hp(ngx_connection_t *c, const EVP_CIPHER *cipher,
|
||||
ngx_quic_secret_t *s, u_char *out, u_char *in);
|
||||
|
||||
|
||||
#if (NGX_HAVE_NONALIGNED)
|
||||
|
||||
#define ngx_quic_parse_uint16(p) ntohs(*(uint16_t *) (p))
|
||||
#define ngx_quic_parse_uint32(p) ntohl(*(uint32_t *) (p))
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_quic_parse_uint16(p) ((p)[0] << 8 | (p)[1])
|
||||
#define ngx_quic_parse_uint32(p) \
|
||||
((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3])
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define ngx_quic_write_uint16_aligned(p, s) \
|
||||
(*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t))
|
||||
#define ngx_quic_write_uint32_aligned(p, s) \
|
||||
(*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t))
|
||||
|
||||
#if (NGX_HAVE_NONALIGNED)
|
||||
|
||||
#define ngx_quic_write_uint16 ngx_quic_write_uint16_aligned
|
||||
#define ngx_quic_write_uint32 ngx_quic_write_uint32_aligned
|
||||
|
||||
#else
|
||||
|
||||
#define ngx_quic_write_uint16(p, s) \
|
||||
((p)[0] = (u_char) ((s) >> 8), \
|
||||
(p)[1] = (u_char) (s), \
|
||||
(p) + sizeof(uint16_t))
|
||||
|
||||
#define ngx_quic_write_uint32(p, s) \
|
||||
((p)[0] = (u_char) ((s) >> 24), \
|
||||
(p)[1] = (u_char) ((s) >> 16), \
|
||||
(p)[2] = (u_char) ((s) >> 8), \
|
||||
(p)[3] = (u_char) (s), \
|
||||
(p) + sizeof(uint32_t))
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _NGX_EVENT_QUIC_H_INCLUDED_ */
|
||||
|
@ -661,402 +661,22 @@ ngx_http_alloc_request(ngx_connection_t *c)
|
||||
static void
|
||||
ngx_http_quic_handshake(ngx_event_t *rev)
|
||||
{
|
||||
int n, sslerr;
|
||||
#if (NGX_DEBUG)
|
||||
u_char buf[512];
|
||||
size_t m;
|
||||
#endif
|
||||
ngx_buf_t *b;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_connection_t *hc;
|
||||
ngx_quic_connection_t *qc;
|
||||
ngx_http_ssl_srv_conf_t *sscf;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake");
|
||||
|
||||
c = rev->data;
|
||||
hc = c->data;
|
||||
b = c->buffer;
|
||||
|
||||
if ((b->pos[0] & 0xf0) != 0xc0) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid initial packet");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_buf_size(b) < 1200) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "too small UDP datagram");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_int_t flags = *b->pos++;
|
||||
uint32_t version = ngx_quic_parse_uint32(b->pos);
|
||||
b->pos += sizeof(uint32_t);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic flags:%xi version:%xD", flags, version);
|
||||
|
||||
if (version != quic_version) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
|
||||
if (qc == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
c->quic = qc;
|
||||
|
||||
qc->dcid.len = *b->pos++;
|
||||
qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len);
|
||||
if (qc->dcid.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(qc->dcid.data, b->pos, qc->dcid.len);
|
||||
b->pos += qc->dcid.len;
|
||||
|
||||
qc->scid.len = *b->pos++;
|
||||
qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
|
||||
if (qc->scid.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(qc->scid.data, b->pos, qc->scid.len);
|
||||
b->pos += qc->scid.len;
|
||||
|
||||
qc->token.len = ngx_quic_parse_int(&b->pos);
|
||||
qc->token.data = ngx_pnalloc(c->pool, qc->token.len);
|
||||
if (qc->token.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(qc->token.data, b->pos, qc->token.len);
|
||||
b->pos += qc->token.len;
|
||||
|
||||
ngx_int_t plen = ngx_quic_parse_int(&b->pos);
|
||||
|
||||
if (plen > b->last - b->pos) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "truncated initial packet");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
/* draft-ietf-quic-tls-23#section-5.4.2:
|
||||
* the Packet Number field is assumed to be 4 bytes long
|
||||
* draft-ietf-quic-tls-23#section-5.4.[34]:
|
||||
* AES-Based and ChaCha20-Based header protections sample 16 bytes
|
||||
*/
|
||||
u_char *sample = b->pos + 4;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, qc->dcid.data, qc->dcid.len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic DCID: %*s, len: %uz", m, buf, qc->dcid.len);
|
||||
|
||||
m = ngx_hex_dump(buf, qc->scid.data, qc->scid.len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic SCID: %*s, len: %uz", m, buf, qc->scid.len);
|
||||
|
||||
m = ngx_hex_dump(buf, qc->token.data, qc->token.len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic token: %*s, len: %uz", m, buf, qc->token.len);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic packet length: %d", plen);
|
||||
|
||||
m = ngx_hex_dump(buf, sample, 16) - buf;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic sample: %*s", m, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
// initial secret
|
||||
|
||||
size_t is_len;
|
||||
uint8_t is[SHA256_DIGEST_LENGTH];
|
||||
ngx_uint_t i;
|
||||
const EVP_MD *digest;
|
||||
const EVP_CIPHER *cipher;
|
||||
static const uint8_t salt[20] =
|
||||
"\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7"
|
||||
"\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02";
|
||||
|
||||
/* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
|
||||
|
||||
cipher = EVP_aes_128_gcm();
|
||||
digest = EVP_sha256();
|
||||
|
||||
if (ngx_hkdf_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len,
|
||||
salt, sizeof(salt))
|
||||
!= NGX_OK)
|
||||
{
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_str_t iss = {
|
||||
.data = is,
|
||||
.len = is_len
|
||||
};
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, (uint8_t *) salt, sizeof(salt)) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic salt: %*s, len: %uz", m, buf, sizeof(salt));
|
||||
|
||||
m = ngx_hex_dump(buf, is, is_len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic initial secret: %*s, len: %uz", m, buf, is_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* draft-ietf-quic-tls-23#section-5.2 */
|
||||
qc->client_in.secret.len = SHA256_DIGEST_LENGTH;
|
||||
qc->server_in.secret.len = SHA256_DIGEST_LENGTH;
|
||||
|
||||
qc->client_in.key.len = EVP_CIPHER_key_length(cipher);
|
||||
qc->server_in.key.len = EVP_CIPHER_key_length(cipher);
|
||||
|
||||
qc->client_in.hp.len = EVP_CIPHER_key_length(cipher);
|
||||
qc->server_in.hp.len = EVP_CIPHER_key_length(cipher);
|
||||
|
||||
qc->client_in.iv.len = EVP_CIPHER_iv_length(cipher);
|
||||
qc->server_in.iv.len = EVP_CIPHER_iv_length(cipher);
|
||||
|
||||
struct {
|
||||
ngx_str_t label;
|
||||
ngx_str_t *key;
|
||||
ngx_str_t *prk;
|
||||
} seq[] = {
|
||||
|
||||
/* draft-ietf-quic-tls-23#section-5.2 */
|
||||
{ ngx_string("tls13 client in"), &qc->client_in.secret, &iss },
|
||||
{
|
||||
ngx_string("tls13 quic key"),
|
||||
&qc->client_in.key,
|
||||
&qc->client_in.secret,
|
||||
},
|
||||
{
|
||||
ngx_string("tls13 quic iv"),
|
||||
&qc->client_in.iv,
|
||||
&qc->client_in.secret,
|
||||
},
|
||||
{
|
||||
/* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
|
||||
ngx_string("tls13 quic hp"),
|
||||
&qc->client_in.hp,
|
||||
&qc->client_in.secret,
|
||||
},
|
||||
{ ngx_string("tls13 server in"), &qc->server_in.secret, &iss },
|
||||
{
|
||||
/* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
|
||||
ngx_string("tls13 quic key"),
|
||||
&qc->server_in.key,
|
||||
&qc->server_in.secret,
|
||||
},
|
||||
{
|
||||
ngx_string("tls13 quic iv"),
|
||||
&qc->server_in.iv,
|
||||
&qc->server_in.secret,
|
||||
},
|
||||
{
|
||||
/* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
|
||||
ngx_string("tls13 quic hp"),
|
||||
&qc->server_in.hp,
|
||||
&qc->server_in.secret,
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) {
|
||||
|
||||
if (ngx_quic_hkdf_expand(c, digest, seq[i].key, &seq[i].label,
|
||||
seq[i].prk->data, seq[i].prk->len)
|
||||
!= NGX_OK)
|
||||
{
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// header protection
|
||||
|
||||
uint8_t mask[16];
|
||||
if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_in, mask, sample)
|
||||
!= NGX_OK)
|
||||
{
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
u_char clearflags = flags ^ (mask[0] & 0x0f);
|
||||
ngx_int_t pnl = (clearflags & 0x03) + 1;
|
||||
uint64_t pn = ngx_quic_parse_pn(&b->pos, pnl, &mask[1]);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, sample, 16) - buf;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic sample: %*s", m, buf);
|
||||
|
||||
m = ngx_hex_dump(buf, mask, 5) - buf;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic mask: %*s", m, buf);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic packet number: %uL, len: %xi", pn, pnl);
|
||||
}
|
||||
#endif
|
||||
|
||||
// packet protection
|
||||
|
||||
ngx_str_t in;
|
||||
in.data = b->pos;
|
||||
in.len = plen - pnl;
|
||||
|
||||
ngx_str_t ad;
|
||||
ad.len = b->pos - b->start;
|
||||
ad.data = ngx_pnalloc(c->pool, ad.len);
|
||||
if (ad.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(ad.data, b->start, ad.len);
|
||||
ad.data[0] = clearflags;
|
||||
ad.data[ad.len - pnl] = (u_char)pn;
|
||||
|
||||
uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_in.iv);
|
||||
nonce[11] ^= pn;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, nonce, 12) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic nonce: %*s, len: %uz", m, buf, 12);
|
||||
|
||||
m = ngx_hex_dump(buf, ad.data, ad.len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic ad: %*s, len: %uz", m, buf, ad.len);
|
||||
}
|
||||
#endif
|
||||
|
||||
ngx_str_t out;
|
||||
|
||||
if (ngx_quic_tls_open(c, EVP_aes_128_gcm(), &qc->client_in, &out, nonce,
|
||||
&in, &ad)
|
||||
!= NGX_OK)
|
||||
{
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, out.data, ngx_min(out.len, 256)) - buf;
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic packet payload: %*s%s, len: %uz",
|
||||
m, buf, m < 512 ? "" : "...", out.len);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (out.data[0] != 0x06) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"unexpected frame in initial packet");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (out.data[1] != 0x00) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"unexpected CRYPTO offset in initial packet");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *crypto = &out.data[2];
|
||||
uint64_t crypto_len = ngx_quic_parse_int(&crypto);
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic initial packet CRYPTO length: %uL pp:%p:%p",
|
||||
crypto_len, out.data, crypto);
|
||||
|
||||
sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
|
||||
|
||||
if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
|
||||
!= NGX_OK)
|
||||
{
|
||||
if (ngx_quic_input(c, &sscf->ssl, c->buffer) != NGX_OK) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
static const uint8_t params[12] = "\x00\x0a\x00\x3a\x00\x01\x00\x00\x09\x00\x01\x03";
|
||||
|
||||
if (SSL_set_quic_transport_params(c->ssl->connection, params,
|
||||
sizeof(params)) == 0)
|
||||
{
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"SSL_set_quic_transport_params() failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
n = SSL_do_handshake(c->ssl->connection);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
|
||||
|
||||
if (n == -1) {
|
||||
sslerr = SSL_get_error(c->ssl->connection, n);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
|
||||
sslerr);
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"SSL_quic_read_level: %d, SSL_quic_write_level: %d",
|
||||
(int) SSL_quic_read_level(c->ssl->connection),
|
||||
(int) SSL_quic_write_level(c->ssl->connection));
|
||||
|
||||
if (!SSL_provide_quic_data(c->ssl->connection,
|
||||
SSL_quic_read_level(c->ssl->connection),
|
||||
crypto, crypto_len))
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"SSL_provide_quic_data() failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
n = SSL_do_handshake(c->ssl->connection);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
|
||||
|
||||
if (n == -1) {
|
||||
sslerr = SSL_get_error(c->ssl->connection, n);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
|
||||
sslerr);
|
||||
|
||||
if (sslerr == SSL_ERROR_SSL) {
|
||||
ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed");
|
||||
}
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"SSL_quic_read_level: %d, SSL_quic_write_level: %d",
|
||||
(int) SSL_quic_read_level(c->ssl->connection),
|
||||
(int) SSL_quic_write_level(c->ssl->connection));
|
||||
|
||||
if (!rev->timer_set) {
|
||||
ngx_add_timer(rev, c->listening->post_accept_timeout);
|
||||
}
|
||||
@ -1069,17 +689,16 @@ ngx_http_quic_handshake(ngx_event_t *rev)
|
||||
static void
|
||||
ngx_http_quic_handshake_handler(ngx_event_t *rev)
|
||||
{
|
||||
size_t m;
|
||||
ssize_t n;
|
||||
ngx_str_t out;
|
||||
ngx_connection_t *c;
|
||||
const EVP_CIPHER *cipher;
|
||||
ngx_quic_connection_t *qc;
|
||||
u_char buf[4096], b[512], *p;
|
||||
u_char buf[512];
|
||||
ngx_buf_t b;
|
||||
|
||||
b.start = buf;
|
||||
b.end = buf + 512;
|
||||
b.pos = b.last = b.start;
|
||||
|
||||
c = rev->data;
|
||||
qc = c->quic;
|
||||
p = b;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake handler");
|
||||
|
||||
@ -1094,7 +713,7 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev)
|
||||
return;
|
||||
}
|
||||
|
||||
n = c->recv(c, b, sizeof(b));
|
||||
n = c->recv(c, b.start, b.end - b.start);
|
||||
|
||||
if (n == NGX_AGAIN) {
|
||||
return;
|
||||
@ -1106,166 +725,12 @@ ngx_http_quic_handshake_handler(ngx_event_t *rev)
|
||||
return;
|
||||
}
|
||||
|
||||
m = ngx_hex_dump(buf, b, n) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic handshake handler: %*s, len: %uz", m, buf, n);
|
||||
b.last += n;
|
||||
|
||||
if ((p[0] & 0xf0) != 0xe0) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid packet type");
|
||||
if (ngx_quic_input(c, NULL, &b) != NGX_OK) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_int_t flags = *p++;
|
||||
uint32_t version = ngx_quic_parse_uint32(p);
|
||||
p += sizeof(uint32_t);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic flags:%xi version:%xD", flags, version);
|
||||
|
||||
if (version != quic_version) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (*p++ != qc->dcid.len) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic dcidl");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_memcmp(p, qc->dcid.data, qc->dcid.len) != 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic dcid");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
p += qc->dcid.len;
|
||||
|
||||
if (*p++ != qc->scid.len) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic scidl");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_memcmp(p, qc->scid.data, qc->scid.len) != 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unexpected quic scid");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
p += qc->scid.len;
|
||||
|
||||
ngx_int_t plen = ngx_quic_parse_int(&p);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic packet length: %d", plen);
|
||||
|
||||
if (plen > b + n - p) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "truncated handshake packet");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
u_char *sample = p + 4;
|
||||
|
||||
m = ngx_hex_dump(buf, sample, 16) - buf;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic sample: %*s", m, buf);
|
||||
|
||||
// header protection
|
||||
|
||||
uint8_t mask[16];
|
||||
if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_hs, mask, sample)
|
||||
!= NGX_OK)
|
||||
{
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
u_char clearflags = flags ^ (mask[0] & 0x0f);
|
||||
ngx_int_t pnl = (clearflags & 0x03) + 1;
|
||||
uint64_t pn = ngx_quic_parse_pn(&p, pnl, &mask[1]);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, mask, 5) - buf;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic mask: %*s", m, buf);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic clear flags: %xi", clearflags);
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic packet number: %uL, len: %xi", pn, pnl);
|
||||
}
|
||||
#endif
|
||||
|
||||
// packet protection
|
||||
|
||||
ngx_str_t in;
|
||||
in.data = p;
|
||||
in.len = plen - pnl;
|
||||
|
||||
ngx_str_t ad;
|
||||
ad.len = p - b;
|
||||
ad.data = ngx_pnalloc(c->pool, ad.len);
|
||||
if (ad.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_memcpy(ad.data, b, ad.len);
|
||||
ad.data[0] = clearflags;
|
||||
ad.data[ad.len - pnl] = (u_char)pn;
|
||||
|
||||
uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_hs.iv);
|
||||
nonce[11] ^= pn;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, nonce, 12) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic nonce: %*s, len: %uz", m, buf, 12);
|
||||
|
||||
m = ngx_hex_dump(buf, ad.data, ad.len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic ad: %*s, len: %uz", m, buf, ad.len);
|
||||
}
|
||||
#endif
|
||||
|
||||
u_char *name = (u_char *) SSL_get_cipher(c->ssl->connection);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic ssl cipher: %s", name);
|
||||
|
||||
if (ngx_strcasecmp(name, (u_char *) "TLS_AES_128_GCM_SHA256") == 0
|
||||
|| ngx_strcasecmp(name, (u_char *) "(NONE)") == 0)
|
||||
{
|
||||
cipher = EVP_aes_128_gcm();
|
||||
|
||||
} else if (ngx_strcasecmp(name, (u_char *) "TLS_AES_256_GCM_SHA384") == 0) {
|
||||
cipher = EVP_aes_256_gcm();
|
||||
|
||||
} else {
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0, "unexpected cipher");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ngx_quic_tls_open(c, cipher, &qc->client_hs, &out, nonce, &in, &ad)
|
||||
!= NGX_OK)
|
||||
{
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, out.data, ngx_min(out.len, 256)) - buf;
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic packet payload: %*s%s, len: %uz",
|
||||
m, buf, m < 512 ? "" : "...", out.len);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user