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/03/16 02:03:01 UTC

[trafficserver] 01/03: Add Stateless Retry Support

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 e10160e6b505b9a285ee85d641f15158409357f9
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Wed Mar 14 12:08:57 2018 +0900

    Add Stateless Retry Support
    
    To enable this feature set `proxy.config.quic.stateless_retry` 1.
    Currently Address Validation Token in cookie ext is dummy.
---
 iocore/net/P_QUICNetVConnection.h        |  3 ++
 iocore/net/QUICNetVConnection.cc         | 48 ++++++++++++++++++++++++++++++--
 iocore/net/QUICPacketHandler.cc          | 31 +++++++++++++++++++++
 iocore/net/quic/QUICConfig.cc            |  9 +++++-
 iocore/net/quic/QUICConfig.h             |  2 ++
 iocore/net/quic/QUICHandshake.cc         | 44 ++++++++++++++++++++++-------
 iocore/net/quic/QUICHandshake.h          | 16 +++++++----
 iocore/net/quic/QUICHandshakeProtocol.cc |  9 ++++++
 iocore/net/quic/QUICHandshakeProtocol.h  |  4 +++
 iocore/net/quic/QUICPacket.cc            |  5 ++--
 iocore/net/quic/QUICPacket.h             |  2 +-
 iocore/net/quic/QUICTLS.cc               | 17 ++++-------
 iocore/net/quic/QUICTLS.h                |  1 -
 iocore/net/quic/QUICTypes.h              |  8 ++++++
 mgmt/RecordsConfig.cc                    |  2 ++
 15 files changed, 166 insertions(+), 35 deletions(-)

diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h
index 781ee3c..03a1c42 100644
--- a/iocore/net/P_QUICNetVConnection.h
+++ b/iocore/net/P_QUICNetVConnection.h
@@ -112,6 +112,8 @@ class SSLNextProtocolSet;
  *  |   _state_handshake_process_zero_rtt_protected_packet()
  *  | WRITE:
  *  |   _state_common_send_packet()
+ *  |   or
+ *  |   _state_handshake_send_retry_packet()
  *  v
  * state_connection_established()
  *  | READ:
@@ -295,6 +297,7 @@ private:
   QUICErrorUPtr _state_common_receive_packet();
   QUICErrorUPtr _state_connection_closing_and_draining_receive_packet();
   QUICErrorUPtr _state_common_send_packet();
+  QUICErrorUPtr _state_handshake_send_retry_packet();
   QUICErrorUPtr _state_closing_send_packet();
 
   Ptr<ProxyMutex> _packet_transmitter_mutex;
diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc
index a6859da..42d2197 100644
--- a/iocore/net/QUICNetVConnection.cc
+++ b/iocore/net/QUICNetVConnection.cc
@@ -176,7 +176,7 @@ QUICNetVConnection::start(SSL_CTX *ssl_ctx)
   if (this->direction() == NET_VCONNECTION_IN) {
     QUICConfig::scoped_config params;
     this->_reset_token.generate(this->_quic_connection_id, params->server_id());
-    this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token);
+    this->_handshake_handler = new QUICHandshake(this, ssl_ctx, this->_reset_token, params->stateless_retry());
   } else {
     this->_handshake_handler = new QUICHandshake(this, ssl_ctx);
     this->_handshake_handler->start(&this->_packet_factory);
@@ -549,7 +549,16 @@ QUICNetVConnection::state_handshake(int event, Event *data)
   }
   case QUIC_EVENT_PACKET_WRITE_READY: {
     this->_close_packet_write_ready(data);
-    error = this->_state_common_send_packet();
+
+    if (this->_handshake_handler && this->_handshake_handler->msg_type() == QUICHandshakeMsgType::HRR) {
+      error = this->_state_handshake_send_retry_packet();
+      if (this->_handshake_handler->is_stateless_retry_enabled()) {
+        this->_switch_to_close_state();
+      }
+    } else {
+      error = this->_state_common_send_packet();
+    }
+
     break;
   }
   case EVENT_IMMEDIATE:
