You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2018/04/04 06:21:31 UTC

[trafficserver] 04/04: Add Version Negotiation support on QUIC client

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 <ma...@apache.org>
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
masaori@apache.org.