1 /* 2 * Copyright 2023-2025 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include "internal/qlog_event_helpers.h" 11 #include "internal/common.h" 12 #include "internal/packet.h" 13 #include "internal/quic_channel.h" 14 #include "internal/quic_error.h" 15 16 void ossl_qlog_event_connectivity_connection_started(QLOG *qlog, 17 const QUIC_CONN_ID *init_dcid) 18 { 19 #ifndef OPENSSL_NO_QLOG 20 QLOG_EVENT_BEGIN(qlog, connectivity, connection_started) 21 QLOG_STR("protocol", "quic"); 22 QLOG_CID("dst_cid", init_dcid); 23 QLOG_EVENT_END() 24 #endif 25 } 26 27 #ifndef OPENSSL_NO_QLOG 28 static const char *map_state_to_qlog(uint32_t state, 29 int handshake_complete, 30 int handshake_confirmed) 31 { 32 switch (state) { 33 default: 34 case QUIC_CHANNEL_STATE_IDLE: 35 return NULL; 36 37 case QUIC_CHANNEL_STATE_ACTIVE: 38 if (handshake_confirmed) 39 return "handshake_confirmed"; 40 else if (handshake_complete) 41 return "handshake_complete"; 42 else 43 return "attempted"; 44 45 case QUIC_CHANNEL_STATE_TERMINATING_CLOSING: 46 return "closing"; 47 48 case QUIC_CHANNEL_STATE_TERMINATING_DRAINING: 49 return "draining"; 50 51 case QUIC_CHANNEL_STATE_TERMINATED: 52 return "closed"; 53 } 54 } 55 #endif 56 57 void ossl_qlog_event_connectivity_connection_state_updated(QLOG *qlog, 58 uint32_t old_state, 59 uint32_t new_state, 60 int handshake_complete, 61 int handshake_confirmed) 62 { 63 #ifndef OPENSSL_NO_QLOG 64 const char *state_s; 65 66 QLOG_EVENT_BEGIN(qlog, connectivity, connection_state_updated) 67 state_s = map_state_to_qlog(new_state, 68 handshake_complete, 69 handshake_confirmed); 70 71 if (state_s != NULL) 72 QLOG_STR("state", state_s); 73 QLOG_EVENT_END() 74 #endif 75 } 76 77 #ifndef OPENSSL_NO_QLOG 78 static const char *quic_err_to_qlog(uint64_t error_code) 79 { 80 switch (error_code) { 81 case OSSL_QUIC_ERR_INTERNAL_ERROR: 82 return "internal_error"; 83 case OSSL_QUIC_ERR_CONNECTION_REFUSED: 84 return "connection_refused"; 85 case OSSL_QUIC_ERR_FLOW_CONTROL_ERROR: 86 return "flow_control_error"; 87 case OSSL_QUIC_ERR_STREAM_LIMIT_ERROR: 88 return "stream_limit_error"; 89 case OSSL_QUIC_ERR_STREAM_STATE_ERROR: 90 return "stream_state_error"; 91 case OSSL_QUIC_ERR_FINAL_SIZE_ERROR: 92 return "final_size_error"; 93 case OSSL_QUIC_ERR_FRAME_ENCODING_ERROR: 94 return "frame_encoding_error"; 95 case OSSL_QUIC_ERR_TRANSPORT_PARAMETER_ERROR: 96 return "transport_parameter_error"; 97 case OSSL_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR: 98 return "connection_id_limit_error"; 99 case OSSL_QUIC_ERR_PROTOCOL_VIOLATION: 100 return "protocol_violation"; 101 case OSSL_QUIC_ERR_INVALID_TOKEN: 102 return "invalid_token"; 103 case OSSL_QUIC_ERR_APPLICATION_ERROR: 104 return "application_error"; 105 case OSSL_QUIC_ERR_CRYPTO_BUFFER_EXCEEDED: 106 return "crypto_buffer_exceeded"; 107 case OSSL_QUIC_ERR_KEY_UPDATE_ERROR: 108 return "key_update_error"; 109 case OSSL_QUIC_ERR_AEAD_LIMIT_REACHED: 110 return "aead_limit_reached"; 111 case OSSL_QUIC_ERR_NO_VIABLE_PATH: 112 return "no_viable_path"; 113 default: 114 return NULL; 115 } 116 } 117 #endif 118 119 void ossl_qlog_event_connectivity_connection_closed(QLOG *qlog, 120 const QUIC_TERMINATE_CAUSE *tcause) 121 { 122 #ifndef OPENSSL_NO_QLOG 123 QLOG_EVENT_BEGIN(qlog, connectivity, connection_closed) 124 QLOG_STR("owner", tcause->remote ? "remote" : "local"); 125 if (tcause->app) { 126 QLOG_U64("application_code", tcause->error_code); 127 } else { 128 const char *m = quic_err_to_qlog(tcause->error_code); 129 char ce[32]; 130 131 if (tcause->error_code >= OSSL_QUIC_ERR_CRYPTO_ERR_BEGIN 132 && tcause->error_code <= OSSL_QUIC_ERR_CRYPTO_ERR_END) { 133 BIO_snprintf(ce, sizeof(ce), "crypto_error_0x%03llx", 134 (unsigned long long)tcause->error_code); 135 m = ce; 136 } 137 /* TODO(QLOG FUTURE): Consider adding ERR information in the output. */ 138 139 if (m != NULL) 140 QLOG_STR("connection_code", m); 141 else 142 QLOG_U64("connection_code", tcause->error_code); 143 } 144 145 QLOG_STR_LEN("reason", tcause->reason, tcause->reason_len); 146 QLOG_EVENT_END() 147 #endif 148 } 149 150 #ifndef OPENSSL_NO_QLOG 151 static const char *quic_pkt_type_to_qlog(uint32_t pkt_type) 152 { 153 switch (pkt_type) { 154 case QUIC_PKT_TYPE_INITIAL: 155 return "initial"; 156 case QUIC_PKT_TYPE_HANDSHAKE: 157 return "handshake"; 158 case QUIC_PKT_TYPE_0RTT: 159 return "0RTT"; 160 case QUIC_PKT_TYPE_1RTT: 161 return "1RTT"; 162 case QUIC_PKT_TYPE_VERSION_NEG: 163 return "version_negotiation"; 164 case QUIC_PKT_TYPE_RETRY: 165 return "retry"; 166 default: 167 return "unknown"; 168 } 169 } 170 #endif 171 172 void ossl_qlog_event_recovery_packet_lost(QLOG *qlog, 173 const QUIC_TXPIM_PKT *tpkt) 174 { 175 #ifndef OPENSSL_NO_QLOG 176 QLOG_EVENT_BEGIN(qlog, recovery, packet_lost) 177 QLOG_BEGIN("header") 178 QLOG_STR("packet_type", quic_pkt_type_to_qlog(tpkt->pkt_type)); 179 if (ossl_quic_pkt_type_has_pn(tpkt->pkt_type)) 180 QLOG_U64("packet_number", tpkt->ackm_pkt.pkt_num); 181 QLOG_END() 182 QLOG_EVENT_END() 183 #endif 184 } 185 186 #ifndef OPENSSL_NO_QLOG 187 #define MAX_ACK_RANGES 32 188 189 static void ignore_res(int x) { } 190 191 /* 192 * For logging received packets, we need to parse all the frames in the packet 193 * to log them. We should do this separately to the RXDP code because we want to 194 * log the packet and its contents before we start to actually process it in 195 * case it causes an error. We also in general don't want to do other 196 * non-logging related work in the middle of an event logging transaction. 197 * Reparsing packet data allows us to meet these needs while avoiding the need 198 * to keep around bookkeeping data on what frames were in a packet, etc. 199 * 200 * For logging transmitted packets, we actually reuse the same code and reparse 201 * the outgoing packet's payload. This again has the advantage that we only log 202 * a packet when it is actually queued for transmission (and not if something 203 * goes wrong before then) while avoiding the need to keep around bookkeeping 204 * data on what frames it contained. 205 */ 206 static int log_frame_actual(QLOG *qlog_instance, PACKET *pkt, 207 size_t *need_skip) 208 { 209 uint64_t frame_type; 210 OSSL_QUIC_FRAME_ACK ack; 211 OSSL_QUIC_ACK_RANGE ack_ranges[MAX_ACK_RANGES]; 212 uint64_t num_ranges, total_ranges; 213 size_t i; 214 PACKET orig_pkt = *pkt; 215 216 if (!ossl_quic_wire_peek_frame_header(pkt, &frame_type, NULL)) { 217 *need_skip = SIZE_MAX; 218 return 0; 219 } 220 221 /* 222 * If something goes wrong decoding a frame we cannot log it as that frame 223 * as we need to know how to decode it in order to be able to do so, but in 224 * that case we log it as an unknown frame to assist with diagnosis. 225 */ 226 switch (frame_type) { 227 case OSSL_QUIC_FRAME_TYPE_PADDING: 228 QLOG_STR("frame_type", "padding"); 229 QLOG_U64("payload_length", 230 ossl_quic_wire_decode_padding(pkt)); 231 break; 232 case OSSL_QUIC_FRAME_TYPE_PING: 233 if (!ossl_quic_wire_decode_frame_ping(pkt)) 234 goto unknown; 235 236 QLOG_STR("frame_type", "ping"); 237 break; 238 case OSSL_QUIC_FRAME_TYPE_ACK_WITHOUT_ECN: 239 case OSSL_QUIC_FRAME_TYPE_ACK_WITH_ECN: 240 if (!ossl_quic_wire_peek_frame_ack_num_ranges(pkt, &num_ranges)) 241 goto unknown; 242 243 ack.ack_ranges = ack_ranges; 244 ack.num_ack_ranges = OSSL_NELEM(ack_ranges); 245 if (!ossl_quic_wire_decode_frame_ack(pkt, 3, &ack, &total_ranges)) 246 goto unknown; 247 248 QLOG_STR("frame_type", "ack"); 249 QLOG_U64("ack_delay", ossl_time2ms(ack.delay_time)); 250 if (ack.ecn_present) { 251 QLOG_U64("ect1", ack.ect0); 252 QLOG_U64("ect0", ack.ect1); 253 QLOG_U64("ce", ack.ecnce); 254 } 255 QLOG_BEGIN_ARRAY("acked_ranges"); 256 for (i = 0; i < ack.num_ack_ranges; ++i) { 257 QLOG_BEGIN_ARRAY(NULL) 258 QLOG_U64(NULL, ack.ack_ranges[i].start); 259 if (ack.ack_ranges[i].end != ack.ack_ranges[i].start) 260 QLOG_U64(NULL, ack.ack_ranges[i].end); 261 QLOG_END_ARRAY() 262 } 263 QLOG_END_ARRAY() 264 break; 265 case OSSL_QUIC_FRAME_TYPE_RESET_STREAM: { 266 OSSL_QUIC_FRAME_RESET_STREAM f; 267 268 if (!ossl_quic_wire_decode_frame_reset_stream(pkt, &f)) 269 goto unknown; 270 271 QLOG_STR("frame_type", "reset_stream"); 272 QLOG_U64("stream_id", f.stream_id); 273 QLOG_U64("error_code", f.app_error_code); 274 QLOG_U64("final_size", f.final_size); 275 } break; 276 case OSSL_QUIC_FRAME_TYPE_STOP_SENDING: { 277 OSSL_QUIC_FRAME_STOP_SENDING f; 278 279 if (!ossl_quic_wire_decode_frame_stop_sending(pkt, &f)) 280 goto unknown; 281 282 QLOG_STR("frame_type", "stop_sending"); 283 QLOG_U64("stream_id", f.stream_id); 284 QLOG_U64("error_code", f.app_error_code); 285 } break; 286 case OSSL_QUIC_FRAME_TYPE_CRYPTO: { 287 OSSL_QUIC_FRAME_CRYPTO f; 288 289 if (!ossl_quic_wire_decode_frame_crypto(pkt, 1, &f)) 290 goto unknown; 291 292 QLOG_STR("frame_type", "crypto"); 293 QLOG_U64("offset", f.offset); 294 QLOG_U64("payload_length", f.len); 295 *need_skip += (size_t)f.len; 296 } break; 297 case OSSL_QUIC_FRAME_TYPE_STREAM: 298 case OSSL_QUIC_FRAME_TYPE_STREAM_FIN: 299 case OSSL_QUIC_FRAME_TYPE_STREAM_LEN: 300 case OSSL_QUIC_FRAME_TYPE_STREAM_LEN_FIN: 301 case OSSL_QUIC_FRAME_TYPE_STREAM_OFF: 302 case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_FIN: 303 case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN: 304 case OSSL_QUIC_FRAME_TYPE_STREAM_OFF_LEN_FIN: { 305 OSSL_QUIC_FRAME_STREAM f; 306 307 if (!ossl_quic_wire_decode_frame_stream(pkt, 1, &f)) 308 goto unknown; 309 310 QLOG_STR("frame_type", "stream"); 311 QLOG_U64("stream_id", f.stream_id); 312 QLOG_U64("offset", f.offset); 313 QLOG_U64("payload_length", f.len); 314 QLOG_BOOL("explicit_length", f.has_explicit_len); 315 if (f.is_fin) 316 QLOG_BOOL("fin", 1); 317 *need_skip = f.has_explicit_len 318 ? *need_skip + (size_t)f.len 319 : SIZE_MAX; 320 } break; 321 case OSSL_QUIC_FRAME_TYPE_MAX_DATA: { 322 uint64_t x; 323 324 if (!ossl_quic_wire_decode_frame_max_data(pkt, &x)) 325 goto unknown; 326 327 QLOG_STR("frame_type", "max_data"); 328 QLOG_U64("maximum", x); 329 } break; 330 case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI: 331 case OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_UNI: { 332 uint64_t x; 333 334 if (!ossl_quic_wire_decode_frame_max_streams(pkt, &x)) 335 goto unknown; 336 337 QLOG_STR("frame_type", "max_streams"); 338 QLOG_STR("stream_type", 339 frame_type == OSSL_QUIC_FRAME_TYPE_MAX_STREAMS_BIDI 340 ? "bidirectional" 341 : "unidirectional"); 342 QLOG_U64("maximum", x); 343 } break; 344 case OSSL_QUIC_FRAME_TYPE_MAX_STREAM_DATA: { 345 uint64_t stream_id, max_data; 346 347 if (!ossl_quic_wire_decode_frame_max_stream_data(pkt, &stream_id, 348 &max_data)) 349 goto unknown; 350 351 QLOG_STR("frame_type", "max_stream_data"); 352 QLOG_U64("stream_id", stream_id); 353 QLOG_U64("maximum", max_data); 354 } break; 355 case OSSL_QUIC_FRAME_TYPE_PATH_CHALLENGE: { 356 uint64_t challenge; 357 358 if (!ossl_quic_wire_decode_frame_path_challenge(pkt, &challenge)) 359 goto unknown; 360 361 QLOG_STR("frame_type", "path_challenge"); 362 } break; 363 case OSSL_QUIC_FRAME_TYPE_PATH_RESPONSE: { 364 uint64_t challenge; 365 366 if (!ossl_quic_wire_decode_frame_path_response(pkt, &challenge)) 367 goto unknown; 368 369 QLOG_STR("frame_type", "path_response"); 370 } break; 371 case OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_APP: 372 case OSSL_QUIC_FRAME_TYPE_CONN_CLOSE_TRANSPORT: { 373 OSSL_QUIC_FRAME_CONN_CLOSE f; 374 375 if (!ossl_quic_wire_decode_frame_conn_close(pkt, &f)) 376 goto unknown; 377 378 QLOG_STR("frame_type", "connection_close"); 379 QLOG_STR("error_space", f.is_app ? "application" : "transport"); 380 QLOG_U64("error_code_value", f.error_code); 381 if (f.is_app) 382 QLOG_U64("error_code", f.error_code); 383 if (!f.is_app && f.frame_type != 0) 384 QLOG_U64("trigger_frame_type", f.frame_type); 385 QLOG_STR_LEN("reason", f.reason, f.reason_len); 386 } break; 387 case OSSL_QUIC_FRAME_TYPE_HANDSHAKE_DONE: { 388 if (!ossl_quic_wire_decode_frame_handshake_done(pkt)) 389 goto unknown; 390 391 QLOG_STR("frame_type", "handshake_done"); 392 } break; 393 case OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID: { 394 OSSL_QUIC_FRAME_NEW_CONN_ID f; 395 396 if (!ossl_quic_wire_decode_frame_new_conn_id(pkt, &f)) 397 goto unknown; 398 399 QLOG_STR("frame_type", "new_connection_id"); 400 QLOG_U64("sequence_number", f.seq_num); 401 QLOG_U64("retire_prior_to", f.retire_prior_to); 402 QLOG_CID("connection_id", &f.conn_id); 403 QLOG_BIN("stateless_reset_token", 404 f.stateless_reset.token, 405 sizeof(f.stateless_reset.token)); 406 } break; 407 case OSSL_QUIC_FRAME_TYPE_RETIRE_CONN_ID: { 408 uint64_t seq_num; 409 410 if (!ossl_quic_wire_decode_frame_retire_conn_id(pkt, &seq_num)) 411 goto unknown; 412 413 QLOG_STR("frame_type", "retire_connection_id"); 414 QLOG_U64("sequence_number", seq_num); 415 } break; 416 case OSSL_QUIC_FRAME_TYPE_DATA_BLOCKED: { 417 uint64_t x; 418 419 if (!ossl_quic_wire_decode_frame_data_blocked(pkt, &x)) 420 goto unknown; 421 422 QLOG_STR("frame_type", "data_blocked"); 423 QLOG_U64("limit", x); 424 } break; 425 case OSSL_QUIC_FRAME_TYPE_STREAM_DATA_BLOCKED: { 426 uint64_t stream_id, x; 427 428 if (!ossl_quic_wire_decode_frame_stream_data_blocked(pkt, 429 &stream_id, 430 &x)) 431 goto unknown; 432 433 QLOG_STR("frame_type", "stream_data_blocked"); 434 QLOG_U64("stream_id", stream_id); 435 QLOG_U64("limit", x); 436 } break; 437 case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI: 438 case OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_UNI: { 439 uint64_t x; 440 441 if (!ossl_quic_wire_decode_frame_streams_blocked(pkt, &x)) 442 goto unknown; 443 444 QLOG_STR("frame_type", "streams_blocked"); 445 QLOG_STR("stream_type", 446 frame_type == OSSL_QUIC_FRAME_TYPE_STREAMS_BLOCKED_BIDI 447 ? "bidirectional" 448 : "unidirectional"); 449 QLOG_U64("limit", x); 450 } break; 451 case OSSL_QUIC_FRAME_TYPE_NEW_TOKEN: { 452 const unsigned char *token; 453 size_t token_len; 454 455 if (!ossl_quic_wire_decode_frame_new_token(pkt, &token, &token_len)) 456 goto unknown; 457 458 QLOG_STR("frame_type", "new_token"); 459 QLOG_BEGIN("token"); 460 QLOG_BEGIN("raw"); 461 QLOG_BIN("data", token, token_len); 462 QLOG_END(); 463 QLOG_END(); 464 } break; 465 default: 466 unknown: 467 QLOG_STR("frame_type", "unknown"); 468 QLOG_U64("frame_type_value", frame_type); 469 470 /* 471 * Can't continue scanning for frames in this case as the frame length 472 * is unknown. We log the entire body of the rest of the packet payload 473 * as the raw data of the frame. 474 */ 475 QLOG_BEGIN("raw"); 476 QLOG_BIN("data", PACKET_data(&orig_pkt), 477 PACKET_remaining(&orig_pkt)); 478 QLOG_END(); 479 ignore_res(PACKET_forward(pkt, PACKET_remaining(pkt))); 480 break; 481 } 482 483 return 1; 484 } 485 486 static void log_frame(QLOG *qlog_instance, PACKET *pkt, 487 size_t *need_skip) 488 { 489 size_t rem_before, rem_after; 490 491 rem_before = PACKET_remaining(pkt); 492 493 if (!log_frame_actual(qlog_instance, pkt, need_skip)) 494 return; 495 496 rem_after = PACKET_remaining(pkt); 497 QLOG_U64("length", rem_before - rem_after); 498 } 499 500 static int log_frames(QLOG *qlog_instance, 501 const OSSL_QTX_IOVEC *iovec, 502 size_t num_iovec) 503 { 504 size_t i; 505 PACKET pkt; 506 size_t need_skip = 0; 507 508 for (i = 0; i < num_iovec; ++i) { 509 if (!PACKET_buf_init(&pkt, iovec[i].buf, iovec[i].buf_len)) 510 return 0; 511 512 while (PACKET_remaining(&pkt) > 0) { 513 if (need_skip > 0) { 514 size_t adv = need_skip; 515 516 if (adv > PACKET_remaining(&pkt)) 517 adv = PACKET_remaining(&pkt); 518 519 if (!PACKET_forward(&pkt, adv)) 520 return 0; 521 522 need_skip -= adv; 523 continue; 524 } 525 526 QLOG_BEGIN(NULL) 527 { 528 log_frame(qlog_instance, &pkt, &need_skip); 529 } 530 QLOG_END() 531 } 532 } 533 534 return 1; 535 } 536 537 static void log_packet(QLOG *qlog_instance, 538 const QUIC_PKT_HDR *hdr, 539 QUIC_PN pn, 540 const OSSL_QTX_IOVEC *iovec, 541 size_t num_iovec, 542 uint64_t datagram_id) 543 { 544 const char *type_s; 545 546 QLOG_BEGIN("header") 547 type_s = quic_pkt_type_to_qlog(hdr->type); 548 if (type_s == NULL) 549 type_s = "unknown"; 550 551 QLOG_STR("packet_type", type_s); 552 if (ossl_quic_pkt_type_has_pn(hdr->type)) 553 QLOG_U64("packet_number", pn); 554 555 QLOG_CID("dcid", &hdr->dst_conn_id); 556 if (ossl_quic_pkt_type_has_scid(hdr->type)) 557 QLOG_CID("scid", &hdr->src_conn_id); 558 559 if (hdr->token_len > 0) { 560 QLOG_BEGIN("token") 561 QLOG_BEGIN("raw") 562 QLOG_BIN("data", hdr->token, hdr->token_len); 563 QLOG_END() 564 QLOG_END() 565 } 566 /* TODO(QLOG FUTURE): flags, length */ 567 QLOG_END() 568 QLOG_U64("datagram_id", datagram_id); 569 570 if (ossl_quic_pkt_type_is_encrypted(hdr->type)) { 571 QLOG_BEGIN_ARRAY("frames") 572 log_frames(qlog_instance, iovec, num_iovec); 573 QLOG_END_ARRAY() 574 } 575 } 576 577 #endif 578 579 void ossl_qlog_event_transport_packet_sent(QLOG *qlog, 580 const QUIC_PKT_HDR *hdr, 581 QUIC_PN pn, 582 const OSSL_QTX_IOVEC *iovec, 583 size_t num_iovec, 584 uint64_t datagram_id) 585 { 586 #ifndef OPENSSL_NO_QLOG 587 QLOG_EVENT_BEGIN(qlog, transport, packet_sent) 588 log_packet(qlog, hdr, pn, iovec, num_iovec, datagram_id); 589 QLOG_EVENT_END() 590 #endif 591 } 592 593 void ossl_qlog_event_transport_packet_received(QLOG *qlog, 594 const QUIC_PKT_HDR *hdr, 595 QUIC_PN pn, 596 const OSSL_QTX_IOVEC *iovec, 597 size_t num_iovec, 598 uint64_t datagram_id) 599 { 600 #ifndef OPENSSL_NO_QLOG 601 QLOG_EVENT_BEGIN(qlog, transport, packet_received) 602 log_packet(qlog, hdr, pn, iovec, num_iovec, datagram_id); 603 QLOG_EVENT_END() 604 #endif 605 } 606