@@ -919,6 +928,37 @@ QUICNetVConnection::_state_common_send_packet()
   return QUICErrorUPtr(new QUICNoError());
 }
 
+// RETRY packet contains ONLY a single STREAM frame
+QUICErrorUPtr
+QUICNetVConnection::_state_handshake_send_retry_packet()
+{
+  size_t len = 0;
+  ats_unique_buf buf(nullptr, [](void *p) { ats_free(p); });
+  QUICPacketType current_packet_type = QUICPacketType::UNINITIALIZED;
+
+  QUICFrameUPtr frame(nullptr, nullptr);
+  bool retransmittable = this->_handshake_handler->is_stateless_retry_enabled() ? false : true;
+
+  SCOPED_MUTEX_LOCK(packet_transmitter_lock, this->_packet_transmitter_mutex, this_ethread());
+  SCOPED_MUTEX_LOCK(frame_transmitter_lock, this->_frame_transmitter_mutex, this_ethread());
+
+  ink_assert(this->_frame_send_queue.size() == 1);
+  frame = std::move(this->_frame_send_queue.front());
+  this->_frame_send_queue.pop();
+  this->_store_frame(buf, len, retransmittable, current_packet_type, std::move(frame));
+  if (len == 0) {
+    return QUICErrorUPtr(new QUICConnectionError(QUICTransErrorCode::INTERNAL_ERROR));
+  }
+
+  QUICPacketUPtr packet = this->_build_packet(std::move(buf), len, retransmittable, QUICPacketType::RETRY);
+  this->_packet_handler->send_packet(*packet, this);
+  this->_loss_detector->on_packet_sent(std::move(packet));
+
+  QUIC_INCREMENT_DYN_STAT_EX(QUICStats::total_packets_sent_stat, 1);
+
+  return QUICErrorUPtr(new QUICNoError());
+}
+
 QUICErrorUPtr
 QUICNetVConnection::_state_closing_send_packet()
 {
@@ -1089,6 +1129,10 @@ QUICNetVConnection::_build_packet(ats_unique_buf buf, size_t len, bool retransmi
     packet = this->_packet_factory.create_initial_packet(this->_original_quic_connection_id, this->largest_acked_packet_number(),
                                                          QUIC_SUPPORTED_VERSIONS[0], std::move(buf), len);
     break;
+  case QUICPacketType::RETRY:
+    packet = this->_packet_factory.create_retry_packet(this->_quic_connection_id, this->largest_acked_packet_number(),
+                                                       std::move(buf), len, retransmittable);
+    break;
   case QUICPacketType::HANDSHAKE:
     packet = this->_packet_factory.create_handshake_packet(this->_quic_connection_id, this->largest_acked_packet_number(),
                                                            std::move(buf), len, retransmittable);
diff --git a/iocore/net/QUICPacketHandler.cc b/iocore/net/QUICPacketHandler.cc
index 2561005..da98693 100644
--- a/iocore/net/QUICPacketHandler.cc
+++ b/iocore/net/QUICPacketHandler.cc
@@ -85,6 +85,32 @@ QUICPacketHandler::_read_connection_id(IOBufferBlock *block)
   return QUICPacket::connection_id(buf);
 }
 
+// TODO: ramdomize token and verify it
+// dummy token to simplify test
+static uint8_t token[] = {0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef,
+                          0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef,
+                          0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef,
+                          0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef, 0xbe, 0xef};
+
+static int
+generate_cookie_callback(SSL * /* ssl */, unsigned char *cookie, size_t *cookie_len)
+{
+  memcpy(cookie, token, sizeof(token));
+  *cookie_len = sizeof(token);
+
+  return 1;
+}
+
+static int
+verify_cookie_callback(SSL *ssl, const unsigned char *cookie, size_t cookie_len)
+{
+  if (memcmp(token, cookie, sizeof(token)) == 0) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
 //
 // QUICPacketHandlerIn
 //
@@ -94,6 +120,11 @@ QUICPacketHandlerIn::QUICPacketHandlerIn(const NetProcessor::AcceptOptions &opt,
   // create Connection Table
   QUICConfig::scoped_config params;
   _ctable = new QUICConnectionTable(params->connection_table_size());
+
+  // callbacks for cookie ext
+  // Requires OpenSSL-1.1.1-pre3+ : https://github.com/openssl/openssl/pull/5463
+  SSL_CTX_set_stateless_cookie_generate_cb(this->_ssl_ctx, generate_cookie_callback);
+  SSL_CTX_set_stateless_cookie_verify_cb(this->_ssl_ctx, verify_cookie_callback);
 }
 
 QUICPacketHandlerIn::~QUICPacketHandlerIn()
diff --git a/iocore/net/quic/QUICConfig.cc b/iocore/net/quic/QUICConfig.cc
index 8bcf9c9..0b8c00c 100644
--- a/iocore/net/quic/QUICConfig.cc
+++ b/iocore/net/quic/QUICConfig.cc
@@ -39,7 +39,8 @@ QUICConfigParams::initialize()
   REC_EstablishStaticConfigInt32U(this->_initial_max_data, "proxy.config.quic.initial_max_data");
   REC_EstablishStaticConfigInt32U(this->_initial_max_stream_data, "proxy.config.quic.initial_max_stream_data");
   REC_EstablishStaticConfigInt32U(this->_server_id, "proxy.config.quic.server_id");
-  REC_EstablishStaticConfigInt32(_connection_table_size, "proxy.config.quic.connection_table.size");
+  REC_EstablishStaticConfigInt32(this->_connection_table_size, "proxy.config.quic.connection_table.size");
+  REC_EstablishStaticConfigInt32U(this->_stateless_retry, "proxy.config.quic.stateless_retry");
 }
 
 uint32_t
@@ -67,6 +68,12 @@ QUICConfigParams::connection_table_size()
 }
 
 uint32_t
