summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/event/ngx_event_quic.c33
-rw-r--r--src/event/ngx_event_quic_transport.c245
-rw-r--r--src/event/ngx_event_quic_transport.h2
3 files changed, 279 insertions, 1 deletions
diff --git a/src/event/ngx_event_quic.c b/src/event/ngx_event_quic.c
index 570945755..5a87092cc 100644
--- a/src/event/ngx_event_quic.c
+++ b/src/event/ngx_event_quic.c
@@ -32,6 +32,7 @@ struct ngx_quic_connection_s {
ngx_str_t dcid;
ngx_str_t token;
+ ngx_uint_t client_tp_done;
ngx_quic_tp_t tp;
/* current packet numbers for each namespace */
@@ -206,7 +207,10 @@ static int
ngx_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;
+ u_char *p, *end;
+ size_t client_params_len;
+ const uint8_t *client_params;
+ ngx_quic_tp_t ctp;
ngx_quic_frame_t *frame;
ngx_connection_t *c;
ngx_quic_connection_t *qc;
@@ -217,6 +221,33 @@ ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
"ngx_quic_add_handshake_data");
+ /* XXX: obtain client parameters after the handshake? */
+ if (!qc->client_tp_done) {
+
+ SSL_get_peer_quic_transport_params(ssl_conn, &client_params,
+ &client_params_len);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "SSL_get_peer_quic_transport_params(): params_len %ui",
+ client_params_len);
+
+ if (client_params_len != 0) {
+ p = (u_char *) client_params;
+ end = p + client_params_len;
+
+ ngx_memzero(&ctp, sizeof(ngx_quic_tp_t));
+
+ if (ngx_quic_parse_transport_params(p, end, &ctp, c->log) != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ /* TODO: save/use obtained client parameters: merge with ours? */
+
+ qc->client_tp_done = 1;
+ }
+ }
+
frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t));
if (frame == NULL) {
return 0;
diff --git a/src/event/ngx_event_quic_transport.c b/src/event/ngx_event_quic_transport.c
index dadc4f197..b70d4da6e 100644
--- a/src/event/ngx_event_quic_transport.c
+++ b/src/event/ngx_event_quic_transport.c
@@ -56,6 +56,7 @@ static u_char *ngx_quic_parse_int_multi(u_char *pos, u_char *end, ...);
static void ngx_quic_build_int(u_char **pos, uint64_t value);
static u_char *ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value);
+/*static*/ u_char *ngx_quic_read_uint16(u_char *pos, u_char *end, uint16_t *value); // usage depends on quic_version
static u_char *ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value);
static u_char *ngx_quic_read_bytes(u_char *pos, u_char *end, size_t len,
u_char **out);
@@ -70,6 +71,9 @@ static size_t ngx_quic_create_max_streams(u_char *p,
ngx_quic_max_streams_frame_t *ms);
static size_t ngx_quic_create_close(u_char *p, ngx_quic_close_frame_t *cl);
+static ngx_int_t ngx_quic_parse_transport_param(u_char *p, u_char *end,
+ uint16_t id, ngx_quic_tp_t *dst);
+
/* literal errors indexed by corresponding value */
static char *ngx_quic_errors[] = {
@@ -167,6 +171,19 @@ ngx_quic_read_uint8(u_char *pos, u_char *end, uint8_t *value)
}
+/*static*/ ngx_inline u_char *
+ngx_quic_read_uint16(u_char *pos, u_char *end, uint16_t *value)
+{
+ if ((size_t)(end - pos) < sizeof(uint16_t)) {
+ return NULL;
+ }
+
+ *value = ngx_quic_parse_uint16(pos);
+
+ return pos + sizeof(uint16_t);
+}
+
+
static ngx_inline u_char *
ngx_quic_read_uint32(u_char *pos, u_char *end, uint32_t *value)
{
@@ -1198,6 +1215,234 @@ ngx_quic_create_max_streams(u_char *p, ngx_quic_max_streams_frame_t *ms)
}
+static ngx_int_t
+ngx_quic_parse_transport_param(u_char *p, u_char *end, uint16_t id,
+ ngx_quic_tp_t *dst)
+{
+ uint64_t varint;
+
+ switch (id) {
+ case NGX_QUIC_TP_ORIGINAL_CONNECTION_ID:
+ case NGX_QUIC_TP_STATELESS_RESET_TOKEN:
+ case NGX_QUIC_TP_PREFERRED_ADDRESS:
+ // TODO
+ return NGX_ERROR;
+ }
+
+ switch (id) {
+
+ case NGX_QUIC_TP_DISABLE_ACTIVE_MIGRATION:
+ /* zero-length option */
+ if (end - p != 0) {
+ return NGX_ERROR;
+ }
+ dst->disable_active_migration = 1;
+ return NGX_OK;
+
+ case NGX_QUIC_TP_MAX_IDLE_TIMEOUT:
+ case NGX_QUIC_TP_MAX_PACKET_SIZE:
+ case NGX_QUIC_TP_INITIAL_MAX_DATA:
+ case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
+ case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
+ case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
+ case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
+ case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI:
+ case NGX_QUIC_TP_ACK_DELAY_EXPONENT:
+ case NGX_QUIC_TP_MAX_ACK_DELAY:
+ case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
+
+ p = ngx_quic_parse_int(p, end, &varint);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+ break;
+
+ default:
+ return NGX_ERROR;
+ }
+
+ switch (id) {
+
+ case NGX_QUIC_TP_MAX_IDLE_TIMEOUT:
+ dst->max_idle_timeout = varint;
+ break;
+
+ case NGX_QUIC_TP_MAX_PACKET_SIZE:
+ dst->max_packet_size = varint;
+ break;
+
+ case NGX_QUIC_TP_INITIAL_MAX_DATA:
+ dst->initial_max_data = varint;
+ break;
+
+ case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_LOCAL:
+ dst->initial_max_stream_data_bidi_local = varint;
+ break;
+
+ case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_BIDI_REMOTE:
+ dst->initial_max_stream_data_bidi_remote = varint;
+ break;
+
+ case NGX_QUIC_TP_INITIAL_MAX_STREAM_DATA_UNI:
+ dst->initial_max_stream_data_uni = varint;
+ break;
+
+ case NGX_QUIC_TP_INITIAL_MAX_STREAMS_BIDI:
+ dst->initial_max_streams_bidi = varint;
+ break;
+
+ case NGX_QUIC_TP_INITIAL_MAX_STREAMS_UNI:
+ dst->initial_max_streams_uni = varint;
+ break;
+
+ case NGX_QUIC_TP_ACK_DELAY_EXPONENT:
+ dst->ack_delay_exponent = varint;
+ break;
+
+ case NGX_QUIC_TP_MAX_ACK_DELAY:
+ dst->max_ack_delay = varint;
+ break;
+
+ case NGX_QUIC_TP_ACTIVE_CONNECTION_ID_LIMIT:
+ dst->active_connection_id_limit = varint;
+ break;
+
+ default:
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+}
+
+
+ngx_int_t
+ngx_quic_parse_transport_params(u_char *p, u_char *end, ngx_quic_tp_t *tp,
+ ngx_log_t *log)
+{
+
+#if (quic_version < 0xff00001b)
+
+ uint16_t id, len, tp_len;
+
+ p = ngx_quic_read_uint16(p, end, &tp_len);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "failed to parse total transport params length");
+ return NGX_ERROR;
+ }
+
+ while (p < end) {
+
+ p = ngx_quic_read_uint16(p, end, &id);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "failed to parse transport param id");
+ return NGX_ERROR;
+ }
+
+ p = ngx_quic_read_uint16(p, end, &len);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "failed to parse transport param id 0x%xi length", id);
+ return NGX_ERROR;
+ }
+
+ if (ngx_quic_parse_transport_param(p, p + len, id, tp) != NGX_OK) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "failed to parse transport param id 0x%xi data", id);
+ return NGX_ERROR;
+ }
+
+ p += len;
+ };
+
+#else
+
+ uint64_t id, len;
+
+ while (p < end) {
+ p = ngx_quic_parse_int(p, end, &id);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "failed to parse transport param id");
+ return NGX_ERROR;
+ }
+
+ p = ngx_quic_parse_int(p, end, &len);
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "failed to parse transport param id 0x%xi length", id);
+ return NGX_ERROR;
+ }
+
+ if (ngx_quic_parse_transport_param(p, p + len, id, tp) != NGX_OK) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "failed to parse transport param id 0x%xi data", id);
+ return NGX_ERROR;
+ }
+
+ p += len;
+
+ }
+
+#endif
+
+ if (p != end) {
+ ngx_log_error(NGX_LOG_INFO, log, 0,
+ "trailing garbage in transport parameters: %ui bytes",
+ end - p);
+ return NGX_ERROR;
+ }
+
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, log, 0,
+ "client transport parameters parsed successfully");
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "disable active migration: %ui",
+ tp->disable_active_migration);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "idle timeout: %ui",
+ tp->max_idle_timeout);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "max packet size: %ui",
+ tp->max_packet_size);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "max data: %ui",
+ tp->initial_max_data);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "max stream data bidi local: %ui",
+ tp->initial_max_stream_data_bidi_local);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "max stream data bidi remote: %ui",
+ tp->initial_max_stream_data_bidi_remote);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "max stream data uni: %ui",
+ tp->initial_max_stream_data_uni);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "initial max streams bidi: %ui",
+ tp->initial_max_streams_bidi);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "initial max streams uni: %ui",
+ tp->initial_max_streams_uni);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "ack delay exponent: %ui",
+ tp->ack_delay_exponent);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "max ack delay: %ui",
+ tp->max_ack_delay);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0,
+ "active connection id limit: %ui",
+ tp->active_connection_id_limit);
+
+ return NGX_OK;
+}
+
+
ssize_t
ngx_quic_create_transport_params(u_char *pos, u_char *end, ngx_quic_tp_t *tp)
{
diff --git a/src/event/ngx_event_quic_transport.h b/src/event/ngx_event_quic_transport.h
index c8af85c33..931361180 100644
--- a/src/event/ngx_event_quic_transport.h
+++ b/src/event/ngx_event_quic_transport.h
@@ -267,6 +267,8 @@ ssize_t ngx_quic_parse_frame(ngx_quic_header_t *pkt, u_char *start, u_char *end,
ngx_quic_frame_t *frame);
ssize_t ngx_quic_create_frame(u_char *p, u_char *end, ngx_quic_frame_t *f);
+ngx_int_t ngx_quic_parse_transport_params(u_char *p, u_char *end,
+ ngx_quic_tp_t *tp, ngx_log_t *log);
ssize_t ngx_quic_create_transport_params(u_char *p, u_char *end,
ngx_quic_tp_t *tp);