From 7d9dc69ae1ff98f6e2c800066e444e172c11a4e8 Mon Sep 17 00:00:00 2001 From: john Date: Fri, 28 Oct 2022 16:55:35 +0800 Subject: [PATCH] SRT: Support encrypt, with utest (#3223) * SRT: support encrypt, with utest * SRT: refine set srt option error log --- trunk/conf/full.conf | 13 ++++ trunk/src/app/srs_app_config.cpp | 36 ++++++++++- trunk/src/app/srs_app_config.hpp | 4 ++ trunk/src/app/srs_app_srt_server.cpp | 36 +++++++---- trunk/src/protocol/srs_protocol_srt.cpp | 12 ++++ trunk/src/protocol/srs_protocol_srt.hpp | 2 + trunk/src/utest/srs_utest_srt.cpp | 82 +++++++++++++++++++++++++ 7 files changed, 172 insertions(+), 13 deletions(-) diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 4cc72b5c2..8aaeb4013 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -350,6 +350,19 @@ srt_server { # Overwrite by env SRS_SRT_SERVER_RECVBUF # default: 8192 * (1500-28) recvbuf 2000000; + # The passphrase of SRT. + # If passphrase is no empty, all the srt client must be using the correct passphrase to publish or play, + # or the srt connection will reject. The length of passphrase must be in range 10~79. + # @see https://github.com/Haivision/srt/blob/master/docs/API/API-socket-options.md#srto_passphrase. + # Overwrite by env SRS_SRT_SERVER_PASSPHRASE + # default: "" + passphrase xxxxxxxxxxxx; + # The pbkeylen of SRT. + # The pbkeylen determined the AES encrypt algorithm, this option only allow 4 values which is 0, 16, 24, 32 + # @see https://github.com/Haivision/srt/blob/master/docs/API/API-socket-options.md#srto_pbkeylen. + # Overwrite by env SRS_SRT_SERVER_PBKEYLEN + # default: 0 + pbkeylen 16; } vhost srt.vhost.srs.com { diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 28ca3f1a8..e03377783 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -2332,7 +2332,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "peerlatency" && n != "tlpkdrop" && n != "connect_timeout" && n != "sendbuf" && n != "recvbuf" && n != "payloadsize" && n != "default_app" && n != "sei_filter" && n != "mix_correct" - && n != "tlpktdrop" && n != "tsbpdmode") { + && n != "tlpktdrop" && n != "tsbpdmode" && n != "passphrase" && n != "pbkeylen") { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal srt_server.%s", n.c_str()); } } @@ -7768,6 +7768,40 @@ int SrsConfig::get_srto_payloadsize() return atoi(conf->arg0().c_str()); } +string SrsConfig::get_srto_passphrase() +{ + SRS_OVERWRITE_BY_ENV_STRING("srs.srt_server.passphrase"); + + static string DEFAULT = ""; + SrsConfDirective* conf = root->get("srt_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("passphrase"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + return conf->arg0(); +} + +int SrsConfig::get_srto_pbkeylen() +{ + SRS_OVERWRITE_BY_ENV_INT("srs.srt_server.pbkeylen"); + + static int DEFAULT = 0; + SrsConfDirective* conf = root->get("srt_server"); + if (!conf) { + return DEFAULT; + } + + conf = conf->get("pbkeylen"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + return atoi(conf->arg0().c_str()); +} + string SrsConfig::get_default_app_name() { SRS_OVERWRITE_BY_ENV_STRING("srs.srt_server.default_app"); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 72bfa73bc..17d5c5e0a 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -684,6 +684,10 @@ public: virtual int get_srto_recvbuf(); // SRTO_PAYLOADSIZE virtual int get_srto_payloadsize(); + // Get the srt SRTO_PASSPHRASE, default is empty. + virtual std::string get_srto_passphrase(); + // Get the srt SRTO_PBKEYLEN, default is 0. + virtual int get_srto_pbkeylen(); // Get the default app. virtual std::string get_default_app_name(); private: diff --git a/trunk/src/app/srs_app_srt_server.cpp b/trunk/src/app/srs_app_srt_server.cpp index 2c497d6fa..977150a23 100644 --- a/trunk/src/app/srs_app_srt_server.cpp +++ b/trunk/src/app/srs_app_srt_server.cpp @@ -66,51 +66,63 @@ srs_error_t SrsSrtAcceptor::set_srt_opt() srs_error_t err = srs_success; if ((err = srs_srt_set_maxbw(listener_->fd(), _srs_config->get_srto_maxbw())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt maxbw=%d failed", _srs_config->get_srto_maxbw()); } if ((err = srs_srt_set_mss(listener_->fd(), _srs_config->get_srto_mss())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt mss=%d failed", _srs_config->get_srto_mss()); } if ((err = srs_srt_set_tsbpdmode(listener_->fd(), _srs_config->get_srto_tsbpdmode())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt tsbpdmode=%d failed", _srs_config->get_srto_tsbpdmode()); } if ((err = srs_srt_set_latency(listener_->fd(), _srs_config->get_srto_latency())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt latency=%d failed", _srs_config->get_srto_latency()); } if ((err = srs_srt_set_rcv_latency(listener_->fd(), _srs_config->get_srto_recv_latency())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt recvlatency=%d failed", _srs_config->get_srto_recv_latency()); } if ((err = srs_srt_set_peer_latency(listener_->fd(), _srs_config->get_srto_peer_latency())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt peerlatency=%d failed", _srs_config->get_srto_peer_latency()); } if ((err = srs_srt_set_tlpktdrop(listener_->fd(), _srs_config->get_srto_tlpktdrop())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt tlpkdrop=%d failed", _srs_config->get_srto_tlpktdrop()); } if ((err = srs_srt_set_connect_timeout(listener_->fd(), srsu2msi(_srs_config->get_srto_conntimeout()))) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt connect_timeout=%d failed", _srs_config->get_srto_conntimeout()); } if ((err = srs_srt_set_peer_idle_timeout(listener_->fd(), srsu2msi(_srs_config->get_srto_peeridletimeout()))) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt peer_idle_timeout=%d failed", _srs_config->get_srto_peeridletimeout()); } if ((err = srs_srt_set_sndbuf(listener_->fd(), _srs_config->get_srto_sendbuf())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt sendbuf=%d failed", _srs_config->get_srto_sendbuf()); } if ((err = srs_srt_set_rcvbuf(listener_->fd(), _srs_config->get_srto_recvbuf())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt recvbuf=%d failed", _srs_config->get_srto_recvbuf()); } if ((err = srs_srt_set_payload_size(listener_->fd(), _srs_config->get_srto_payloadsize())) != srs_success) { - return srs_error_wrap(err, "set opt"); + return srs_error_wrap(err, "set opt payload_size=%d failed", _srs_config->get_srto_payloadsize()); + } + + string passphrase = _srs_config->get_srto_passphrase(); + if (! passphrase.empty()) { + if ((err = srs_srt_set_passphrase(listener_->fd(), passphrase)) != srs_success) { + return srs_error_wrap(err, "set opt passphrase=%s failed", passphrase.c_str()); + } + + int pbkeylen = _srs_config->get_srto_pbkeylen(); + if ((err = srs_srt_set_pbkeylen(listener_->fd(), pbkeylen)) != srs_success) { + return srs_error_wrap(err, "set opt pbkeylen=%d failed", pbkeylen); + } } return err; diff --git a/trunk/src/protocol/srs_protocol_srt.cpp b/trunk/src/protocol/srs_protocol_srt.cpp index c1fccdddd..f05fe02ae 100644 --- a/trunk/src/protocol/srs_protocol_srt.cpp +++ b/trunk/src/protocol/srs_protocol_srt.cpp @@ -299,6 +299,18 @@ srs_error_t srs_srt_set_streamid(srs_srt_t srt_fd, const std::string& streamid) return srs_success; } +srs_error_t srs_srt_set_passphrase(srs_srt_t srt_fd, const std::string& passphrase) +{ + SET_SRT_OPT_STR(srt_fd, SRTO_PASSPHRASE, passphrase.data(), passphrase.size()); + return srs_success; +} + +srs_error_t srs_srt_set_pbkeylen(srs_srt_t srt_fd, int pbkeylen) +{ + SET_SRT_OPT(srt_fd, SRTO_PBKEYLEN, pbkeylen); + return srs_success; +} + srs_error_t srs_srt_get_maxbw(srs_srt_t srt_fd, int& maxbw) { GET_SRT_OPT(srt_fd, SRTO_MAXBW, maxbw); diff --git a/trunk/src/protocol/srs_protocol_srt.hpp b/trunk/src/protocol/srs_protocol_srt.hpp index 772e88b77..92649319c 100644 --- a/trunk/src/protocol/srs_protocol_srt.hpp +++ b/trunk/src/protocol/srs_protocol_srt.hpp @@ -47,6 +47,8 @@ extern srs_error_t srs_srt_set_latency(srs_srt_t srt_fd, int latency); extern srs_error_t srs_srt_set_rcv_latency(srs_srt_t srt_fd, int rcv_latency); extern srs_error_t srs_srt_set_peer_latency(srs_srt_t srt_fd, int peer_latency); extern srs_error_t srs_srt_set_streamid(srs_srt_t srt_fd, const std::string& streamid); +extern srs_error_t srs_srt_set_passphrase(srs_srt_t srt_fd, const std::string& passphrase); +extern srs_error_t srs_srt_set_pbkeylen(srs_srt_t srt_fd, int pbkeylen); // Get SRT options. extern srs_error_t srs_srt_get_maxbw(srs_srt_t srt_fd, int& maxbw); diff --git a/trunk/src/utest/srs_utest_srt.cpp b/trunk/src/utest/srs_utest_srt.cpp index 1b662af06..ff2cd0a26 100644 --- a/trunk/src/utest/srs_utest_srt.cpp +++ b/trunk/src/utest/srs_utest_srt.cpp @@ -20,6 +20,8 @@ using namespace std; extern SrsSrtEventLoop* _srt_eventloop; +// TODO: FIXME: set srt log handler. + // Test srt st service VOID TEST(ServiceSrtPoller, SrtPollOperateSocket) { @@ -146,6 +148,10 @@ public: return err; } + srs_srt_t fd() { + return srt_server_fd_; + } + srs_error_t listen(std::string ip, int port) { srs_error_t err = srs_success; @@ -463,6 +469,82 @@ VOID TEST(ProtocolSrtTest, SrtStreamIdToRequest) } } +VOID TEST(ServiceSRTTest, Encrypt) +{ + srs_error_t err = srs_success; + + std::string server_ip = "127.0.0.1"; + int server_port = 19000; + + MockSrtServer srt_server; + HELPER_EXPECT_SUCCESS(srt_server.create_socket()); + + string passphrase = "srt_passphrase"; + HELPER_EXPECT_SUCCESS(srs_srt_set_passphrase(srt_server.fd(), passphrase)); + HELPER_EXPECT_SUCCESS(srt_server.listen(server_ip, server_port)); + + std::string streamid = "SRS_SRT_Streamid"; + if (true) { + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); + HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); + HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_client_fd, streamid)); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); + + // SRT connect without passphrase, will reject. + HELPER_EXPECT_FAILED(srt_client_socket->connect(server_ip, server_port)); + } + + if (true) { + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); + HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); + HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_client_fd, streamid)); + HELPER_EXPECT_SUCCESS(srs_srt_set_passphrase(srt_client_fd, "wrong_passphrase")); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); + + // SRT connect with wrong passphrase, will reject. + HELPER_EXPECT_FAILED(srt_client_socket->connect(server_ip, server_port)); + } + + if (true) { + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); + HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); + HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_client_fd, streamid)); + // Set correct passphrase. + HELPER_EXPECT_SUCCESS(srs_srt_set_passphrase(srt_client_fd, passphrase)); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); + HELPER_EXPECT_SUCCESS(srt_client_socket->connect(server_ip, server_port)); + + srs_srt_t srt_server_accepted_fd = srs_srt_socket_invalid(); + HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_server_accepted_fd)); + EXPECT_NE(srt_server_accepted_fd, srs_srt_socket_invalid()); + std::string s; + HELPER_EXPECT_SUCCESS(srs_srt_get_streamid(srt_server_accepted_fd, s)); + EXPECT_EQ(s, streamid); + } + + if (true) { + int pbkeylens[4] = {0, 16, 24, 32}; + for (int i = 0; i < sizeof(pbkeylens) / sizeof(pbkeylens[0]); ++i) { + srs_srt_t srt_client_fd = srs_srt_socket_invalid(); + HELPER_EXPECT_SUCCESS(srs_srt_socket_with_default_option(&srt_client_fd)); + HELPER_EXPECT_SUCCESS(srs_srt_set_streamid(srt_client_fd, streamid)); + // Set correct passphrase. + HELPER_EXPECT_SUCCESS(srs_srt_set_passphrase(srt_client_fd, passphrase)); + // Set different pbkeylen. + HELPER_EXPECT_SUCCESS(srs_srt_set_pbkeylen(srt_client_fd, pbkeylens[i])); + SrsSrtSocket* srt_client_socket = new SrsSrtSocket(_srt_eventloop->poller(), srt_client_fd); + HELPER_EXPECT_SUCCESS(srt_client_socket->connect(server_ip, server_port)); + + srs_srt_t srt_server_accepted_fd = srs_srt_socket_invalid(); + HELPER_EXPECT_SUCCESS(srt_server.accept(&srt_server_accepted_fd)); + EXPECT_NE(srt_server_accepted_fd, srs_srt_socket_invalid()); + std::string s; + HELPER_EXPECT_SUCCESS(srs_srt_get_streamid(srt_server_accepted_fd, s)); + EXPECT_EQ(s, streamid); + } + } +} + // TODO: FIXME: add mpegts conn test // set srt option, recv srt client, get srt client opt and check.