+QUICConfigParams::stateless_retry() const
+{
+  return this->_stateless_retry;
+}
+
+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 a7a4f60..4ae7721 100644
--- a/iocore/net/quic/QUICConfig.h
+++ b/iocore/net/quic/QUICConfig.h
@@ -39,6 +39,7 @@ public:
   uint32_t initial_max_stream_id_uni_out() const;
   uint32_t server_id() const;
   static int connection_table_size();
+  uint32_t stateless_retry() const;
 
 private:
   // FIXME Fill appropriate default values in RecordsConfig.cc
@@ -48,6 +49,7 @@ private:
   uint32_t _initial_max_stream_data = 0;
   uint32_t _server_id               = 0;
   static int _connection_table_size;
+  uint32_t _stateless_retry = 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 428106a..4276715 100644
--- a/iocore/net/quic/QUICHandshake.cc
+++ b/iocore/net/quic/QUICHandshake.cc
@@ -86,17 +86,18 @@ static constexpr int UDP_MAXIMUM_PAYLOAD_SIZE = 65527;
 // TODO: fix size
 static constexpr int MAX_HANDSHAKE_MSG_LEN = 65527;
 
-QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {})
+QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx) : QUICHandshake(qc, ssl_ctx, {}, false)
 {
 }
 
-QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token)
+QUICHandshake::QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry)
   : QUICApplication(qc),
     _ssl(SSL_new(ssl_ctx)),
-    _hs_protocol(new QUICTLS(this->_ssl, qc->direction())),
+    _hs_protocol(new QUICTLS(this->_ssl, qc->direction(), stateless_retry)),
     _version_negotiator(new QUICVersionNegotiator()),
     _netvc_context(qc->direction()),
-    _reset_token(token)
+    _reset_token(token),
+    _stateless_retry(stateless_retry)
 {
   SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_qc_index, qc);
   SSL_set_ex_data(this->_ssl, QUIC::ssl_quic_hs_index, this);
