lsquic_trans_params.c revision 92f6e17b
1/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc.  See LICENSE. */
2/*
3 * lsquic_trans_params.c
4 */
5
6#include <assert.h>
7#include <errno.h>
8#include <inttypes.h>
9#include <stddef.h>
10#include <stdint.h>
11#include <string.h>
12
13#include <arpa/inet.h>
14#include <sys/socket.h>
15
16#include "lsquic_byteswap.h"
17#include "lsquic_int_types.h"
18#include "lsquic_types.h"
19#include "lsquic_version.h"
20#include "lsquic_sizes.h"
21#include "lsquic_trans_params.h"
22#include "lsquic_util.h"
23#include "lsquic_varint.h"
24
25#define LSQUIC_LOGGER_MODULE LSQLM_TRAPA
26#include "lsquic_logger.h"
27
28
29static const uint64_t def_vals[MAX_TPI + 1] =
30{
31    [TPI_MAX_PACKET_SIZE]                   =  TP_DEF_MAX_PACKET_SIZE,
32    [TPI_ACK_DELAY_EXPONENT]                =  TP_DEF_ACK_DELAY_EXP,
33    [TPI_INIT_MAX_STREAMS_UNI]              =  TP_DEF_INIT_MAX_STREAMS_UNI,
34    [TPI_INIT_MAX_STREAMS_BIDI]             =  TP_DEF_INIT_MAX_STREAMS_BIDI,
35    [TPI_INIT_MAX_DATA]                     =  TP_DEF_INIT_MAX_DATA,
36    [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]   =  TP_DEF_INIT_MAX_STREAM_DATA_BIDI_LOCAL,
37    [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]  =  TP_DEF_INIT_MAX_STREAM_DATA_BIDI_REMOTE,
38    [TPI_INIT_MAX_STREAM_DATA_UNI]          =  TP_DEF_INIT_MAX_STREAM_DATA_UNI,
39    [TPI_IDLE_TIMEOUT]                      =  TP_DEF_IDLE_TIMEOUT,
40    [TPI_MAX_ACK_DELAY]                     =  TP_DEF_MAX_ACK_DELAY,
41    [TPI_ACTIVE_CONNECTION_ID_LIMIT]        =  TP_DEF_ACTIVE_CONNECTION_ID_LIMIT,
42};
43
44
45static const uint64_t max_vals[MAX_TPI + 1] =
46{
47    [TPI_MAX_PACKET_SIZE]                   =  VINT_MAX_VALUE,
48    [TPI_ACK_DELAY_EXPONENT]                =  VINT_MAX_VALUE,
49    [TPI_INIT_MAX_STREAMS_UNI]              =  VINT_MAX_VALUE,
50    [TPI_INIT_MAX_STREAMS_BIDI]             =  VINT_MAX_VALUE,
51    [TPI_INIT_MAX_DATA]                     =  VINT_MAX_VALUE,
52    [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]   =  VINT_MAX_VALUE,
53    [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]  =  VINT_MAX_VALUE,
54    [TPI_INIT_MAX_STREAM_DATA_UNI]          =  VINT_MAX_VALUE,
55    [TPI_IDLE_TIMEOUT]                      =  VINT_MAX_VALUE,
56    [TPI_MAX_ACK_DELAY]                     =  TP_MAX_MAX_ACK_DELAY,
57    [TPI_ACTIVE_CONNECTION_ID_LIMIT]        =  VINT_MAX_VALUE,
58};
59
60
61#define TP_OFF(name_) ((uint64_t *) &((struct transport_params *) 0 \
62    )->tp_numerics_u.s.name_ - (uint64_t *) &((struct transport_params *) \
63    0)->tp_numerics_u.s)
64
65/* Map enum transport_params to index of tp_numerics_u.a; for numeric values only */
66static const unsigned tpi2idx[MAX_TPI + 1] =
67{
68    [TPI_MAX_PACKET_SIZE]                   =  TP_OFF(max_packet_size),
69    [TPI_ACK_DELAY_EXPONENT]                =  TP_OFF(ack_delay_exponent),
70    [TPI_INIT_MAX_STREAMS_UNI]              =  TP_OFF(init_max_streams_uni),
71    [TPI_INIT_MAX_STREAMS_BIDI]             =  TP_OFF(init_max_streams_bidi),
72    [TPI_INIT_MAX_DATA]                     =  TP_OFF(init_max_data),
73    [TPI_INIT_MAX_STREAM_DATA_BIDI_LOCAL]   =  TP_OFF(init_max_stream_data_bidi_local),
74    [TPI_INIT_MAX_STREAM_DATA_BIDI_REMOTE]  =  TP_OFF(init_max_stream_data_bidi_remote),
75    [TPI_INIT_MAX_STREAM_DATA_UNI]          =  TP_OFF(init_max_stream_data_uni),
76    [TPI_IDLE_TIMEOUT]                      =  TP_OFF(idle_timeout),
77    [TPI_MAX_ACK_DELAY]                     =  TP_OFF(max_ack_delay),
78    [TPI_ACTIVE_CONNECTION_ID_LIMIT]        =  TP_OFF(active_connection_id_limit),
79};
80
81
82static size_t
83preferred_address_size (const struct transport_params *params)
84{
85    return sizeof(params->tp_preferred_address.ipv4_addr)
86         + sizeof(params->tp_preferred_address.ipv4_port)
87         + sizeof(params->tp_preferred_address.ipv6_addr)
88         + sizeof(params->tp_preferred_address.ipv6_port)
89         + 1 + params->tp_preferred_address.cid.len
90         + sizeof(params->tp_preferred_address.srst)
91         ;
92}
93
94
95int
96lsquic_tp_encode (const struct transport_params *params,
97                  unsigned char *const buf, size_t bufsz)
98{
99    unsigned char *p;
100    size_t need = 2;
101    uint16_t u16;
102    enum transport_param_id tpi;
103    unsigned bits[MAX_TPI + 1];
104
105    if (params->tp_flags & TRAPA_SERVER)
106    {
107        if (params->tp_flags & TRAPA_ORIGINAL_CID)
108            need += 4 + params->tp_original_cid.len;
109        if (params->tp_flags & TRAPA_RESET_TOKEN)
110            need += 4 + sizeof(params->tp_stateless_reset_token);
111        if (params->tp_flags & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
112            need += 4 + preferred_address_size(params);
113    }
114
115    for (tpi = 0; tpi <= MAX_TPI; ++tpi)
116        if ((NUMERIC_TRANS_PARAMS & (1 << tpi))
117                    && params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi])
118        {
119            if (params->tp_numerics_u.a[tpi2idx[tpi]] < max_vals[tpi])
120            {
121                bits[tpi] = vint_val2bits(params->tp_numerics_u.a[tpi2idx[tpi]]);
122                need += 4 + (1 << bits[tpi]);
123            }
124            else
125            {
126                LSQ_DEBUG("numeric value is too large (%"PRIu64" vs maximum "
127                    "of %"PRIu64, params->tp_numerics_u.a[tpi2idx[tpi]],
128                    max_vals[tpi]);
129                return -1;
130            }
131        }
132
133    if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION)
134        need += 4 + 0;
135
136    if (need > bufsz || need > UINT16_MAX)
137    {
138        errno = ENOBUFS;
139        return -1;
140    }
141
142    p = buf;
143
144#define WRITE_TO_P(src, len) do {                                       \
145    memcpy(p, src, len);                                                \
146    p += len;                                                           \
147} while (0)
148
149#if __BYTE_ORDER == __LITTLE_ENDIAN
150#define WRITE_UINT_TO_P(val, width) do {                                \
151    u##width = bswap_##width(val);                                      \
152    WRITE_TO_P(&u##width, sizeof(u##width));                            \
153} while (0)
154#else
155#define WRITE_UINT_TO_P(val, width) do {                                \
156    u##width = val;                                                     \
157    WRITE_TO_P(&u##width, sizeof(u##width));                            \
158} while (0)
159#endif
160
161#define WRITE_PARAM_TO_P(tpidx, tpval, width) do {                      \
162    WRITE_UINT_TO_P(tpidx, 16);                                         \
163    WRITE_UINT_TO_P(width / 8, 16);                                     \
164    if (width > 8)                                                      \
165        WRITE_UINT_TO_P(tpval, width);                                  \
166    else if (width)                                                     \
167        *p++ = tpval;                                                   \
168} while (0)
169
170    WRITE_UINT_TO_P(need - 2 + buf - p, 16);
171
172    for (tpi = 0; tpi <= MAX_TPI; ++tpi)
173        if (NUMERIC_TRANS_PARAMS & (1 << tpi))
174        {
175            if (params->tp_numerics_u.a[tpi2idx[tpi]] != def_vals[tpi])
176            {
177                WRITE_UINT_TO_P(tpi, 16);
178                WRITE_UINT_TO_P(1 << bits[tpi], 16);
179                vint_write(p, params->tp_numerics_u.a[tpi2idx[tpi]], bits[tpi],
180                                                                1 << bits[tpi]);
181                p += 1 << bits[tpi];
182            }
183        }
184        else
185            switch (tpi)
186            {
187            case TPI_ORIGINAL_CONNECTION_ID:
188                if (params->tp_flags & TRAPA_ORIGINAL_CID)
189                {
190                    WRITE_UINT_TO_P(TPI_ORIGINAL_CONNECTION_ID, 16);
191                    WRITE_UINT_TO_P(params->tp_original_cid.len, 16);
192                    WRITE_TO_P(params->tp_original_cid.idbuf,
193                                                params->tp_original_cid.len);
194                }
195                break;
196            case TPI_STATELESS_RESET_TOKEN:
197                if (params->tp_flags & TRAPA_RESET_TOKEN)
198                {
199                    WRITE_UINT_TO_P(TPI_STATELESS_RESET_TOKEN, 16);
200                    WRITE_UINT_TO_P(sizeof(params->tp_stateless_reset_token),
201                                                                            16);
202                    WRITE_TO_P(params->tp_stateless_reset_token,
203                                    sizeof(params->tp_stateless_reset_token));
204                }
205                break;
206            case TPI_PREFERRED_ADDRESS:
207                if (params->tp_flags
208                                & (TRAPA_PREFADDR_IPv4|TRAPA_PREFADDR_IPv6))
209                {
210                    WRITE_UINT_TO_P(TPI_PREFERRED_ADDRESS, 16);
211                    WRITE_UINT_TO_P(preferred_address_size(params), 16);
212                    if (params->tp_flags & TRAPA_PREFADDR_IPv4)
213                    {
214                        WRITE_TO_P(&params->tp_preferred_address.ipv4_addr,
215                                sizeof(params->tp_preferred_address.ipv4_addr));
216                        WRITE_UINT_TO_P(params->tp_preferred_address.ipv4_port,
217                                                                            16);
218                    }
219                    else
220                    {
221                        memset(p, 0, 6);
222                        p += 6;
223                    }
224                    if (params->tp_flags & TRAPA_PREFADDR_IPv6)
225                    {
226                        WRITE_TO_P(&params->tp_preferred_address.ipv6_addr,
227                                sizeof(params->tp_preferred_address.ipv6_addr));
228                        WRITE_UINT_TO_P(params->tp_preferred_address.ipv6_port,
229                                                                            16);
230                    }
231                    else
232                    {
233                        memset(p, 0, 18);
234                        p += 18;
235                    }
236                    *p++ = params->tp_preferred_address.cid.len;
237                    WRITE_TO_P(params->tp_preferred_address.cid.idbuf,
238                                        params->tp_preferred_address.cid.len);
239                    WRITE_TO_P(params->tp_preferred_address.srst,
240                                    sizeof(params->tp_preferred_address.srst));
241                }
242                break;
243            case TPI_DISABLE_ACTIVE_MIGRATION:
244                if (params->tp_disable_active_migration != TP_DEF_DISABLE_ACTIVE_MIGRATION)
245                {
246                    WRITE_UINT_TO_P(TPI_DISABLE_ACTIVE_MIGRATION, 16);
247                    WRITE_UINT_TO_P(0, 16);
248                }
249                break;
250            default:
251                assert(0);
252                return -1;
253            }
254
255    assert(buf + need == p);
256    return (int) (p - buf);
257
258#undef WRITE_TO_P
259#undef WRITE_UINT_TO_P
260}
261
262
263int
264lsquic_tp_decode (const unsigned char *const buf, size_t bufsz,
265                  int is_server,
266                  struct transport_params *params)
267{
268    const unsigned char *p, *end, *q;
269    uint16_t len, param_id, tlen;
270    unsigned set_of_ids;
271    int s;
272
273    p = buf;
274    end = buf + bufsz;
275
276    *params = TP_INITIALIZER();
277
278    if (is_server)
279        params->tp_flags |= TRAPA_SERVER;
280
281    if (end - p < 2)
282        return -1;
283    READ_UINT(len, 16, p, 2);
284    p += 2;
285    if (len > end - p)
286        return -1;
287    end = p + len;
288
289#define EXPECT_LEN(expected_len) do {                               \
290    if (expected_len != len)                                        \
291        return -1;                                                  \
292} while (0)
293
294#define EXPECT_AT_LEAST(expected_len) do {                          \
295    if ((expected_len) > (uintptr_t) (p + len - q))                 \
296        return -1;                                                  \
297} while (0)
298
299    set_of_ids = 0;
300    while (p < end)
301    {
302        READ_UINT(param_id, 16, p, 2);
303        p += 2;
304        READ_UINT(len, 16, p, 2);
305        p += 2;
306        if (len > end - p)
307            return -1;
308        /* If we need to support parameter IDs 31 and up, we will need to
309         * change this code:
310         */
311        if (param_id < sizeof(set_of_ids) * 8)
312        {
313            /* Only check duplicates for IDs <= 31: all standard parameters
314             * fit in a bitmask 32 bits wide.
315             */
316            if (set_of_ids & (1 << param_id))
317                return -1;
318            set_of_ids |= 1 << param_id;
319        }
320        else
321            goto unknown;
322        if (NUMERIC_TRANS_PARAMS & (1u << param_id))
323        {
324            switch (len)
325            {
326            case 1:
327            case 2:
328            case 4:
329            case 8:
330                s = vint_read(p, p + len,
331                            &params->tp_numerics_u.a[tpi2idx[param_id]]);
332                if (s == len)
333                {
334                    if (params->tp_numerics_u.a[tpi2idx[param_id]]
335                                                        > max_vals[param_id])
336                    {
337                        LSQ_DEBUG("numeric value of parameter 0x%X is too "
338                            "large (%"PRIu64" vs maximum of %"PRIu64,
339                            param_id,
340                            params->tp_numerics_u.a[tpi2idx[param_id]],
341                            max_vals[param_id]);
342                        return -1;
343                    }
344                    p += s;
345                    break;
346                }
347                else
348                {
349                    LSQ_DEBUG("cannot read the value of numeric transport "
350                                        "param %u of length %u", param_id, len);
351                    return -1;
352                }
353            default:
354                LSQ_DEBUG("invalid length=%u for numeric transport parameter",
355                                                                        len);
356                return -1;
357            }
358        }
359        else
360        {
361            switch (param_id)
362            {
363            case TPI_DISABLE_ACTIVE_MIGRATION:
364                EXPECT_LEN(0);
365                params->tp_disable_active_migration = 1;
366                break;
367            case TPI_STATELESS_RESET_TOKEN:
368                /* Client MUST not include reset token,
369                 * see [draft-ietf-quic-transport-11], Section 6.4.1
370                 */
371                if (!is_server)
372                    return -1;
373                EXPECT_LEN(sizeof(params->tp_stateless_reset_token));
374                memcpy(params->tp_stateless_reset_token, p,
375                                    sizeof(params->tp_stateless_reset_token));
376                params->tp_flags |= TRAPA_RESET_TOKEN;
377                break;
378            case TPI_ORIGINAL_CONNECTION_ID:
379                /* Client MUST not original connecti ID,
380                 * see [draft-ietf-quic-transport-15], Section 6.6.1
381                 */
382                if (!is_server)
383                    return -1;
384                if (len > MAX_CID_LEN)
385                    return -1;
386                memcpy(params->tp_original_cid.idbuf, p, len);
387                params->tp_original_cid.len = len;
388                params->tp_flags |= TRAPA_ORIGINAL_CID;
389                break;
390            case TPI_PREFERRED_ADDRESS:
391                /* Client MUST not include preferred address,
392                 * see [draft-ietf-quic-transport-12], Section 6.4.1
393                 */
394                if (!is_server)
395                    return -1;
396                q = p;
397                EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_addr));
398                memcpy(params->tp_preferred_address.ipv4_addr, q,
399                            sizeof(params->tp_preferred_address.ipv4_addr));
400                q += sizeof(params->tp_preferred_address.ipv4_addr);
401                EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv4_port));
402                READ_UINT(params->tp_preferred_address.ipv4_port, 16, q, 2);
403                q += 2;
404                EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_addr));
405                memcpy(params->tp_preferred_address.ipv6_addr, q,
406                            sizeof(params->tp_preferred_address.ipv6_addr));
407                q += sizeof(params->tp_preferred_address.ipv6_addr);
408                EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.ipv6_port));
409                READ_UINT(params->tp_preferred_address.ipv6_port, 16, q, 2);
410                q += 2;
411                EXPECT_AT_LEAST(1);
412                tlen = *q;
413                q += 1;
414                if (tlen < 4 || tlen > MAX_CID_LEN)
415                {
416                    LSQ_DEBUG("preferred server address contains invalid "
417                        "CID length of %"PRIu16" bytes", tlen);
418                    return -1;
419                }
420                EXPECT_AT_LEAST(tlen);
421                memcpy(params->tp_preferred_address.cid.idbuf, q, tlen);
422                params->tp_preferred_address.cid.len = tlen;
423                q += tlen;
424                EXPECT_AT_LEAST(sizeof(params->tp_preferred_address.srst));
425                memcpy(params->tp_preferred_address.srst, q,
426                                sizeof(params->tp_preferred_address.srst));
427                q += sizeof(params->tp_preferred_address.srst);
428                if (q != p + len)
429                    return -1;
430                if (params->tp_preferred_address.ipv4_port
431                    && !lsquic_is_zero(params->tp_preferred_address.ipv4_addr,
432                                sizeof(params->tp_preferred_address.ipv4_addr)))
433                    params->tp_flags |= TRAPA_PREFADDR_IPv4;
434                if (params->tp_preferred_address.ipv6_port
435                    && !lsquic_is_zero(params->tp_preferred_address.ipv6_addr,
436                                sizeof(params->tp_preferred_address.ipv6_addr)))
437                    params->tp_flags |= TRAPA_PREFADDR_IPv6;
438                break;
439            }
440  unknown:
441            p += len;
442        }
443    }
444
445    if (p != end)
446        return -1;
447
448    return (int) (end - buf);
449#undef EXPECT_LEN
450}
451
452
453void
454lsquic_tp_to_str (const struct transport_params *params, char *buf, size_t sz)
455{
456    char *const end = buf + sz;
457    int nw;
458    char tok_str[sizeof(params->tp_stateless_reset_token) * 2 + 1];
459    char addr_str[INET6_ADDRSTRLEN];
460
461#define SEMICOLON "; "
462#define WRITE_ONE_PARAM(name, fmt) do {  \
463    nw = snprintf(buf, end - buf, #name ": " fmt SEMICOLON, params->tp_##name); \
464    buf += nw; \
465    if (buf >= end) \
466        return; \
467} while (0)
468
469    WRITE_ONE_PARAM(init_max_stream_data_bidi_local, "%"PRIu64);
470    WRITE_ONE_PARAM(init_max_stream_data_bidi_remote, "%"PRIu64);
471    WRITE_ONE_PARAM(init_max_stream_data_uni, "%"PRIu64);
472    WRITE_ONE_PARAM(init_max_data, "%"PRIu64);
473    WRITE_ONE_PARAM(idle_timeout, "%"PRIu64);
474    WRITE_ONE_PARAM(init_max_streams_bidi, "%"PRIu64);
475    WRITE_ONE_PARAM(init_max_streams_uni, "%"PRIu64);
476    WRITE_ONE_PARAM(max_packet_size, "%"PRIu64);
477    WRITE_ONE_PARAM(ack_delay_exponent, "%"PRIu64);
478    WRITE_ONE_PARAM(active_connection_id_limit, "%"PRIu64);
479    WRITE_ONE_PARAM(disable_active_migration, "%hhd");
480#undef SEMICOLON
481#define SEMICOLON ""
482    WRITE_ONE_PARAM(max_ack_delay, "%"PRIu64);
483    if (params->tp_flags & TRAPA_RESET_TOKEN)
484    {
485        lsquic_hexstr(params->tp_stateless_reset_token,
486            sizeof(params->tp_stateless_reset_token), tok_str, sizeof(tok_str));
487        nw = snprintf(buf, end - buf, "; stateless_reset_token: %s", tok_str);
488        buf += nw;
489        if (buf >= end)
490            return;
491    }
492    if (params->tp_flags & TRAPA_RESET_TOKEN)
493    {
494        char cidbuf_[MAX_CID_LEN * 2 + 1];
495        nw = snprintf(buf, end - buf, "; original DCID (ODCID): %"CID_FMT,
496                                        CID_BITS(&params->tp_original_cid));
497        buf += nw;
498        if (buf >= end)
499            return;
500    }
501    if (params->tp_flags & TRAPA_PREFADDR_IPv4)
502    {
503        if (inet_ntop(AF_INET, params->tp_preferred_address.ipv4_addr,
504                                                addr_str, sizeof(addr_str)))
505        {
506            nw = snprintf(buf, end - buf, "; IPv4 preferred address: %s:%u",
507                            addr_str, params->tp_preferred_address.ipv4_port);
508            buf += nw;
509            if (buf >= end)
510                return;
511        }
512    }
513    if (params->tp_flags & TRAPA_PREFADDR_IPv6)
514    {
515        if (inet_ntop(AF_INET6, params->tp_preferred_address.ipv6_addr,
516                                                addr_str, sizeof(addr_str)))
517        {
518            nw = snprintf(buf, end - buf, "; IPv6 preferred address: %s:%u",
519                            addr_str, params->tp_preferred_address.ipv6_port);
520            buf += nw;
521            if (buf >= end)
522                return;
523        }
524    }
525
526#undef SEMICOLON
527#undef WRITE_ONE_PARAM
528}
529