aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/event/ngx_event_quic.c21
-rw-r--r--src/event/ngx_event_quic_protection.c4
-rw-r--r--src/event/ngx_event_quic_transport.c99
-rw-r--r--src/event/ngx_event_quic_transport.h116
4 files changed, 172 insertions, 68 deletions
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
index 2f623ee30..86bf815dc 100644
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -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;
}
diff --git a/src/event/ngx_event_quic_protection.c b/src/event/ngx_event_quic_protection.c
index 23b8c011f..f648bbee8 100644
--- a/src/event/ngx_event_quic_protection.c
+++ b/src/event/ngx_event_quic_protection.c
@@ -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 {
diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c
index 2ea80ca7e..b12ea2bc1 100644
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -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;
}
diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h
index 39a11040f..a6d64aeb9 100644
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -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 {