@@ -144,17 +145,24 @@ QUICHandshake::start(const QUICPacket *initial_packet, QUICPacketFactory *packet
 }
 
 bool
-QUICHandshake::is_version_negotiated()
+QUICHandshake::is_version_negotiated() const
 {
   return (this->_version_negotiator->status() == QUICVersionNegotiationStatus::NEGOTIATED);
 }
 
 bool
-QUICHandshake::is_completed()
+QUICHandshake::is_completed() const
 {
   return this->handler == &QUICHandshake::state_complete;
 }
 
+bool
+QUICHandshake::is_stateless_retry_enabled() const
+{
+  return this->_stateless_retry;
+}
+
+
 QUICHandshakeProtocol *
 QUICHandshake::protocol()
 {
@@ -393,6 +401,16 @@ QUICHandshake::state_closed(int event, void *data)
 {
   return EVENT_DONE;
 }
+
+QUICHandshakeMsgType
+QUICHandshake::msg_type() const {
+  if (this->_hs_protocol) {
+    return this->_hs_protocol->msg_type();
+  } else {
+    return QUICHandshakeMsgType::NONE;
+  }
+}
+
 void
 QUICHandshake::_load_local_server_transport_parameters(QUICVersion negotiated_version)
 {
@@ -505,12 +523,18 @@ QUICHandshake::_process_client_hello()
   QUICErrorUPtr error     = QUICErrorUPtr(new QUICNoError());
 
   switch (result) {
+  case SSL_ERROR_NONE:
   case SSL_ERROR_WANT_READ: {
-    QUICHSDebug("Enter state_auth");
-    SET_HANDLER(&QUICHandshake::state_auth);
+    if (this->_hs_protocol->msg_type() == QUICHandshakeMsgType::HRR) {
+      // TODO: Send HRR on Retry Packet directly
+      stream_io->write_reenable();
+    } else {
+      QUICHSDebug("Enter state_auth");
+      SET_HANDLER(&QUICHandshake::state_auth);
 
-    stream_io->write_reenable();
-    stream_io->read_reenable();
+      stream_io->write_reenable();
+      stream_io->read_reenable();
+    }
 
     break;
   }
diff --git a/iocore/net/quic/QUICHandshake.h b/iocore/net/quic/QUICHandshake.h
index 3fd0dfe..d53171f 100644
--- a/iocore/net/quic/QUICHandshake.h
+++ b/iocore/net/quic/QUICHandshake.h
@@ -55,7 +55,7 @@ public:
   // Constructor for client side
   QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx);
   // Constructor for server side
-  QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token);
+  QUICHandshake(QUICConnection *qc, SSL_CTX *ssl_ctx, QUICStatelessResetToken token, bool stateless_retry);
   ~QUICHandshake();
 
   // for client side
@@ -79,13 +79,17 @@ public:
   std::shared_ptr<const QUICTransportParameters> local_transport_parameters();
   std::shared_ptr<const QUICTransportParameters> remote_transport_parameters();
 
-  bool is_version_negotiated();
-  bool is_completed();
+  bool is_version_negotiated() const;
+  bool is_completed() const;
+  bool is_stateless_retry_enabled() const;
 
   void set_transport_parameters(std::shared_ptr<QUICTransportParametersInClientHello> tp);
   void set_transport_parameters(std::shared_ptr<QUICTransportParametersInEncryptedExtensions> tp);
   void set_transport_parameters(std::shared_ptr<QUICTransportParametersInNewSessionTicket> tp);
 
+  // A workaround API to indicate handshake msg type to QUICNetVConnection
+  QUICHandshakeMsgType msg_type() const;
+
 private:
   SSL *_ssl                                                             = nullptr;
   QUICHandshakeProtocol *_hs_protocol                                   = nullptr;
@@ -93,6 +97,9 @@ private:
   std::shared_ptr<QUICTransportParameters> _remote_transport_parameters = nullptr;
 
   QUICVersionNegotiator *_version_negotiator = nullptr;
+  NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET;
+  QUICStatelessResetToken _reset_token;
+  bool _stateless_retry = false;
 
   void _load_local_server_transport_parameters(QUICVersion negotiated_version);
   void _load_local_client_transport_parameters(QUICVersion initial_version);
@@ -106,7 +113,4 @@ private:
 
   int _complete_handshake();
   void _abort_handshake(QUICTransErrorCode code);
-
-  NetVConnectionContext_t _netvc_context = NET_VCONNECTION_UNSET;
-  QUICStatelessResetToken _reset_token;
 };
