]> git.kaiwu.me - nginx.git/commitdiff
Added processing of client transport parameters.
authorVladimir Homutov <vl@nginx.com>
Sat, 21 Mar 2020 17:51:59 +0000 (20:51 +0300)
committerVladimir Homutov <vl@nginx.com>
Sat, 21 Mar 2020 17:51:59 +0000 (20:51 +0300)
note:
 + parameters are available in SSL connection since they are obtained by ssl
   stack

quote:
   During connection establishment, both endpoints make authenticated
   declarations of their transport parameters.  These declarations are
   made unilaterally by each endpoint.

and really, we send our parameters before we read client's.

no handling of incoming parameters is made by this patch.

src/event/ngx_event_quic.c
src/event/ngx_event_quic_transport.c
src/event/ngx_event_quic_transport.h

index 5709457552c339a5f96c2c343f3c436d27d6554f..5a87092ccc0186113a23282ca864365da683bdea 100644 (file)
@@ -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;
index dadc4f19716660b04e38d2dd73ddd1255141ed28..b70d4da6e5f9a92613f7e41eb703a603be3db2b9 100644 (file)
@@ -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)
 {
index c8af85c333f40f51e5a62fbcf240345e77fa1c70..931361180d844185e128a6529f43d72964f2aaeb 100644 (file)
@@ -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);