You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@brpc.apache.org by ww...@apache.org on 2023/12/25 03:52:53 UTC
(brpc) branch master updated: Add client ALPN support (#2251)
This is an automated email from the ASF dual-hosted git repository.
wwbmmm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git
The following commit(s) were added to refs/heads/master by this push:
new 4b149518 Add client ALPN support (#2251)
4b149518 is described below
commit 4b1495186268a07eb9cae5db86176bb1dd9a0fe4
Author: Menci <hu...@gmail.com>
AuthorDate: Mon Dec 25 11:52:48 2023 +0800
Add client ALPN support (#2251)
* Add client ALPN support
* Fix build error
* Remove ALPN code from mesalink_ssl_helper
* Add alpn_protocol.size() to error message
* Add docs
---
docs/cn/client.md | 3 +++
docs/en/client.md | 4 ++++
src/brpc/channel.cpp | 1 +
src/brpc/details/ssl_helper.cpp | 38 ++++++++++++++++++++++++++++++++++++++
src/brpc/details/ssl_helper.h | 7 +++++++
src/brpc/socket.cpp | 27 +++++++++++++++++++++++++++
src/brpc/socket.h | 5 +++--
src/brpc/ssl_options.h | 4 ++++
8 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/docs/cn/client.md b/docs/cn/client.md
index ef714ed8..27f1fa70 100755
--- a/docs/cn/client.md
+++ b/docs/cn/client.md
@@ -831,6 +831,9 @@ options.mutable_ssl_options();
// 开启客户端SSL并定制选项。
options.mutable_ssl_options()->ciphers_name = "...";
options.mutable_ssl_options()->sni_name = "...";
+
+// 设置 ALPN 的协议优先级(默认不启用 ALPN)。
+options.mutable_ssl_options()->alpn_protocols = {"h2", "http/1.1"};
```
- 连接单点和集群的Channel均可以开启SSL访问(初始实现曾不支持集群)。
- 开启后,该Channel上任何协议的请求,都会被SSL加密后发送。如果希望某些请求不加密,需要额外再创建一个Channel。
diff --git a/docs/en/client.md b/docs/en/client.md
index 358bf2f2..f199fc6b 100644
--- a/docs/en/client.md
+++ b/docs/en/client.md
@@ -755,6 +755,10 @@ options.mutable_ssl_options();
// Enable client-side SSL and customize values.
options.mutable_ssl_options()->ciphers_name = "...";
options.mutable_ssl_options()->sni_name = "...";
+
+// Set the protocol preference of ALPN.
+// (By default ALPN is disabled.)
+options.mutable_ssl_options()->alpn_protocols = {"h2", "http/1.1"};
```
- Channels connecting to a single server or a cluster both support SSL (the initial implementation does not support cluster)
diff --git a/src/brpc/channel.cpp b/src/brpc/channel.cpp
index a94c09b5..67ab4969 100644
--- a/src/brpc/channel.cpp
+++ b/src/brpc/channel.cpp
@@ -303,6 +303,7 @@ static int CreateSocketSSLContext(const ChannelOptions& options,
*ssl_ctx = std::make_shared<SocketSSLContext>();
(*ssl_ctx)->raw_ctx = raw_ctx;
(*ssl_ctx)->sni_name = options.ssl_options().sni_name;
+ (*ssl_ctx)->alpn_protocols = options.ssl_options().alpn_protocols;
} else {
(*ssl_ctx) = NULL;
}
diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp
index a0275261..d33d0ee7 100644
--- a/src/brpc/details/ssl_helper.cpp
+++ b/src/brpc/details/ssl_helper.cpp
@@ -498,6 +498,14 @@ SSL_CTX* CreateClientSSLContext(const ChannelSSLOptions& options) {
return NULL;
}
+ if (!options.alpn_protocols.empty()) {
+ std::vector<unsigned char> alpn_list;
+ if (!BuildALPNProtocolList(options.alpn_protocols, alpn_list)) {
+ return NULL;
+ }
+ SSL_CTX_set_alpn_protos(ssl_ctx.get(), alpn_list.data(), alpn_list.size());
+ }
+
SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_CLIENT);
return ssl_ctx.release();
}
@@ -896,6 +904,36 @@ std::string ALPNProtocolToString(const AdaptiveProtocolType& protocol) {
return std::string(&length, 1) + name.data();
}
+bool BuildALPNProtocolList(
+ const std::vector<std::string>& alpn_protocols,
+ std::vector<unsigned char>& result
+) {
+ size_t alpn_list_length = 0;
+ for (const auto& alpn_protocol : alpn_protocols) {
+ if (alpn_protocol.size() > UCHAR_MAX) {
+ LOG(ERROR) << "Fail to build ALPN procotol list: "
+ << "protocol name length " << alpn_protocol.size() << " too long, "
+ << "max 255 supported.";
+ return false;
+ }
+ alpn_list_length += alpn_protocol.size() + 1;
+ }
+
+ result.resize(alpn_list_length);
+ for (size_t curr = 0, i = 0; i < alpn_protocols.size(); i++) {
+ result[curr++] = static_cast<unsigned char>(
+ alpn_protocols[i].size()
+ );
+ std::copy(
+ alpn_protocols[i].begin(),
+ alpn_protocols[i].end(),
+ result.begin() + curr
+ );
+ curr += alpn_protocols[i].size();
+ }
+ return true;
+}
+
} // namespace brpc
#endif // USE_MESALINK
diff --git a/src/brpc/details/ssl_helper.h b/src/brpc/details/ssl_helper.h
index 4f1e55b2..da126b39 100644
--- a/src/brpc/details/ssl_helper.h
+++ b/src/brpc/details/ssl_helper.h
@@ -113,6 +113,13 @@ void Print(std::ostream& os, X509* cert, const char* sep);
std::string ALPNProtocolToString(const AdaptiveProtocolType& protocol);
+// Build a binary formatted ALPN protocol list that OpenSSL's
+// `SSL_CTX_set_alpn_protos` accepts from a C++ string vector.
+bool BuildALPNProtocolList(
+ const std::vector<std::string>& alpn_protocols,
+ std::vector<unsigned char>& result
+);
+
} // namespace brpc
#endif // BRPC_SSL_HELPER_H
diff --git a/src/brpc/socket.cpp b/src/brpc/socket.cpp
index acd1b54d..2a391f35 100644
--- a/src/brpc/socket.cpp
+++ b/src/brpc/socket.cpp
@@ -1958,6 +1958,33 @@ int Socket::SSLHandshake(int fd, bool server_mode) {
ERR_clear_error();
int rc = SSL_do_handshake(_ssl_session);
if (rc == 1) {
+ // In client, check if server returned ALPN selection is acceptable.
+ if (!server_mode && !_ssl_ctx->alpn_protocols.empty()) {
+ const unsigned char *alpn_proto;
+ unsigned int alpn_proto_length;
+ SSL_get0_alpn_selected(_ssl_session, &alpn_proto, &alpn_proto_length);
+ if (!alpn_proto) {
+ LOG(ERROR) << "Server returned no ALPN protocol";
+ return -1;
+ }
+
+ std::string alpn_protocol(
+ reinterpret_cast<char const *>(alpn_proto),
+ alpn_proto_length
+ );
+ if (
+ std::find(
+ _ssl_ctx->alpn_protocols.begin(),
+ _ssl_ctx->alpn_protocols.end(),
+ alpn_protocol
+ ) == _ssl_ctx->alpn_protocols.end()
+ ) {
+ LOG(ERROR) << "Server returned unacceptable ALPN protocol: "
+ << alpn_protocol;
+ return -1;
+ }
+ }
+
_ssl_state = SSL_CONNECTED;
AddBIOBuffer(_ssl_session, fd, FLAGS_ssl_bio_buffer_size);
return 0;
diff --git a/src/brpc/socket.h b/src/brpc/socket.h
index 44ea0b02..9d85aafa 100644
--- a/src/brpc/socket.h
+++ b/src/brpc/socket.h
@@ -170,8 +170,9 @@ struct SocketSSLContext {
SocketSSLContext();
~SocketSSLContext();
- SSL_CTX* raw_ctx; // owned
- std::string sni_name; // useful for clients
+ SSL_CTX* raw_ctx; // owned
+ std::string sni_name; // useful for clients
+ std::vector<std::string> alpn_protocols; // useful for clients
};
struct SocketKeepaliveOptions {
diff --git a/src/brpc/ssl_options.h b/src/brpc/ssl_options.h
index c7caa1dd..bbe9ccf1 100644
--- a/src/brpc/ssl_options.h
+++ b/src/brpc/ssl_options.h
@@ -84,6 +84,10 @@ struct ChannelSSLOptions {
// Default: see above
VerifyOptions verify;
+ // Set the protocol preference of ALPN (Application-Layer Protocol Negotiation)
+ // Default: unset
+ std::vector<std::string> alpn_protocols;
+
// TODO: Support CRL
};
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@brpc.apache.org
For additional commands, e-mail: dev-help@brpc.apache.org