mirror of
https://github.com/nginx/nginx.git
synced 2025-06-25 16:00:40 +08:00
QUIC: added version negotiation support.
If a client attemtps to start a new connection with unsupported version, a version negotiation packet is sent that contains a list of supported versions (currently this is a single version, selected at compile time).
This commit is contained in:
parent
5a4aaa6aed
commit
4ecea6cbed
@ -169,6 +169,8 @@ static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
|
|||||||
|
|
||||||
static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
|
static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
|
||||||
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
ngx_quic_conf_t *conf, ngx_quic_header_t *pkt);
|
||||||
|
static ngx_int_t ngx_quic_negotiate_version(ngx_connection_t *c,
|
||||||
|
ngx_quic_header_t *inpkt);
|
||||||
static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid);
|
static ngx_int_t ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid);
|
||||||
static ngx_int_t ngx_quic_retry(ngx_connection_t *c);
|
static ngx_int_t ngx_quic_retry(ngx_connection_t *c);
|
||||||
static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token);
|
static ngx_int_t ngx_quic_new_token(ngx_connection_t *c, ngx_str_t *token);
|
||||||
@ -659,6 +661,10 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pkt->version != NGX_QUIC_VERSION) {
|
||||||
|
return ngx_quic_negotiate_version(c, pkt);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ngx_quic_pkt_in(pkt->flags)) {
|
if (!ngx_quic_pkt_in(pkt->flags)) {
|
||||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
"quic invalid initial packet: 0x%xd", pkt->flags);
|
"quic invalid initial packet: 0x%xd", pkt->flags);
|
||||||
@ -823,6 +829,35 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_quic_negotiate_version(ngx_connection_t *c, ngx_quic_header_t *inpkt)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
ngx_quic_header_t pkt;
|
||||||
|
|
||||||
|
/* buffer size is calculated assuming a single supported version */
|
||||||
|
static u_char buf[NGX_QUIC_MAX_LONG_HEADER + sizeof(uint32_t)];
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
|
||||||
|
"sending version negotiation packet");
|
||||||
|
|
||||||
|
pkt.log = c->log;
|
||||||
|
pkt.flags = NGX_QUIC_PKT_LONG | NGX_QUIC_PKT_FIXED_BIT;
|
||||||
|
pkt.dcid = inpkt->scid;
|
||||||
|
pkt.scid = inpkt->dcid;
|
||||||
|
|
||||||
|
len = ngx_quic_create_version_negotiation(&pkt, buf);
|
||||||
|
|
||||||
|
#ifdef NGX_QUIC_DEBUG_PACKETS
|
||||||
|
ngx_quic_hexdump(c->log, "quic vnego packet to send", buf, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(void) c->send(c, buf, len);
|
||||||
|
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid)
|
ngx_quic_new_dcid(ngx_connection_t *c, ngx_str_t *odcid)
|
||||||
{
|
{
|
||||||
@ -1628,6 +1663,12 @@ ngx_quic_retry_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pkt->version != NGX_QUIC_VERSION) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
|
"quic unsupported version: 0x%xD", pkt->version);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_quic_pkt_zrtt(pkt->flags)) {
|
if (ngx_quic_pkt_zrtt(pkt->flags)) {
|
||||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
"quic discard inflight 0-RTT packet");
|
"quic discard inflight 0-RTT packet");
|
||||||
@ -1715,6 +1756,12 @@ ngx_quic_initial_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pkt->version != NGX_QUIC_VERSION) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
|
"quic unsupported version: 0x%xD", pkt->version);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_quic_parse_initial_header(pkt) != NGX_OK) {
|
if (ngx_quic_parse_initial_header(pkt) != NGX_OK) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
@ -1765,6 +1812,12 @@ ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pkt->version != NGX_QUIC_VERSION) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
|
"quic unsupported version: 0x%xD", pkt->version);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
|
if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
@ -1825,6 +1878,12 @@ ngx_quic_early_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pkt->version != NGX_QUIC_VERSION) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
|
"quic unsupported version: 0x%xD", pkt->version);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
|
if (ngx_quic_check_peer(qc, pkt) != NGX_OK) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -88,6 +88,15 @@ static ngx_int_t ngx_quic_parse_transport_param(u_char *p, u_char *end,
|
|||||||
uint16_t id, ngx_quic_tp_t *dst);
|
uint16_t id, ngx_quic_tp_t *dst);
|
||||||
|
|
||||||
|
|
||||||
|
/* currently only single version (selected at compile-time) is supported */
|
||||||
|
uint32_t ngx_quic_versions[] = {
|
||||||
|
NGX_QUIC_VERSION
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NGX_QUIC_NVERSIONS \
|
||||||
|
(sizeof(ngx_quic_versions) / sizeof(ngx_quic_versions[0]))
|
||||||
|
|
||||||
|
|
||||||
/* literal errors indexed by corresponding value */
|
/* literal errors indexed by corresponding value */
|
||||||
static char *ngx_quic_errors[] = {
|
static char *ngx_quic_errors[] = {
|
||||||
"NO_ERROR",
|
"NO_ERROR",
|
||||||
@ -232,8 +241,8 @@ ngx_quic_error_text(uint64_t error_code)
|
|||||||
ngx_int_t
|
ngx_int_t
|
||||||
ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
|
ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
|
||||||
{
|
{
|
||||||
u_char *p, *end;
|
u_char *p, *end;
|
||||||
uint8_t idlen;
|
uint8_t idlen;
|
||||||
|
|
||||||
p = pkt->data;
|
p = pkt->data;
|
||||||
end = pkt->data + pkt->len;
|
end = pkt->data + pkt->len;
|
||||||
@ -270,12 +279,6 @@ ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
|
|||||||
return NGX_DECLINED;
|
return NGX_DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pkt->version != NGX_QUIC_VERSION) {
|
|
||||||
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
|
||||||
"quic unsupported version: 0x%xD", pkt->version);
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
p = ngx_quic_read_uint8(p, end, &idlen);
|
p = ngx_quic_read_uint8(p, end, &idlen);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
|
||||||
@ -326,6 +329,36 @@ ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t
|
||||||
|
ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out)
|
||||||
|
{
|
||||||
|
u_char *p, *start;
|
||||||
|
ngx_uint_t i;
|
||||||
|
|
||||||
|
p = start = out;
|
||||||
|
|
||||||
|
*p++ = pkt->flags;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Version field of a Version Negotiation packet
|
||||||
|
* MUST be set to 0x00000000
|
||||||
|
*/
|
||||||
|
p = ngx_quic_write_uint32(p, 0);
|
||||||
|
|
||||||
|
*p++ = pkt->dcid.len;
|
||||||
|
p = ngx_cpymem(p, pkt->dcid.data, pkt->dcid.len);
|
||||||
|
|
||||||
|
*p++ = pkt->scid.len;
|
||||||
|
p = ngx_cpymem(p, pkt->scid.data, pkt->scid.len);
|
||||||
|
|
||||||
|
for (i = 0; i < NGX_QUIC_NVERSIONS; i++) {
|
||||||
|
p = ngx_quic_write_uint32(p, ngx_quic_versions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
|
ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
|
||||||
size_t pkt_len, u_char **pnp)
|
size_t pkt_len, u_char **pnp)
|
||||||
|
@ -317,6 +317,8 @@ typedef struct {
|
|||||||
|
|
||||||
u_char *ngx_quic_error_text(uint64_t error_code);
|
u_char *ngx_quic_error_text(uint64_t error_code);
|
||||||
|
|
||||||
|
size_t ngx_quic_create_version_negotiation(ngx_quic_header_t *pkt, u_char *out);
|
||||||
|
|
||||||
ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt);
|
ngx_int_t ngx_quic_parse_long_header(ngx_quic_header_t *pkt);
|
||||||
size_t ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
|
size_t ngx_quic_create_long_header(ngx_quic_header_t *pkt, u_char *out,
|
||||||
size_t pkt_len, u_char **pnp);
|
size_t pkt_len, u_char **pnp);
|
||||||
|
Loading…
Reference in New Issue
Block a user