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.