diff --git a/iocore/net/quic/QUICHandshakeProtocol.cc b/iocore/net/quic/QUICHandshakeProtocol.cc
index 4cb7a10..d73826a 100644
--- a/iocore/net/quic/QUICHandshakeProtocol.cc
+++ b/iocore/net/quic/QUICHandshakeProtocol.cc
@@ -79,3 +79,12 @@ QUICPacketProtection::key_phase() const
 {
   return this->_key_phase;
 }
+
+//
+// QUICHandshakeProtocol
+//
+QUICHandshakeMsgType
+QUICHandshakeProtocol::msg_type() const
+{
+  return this->_msg_type;
+}
diff --git a/iocore/net/quic/QUICHandshakeProtocol.h b/iocore/net/quic/QUICHandshakeProtocol.h
index 86412f4..3e4649d 100644
--- a/iocore/net/quic/QUICHandshakeProtocol.h
+++ b/iocore/net/quic/QUICHandshakeProtocol.h
@@ -59,4 +59,8 @@ public:
                        uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0;
   virtual bool decrypt(uint8_t *plain, size_t &plain_len, size_t max_plain_len, const uint8_t *cipher, size_t cipher_len,
                        uint64_t pkt_num, const uint8_t *ad, size_t ad_len, QUICKeyPhase phase) const = 0;
+  virtual QUICHandshakeMsgType msg_type() const;
+
+protected:
+  QUICHandshakeMsgType _msg_type = QUICHandshakeMsgType::NONE;
 };
diff --git a/iocore/net/quic/QUICPacket.cc b/iocore/net/quic/QUICPacket.cc
index 35e8749..610a67b 100644
--- a/iocore/net/quic/QUICPacket.cc
+++ b/iocore/net/quic/QUICPacket.cc
@@ -782,14 +782,13 @@ QUICPacketFactory::create_initial_packet(QUICConnectionId connection_id, QUICPac
   return this->_create_encrypted_packet(std::move(header), true);
 }
 
-// retransmittable? depends on stateless?
 QUICPacketUPtr
 QUICPacketFactory::create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload,
-                                       size_t len)
+                                       size_t len, bool retransmittable)
 {
   QUICPacketHeaderUPtr header = QUICPacketHeader::build(QUICPacketType::RETRY, connection_id, this->_packet_number_generator.next(),
                                                         base_packet_number, this->_version, std::move(payload), len);
-  return this->_create_encrypted_packet(std::move(header), false);
+  return this->_create_encrypted_packet(std::move(header), retransmittable);
 }
 
 QUICPacketUPtr
diff --git a/iocore/net/quic/QUICPacket.h b/iocore/net/quic/QUICPacket.h
index c4b13cb..669cbea 100644
--- a/iocore/net/quic/QUICPacket.h
+++ b/iocore/net/quic/QUICPacket.h
@@ -343,7 +343,7 @@ public:
   QUICPacketUPtr create_initial_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, QUICVersion version,
                                        ats_unique_buf payload, size_t len);
   QUICPacketUPtr create_retry_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number, ats_unique_buf payload,
