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(¶ms->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(¶ms->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 ¶ms->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(¶ms->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