mirror of
https://github.com/nginx/nginx.git
synced 2025-02-25 18:55:26 -06:00
Initial QUIC support in http.
This commit is contained in:
parent
e92cb24f40
commit
26ac1c73f0
@ -1242,7 +1242,8 @@ if [ $USE_OPENSSL = YES ]; then
|
||||
ngx_module_type=CORE
|
||||
ngx_module_name=ngx_openssl_module
|
||||
ngx_module_incs=
|
||||
ngx_module_deps=src/event/ngx_event_openssl.h
|
||||
ngx_module_deps="src/event/ngx_event_openssl.h \
|
||||
src/event/ngx_event_quic.h"
|
||||
ngx_module_srcs="src/event/ngx_event_openssl.c
|
||||
src/event/ngx_event_openssl_stapling.c"
|
||||
ngx_module_libs=
|
||||
|
@ -147,13 +147,14 @@ struct ngx_connection_s {
|
||||
socklen_t socklen;
|
||||
ngx_str_t addr_text;
|
||||
|
||||
ngx_proxy_protocol_t *proxy_protocol;
|
||||
ngx_proxy_protocol_t *proxy_protocol;
|
||||
|
||||
#if (NGX_SSL || NGX_COMPAT)
|
||||
ngx_ssl_connection_t *ssl;
|
||||
ngx_quic_connection_t *quic;
|
||||
ngx_ssl_connection_t *ssl;
|
||||
#endif
|
||||
|
||||
ngx_udp_connection_t *udp;
|
||||
ngx_udp_connection_t *udp;
|
||||
|
||||
struct sockaddr *local_sockaddr;
|
||||
socklen_t local_socklen;
|
||||
|
@ -12,23 +12,24 @@
|
||||
#include <ngx_config.h>
|
||||
|
||||
|
||||
typedef struct ngx_module_s ngx_module_t;
|
||||
typedef struct ngx_conf_s ngx_conf_t;
|
||||
typedef struct ngx_cycle_s ngx_cycle_t;
|
||||
typedef struct ngx_pool_s ngx_pool_t;
|
||||
typedef struct ngx_chain_s ngx_chain_t;
|
||||
typedef struct ngx_log_s ngx_log_t;
|
||||
typedef struct ngx_open_file_s ngx_open_file_t;
|
||||
typedef struct ngx_command_s ngx_command_t;
|
||||
typedef struct ngx_file_s ngx_file_t;
|
||||
typedef struct ngx_event_s ngx_event_t;
|
||||
typedef struct ngx_event_aio_s ngx_event_aio_t;
|
||||
typedef struct ngx_connection_s ngx_connection_t;
|
||||
typedef struct ngx_thread_task_s ngx_thread_task_t;
|
||||
typedef struct ngx_ssl_s ngx_ssl_t;
|
||||
typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t;
|
||||
typedef struct ngx_ssl_connection_s ngx_ssl_connection_t;
|
||||
typedef struct ngx_udp_connection_s ngx_udp_connection_t;
|
||||
typedef struct ngx_module_s ngx_module_t;
|
||||
typedef struct ngx_conf_s ngx_conf_t;
|
||||
typedef struct ngx_cycle_s ngx_cycle_t;
|
||||
typedef struct ngx_pool_s ngx_pool_t;
|
||||
typedef struct ngx_chain_s ngx_chain_t;
|
||||
typedef struct ngx_log_s ngx_log_t;
|
||||
typedef struct ngx_open_file_s ngx_open_file_t;
|
||||
typedef struct ngx_command_s ngx_command_t;
|
||||
typedef struct ngx_file_s ngx_file_t;
|
||||
typedef struct ngx_event_s ngx_event_t;
|
||||
typedef struct ngx_event_aio_s ngx_event_aio_t;
|
||||
typedef struct ngx_connection_s ngx_connection_t;
|
||||
typedef struct ngx_thread_task_s ngx_thread_task_t;
|
||||
typedef struct ngx_ssl_s ngx_ssl_t;
|
||||
typedef struct ngx_proxy_protocol_s ngx_proxy_protocol_t;
|
||||
typedef struct ngx_quic_connection_s ngx_quic_connection_t;
|
||||
typedef struct ngx_ssl_connection_s ngx_ssl_connection_t;
|
||||
typedef struct ngx_udp_connection_s ngx_udp_connection_t;
|
||||
|
||||
typedef void (*ngx_event_handler_pt)(ngx_event_t *ev);
|
||||
typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
|
||||
@ -82,6 +83,7 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
|
||||
#include <ngx_resolver.h>
|
||||
#if (NGX_OPENSSL)
|
||||
#include <ngx_event_openssl.h>
|
||||
#include <ngx_event_quic.h>
|
||||
#endif
|
||||
#include <ngx_process_cycle.h>
|
||||
#include <ngx_conf_file.h>
|
||||
|
@ -89,6 +89,126 @@ static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
|
||||
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)
|
||||
{
|
||||
size_t *len;
|
||||
uint8_t **rsec, **wsec;
|
||||
ngx_connection_t *c;
|
||||
|
||||
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: %*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: %*s, len: %uz, level:%d",
|
||||
m, buf, secret_len, (int) level);
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (level) {
|
||||
|
||||
case ssl_encryption_handshake:
|
||||
len = &c->quic->handshake_secret_len;
|
||||
rsec = &c->quic->handshake_read_secret;
|
||||
wsec = &c->quic->handshake_write_secret;
|
||||
break;
|
||||
|
||||
case ssl_encryption_application:
|
||||
len = &c->quic->application_secret_len;
|
||||
rsec = &c->quic->application_read_secret;
|
||||
wsec = &c->quic->application_write_secret;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
*len = secret_len;
|
||||
|
||||
*rsec = ngx_pnalloc(c->pool, secret_len);
|
||||
if (*rsec == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(*rsec, read_secret, secret_len);
|
||||
|
||||
*wsec = ngx_pnalloc(c->pool, secret_len);
|
||||
if (*wsec == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(*wsec, write_secret, secret_len);
|
||||
|
||||
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 buf[512];
|
||||
ngx_int_t m;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
|
||||
|
||||
m = ngx_hex_dump(buf, (u_char *) data, ngx_min(len, 256)) - buf;
|
||||
ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||
"quic_add_handshake_data: %*s%s, len: %uz, level:%d",
|
||||
m, buf, len < 512 ? "" : "...", len, (int) level);
|
||||
|
||||
if (!(SSL_provide_quic_data(ssl_conn, level, data, len))) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
quic_flush_flight(ngx_ssl_conn_t *ssl_conn)
|
||||
{
|
||||
printf("quic_flush_flight()\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
quic_send_alert(ngx_ssl_conn_t *ssl_conn, enum ssl_encryption_level_t level,
|
||||
uint8_t alert)
|
||||
{
|
||||
printf("quic_send_alert(), lvl=%d, alert=%d\n", level, 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[] = {
|
||||
|
||||
@ -1459,6 +1579,29 @@ ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable)
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_quic(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable)
|
||||
{
|
||||
if (!enable) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#if NGX_OPENSSL_QUIC
|
||||
|
||||
SSL_CTX_set_quic_method(ssl->ctx, &quic_method);
|
||||
printf("%s\n", __func__);
|
||||
return NGX_OK;
|
||||
|
||||
#else
|
||||
|
||||
ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
|
||||
"\"ssl_quic\" is not supported on this platform");
|
||||
return NGX_ERROR;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/crypto.h>
|
||||
@ -22,6 +23,7 @@
|
||||
#include <openssl/engine.h>
|
||||
#endif
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hkdf.h>
|
||||
#include <openssl/hmac.h>
|
||||
#ifndef OPENSSL_NO_OCSP
|
||||
#include <openssl/ocsp.h>
|
||||
@ -189,6 +191,7 @@ ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
|
||||
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
|
||||
ngx_int_t ngx_ssl_early_data(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_uint_t enable);
|
||||
ngx_int_t ngx_ssl_quic(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_uint_t enable);
|
||||
ngx_int_t ngx_ssl_client_session_cache(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_uint_t enable);
|
||||
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
|
31
src/event/ngx_event_quic.h
Normal file
31
src/event/ngx_event_quic.h
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_EVENT_QUIC_H_INCLUDED_
|
||||
#define _NGX_EVENT_QUIC_H_INCLUDED_
|
||||
|
||||
|
||||
struct ngx_quic_connection_s {
|
||||
ngx_str_t scid;
|
||||
ngx_str_t dcid;
|
||||
ngx_str_t token;
|
||||
|
||||
ngx_str_t client_in;
|
||||
ngx_str_t client_in_key;
|
||||
ngx_str_t client_in_iv;
|
||||
ngx_str_t client_in_hp;
|
||||
|
||||
size_t handshake_secret_len;
|
||||
uint8_t *handshake_read_secret;
|
||||
uint8_t *handshake_write_secret;
|
||||
|
||||
size_t application_secret_len;
|
||||
uint8_t *application_read_secret;
|
||||
uint8_t *application_write_secret;
|
||||
};
|
||||
|
||||
|
||||
#endif /* _NGX_EVENT_QUIC_H_INCLUDED_ */
|
@ -249,6 +249,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
|
||||
offsetof(ngx_http_ssl_srv_conf_t, early_data),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("ssl_quic"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
|
||||
ngx_conf_set_flag_slot,
|
||||
NGX_HTTP_SRV_CONF_OFFSET,
|
||||
offsetof(ngx_http_ssl_srv_conf_t, quic),
|
||||
NULL },
|
||||
|
||||
ngx_null_command
|
||||
};
|
||||
|
||||
@ -568,6 +575,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
|
||||
sscf->enable = NGX_CONF_UNSET;
|
||||
sscf->prefer_server_ciphers = NGX_CONF_UNSET;
|
||||
sscf->early_data = NGX_CONF_UNSET;
|
||||
sscf->quic = NGX_CONF_UNSET;
|
||||
sscf->buffer_size = NGX_CONF_UNSET_SIZE;
|
||||
sscf->verify = NGX_CONF_UNSET_UINT;
|
||||
sscf->verify_depth = NGX_CONF_UNSET_UINT;
|
||||
@ -612,6 +620,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
|
||||
ngx_conf_merge_value(conf->early_data, prev->early_data, 0);
|
||||
|
||||
ngx_conf_merge_value(conf->quic, prev->quic, 0);
|
||||
|
||||
ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
|
||||
(NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
|
||||
|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
|
||||
@ -696,6 +706,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
}
|
||||
}
|
||||
|
||||
printf("ngx_ssl_create\n");
|
||||
if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
@ -857,6 +868,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_ssl_quic(cf, &conf->ssl, conf->quic) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
@ -1141,13 +1156,15 @@ ngx_http_ssl_init(ngx_conf_t *cf)
|
||||
|
||||
addr = port[p].addrs.elts;
|
||||
for (a = 0; a < port[p].addrs.nelts; a++) {
|
||||
printf("ssl %d http3 %d\n", addr[a].opt.ssl, addr[a].opt.http3);
|
||||
|
||||
if (!addr[a].opt.ssl) {
|
||||
if (!addr[a].opt.ssl && !addr[a].opt.http3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cscf = addr[a].default_server;
|
||||
sscf = cscf->ctx->srv_conf[ngx_http_ssl_module.ctx_index];
|
||||
printf("sscf->protocols %lx\n", sscf->protocols);
|
||||
|
||||
if (sscf->certificates == NULL) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||||
@ -1156,6 +1173,14 @@ ngx_http_ssl_init(ngx_conf_t *cf)
|
||||
cscf->file_name, cscf->line);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (addr[a].opt.http3 && !(sscf->protocols & NGX_SSL_TLSv1_3)) {
|
||||
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||||
"\"ssl_protocols\" did not enable TLSv1.3 for "
|
||||
"the \"listen ... http3\" directive in %s:%ui",
|
||||
cscf->file_name, cscf->line);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ typedef struct {
|
||||
|
||||
ngx_flag_t prefer_server_ciphers;
|
||||
ngx_flag_t early_data;
|
||||
ngx_flag_t quic;
|
||||
|
||||
ngx_uint_t protocols;
|
||||
|
||||
|
@ -1203,6 +1203,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
|
||||
#if (NGX_HTTP_V2)
|
||||
ngx_uint_t http2;
|
||||
#endif
|
||||
#if (NGX_HTTP_SSL)
|
||||
ngx_uint_t http3;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* we cannot compare whole sockaddr struct's as kernel
|
||||
@ -1238,6 +1241,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
|
||||
#if (NGX_HTTP_V2)
|
||||
http2 = lsopt->http2 || addr[i].opt.http2;
|
||||
#endif
|
||||
#if (NGX_HTTP_SSL)
|
||||
http3 = lsopt->http3 || addr[i].opt.http3;
|
||||
#endif
|
||||
|
||||
if (lsopt->set) {
|
||||
|
||||
@ -1274,6 +1280,9 @@ ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
|
||||
#if (NGX_HTTP_V2)
|
||||
addr[i].opt.http2 = http2;
|
||||
#endif
|
||||
#if (NGX_HTTP_SSL)
|
||||
addr[i].opt.http3 = http3;
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
@ -1315,6 +1324,17 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
|
||||
&lsopt->addr_text);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_SSL && !defined NGX_OPENSSL_QUIC)
|
||||
|
||||
if (lsopt->http3) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"nginx was built with OpenSSL that lacks QUIC "
|
||||
"support, HTTP/3 is not enabled for %V",
|
||||
&lsopt->addr_text);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
addr = ngx_array_push(&port->addrs);
|
||||
@ -1806,6 +1826,9 @@ ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport,
|
||||
#endif
|
||||
#if (NGX_HTTP_V2)
|
||||
addrs[i].conf.http2 = addr[i].opt.http2;
|
||||
#endif
|
||||
#if (NGX_HTTP_SSL)
|
||||
addrs[i].conf.http3 = addr[i].opt.http3;
|
||||
#endif
|
||||
addrs[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
|
||||
|
||||
@ -1871,6 +1894,9 @@ ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport,
|
||||
#endif
|
||||
#if (NGX_HTTP_V2)
|
||||
addrs6[i].conf.http2 = addr[i].opt.http2;
|
||||
#endif
|
||||
#if (NGX_HTTP_SSL)
|
||||
addrs6[i].conf.http3 = addr[i].opt.http3;
|
||||
#endif
|
||||
addrs6[i].conf.proxy_protocol = addr[i].opt.proxy_protocol;
|
||||
|
||||
|
@ -3822,11 +3822,6 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strcmp(value[n].data, "quic") == 0) {
|
||||
lsopt.type = SOCK_DGRAM;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ngx_strcmp(value[n].data, "bind") == 0) {
|
||||
lsopt.set = 1;
|
||||
lsopt.bind = 1;
|
||||
@ -4004,6 +3999,19 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ngx_strcmp(value[n].data, "http3") == 0) {
|
||||
#if (NGX_HTTP_SSL)
|
||||
lsopt.http3 = 1;
|
||||
lsopt.type = SOCK_DGRAM;
|
||||
continue;
|
||||
#else
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"the \"http3\" parameter requires "
|
||||
"ngx_http_ssl_module");
|
||||
return NGX_CONF_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ngx_strcmp(value[n].data, "spdy") == 0) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"invalid parameter \"spdy\": "
|
||||
|
@ -75,6 +75,7 @@ typedef struct {
|
||||
unsigned wildcard:1;
|
||||
unsigned ssl:1;
|
||||
unsigned http2:1;
|
||||
unsigned http3:1;
|
||||
#if (NGX_HAVE_INET6)
|
||||
unsigned ipv6only:1;
|
||||
#endif
|
||||
@ -238,6 +239,7 @@ struct ngx_http_addr_conf_s {
|
||||
|
||||
unsigned ssl:1;
|
||||
unsigned http2:1;
|
||||
unsigned http3:1;
|
||||
unsigned proxy_protocol:1;
|
||||
};
|
||||
|
||||
|
@ -62,6 +62,8 @@ static u_char *ngx_http_log_error_handler(ngx_http_request_t *r,
|
||||
#if (NGX_HTTP_SSL)
|
||||
static void ngx_http_ssl_handshake(ngx_event_t *rev);
|
||||
static void ngx_http_ssl_handshake_handler(ngx_connection_t *c);
|
||||
|
||||
static void ngx_http_quic_handshake(ngx_event_t *rev);
|
||||
#endif
|
||||
|
||||
|
||||
@ -328,6 +330,14 @@ ngx_http_init_connection(ngx_connection_t *c)
|
||||
rev->ready = 1;
|
||||
}
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
if (hc->addr_conf->http3) {
|
||||
hc->quic = 1;
|
||||
c->log->action = "QUIC handshaking";
|
||||
rev->handler = ngx_http_quic_handshake;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
if (hc->addr_conf->http2) {
|
||||
rev->handler = ngx_http_v2_init;
|
||||
@ -647,6 +657,491 @@ ngx_http_alloc_request(ngx_connection_t *c)
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
|
||||
static uint64_t
|
||||
ngx_quic_parse_int(u_char **pos)
|
||||
{
|
||||
u_char *p;
|
||||
uint64_t value;
|
||||
ngx_uint_t len;
|
||||
|
||||
p = *pos;
|
||||
len = 1 << ((*p & 0xc0) >> 6);
|
||||
value = *p++ & 0x3f;
|
||||
|
||||
while (--len) {
|
||||
value = (value << 8) + *p++;
|
||||
}
|
||||
|
||||
*pos = p;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
static uint64_t
|
||||
ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask)
|
||||
{
|
||||
u_char *p;
|
||||
uint64_t value;
|
||||
|
||||
p = *pos;
|
||||
value = *p++ ^ *mask++;
|
||||
|
||||
while (--len) {
|
||||
value = (value << 8) + (*p++ ^ *mask++);
|
||||
}
|
||||
|
||||
*pos = p;
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
|
||||
if (qc == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
c->quic = qc;
|
||||
|
||||
printf("buffer %p %p:%p:%p:%p \n", b, b->start, b->pos, b->last, b->end);
|
||||
|
||||
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_http_v2_parse_uint32(b->pos);
|
||||
b->pos += 4;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic flags:%xi version:%xD", flags, version);
|
||||
|
||||
if (version != 0xff000017) {
|
||||
ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
uint64_t plen = ngx_quic_parse_int(&b->pos);
|
||||
/* 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.3:
|
||||
* AES-Based header protection samples 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];
|
||||
const EVP_MD *digest;
|
||||
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";
|
||||
|
||||
digest = EVP_sha256();
|
||||
HKDF_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, salt,
|
||||
sizeof(salt));
|
||||
|
||||
#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
|
||||
|
||||
size_t hkdfl_len;
|
||||
uint8_t hkdfl[20];
|
||||
uint8_t *p;
|
||||
|
||||
/* draft-ietf-quic-tls-23#section-5.2 */
|
||||
|
||||
qc->client_in.len = SHA256_DIGEST_LENGTH;
|
||||
qc->client_in.data = ngx_pnalloc(c->pool, qc->client_in.len);
|
||||
if (qc->client_in.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1;
|
||||
hkdfl[0] = 0;
|
||||
hkdfl[1] = qc->client_in.len;
|
||||
hkdfl[2] = sizeof("tls13 client in") - 1;
|
||||
p = ngx_cpymem(&hkdfl[3], "tls13 client in",
|
||||
sizeof("tls13 client in") - 1);
|
||||
*p = '\0';
|
||||
|
||||
if (HKDF_expand(qc->client_in.data, qc->client_in.len,
|
||||
digest, is, is_len, hkdfl, hkdfl_len)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"HKDF_expand(client_in) failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic EVP key:%d tag:%d nonce:%d",
|
||||
EVP_AEAD_key_length(EVP_aead_aes_128_gcm()),
|
||||
EVP_AEAD_max_tag_len(EVP_aead_aes_128_gcm()),
|
||||
EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()));
|
||||
|
||||
/* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
|
||||
|
||||
qc->client_in_key.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm());
|
||||
qc->client_in_key.data = ngx_pnalloc(c->pool, qc->client_in_key.len);
|
||||
if (qc->client_in_key.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1;
|
||||
hkdfl[1] = qc->client_in_key.len;
|
||||
hkdfl[2] = sizeof("tls13 quic key") - 1;
|
||||
p = ngx_cpymem(&hkdfl[3], "tls13 quic key",
|
||||
sizeof("tls13 quic key") - 1);
|
||||
*p = '\0';
|
||||
|
||||
if (HKDF_expand(qc->client_in_key.data, qc->client_in_key.len,
|
||||
digest, qc->client_in.data, qc->client_in.len,
|
||||
hkdfl, hkdfl_len)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"HKDF_expand(client_in_key) failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
qc->client_in_iv.len = EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm());
|
||||
qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len);
|
||||
if (qc->client_in_iv.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1;
|
||||
hkdfl[1] = qc->client_in_iv.len;
|
||||
hkdfl[2] = sizeof("tls13 quic iv") - 1;
|
||||
p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1);
|
||||
*p = '\0';
|
||||
|
||||
if (HKDF_expand(qc->client_in_iv.data, qc->client_in_iv.len, digest,
|
||||
qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"HKDF_expand(client_in_iv) failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
/* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
|
||||
|
||||
qc->client_in_hp.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm());
|
||||
qc->client_in_hp.data = ngx_pnalloc(c->pool, qc->client_in_hp.len);
|
||||
if (qc->client_in_hp.data == NULL) {
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1;
|
||||
hkdfl[1] = qc->client_in_hp.len;
|
||||
hkdfl[2] = sizeof("tls13 quic hp") - 1;
|
||||
p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1);
|
||||
*p = '\0';
|
||||
|
||||
if (HKDF_expand(qc->client_in_hp.data, qc->client_in_hp.len, digest,
|
||||
qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len)
|
||||
== 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"HKDF_expand(client_in_hp) failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, qc->client_in.data, qc->client_in.len) - buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic client initial secret: %*s, len: %uz",
|
||||
m, buf, qc->client_in.len);
|
||||
|
||||
m = ngx_hex_dump(buf, qc->client_in_key.data, qc->client_in_key.len)
|
||||
- buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic key: %*s, len: %uz",
|
||||
m, buf, qc->client_in_key.len);
|
||||
|
||||
m = ngx_hex_dump(buf, qc->client_in_iv.data, qc->client_in_iv.len)
|
||||
- buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic iv: %*s, len: %uz", m, buf, qc->client_in_iv.len);
|
||||
|
||||
m = ngx_hex_dump(buf, qc->client_in_hp.data, qc->client_in_hp.len)
|
||||
- buf;
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic hp: %*s, len: %uz", m, buf, qc->client_in_hp.len);
|
||||
}
|
||||
#endif
|
||||
|
||||
// header protection
|
||||
|
||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||
uint8_t mask[16];
|
||||
int outlen;
|
||||
|
||||
if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL,
|
||||
qc->client_in_hp.data, NULL)
|
||||
!= 1)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"EVP_EncryptInit_ex() failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"EVP_EncryptUpdate() failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
|
||||
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 ciphertext;
|
||||
ciphertext.data = b->pos;
|
||||
ciphertext.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
|
||||
|
||||
EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(EVP_aead_aes_128_gcm(),
|
||||
qc->client_in_key.data,
|
||||
qc->client_in_key.len,
|
||||
EVP_AEAD_DEFAULT_TAG_LENGTH);
|
||||
uint8_t cleartext[1600];
|
||||
size_t cleartext_len = sizeof(cleartext);
|
||||
|
||||
if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext),
|
||||
nonce, qc->client_in_iv.len, ciphertext.data,
|
||||
ciphertext.len, ad.data, ad.len)
|
||||
!= 1)
|
||||
{
|
||||
EVP_AEAD_CTX_free(aead);
|
||||
ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
|
||||
"EVP_AEAD_CTX_open() failed");
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
EVP_AEAD_CTX_free(aead);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
|
||||
m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf;
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
|
||||
"quic packet: %*s%s, len: %uz",
|
||||
m, buf, m < 512 ? "" : "...", cleartext_len);
|
||||
}
|
||||
#endif
|
||||
|
||||
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)
|
||||
{
|
||||
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),
|
||||
&cleartext[4], cleartext_len - 4))
|
||||
{
|
||||
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));
|
||||
|
||||
ngx_http_close_connection(c);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_ssl_handshake(ngx_event_t *rev)
|
||||
{
|
||||
|
@ -323,6 +323,7 @@ typedef struct {
|
||||
ngx_chain_t *free;
|
||||
|
||||
unsigned ssl:1;
|
||||
unsigned quic:1;
|
||||
unsigned proxy_protocol:1;
|
||||
} ngx_http_connection_t;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user