-                                     size_t len);
+                                     size_t len, bool retransmittable);
   QUICPacketUPtr create_handshake_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number,
                                          ats_unique_buf payload, size_t len, bool retransmittable);
   QUICPacketUPtr create_server_protected_packet(QUICConnectionId connection_id, QUICPacketNumber base_packet_number,
diff --git a/iocore/net/quic/QUICTLS.cc b/iocore/net/quic/QUICTLS.cc
index 74e8c46..50b2e73 100644
--- a/iocore/net/quic/QUICTLS.cc
+++ b/iocore/net/quic/QUICTLS.cc
@@ -79,7 +79,7 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint
     ERR_clear_error();
     int ret = 0;
     if (this->_netvc_context == NET_VCONNECTION_IN) {
-      // // process early data
+      // process early data
       if (!this->_early_data_processed) {
         if (this->_read_early_data()) {
           this->_early_data_processed = true;
@@ -106,14 +106,15 @@ QUICTLS::handshake(uint8_t *out, size_t &out_len, size_t max_out_len, const uint
         SSL_set_bio(this->_ssl, rbio, wbio);
 
         ret = SSL_stateless(this->_ssl);
-        if (ret >= 0) {
-          Debug(tag, "Sending HRR");
+        if (ret > 0) {
           this->_stateless = false;
-        } else {
-          Debug(tag, "SSL_stateless error");
+          this->_msg_type = QUICHandshakeMsgType::SH;
+        } else if (ret == 0) {
+          this->_msg_type = QUICHandshakeMsgType::HRR;
         }
       } else {
         ret = SSL_accept(this->_ssl);
+        this->_msg_type = QUICHandshakeMsgType::SH;
       }
     } else {
       ret = SSL_connect(this->_ssl);
@@ -165,12 +166,6 @@ QUICTLS::is_key_derived(QUICKeyPhase key_phase) const
   }
 }
 
-bool
-QUICTLS::is_stateless()
-{
-  return this->_stateless;
-}
-
 int
 QUICTLS::initialize_key_materials(QUICConnectionId cid)
 {
diff --git a/iocore/net/quic/QUICTLS.h b/iocore/net/quic/QUICTLS.h
index 20d1c61..4c6ebef 100644
--- a/iocore/net/quic/QUICTLS.h
+++ b/iocore/net/quic/QUICTLS.h
@@ -56,7 +56,6 @@ public:
 
   // FIXME SSL handle should not be exported
   SSL *ssl_handle();
-  bool is_stateless();
 
 private:
   QUICKeyGenerator _keygen_for_client = QUICKeyGenerator(QUICKeyGenerator::Context::CLIENT);
diff --git a/iocore/net/quic/QUICTypes.h b/iocore/net/quic/QUICTypes.h
index 25c1aab..2b4814d 100644
--- a/iocore/net/quic/QUICTypes.h
+++ b/iocore/net/quic/QUICTypes.h
@@ -136,6 +136,14 @@ enum class QUICTransErrorCode : uint16_t {
   TLS_FATAL_ALERT_RECEIVED,
 };
 
+enum class QUICHandshakeMsgType {
+  NONE = 0,
+  CH,
+  SH,
+  HRR,
+  FN,
+};
+
 // Application Protocol Error Codes defined in application
 using QUICAppErrorCode                          = uint16_t;
 constexpr uint16_t QUIC_APP_ERROR_CODE_STOPPING = 0;
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index 86e6af2..87531c7 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -1328,6 +1328,8 @@ static const RecordElement RecordsConfig[] =
   ,
   {RECT_CONFIG, "proxy.config.quic.connection_table.size", RECD_INT, "65521", RECU_RESTART_TS, RR_NULL, RECC_INT, "[1-536870909]", RECA_NULL}
   ,
+  {RECT_CONFIG, "proxy.config.quic.stateless_retry", RECD_INT, "0", RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL}
+  ,
 
   //# Add LOCAL Records Here
   {RECT_LOCAL, "proxy.local.incoming_ip_to_bind", RECD_STRING, nullptr, RECU_NULL, RR_NULL, RECC_NULL, nullptr, RECA_NULL}

-- 
To stop receiving notification emails like this one, please contact
masaori@apache.org.