QUIC_CONN_ID odcid, scid;
uint8_t gen_new_token = 0;
OSSL_QRX *qrx = NULL;
+ OSSL_QRX *qrx_src = NULL;
OSSL_QRX_ARGS qrx_args = {0};
uint64_t cause_flags = 0;
+ OSSL_QRX_PKT *qrx_pkt = NULL;
/* Don't handle anything if we are no longer running. */
if (!ossl_quic_port_is_running(port))
if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0)
goto undesirable;
+ if (port->validate_addr == 0) {
+ /*
+ * Forget qrx, because it becomes (almost) useless here. We must let
+ * channel to create a new QRX for connection ID server chooses. The
+ * validation keys for new DCID will be derived by
+ * ossl_quic_channel_on_new_conn() when we will be creating channel.
+ * See RFC 9000 section 7.2 negotiating connection id to better
+ * understand what's going on here.
+ *
+ * Did we say qrx is almost useless? Why? Because qrx remembers packets
+ * we just validated. Those packets must be injected to channel we are
+ * going to create. We use qrx_src alias so we can read packets from
+ * qrx and inject them to channel.
+ */
+ qrx_src = qrx;
+ qrx = NULL;
+ }
/*
* TODO(QUIC FUTURE): there should be some logic similar to accounting half-open
* states in TCP. If we reach certain threshold, then we want to
*/
if (port->validate_addr == 1 && hdr.token == NULL) {
port_send_retry(port, &e->peer, &hdr);
- /*
- * This is a kind of bummer because we forget secrets for initial
- * level encryption. The secrets costs us CPU to compute. What we can
- * do here is to store them within retry token. Then we can retrieve them
- * from initial packet which will carry our retry token to validate
- * client's address.
- */
goto undesirable;
}
port_send_retry(port, &e->peer, &hdr);
goto undesirable;
}
+
+ /*
+ * client is under amplification limit, until it completes
+ * handshake.
+ *
+ * forget qrx so channel can create a new one
+ * with valid initial encryption level keys.
+ */
+ qrx_src = qrx;
+ qrx = NULL;
}
port_bind_channel(port, &e->peer, &scid, &hdr.dst_conn_id,
if (gen_new_token == 1)
generate_new_token(new_ch, &e->peer);
- /*
- * The qrx belongs to channel now, so don't free it.
- */
- qrx = NULL;
+ if (qrx != NULL) {
+ /*
+ * The qrx belongs to channel now, so don't free it.
+ */
+ qrx = NULL;
+ } else {
+ /*
+ * We still need to salvage packets from almost forgotten qrx
+ * and pass them to channel.
+ */
+ while (ossl_qrx_read_pkt(qrx_src, &qrx_pkt) == 1)
+ ossl_quic_channel_inject_pkt(new_ch, qrx_pkt);
+ }
/*
* If function reaches this place, then packet got validated in
undesirable:
ossl_qrx_free(qrx);
+ ossl_qrx_free(qrx_src);
ossl_quic_demux_release_urxe(port->demux, e);
}