Added checks for permitted frame types.

+ cleanup in macros for packet types
 + some style fixes in quic_transport.h (case, indentation)
This commit is contained in:
Vladimir Homutov 2020-03-20 20:03:44 +03:00
parent 1d35d0f31e
commit 21b6854bfe
4 changed files with 172 additions and 68 deletions

View File

@ -336,7 +336,7 @@ ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_quic_tp_t *tp,
return NGX_ERROR;
}
if ((pkt->flags & 0xf0) != NGX_QUIC_PKT_INITIAL) {
if (!ngx_quic_pkt_in(pkt->flags)) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"invalid initial packet: 0x%xi", pkt->flags);
return NGX_ERROR;
@ -563,20 +563,21 @@ ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b)
pkt.data = p;
pkt.len = b->last - p;
pkt.log = c->log;
pkt.flags = p[0];
if (p[0] == 0) {
if (pkt.flags == 0) {
/* XXX: no idea WTF is this, just ignore */
ngx_log_error(NGX_LOG_ALERT, c->log, 0, "FIREFOX: ZEROES");
break;
}
// TODO: check current state
if (p[0] & NGX_QUIC_PKT_LONG) {
if (ngx_quic_long_pkt(pkt.flags)) {
if ((p[0] & 0xf0) == NGX_QUIC_PKT_INITIAL) {
if (ngx_quic_pkt_in(pkt.flags)) {
rc = ngx_quic_initial_input(c, &pkt);
} else if ((p[0] & 0xf0) == NGX_QUIC_PKT_HANDSHAKE) {
} else if (ngx_quic_pkt_hs(pkt.flags)) {
rc = ngx_quic_handshake_input(c, &pkt);
} else {
@ -665,7 +666,7 @@ ngx_quic_handshake_input(ngx_connection_t *c, ngx_quic_header_t *pkt)
return NGX_ERROR;
}
if ((pkt->flags & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) {
if (!ngx_quic_pkt_hs(pkt->flags)) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"invalid packet type: 0x%xi", pkt->flags);
return NGX_ERROR;
@ -734,6 +735,14 @@ ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
while (p < end) {
len = ngx_quic_parse_frame(pkt, p, end, &frame);
if (len == NGX_DECLINED) {
/* TODO: handle protocol violation:
* such frame not allowed in this packet
*/
return NGX_ERROR;
}
if (len < 0) {
return NGX_ERROR;
}

View File

@ -904,7 +904,7 @@ ngx_quic_decrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
return NGX_ERROR;
}
if (pkt->flags & NGX_QUIC_PKT_LONG) {
if (ngx_quic_long_pkt(pkt->flags)) {
clearflags = pkt->flags ^ (mask[0] & 0x0f);
} else {
@ -926,7 +926,7 @@ ngx_quic_decrypt(ngx_pool_t *pool, ngx_ssl_conn_t *ssl_conn,
in.data = p;
if (pkt->flags & NGX_QUIC_PKT_LONG) {
if (ngx_quic_long_pkt(pkt->flags)) {
in.len = pkt->len - pnl;
} else {

View File

@ -261,7 +261,7 @@ ngx_quic_parse_long_header(ngx_quic_header_t *pkt)
return NGX_ERROR;
}
if (!(pkt->flags & NGX_QUIC_PKT_LONG)) {
if (!ngx_quic_long_pkt(pkt->flags)) {
ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "not a long packet");
return NGX_ERROR;
}
@ -368,7 +368,7 @@ ngx_quic_parse_short_header(ngx_quic_header_t *pkt, ngx_str_t *dcid)
return NGX_ERROR;
}
if (pkt->flags & NGX_QUIC_PKT_LONG) {
if (!ngx_quic_short_pkt(pkt->flags)) {
ngx_log_error(NGX_LOG_ERR, pkt->log, 0, "not a short packet");
return NGX_ERROR;
}
@ -489,12 +489,12 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
ngx_quic_frame_t *f)
{
u_char *p;
uint8_t flags;
uint64_t varint;
flags = pkt->flags;
p = start;
/* TODO: add a check if frame is allowed in this type of packet */
p = ngx_quic_parse_int(p, end, &varint);
if (p == NULL) {
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
@ -508,6 +508,10 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
case NGX_QUIC_FT_CRYPTO:
if (ngx_quic_pkt_zrtt(flags)) {
goto not_allowed;
}
p = ngx_quic_parse_int(p, end, &f->u.crypto.offset);
if (p == NULL) {
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
@ -539,6 +543,9 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
break;
case NGX_QUIC_FT_PADDING:
/* allowed in any packet type */
while (p < end && *p == NGX_QUIC_FT_PADDING) {
p++;
}
@ -548,6 +555,10 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
case NGX_QUIC_FT_ACK:
case NGX_QUIC_FT_ACK_ECN:
if (ngx_quic_pkt_zrtt(flags)) {
goto not_allowed;
}
p = ngx_quic_parse_int_multi(p, end, &f->u.ack.largest,
&f->u.ack.delay, &f->u.ack.range_count,
&f->u.ack.first_range, NULL);
@ -583,10 +594,17 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
break;
case NGX_QUIC_FT_PING:
/* allowed in any packet type */
break;
case NGX_QUIC_FT_NEW_CONNECTION_ID:
if (!(ngx_quic_short_pkt(flags) || ngx_quic_pkt_zrtt(flags))) {
goto not_allowed;
}
p = ngx_quic_parse_int_multi(p, end, &f->u.ncid.seqnum,
&f->u.ncid.retire, NULL);
if (p == NULL) {
@ -621,9 +639,20 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
f->u.ncid.seqnum, f->u.ncid.retire, f->u.ncid.len);
break;
case NGX_QUIC_FT_CONNECTION_CLOSE:
case NGX_QUIC_FT_CONNECTION_CLOSE2:
if (!ngx_quic_short_pkt(flags)) {
goto not_allowed;
}
/* fall through */
case NGX_QUIC_FT_CONNECTION_CLOSE:
if (ngx_quic_pkt_zrtt(flags)) {
goto not_allowed;
}
p = ngx_quic_parse_int(p, end, &f->u.close.error_code);
if (p == NULL) {
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
@ -685,6 +714,10 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
case NGX_QUIC_FT_STREAM6:
case NGX_QUIC_FT_STREAM7:
if (!(ngx_quic_short_pkt(flags) || ngx_quic_pkt_zrtt(flags))) {
goto not_allowed;
}
f->u.stream.type = f->type;
f->u.stream.off = ngx_quic_stream_bit_off(f->type);
@ -743,6 +776,10 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
case NGX_QUIC_FT_MAX_DATA:
if (!(ngx_quic_short_pkt(flags) || ngx_quic_pkt_zrtt(flags))) {
goto not_allowed;
}
p = ngx_quic_parse_int(p, end, &f->u.max_data.max_data);
if (p == NULL) {
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
@ -757,6 +794,10 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
case NGX_QUIC_FT_RESET_STREAM:
if (!(ngx_quic_short_pkt(flags) || ngx_quic_pkt_zrtt(flags))) {
goto not_allowed;
}
p = ngx_quic_parse_int_multi(p, end, &f->u.reset_stream.id,
&f->u.reset_stream.error_code,
&f->u.reset_stream.final_size, NULL);
@ -775,6 +816,10 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
case NGX_QUIC_FT_STOP_SENDING:
if (!(ngx_quic_short_pkt(flags) || ngx_quic_pkt_zrtt(flags))) {
goto not_allowed;
}
p = ngx_quic_parse_int_multi(p, end, &f->u.stop_sending.id,
&f->u.stop_sending.error_code, NULL);
if (p == NULL) {
@ -792,6 +837,10 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
case NGX_QUIC_FT_STREAMS_BLOCKED:
case NGX_QUIC_FT_STREAMS_BLOCKED2:
if (!(ngx_quic_short_pkt(flags) || ngx_quic_pkt_zrtt(flags))) {
goto not_allowed;
}
p = ngx_quic_parse_int(p, end, &f->u.streams_blocked.limit);
if (p == NULL) {
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
@ -809,14 +858,52 @@ ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
break;
/* TODO: implement parsing for all frames below */
case NGX_QUIC_FT_NEW_TOKEN:
case NGX_QUIC_FT_HANDSHAKE_DONE:
if (!ngx_quic_short_pkt(flags)) {
goto not_allowed;
}
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
"unimplemented frame type 0x%xi in packet", f->type);
break;
case NGX_QUIC_FT_MAX_STREAMS:
case NGX_QUIC_FT_MAX_STREAMS2:
case NGX_QUIC_FT_MAX_STREAM_DATA:
case NGX_QUIC_FT_DATA_BLOCKED:
case NGX_QUIC_FT_STREAM_DATA_BLOCKED:
case NGX_QUIC_FT_RETIRE_CONNECTION_ID:
case NGX_QUIC_FT_PATH_CHALLENGE:
case NGX_QUIC_FT_PATH_RESPONSE:
if (!(ngx_quic_short_pkt(flags) || ngx_quic_pkt_zrtt(flags))) {
goto not_allowed;
}
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
"unimplemented frame type 0x%xi in packet", f->type);
break;
default:
ngx_log_error(NGX_LOG_ERR, pkt->log, 0,
"unsupported frame type 0x%xd in packet", f->type);
"unknown frame type 0x%xi in packet", f->type);
return NGX_ERROR;
}
return p - start;
not_allowed:
ngx_log_error(NGX_LOG_INFO, pkt->log, 0,
"frame type 0x%xi is not allowed in packet with flags 0x%xi",
f->type, pkt->flags);
return NGX_DECLINED;
}

View File

@ -11,62 +11,70 @@
#include <ngx_event_openssl.h>
/* 17.2. Long Header Packets */
#define NGX_QUIC_PKT_LONG 0x80
#define ngx_quic_long_pkt(flags) ((flags) & 0x80) /* 17.2 */
#define ngx_quic_short_pkt(flags) (((flags) & 0x80) == 0) /* 17.3 */
#define NGX_QUIC_PKT_INITIAL 0xC0
#define NGX_QUIC_PKT_HANDSHAKE 0xE0
/* Long packet types */
#define NGX_QUIC_PKT_INITIAL 0xC0 /* 17.2.2 */
#define NGX_QUIC_PKT_ZRTT 0xD0 /* 17.2.3 */
#define NGX_QUIC_PKT_HANDSHAKE 0xE0 /* 17.2.4 */
#define NGX_QUIC_PKT_RETRY 0xF0 /* 17.2.5 */
#define ngx_quic_pkt_in(flags) (((flags) & 0xF0) == NGX_QUIC_PKT_INITIAL)
#define ngx_quic_pkt_zrtt(flags) (((flags) & 0xF0) == NGX_QUIC_PKT_ZRTT)
#define ngx_quic_pkt_hs(flags) (((flags) & 0xF0) == NGX_QUIC_PKT_HANDSHAKE)
#define ngx_quic_pkt_retry(flags) (((flags) & 0xF0) == NGX_QUIC_PKT_RETRY)
/* 12.4. Frames and Frame Types */
#define NGX_QUIC_FT_PADDING 0x00
#define NGX_QUIC_FT_PING 0x01
#define NGX_QUIC_FT_ACK 0x02
#define NGX_QUIC_FT_ACK_ECN 0x03
#define NGX_QUIC_FT_RESET_STREAM 0x04
#define NGX_QUIC_FT_STOP_SENDING 0x05
#define NGX_QUIC_FT_CRYPTO 0x06
#define NGX_QUIC_FT_NEW_TOKEN 0x07
#define NGX_QUIC_FT_STREAM0 0x08
#define NGX_QUIC_FT_STREAM1 0x09
#define NGX_QUIC_FT_STREAM2 0x0A
#define NGX_QUIC_FT_STREAM3 0x0B
#define NGX_QUIC_FT_STREAM4 0x0C
#define NGX_QUIC_FT_STREAM5 0x0D
#define NGX_QUIC_FT_STREAM6 0x0E
#define NGX_QUIC_FT_STREAM7 0x0F
#define NGX_QUIC_FT_MAX_DATA 0x10
#define NGX_QUIC_FT_MAX_STREAM_DATA 0x11
#define NGX_QUIC_FT_MAX_STREAMS 0x12
#define NGX_QUIC_FT_MAX_STREAMS2 0x13 // XXX
#define NGX_QUIC_FT_DATA_BLOCKED 0x14
#define NGX_QUIC_FT_STREAM_DATA_BLOCKED 0x15
#define NGX_QUIC_FT_STREAMS_BLOCKED 0x16
#define NGX_QUIC_FT_STREAMS_BLOCKED2 0x17 // XXX
#define NGX_QUIC_FT_NEW_CONNECTION_ID 0x18
#define NGX_QUIC_FT_RETIRE_CONNECTION_ID 0x19
#define NGX_QUIC_FT_PATH_CHALLENGE 0x1A
#define NGX_QUIC_FT_PATH_RESPONSE 0x1B
#define NGX_QUIC_FT_CONNECTION_CLOSE 0x1C
#define NGX_QUIC_FT_CONNECTION_CLOSE2 0x1D
#define NGX_QUIC_FT_HANDSHAKE_DONE 0x1E
#define NGX_QUIC_FT_PADDING 0x00
#define NGX_QUIC_FT_PING 0x01
#define NGX_QUIC_FT_ACK 0x02
#define NGX_QUIC_FT_ACK_ECN 0x03
#define NGX_QUIC_FT_RESET_STREAM 0x04
#define NGX_QUIC_FT_STOP_SENDING 0x05
#define NGX_QUIC_FT_CRYPTO 0x06
#define NGX_QUIC_FT_NEW_TOKEN 0x07
#define NGX_QUIC_FT_STREAM0 0x08
#define NGX_QUIC_FT_STREAM1 0x09
#define NGX_QUIC_FT_STREAM2 0x0A
#define NGX_QUIC_FT_STREAM3 0x0B
#define NGX_QUIC_FT_STREAM4 0x0C
#define NGX_QUIC_FT_STREAM5 0x0D
#define NGX_QUIC_FT_STREAM6 0x0E
#define NGX_QUIC_FT_STREAM7 0x0F
#define NGX_QUIC_FT_MAX_DATA 0x10
#define NGX_QUIC_FT_MAX_STREAM_DATA 0x11
#define NGX_QUIC_FT_MAX_STREAMS 0x12
#define NGX_QUIC_FT_MAX_STREAMS2 0x13
#define NGX_QUIC_FT_DATA_BLOCKED 0x14
#define NGX_QUIC_FT_STREAM_DATA_BLOCKED 0x15
#define NGX_QUIC_FT_STREAMS_BLOCKED 0x16
#define NGX_QUIC_FT_STREAMS_BLOCKED2 0x17
#define NGX_QUIC_FT_NEW_CONNECTION_ID 0x18
#define NGX_QUIC_FT_RETIRE_CONNECTION_ID 0x19
#define NGX_QUIC_FT_PATH_CHALLENGE 0x1A
#define NGX_QUIC_FT_PATH_RESPONSE 0x1B
#define NGX_QUIC_FT_CONNECTION_CLOSE 0x1C
#define NGX_QUIC_FT_CONNECTION_CLOSE2 0x1D
#define NGX_QUIC_FT_HANDSHAKE_DONE 0x1E
/* 22.4. QUIC Transport Error Codes Registry */
#define NGX_QUIC_ERR_NO_ERROR 0x00
#define NGX_QUIC_ERR_INTERNAL_ERROR 0x01
#define NGX_QUIC_ERR_SERVER_BUSY 0x02
#define NGX_QUIC_ERR_FLOW_CONTROL_ERROR 0x03
#define NGX_QUIC_ERR_STREAM_LIMIT_ERROR 0x04
#define NGX_QUIC_ERR_STREAM_STATE_ERROR 0x05
#define NGX_QUIC_ERR_FINAL_SIZE_ERROR 0x06
#define NGX_QUIC_ERR_FRAME_ENCODING_ERROR 0x07
#define NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR 0x08
#define NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR 0x09
#define NGX_QUIC_ERR_PROTOCOL_VIOLATION 0x0A
#define NGX_QUIC_ERR_INVALID_TOKEN 0x0B
#define NGX_QUIC_ERR_NO_ERROR 0x00
#define NGX_QUIC_ERR_INTERNAL_ERROR 0x01
#define NGX_QUIC_ERR_SERVER_BUSY 0x02
#define NGX_QUIC_ERR_FLOW_CONTROL_ERROR 0x03
#define NGX_QUIC_ERR_STREAM_LIMIT_ERROR 0x04
#define NGX_QUIC_ERR_STREAM_STATE_ERROR 0x05
#define NGX_QUIC_ERR_FINAL_SIZE_ERROR 0x06
#define NGX_QUIC_ERR_FRAME_ENCODING_ERROR 0x07
#define NGX_QUIC_ERR_TRANSPORT_PARAMETER_ERROR 0x08
#define NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR 0x09
#define NGX_QUIC_ERR_PROTOCOL_VIOLATION 0x0A
#define NGX_QUIC_ERR_INVALID_TOKEN 0x0B
/* 0xC is not defined */
#define NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED 0x0D
#define NGX_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED 0x0D
/* 0xE is not defined */
#define NGX_QUIC_ERR_CRYPTO_ERROR 0x10
#define NGX_QUIC_ERR_CRYPTO_ERROR 0x10
#define NGX_QUIC_ERR_LAST NGX_QUIC_ERR_CRYPTO_ERROR
@ -81,11 +89,11 @@
#define NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI 0x07
#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI 0x08
#define NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI 0x09
#define NGX_QUIC_TP_ACK_DELAY_EXPONENT 0x0a
#define NGX_QUIC_TP_MAX_ACK_DELAY 0x0b
#define NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION 0x0c
#define NGX_QUIC_TP_PREFERRED_ADDRESS 0x0d
#define NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT 0x0e
#define NGX_QUIC_TP_ACK_DELAY_EXPONENT 0x0A
#define NGX_QUIC_TP_MAX_ACK_DELAY 0x0B
#define NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION 0x0C
#define NGX_QUIC_TP_PREFERRED_ADDRESS 0x0D
#define NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT 0x0E
typedef struct {