This is an automated email from the ASF dual-hosted git repository. masaori pushed a commit to branch quic-latest in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit 6ff1a3f373f7af9339285c6f4b96d5636ca8912c Author: Masaori Koshiba <[email protected]> AuthorDate: Wed Apr 4 15:15:47 2018 +0900 Add Version Negotiation support on QUIC client To enforce version negotiation exercise, set below config 1. ``` proxy.config.quic.client.vn_exercise_enabled ``` --- iocore/net/P_QUICNetVConnection.h | 1 + iocore/net/QUICNetVConnection.cc | 21 ++++++++++++++++- iocore/net/quic/QUICConfig.cc | 8 +++++++ iocore/net/quic/QUICConfig.h | 3 +++ iocore/net/quic/QUICHandshake.cc | 49 +++++++++++++++++++++++++++++++++++---- iocore/net/quic/QUICHandshake.h | 4 +++- mgmt/RecordsConfig.cc | 2 ++ 7 files changed, 82 insertions(+), 6 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index eb7defd..e68b2e2 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -285,6 +285,7 @@ private: QUICErrorUPtr _recv_and_ack(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_packet(QUICPacketUPtr packet); + QUICErrorUPtr _state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_initial_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_retry_packet(QUICPacketUPtr packet); QUICErrorUPtr _state_handshake_process_handshake_packet(QUICPacketUPtr packet); diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index a22a7b1..6ea5de4 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -186,7 +186,7 @@ QUICNetVConnection::start() this->_handshake_handler = new QUICHandshake(this, params->server_ssl_ctx(), this->_reset_token, params->stateless_retry()); } else { this->_handshake_handler = new QUICHandshake(this, params->client_ssl_ctx()); - this->_handshake_handler->start(&this->_packet_factory); + this->_handshake_handler->start(&this->_packet_factory, params->vn_exercise_enabled()); } this->_application_map = new QUICApplicationMap(); this->_application_map->set(STREAM_ID_FOR_HANDSHAKE, this->_handshake_handler); @@ -783,6 +783,9 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) { QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); switch (packet->type()) { + case QUICPacketType::VERSION_NEGOTIATION: + error = this->_state_handshake_process_version_negotiation_packet(std::move(packet)); + break; case QUICPacketType::INITIAL: error = this->_state_handshake_process_initial_packet(std::move(packet)); break; @@ -806,6 +809,22 @@ QUICNetVConnection::_state_handshake_process_packet(QUICPacketUPtr packet) } QUICErrorUPtr +QUICNetVConnection::_state_handshake_process_version_negotiation_packet(QUICPacketUPtr packet) +{ + QUICErrorUPtr error = QUICErrorUPtr(new QUICNoError()); + + if (packet->connection_id() != this->connection_id()) { + QUICConDebug("Ignore Version Negotiation packet"); + return error; + } + + error = this->_handshake_handler->negotiate_version(packet.get(), &this->_packet_factory); + // Initial packet will be retransmited with negotiated version + + return error; +} + +QUICErrorUPtr QUICNetVConnection::_state_handshake_process_initial_packet(QUICPacketUPtr packet) { if (packet->size() < MINIMUM_INITIAL_PACKET_SIZE) { diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc index 5d5654b..897002b 100644 --- a/iocore/net/quic/QUICConfig.cc +++ b/iocore/net/quic/QUICConfig.cc @@ -121,6 +121,8 @@ QUICConfigParams::initialize() REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id"); REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size"); REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry"); + REC_EstablishStaticConfigInt32U(this->_vn_exercise_enabled, "proxy.config.quic.client.vn_exercise_enabled"); + REC_ReadConfigStringAlloc(this->_server_supported_groups, "proxy.config.quic.server.supported_groups"); REC_ReadConfigStringAlloc(this->_client_supported_groups, "proxy.config.quic.client.supported_groups"); @@ -184,6 +186,12 @@ QUICConfigParams::stateless_retry() const } uint32_t +QUICConfigParams::vn_exercise_enabled() const +{ + return this->_vn_exercise_enabled; +} + +uint32_t QUICConfigParams::initial_max_data() const { return this->_initial_max_data; diff --git a/iocore/net/quic/QUICConfig.h b/iocore/net/quic/QUICConfig.h index af76499..3de36c7 100644 --- a/iocore/net/quic/QUICConfig.h +++ b/iocore/net/quic/QUICConfig.h @@ -46,6 +46,8 @@ public: uint32_t server_id() const; static int connection_table_size(); uint32_t stateless_retry() const; + uint32_t vn_exercise_enabled() const; + const char *server_supported_groups() const; const char *client_supported_groups() const; @@ -76,6 +78,7 @@ private: uint32_t _initial_max_stream_data = 0; uint32_t _server_id = 0; uint32_t _stateless_retry = 0; + uint32_t _vn_exercise_enabled = 0; uint32_t _initial_max_stream_id_bidi_in = 100; uint32_t _initial_max_stream_id_bidi_out = 101; diff --git a/iocore/net/quic/QUICHandshake.cc b/iocore/net/quic/QUICHandshake.cc index f6a6cec..5d2484e 100644 --- a/iocore/net/quic/QUICHandshake.cc +++ b/iocore/net/quic/QUICHandshake.cc @@ -116,10 +116,16 @@ QUICHandshake::~QUICHandshake() } QUICErrorUPtr -QUICHandshake::start(QUICPacketFactory *packet_factory) +QUICHandshake::start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled) { - this->_load_local_client_transport_parameters(QUIC_SUPPORTED_VERSIONS[0]); - packet_factory->set_version(QUIC_SUPPORTED_VERSIONS[0]); + QUICVersion initital_version = QUIC_SUPPORTED_VERSIONS[0]; + if (vn_exercise_enabled) { + initital_version = QUIC_EXERCISE_VERSIONS; + } + + this->_load_local_client_transport_parameters(initital_version); + packet_factory->set_version(initital_version); + return QUICErrorUPtr(new QUICNoError()); } @@ -147,6 +153,36 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet return QUICErrorUPtr(new QUICNoError()); } +QUICErrorUPtr +QUICHandshake::negotiate_version(const QUICPacket *vn, QUICPacketFactory *packet_factory) +{ + // Client side only + ink_assert(this->_netvc_context == NET_VCONNECTION_OUT); + + // If already negotiated, just ignore it + if (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED || + this->_version_negotiator->status() == QUICVersionNegotiationStatus::VALIDATED) { + QUICHSDebug("Ignore Version Negotiation packet"); + return QUICErrorUPtr(new QUICNoError()); + } + + if (vn->version() != 0x00) { + QUICHSDebug("Version field must be 0x00000000"); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::PROTOCOL_VIOLATION)); + } + + if (this->_version_negotiator->negotiate(vn) == QUICVersionNegotiationStatus::NEGOTIATED) { + QUICVersion version = this->_version_negotiator->negotiated_version(); + QUICHSDebug("Version negotiation succeeded: 0x%x", version); + packet_factory->set_version(version); + } else { + QUICHSDebug("Version negotiation failed"); + return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR)); + } + + return QUICErrorUPtr(new QUICNoError()); +} + bool QUICHandshake::is_version_negotiated() const { @@ -235,7 +271,12 @@ QUICHandshake::set_transport_parameters(std::shared_ptr<QUICTransportParametersI this->_remote_transport_parameters = tp; - // TODO Add client side implementation + // Version revalidation + if (this->_version_negotiator->validate(tp.get()) != QUICVersionNegotiationStatus::VALIDATED) { + QUICHSDebug("Version revalidation failed"); + this->_abort_handshake(QUICTransErrorCode::VERSION_NEGOTIATION_ERROR); + return; + } return; } diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h index 2005041..37e316e 100644 --- a/iocore/net/quic/QUICHandshake.h +++ b/iocore/net/quic/QUICHandshake.h @@ -52,7 +52,9 @@ public: ~QUICHandshake(); // for client side - QUICErrorUPtr start(QUICPacketFactory *packet_factory); + QUICErrorUPtr start(QUICPacketFactory *packet_factory, bool vn_exercise_enabled); + QUICErrorUPtr negotiate_version(const QUICPacket *packet, QUICPacketFactory *packet_factory); + // for server side QUICErrorUPtr start(const QUICPacket *initial_packet, QUICPacketFactory *packet_factory); diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 4705eed..b69e2b5 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1330,6 +1330,8 @@ static const RecordElement RecordsConfig[] = , {RECT_CONFIG, "proxy.config.quic.stateless_retry", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} , + {RECT_CONFIG, "proxy.config.quic.client.vn_exercise_enabled", RECD_INT, "0", RECU_DYNAMIC, RR_NULL, RECC_INT, "[0-1]", RECA_NULL} + , {RECT_CONFIG, "proxy.config.quic.server.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} , {RECT_CONFIG, "proxy.config.quic.client.supported_groups", RECD_STRING, "P-256:X25519:P-384:P-521" , RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_NULL} -- To stop receiving notification emails like this one, please contact [email protected].
