This is an automated email from the ASF dual-hosted git repository. shinrich pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/trafficserver.git
commit d7e90a462a28d40f6d9a457aa0c09e323c480684 Author: Susan Hinrichs <[email protected]> AuthorDate: Tue Aug 6 20:38:08 2019 +0000 Update for QUIC integration. --- iocore/net/P_QUICNetVConnection.h | 14 ++++++++++++++ iocore/net/P_QUICNextProtocolAccept.h | 6 ++---- iocore/net/QUICMultiCertConfigLoader.cc | 10 ++-------- iocore/net/QUICNetVConnection.cc | 32 ++++++++++++++++++++++++++++++++ iocore/net/QUICNextProtocolAccept.cc | 13 ++++--------- iocore/net/quic/Mock.h | 28 ++++++++++++++++++++++++++++ iocore/net/quic/QUICConnection.h | 14 +++++++++----- proxy/http/HttpProxyServerMain.cc | 10 ++++------ src/traffic_server/InkAPI.cc | 1 - src/traffic_server/traffic_server.cc | 3 --- 10 files changed, 95 insertions(+), 36 deletions(-) diff --git a/iocore/net/P_QUICNetVConnection.h b/iocore/net/P_QUICNetVConnection.h index 8ca2588..d9a0adb 100644 --- a/iocore/net/P_QUICNetVConnection.h +++ b/iocore/net/P_QUICNetVConnection.h @@ -168,6 +168,15 @@ public: int populate_protocol(std::string_view *results, int n) const override; const char *protocol_contains(std::string_view tag) const override; + int select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned inlen) const override; + + void + setEnabledProtocols(const SessionProtocolSet &protos) + { + this->_protoenabled = protos; + } + // QUICNetVConnection void registerNextProtocolSet(SSLNextProtocolSet *s); @@ -187,6 +196,7 @@ public: uint32_t pmtu() const override; NetVConnectionContext_t direction() const override; SSLNextProtocolSet *next_protocol_set() const override; + const SessionProtocolSet &get_enabled_protocols() const override; std::string_view negotiated_application_name() const override; bool is_closed() const override; @@ -236,6 +246,10 @@ private: uint32_t _pmtu = 1280; SSLNextProtocolSet *_next_protocol_set = nullptr; + SessionProtocolSet _protoenabled; + // Local copies of the npn strings + unsigned char *_npn = nullptr; + size_t _npnsz = 0; // TODO: use custom allocator and make them std::unique_ptr or std::shared_ptr // or make them just member variables. diff --git a/iocore/net/P_QUICNextProtocolAccept.h b/iocore/net/P_QUICNextProtocolAccept.h index 5b03652..95752dd 100644 --- a/iocore/net/P_QUICNextProtocolAccept.h +++ b/iocore/net/P_QUICNextProtocolAccept.h @@ -40,13 +40,10 @@ public: // lifetime is at least as long as that of the acceptor. bool registerEndpoint(const char *protocol, Continuation *handler); - // Unregister the handler. Returns false if this protocol is not registered - // or if it is not registered for the specified handler. - bool unregisterEndpoint(const char *protocol, Continuation *handler); + void enableProtocols(const SessionProtocolSet &protos); SLINK(QUICNextProtocolAccept, link); SSLNextProtocolSet *getProtoSet(); - SSLNextProtocolSet *cloneProtoSet(); // noncopyable QUICNextProtocolAccept(const QUICNextProtocolAccept &) = delete; // disabled @@ -56,6 +53,7 @@ private: int mainEvent(int event, void *netvc); SSLNextProtocolSet protoset; + SessionProtocolSet protoenabled; friend struct QUICNextProtocolTrampoline; }; diff --git a/iocore/net/QUICMultiCertConfigLoader.cc b/iocore/net/QUICMultiCertConfigLoader.cc index a948a6f..7a3fe2c 100644 --- a/iocore/net/QUICMultiCertConfigLoader.cc +++ b/iocore/net/QUICMultiCertConfigLoader.cc @@ -274,17 +274,11 @@ int QUICMultiCertConfigLoader::ssl_select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned inlen, void *) { - const unsigned char *npn; - unsigned npnsz = 0; QUICConnection *qc = static_cast<QUICConnection *>(SSL_get_ex_data(ssl, QUIC::ssl_quic_qc_index)); - qc->next_protocol_set()->advertiseProtocols(&npn, &npnsz); - if (SSL_select_next_proto((unsigned char **)out, outlen, npn, npnsz, in, inlen) == OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_OK; + if (qc) { + return qc->select_next_protocol(ssl, out, outlen, in, inlen); } - - *out = nullptr; - *outlen = 0; return SSL_TLSEXT_ERR_NOACK; } diff --git a/iocore/net/QUICNetVConnection.cc b/iocore/net/QUICNetVConnection.cc index 5bbd25b..36f55cc 100644 --- a/iocore/net/QUICNetVConnection.cc +++ b/iocore/net/QUICNetVConnection.cc @@ -503,6 +503,11 @@ QUICNetVConnection::free(EThread *t) super::clear(); */ + if (this->_npn) { + ats_free(this->_npn); + this->_npn = nullptr; + this->_npnsz = 0; + } this->_packet_handler->close_connection(this); } @@ -1018,6 +1023,27 @@ void QUICNetVConnection::registerNextProtocolSet(SSLNextProtocolSet *s) { this->_next_protocol_set = s; + this->_next_protocol_set->create_npn_advertisement(this->_protoenabled, &this->_npn, &this->_npnsz); +} + +// ALPN TLS extension callback. Given the client's set of offered +// protocols, we have to select a protocol to use for this session. +int +QUICNetVConnection::select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned inlen) const +{ + if (this->_npn && this->_npnsz) { + // SSL_select_next_proto chooses the first server-offered protocol that appears in the clients protocol set, ie. the + // server selects the protocol. This is a n^2 search, so it's preferable to keep the protocol set short. + if (SSL_select_next_proto((unsigned char **)out, outlen, this->_npn, this->_npnsz, in, inlen) == OPENSSL_NPN_NEGOTIATED) { + Debug("ssl", "selected ALPN protocol %.*s", (int)(*outlen), *out); + return SSL_TLSEXT_ERR_OK; + } + } + + *out = nullptr; + *outlen = 0; + return SSL_TLSEXT_ERR_NOACK; } bool @@ -1032,6 +1058,12 @@ QUICNetVConnection::next_protocol_set() const return this->_next_protocol_set; } +const SessionProtocolSet & +QUICNetVConnection::get_enabled_protocols() const +{ + return this->_protoenabled; +} + QUICPacketNumber QUICNetVConnection::_largest_acked_packet_number(QUICEncryptionLevel level) const { diff --git a/iocore/net/QUICNextProtocolAccept.cc b/iocore/net/QUICNextProtocolAccept.cc index 1f721fa..4662a09 100644 --- a/iocore/net/QUICNextProtocolAccept.cc +++ b/iocore/net/QUICNextProtocolAccept.cc @@ -54,6 +54,7 @@ QUICNextProtocolAccept::mainEvent(int event, void *edata) switch (event) { case NET_EVENT_ACCEPT: ink_release_assert(netvc != nullptr); + netvc->setEnabledProtocols(this->protoenabled); netvc->registerNextProtocolSet(&this->protoset); return EVENT_CONT; default: @@ -75,10 +76,10 @@ QUICNextProtocolAccept::registerEndpoint(const char *protocol, Continuation *han return this->protoset.registerEndpoint(protocol, handler); } -bool -QUICNextProtocolAccept::unregisterEndpoint(const char *protocol, Continuation *handler) +void +QUICNextProtocolAccept::enableProtocols(const SessionProtocolSet &protos) { - return this->protoset.unregisterEndpoint(protocol, handler); + this->protoenabled = protos; } QUICNextProtocolAccept::QUICNextProtocolAccept() : SessionAccept(nullptr) @@ -92,10 +93,4 @@ QUICNextProtocolAccept::getProtoSet() return &this->protoset; } -SSLNextProtocolSet * -QUICNextProtocolAccept::cloneProtoSet() -{ - return this->protoset.clone(); -} - QUICNextProtocolAccept::~QUICNextProtocolAccept() {} diff --git a/iocore/net/quic/Mock.h b/iocore/net/quic/Mock.h index 45f5e8f..cb107c9 100644 --- a/iocore/net/quic/Mock.h +++ b/iocore/net/quic/Mock.h @@ -220,6 +220,12 @@ public: return nullptr; } + const SessionProtocolSet & + get_enabled_protocols() const override + { + return _protocolsenabled; + } + void close(QUICConnectionErrorUPtr error) override { @@ -259,6 +265,13 @@ public: return negotiated_application_name_sv; } + int + select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned inlen) const override + { + return SSL_TLSEXT_ERR_OK; + } + int _transmit_count = 0; int _retransmit_count = 0; Ptr<ProxyMutex> _mutex; @@ -268,6 +281,7 @@ public: QUICTransportParametersInEncryptedExtensions dummy_transport_parameters(); NetVConnectionContext_t _direction; + SessionProtocolSet _protocolsenabled; }; class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider @@ -326,6 +340,18 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider { return nullptr; } + const SessionProtocolSet & + get_enabled_protocols() const override + { + return _protocolsenabled; + } + + int + select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned inlen) const override + { + return SSL_TLSEXT_ERR_OK; + } bool is_closed() const override @@ -338,6 +364,8 @@ class MockQUICConnectionInfoProvider : public QUICConnectionInfoProvider { return negotiated_application_name_sv; } + + SessionProtocolSet _protocolsenabled; }; class MockQUICCongestionController : public QUICCongestionController diff --git a/iocore/net/quic/QUICConnection.h b/iocore/net/quic/QUICConnection.h index 36cc5fb..c57b19f 100644 --- a/iocore/net/quic/QUICConnection.h +++ b/iocore/net/quic/QUICConnection.h @@ -31,6 +31,7 @@ class QUICApplication; class QUICStreamManager; class UDPPacket; class SSLNextProtocolSet; +class SessionProtocolSet; class QUICConnectionInfoProvider { @@ -42,11 +43,14 @@ public: virtual std::string_view cids() const = 0; virtual const QUICFiveTuple five_tuple() const = 0; - virtual uint32_t pmtu() const = 0; - virtual NetVConnectionContext_t direction() const = 0; - virtual SSLNextProtocolSet *next_protocol_set() const = 0; - virtual bool is_closed() const = 0; - virtual std::string_view negotiated_application_name() const = 0; + virtual uint32_t pmtu() const = 0; + virtual NetVConnectionContext_t direction() const = 0; + virtual SSLNextProtocolSet *next_protocol_set() const = 0; + virtual const SessionProtocolSet &get_enabled_protocols() const = 0; + virtual int select_next_protocol(SSL *ssl, const unsigned char **out, unsigned char *outlen, const unsigned char *in, + unsigned inlen) const = 0; + virtual bool is_closed() const = 0; + virtual std::string_view negotiated_application_name() const = 0; }; class QUICConnection : public QUICFrameHandler, public QUICConnectionInfoProvider diff --git a/proxy/http/HttpProxyServerMain.cc b/proxy/http/HttpProxyServerMain.cc index 78f05a3..48ea161 100644 --- a/proxy/http/HttpProxyServerMain.cc +++ b/proxy/http/HttpProxyServerMain.cc @@ -235,15 +235,13 @@ MakeHttpProxyAcceptor(HttpProxyAcceptor &acceptor, HttpProxyPort &port, unsigned } else if (port.isQUIC()) { QUICNextProtocolAccept *quic = new QUICNextProtocolAccept(); + quic->enableProtocols(port.m_session_protocol_preference); + // HTTP/3 - if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_3)) { - quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3, new Http3SessionAccept(accept_opt)); - } + quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_3, new Http3SessionAccept(accept_opt)); // HTTP/0.9 over QUIC (for interop only, will be removed) - if (port.m_session_protocol_preference.contains(TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC)) { - quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new Http3SessionAccept(accept_opt)); - } + quic->registerEndpoint(TS_ALPN_PROTOCOL_HTTP_QUIC, new Http3SessionAccept(accept_opt)); quic->proxyPort = &port; acceptor._accept = quic; diff --git a/src/traffic_server/InkAPI.cc b/src/traffic_server/InkAPI.cc index 7b13540..d4c56b3 100644 --- a/src/traffic_server/InkAPI.cc +++ b/src/traffic_server/InkAPI.cc @@ -7160,7 +7160,6 @@ TSNetAccept(TSCont contp, int port, int domain, int accept_threads) /* From proxy/http/HttpProxyServerMain.c: */ extern bool ssl_register_protocol(const char *, Continuation *); -// extern bool ssl_unregister_protocol(const char *, Continuation *); TSReturnCode TSNetAcceptNamedProtocol(TSCont contp, const char *protocol) diff --git a/src/traffic_server/traffic_server.cc b/src/traffic_server/traffic_server.cc index 61fe2cc..2c82fd5 100644 --- a/src/traffic_server/traffic_server.cc +++ b/src/traffic_server/traffic_server.cc @@ -1958,9 +1958,6 @@ main(int /* argc ATS_UNUSED */, const char **argv) start_HttpProxyServer(); // PORTS_READY_HOOK called from in here } } -#ifdef OLD - SNIConfig::cloneProtoSet(); -#endif // Plugins can register their own configuration names so now after they've done that // check for unexpected names. This is very late because remap plugins must be allowed to // fire up as well.
