@@ -1148,28 +1148,6 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
11481148 break ;
11491149 }
11501150
1151- /* Check reserved bits AFTER unmasking! */
1152- if (p [0 ] & 0x80 ) {
1153- /* Long header: Bits 0x0c MUST be zero */
1154- if (p [0 ] & 0x0c ) {
1155- lwsl_wsi_notice (wsi , "QUIC RX: Reserved bits non-zero in long header" );
1156- if (nwsi && nwsi != wsi ) {
1157- lws_quic_enter_closing_state (nwsi , LWS_QUIC_ERR_PROTOCOL_VIOLATION , 0 , 0 );
1158- goto next_packet ;
1159- }
1160- return LWS_HPI_RET_PLEASE_CLOSE_ME ;
1161- }
1162- } else {
1163- /* Short header: Bits 0x18 MUST be zero */
1164- if (p [0 ] & 0x18 ) {
1165- lwsl_wsi_notice (wsi , "QUIC RX: Reserved bits non-zero in short header" );
1166- if (nwsi && nwsi != wsi ) {
1167- lws_quic_enter_closing_state (nwsi , LWS_QUIC_ERR_PROTOCOL_VIOLATION , 0 , 0 );
1168- goto next_packet ;
1169- }
1170- return LWS_HPI_RET_PLEASE_CLOSE_ME ;
1171- }
1172- }
11731151
11741152 /*
11751153 * Reconstruct full 62-bit PN.
@@ -1221,6 +1199,29 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
12211199 goto next_packet ;
12221200 }
12231201
1202+ /* Check reserved bits AFTER successful AEAD decryption (RFC 9000 5.4.1 & 12.2) */
1203+ if (p [0 ] & 0x80 ) {
1204+ /* Long header: Bits 0x0c MUST be zero */
1205+ if (p [0 ] & 0x0c ) {
1206+ lwsl_wsi_notice (wsi , "QUIC RX: Reserved bits non-zero in long header" );
1207+ if (nwsi && nwsi != wsi ) {
1208+ lws_quic_enter_closing_state (nwsi , LWS_QUIC_ERR_PROTOCOL_VIOLATION , 0 , 0 );
1209+ goto next_packet ;
1210+ }
1211+ return LWS_HPI_RET_PLEASE_CLOSE_ME ;
1212+ }
1213+ } else {
1214+ /* Short header: Bits 0x18 MUST be zero */
1215+ if (p [0 ] & 0x18 ) {
1216+ lwsl_wsi_notice (wsi , "QUIC RX: Reserved bits non-zero in short header" );
1217+ if (nwsi && nwsi != wsi ) {
1218+ lws_quic_enter_closing_state (nwsi , LWS_QUIC_ERR_PROTOCOL_VIOLATION , 0 , 0 );
1219+ goto next_packet ;
1220+ }
1221+ return LWS_HPI_RET_PLEASE_CLOSE_ME ;
1222+ }
1223+ }
1224+
12241225 /* Decryption succeeded! Commit key update if pending */
12251226 if (is_key_update ) {
12261227 lws_quic_keys_release_aead_rx (k );
@@ -1318,7 +1319,7 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
13181319 buf_old , (unsigned int )ntohs (port_old ),
13191320 buf_new , (unsigned int )ntohs (port_new ));
13201321#endif
1321- /* F-60: Do NOT commit nwsi->udp->sa46 yet! Wait for PATH_RESPONSE! */
1322+ nwsi -> quic . qn -> rx_has_non_probing = 0 ;
13221323 nwsi -> quic .qn -> probing_sa46 = migration_sa46 ;
13231324 nwsi -> quic .qn -> probing_sa46_valid = 1 ;
13241325
@@ -1400,6 +1401,44 @@ rops_handle_POLLIN_quic(struct lws_context_per_thread *pt, struct lws *wsi,
14001401 nwsi = lws_get_quic_network_wsi (nwsi );
14011402 }
14021403
1404+ /* RFC 9000 Section 9.3: Receiving non-probing frames (STREAM, ACK, etc.) from a new address
1405+ * indicates that the peer has migrated (e.g. due to NAT rebinding or active client migration).
1406+ * The server MUST commit its active path to the new address. */
1407+ if (nwsi && nwsi -> quic .qn && nwsi -> quic .qn -> is_server &&
1408+ nwsi -> quic .qn -> probing_sa46_valid && nwsi -> quic .qn -> rx_has_non_probing ) {
1409+ char buf_old [64 ], buf_new [64 ];
1410+ uint16_t port_old , port_new ;
1411+ lws_sa46_write_numeric_address (& nwsi -> udp -> sa46 , buf_old , sizeof (buf_old ));
1412+ lws_sa46_write_numeric_address (& nwsi -> quic .qn -> probing_sa46 , buf_new , sizeof (buf_new ));
1413+ #if defined(LWS_WITH_IPV6 )
1414+ port_old = nwsi -> udp -> sa46 .sa4 .sin_family == AF_INET ? nwsi -> udp -> sa46 .sa4 .sin_port : nwsi -> udp -> sa46 .sa6 .sin6_port ;
1415+ port_new = nwsi -> quic .qn -> probing_sa46 .sa4 .sin_family == AF_INET ? nwsi -> quic .qn -> probing_sa46 .sa4 .sin_port : nwsi -> quic .qn -> probing_sa46 .sa6 .sin6_port ;
1416+ #else
1417+ port_old = nwsi -> udp -> sa46 .sa4 .sin_port ;
1418+ port_new = nwsi -> quic .qn -> probing_sa46 .sa4 .sin_port ;
1419+ #endif
1420+ lwsl_notice ("QUIC Server: Connection Migration committed via non-probing packet! Peer address updated from %s:%u to %s:%u\n" ,
1421+ buf_old , (unsigned int )ntohs (port_old ),
1422+ buf_new , (unsigned int )ntohs (port_new ));
1423+
1424+ nwsi -> udp -> sa46 = nwsi -> quic .qn -> probing_sa46 ;
1425+ nwsi -> quic .qn -> probing_sa46_valid = 0 ;
1426+
1427+ /* Reset Congestion Control State (RFC 9000 9.3.3) */
1428+ if (nwsi -> quic .qn -> cc_ops && nwsi -> quic .qn -> cc_ops -> init )
1429+ nwsi -> quic .qn -> cc_ops -> init (nwsi );
1430+
1431+ /* Reset RTT estimator */
1432+ nwsi -> quic .qn -> smoothed_rtt = 0 ;
1433+ nwsi -> quic .qn -> rttvar = 0 ;
1434+ nwsi -> quic .qn -> latest_rtt = 0 ;
1435+
1436+ /* Reset PMTUD */
1437+ nwsi -> quic .qn -> current_mtu = 1280 ;
1438+ nwsi -> quic .qn -> probed_mtu = 1380 ;
1439+ nwsi -> quic .qn -> pmtud_state = 1 ;
1440+ }
1441+
14031442 if (nwsi ) {
14041443 struct lws * w = nwsi -> mux .child_list ;
14051444 while (w ) {
0 commit comments