RTC: Support config the DTLS role and version

pull/1831/head
winlin 5 years ago
parent a6ade57ce5
commit 94ebcf6306

@ -495,6 +495,12 @@ vhost rtc.vhost.srs.com {
# If off, we will regenerate the sequence number for RTP packet.
# default: off
keep_sequence off;
# The role of dtls when peer is actpass: passive or active
# default: passive
dtls_role passive;
# The version of dtls, support dtls1.0, dtls1.2, and auto
# default: auto
dtls_version auto;
}
# whether enable min delay mode for vhost.
# default: on, for RTC.

@ -3935,7 +3935,7 @@ srs_error_t SrsConfig::check_normal_config()
for (int j = 0; j < (int)conf->directives.size(); j++) {
string m = conf->at(j)->name;
if (m != "enabled" && m != "bframe" && m != "aac" && m != "stun_timeout" && m != "stun_strict_check"
&& m != "keep_sequence") {
&& m != "keep_sequence" && m != "dtls_role" && m != "dtls_version") {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal vhost.rtc.%s of %s", m.c_str(), vhost->arg0().c_str());
}
}
@ -5038,6 +5038,42 @@ bool SrsConfig::get_rtc_keep_sequence(string vhost)
return SRS_CONF_PERFER_FALSE(conf->arg0());
}
std::string SrsConfig::get_rtc_dtls_role(string vhost)
{
static std::string DEFAULT = "passive";
SrsConfDirective* conf = get_rtc(vhost);
if (!conf) {
return DEFAULT;
}
conf = conf->get("dtls_role");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return conf->arg0();
}
std::string SrsConfig::get_rtc_dtls_version(string vhost)
{
static std::string DEFAULT = "auto";
SrsConfDirective* conf = get_rtc(vhost);
if (!conf) {
return DEFAULT;
}
conf = conf->get("dtls_version");
if (!conf || conf->arg0().empty()) {
return DEFAULT;
}
return conf->arg0();
}
bool SrsConfig::get_rtc_nack_enabled(string vhost)
{
static bool DEFAULT = true;
@ -5078,6 +5114,7 @@ bool SrsConfig::get_rtc_twcc_enabled(string vhost)
}
return SRS_CONF_PERFER_TRUE(conf->arg0());
}
SrsConfDirective* SrsConfig::get_vhost(string vhost, bool try_default_vhost)
{
srs_assert(root);

@ -547,6 +547,8 @@ public:
bool get_rtc_keep_sequence(std::string vhost);
bool get_rtc_nack_enabled(std::string vhost);
bool get_rtc_twcc_enabled(std::string vhost);
std::string get_rtc_dtls_role(std::string vhost);
std::string get_rtc_dtls_version(std::string vhost);
// vhost specified section
public:

@ -169,6 +169,11 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe
}
SrsSdp local_sdp;
// Config for SDP and session.
local_sdp.session_config_.dtls_role = _srs_config->get_rtc_dtls_role(request.vhost);
local_sdp.session_config_.dtls_version = _srs_config->get_rtc_dtls_version(request.vhost);
if ((err = exchange_sdp(&request, remote_sdp, local_sdp)) != srs_success) {
return srs_error_wrap(err, "remote sdp have error or unsupport attributes");
}
@ -369,7 +374,7 @@ srs_error_t SrsGoApiRtcPlay::exchange_sdp(SrsRequest* req, const SrsSdp& remote_
} else if (remote_media_desc.session_info_.setup_ == "passive") {
local_media_desc.session_info_.setup_ = "active";
} else if (remote_media_desc.session_info_.setup_ == "actpass") {
local_media_desc.session_info_.setup_ = "passive";
local_media_desc.session_info_.setup_ = local_sdp.session_config_.dtls_role;
} else {
// @see: https://tools.ietf.org/html/rfc4145#section-4.1
// The default value of the setup attribute in an offer/answer exchange
@ -527,6 +532,11 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt
}
SrsSdp local_sdp;
// Config for SDP and session.
local_sdp.session_config_.dtls_role = _srs_config->get_rtc_dtls_role(request.vhost);
local_sdp.session_config_.dtls_version = _srs_config->get_rtc_dtls_version(request.vhost);
if ((err = exchange_sdp(&request, remote_sdp, local_sdp)) != srs_success) {
return srs_error_wrap(err, "remote sdp have error or unsupport attributes");
}
@ -746,7 +756,7 @@ srs_error_t SrsGoApiRtcPublish::exchange_sdp(SrsRequest* req, const SrsSdp& remo
} else if (remote_media_desc.session_info_.setup_ == "passive") {
local_media_desc.session_info_.setup_ = "active";
} else if (remote_media_desc.session_info_.setup_ == "actpass") {
local_media_desc.session_info_.setup_ = "passive";
local_media_desc.session_info_.setup_ = local_sdp.session_config_.dtls_role;
} else {
// @see: https://tools.ietf.org/html/rfc4145#section-4.1
// The default value of the setup attribute in an offer/answer exchange

@ -130,14 +130,14 @@ SrsSecurityTransport::~SrsSecurityTransport()
}
}
srs_error_t SrsSecurityTransport::initialize(SrsRequest* r)
srs_error_t SrsSecurityTransport::initialize(SrsSessionConfig* cfg)
{
return dtls_->initialize(r);
return dtls_->initialize(cfg->dtls_role, cfg->dtls_version);
}
srs_error_t SrsSecurityTransport::do_handshake()
srs_error_t SrsSecurityTransport::start_active_handshake()
{
return dtls_->do_handshake();
return dtls_->start_active_handshake();
}
srs_error_t SrsSecurityTransport::write_dtls_data(void* data, int size)
@ -1862,7 +1862,8 @@ srs_error_t SrsRtcSession::initialize(SrsRtcSource* source, SrsRequest* r, bool
is_publisher_ = is_publisher;
source_ = source;
if ((err = transport_->initialize(req)) != srs_success) {
SrsSessionConfig* cfg = &local_sdp.session_config_;
if ((err = transport_->initialize(cfg)) != srs_success) {
return srs_error_wrap(err, "init");
}
@ -1872,7 +1873,8 @@ srs_error_t SrsRtcSession::initialize(SrsRtcSource* source, SrsRequest* r, bool
blackhole = _srs_config->get_rtc_server_black_hole();
srs_trace("RTC init session, timeout=%dms, blackhole=%d", srsu2msi(sessionStunTimeout), blackhole);
srs_trace("RTC init session, DTLS(role=%s, version=%s), timeout=%dms, blackhole=%d",
cfg->dtls_role.c_str(), cfg->dtls_version.c_str(), srsu2msi(sessionStunTimeout), blackhole);
if (blackhole) {
string blackhole_ep = _srs_config->get_rtc_server_black_hole_addr();
@ -2150,6 +2152,10 @@ srs_error_t SrsRtcSession::on_binding_request(SrsStunPacket* r)
state_ = DOING_DTLS_HANDSHAKE;
srs_trace("rtc session=%s, STUN done, waitting DTLS handshake.", id().c_str());
if((err = transport_->start_active_handshake()) != srs_success) {
return srs_error_wrap(err, "fail to dtls handshake");
}
}
if (blackhole && blackhole_addr && blackhole_stfd) {

@ -117,9 +117,9 @@ public:
SrsSecurityTransport(SrsRtcSession* s);
virtual ~SrsSecurityTransport();
srs_error_t initialize(SrsRequest* r);
srs_error_t do_handshake();
srs_error_t initialize(SrsSessionConfig* cfg);
// When play role of dtls client, it send handshake.
srs_error_t start_active_handshake();
srs_error_t on_dtls(char* data, int nb_data);
public:
// Encrypt the input plaintext to output cipher with nb_cipher bytes.
@ -377,6 +377,7 @@ public:
void switch_to_context();
std::string context_id();
public:
// Before initialize, user must set the local SDP, which is used to inititlize DTLS.
srs_error_t initialize(SrsRtcSource* source, SrsRequest* r, bool is_publisher, std::string username, std::string context_id);
// The peer address may change, we can identify that by STUN messages.
srs_error_t on_stun(SrsUdpMuxSocket* skt, SrsStunPacket* r);

@ -31,6 +31,7 @@ using namespace std;
#include <srs_kernel_error.hpp>
#include <srs_app_config.hpp>
#include <srs_core_autofree.hpp>
#include <srs_rtmp_stack.hpp>
#include <srtp2/srtp.h>
#include <openssl/ssl.h>
@ -244,6 +245,9 @@ SrsDtls::SrsDtls(ISrsDtlsCallback* cb)
{
callback = cb;
handshake_done = false;
role_ = SrsDtlsRoleServer;
version_ = SrsDtlsVersionAuto;
}
SrsDtls::~SrsDtls()
@ -266,9 +270,14 @@ SSL_CTX* SrsDtls::build_dtls_ctx()
#if OPENSSL_VERSION_NUMBER < 0x10002000L // v1.0.2
dtls_ctx = SSL_CTX_new(DTLSv1_method());
#else
dtls_ctx = SSL_CTX_new(DTLS_method());
//dtls_ctx = SSL_CTX_new(DTLSv1_method());
//dtls_ctx = SSL_CTX_new(DTLSv1_2_method());
if (version_ == SrsDtlsVersion1_0) {
dtls_ctx = SSL_CTX_new(DTLSv1_method());
} else if (version_ == SrsDtlsVersion1_2) {
dtls_ctx = SSL_CTX_new(DTLSv1_2_method());
} else {
// SrsDtlsVersionAuto, use version-flexible DTLS methods
dtls_ctx = SSL_CTX_new(DTLS_method());
}
#endif
if (_srs_rtc_dtls_certificate->is_ecdsa()) { // By ECDSA, https://stackoverflow.com/a/6006898
@ -323,18 +332,38 @@ SSL_CTX* SrsDtls::build_dtls_ctx()
return dtls_ctx;
}
srs_error_t SrsDtls::initialize(SrsRequest* r)
srs_error_t SrsDtls::initialize(std::string role, std::string version)
{
srs_error_t err = srs_success;
role_ = SrsDtlsRoleServer;
if (role == "active") {
role_ = SrsDtlsRoleClient;
}
if (version == "dtls1.0") {
version_ = SrsDtlsVersion1_0;
} else if (version == "dtls1.2") {
version_ = SrsDtlsVersion1_2;
} else {
version_ = SrsDtlsVersionAuto;
}
dtls_ctx = build_dtls_ctx();
// TODO: FIXME: Leak for SSL_CTX* return by build_dtls_ctx.
if ((dtls = SSL_new(dtls_ctx)) == NULL) {
return srs_error_new(ERROR_OpenSslCreateSSL, "SSL_new dtls");
}
// Dtls setup passive, as server role.
SSL_set_accept_state(dtls);
if (role == "active") {
// Dtls setup active, as client role.
SSL_set_connect_state(dtls);
SSL_set_max_send_fragment(dtls, 1500);
} else {
// Dtls setup passive, as server role.
SSL_set_accept_state(dtls);
}
if ((bio_in = BIO_new(BIO_s_mem())) == NULL) {
return srs_error_new(ERROR_OpenSslBIONew, "BIO_new in");
@ -350,7 +379,7 @@ srs_error_t SrsDtls::initialize(SrsRequest* r)
return err;
}
srs_error_t SrsDtls::handshake()
srs_error_t SrsDtls::do_handshake()
{
srs_error_t err = srs_success;
@ -406,7 +435,7 @@ srs_error_t SrsDtls::on_dtls(char* data, int nb_data)
}
if (!handshake_done) {
err = handshake();
err = do_handshake();
} else {
while (BIO_ctrl_pending(bio_in) > 0) {
char dtls_read_buf[8092];
@ -423,9 +452,13 @@ srs_error_t SrsDtls::on_dtls(char* data, int nb_data)
return err;
}
srs_error_t SrsDtls::do_handshake()
srs_error_t SrsDtls::start_active_handshake()
{
return handshake();
if (role_ == SrsDtlsRoleClient) {
return do_handshake();
}
return srs_success;
}
const int SRTP_MASTER_KEY_KEY_LEN = 16;
@ -450,8 +483,13 @@ srs_error_t SrsDtls::get_srtp_key(std::string& recv_key, std::string& send_key)
offset += SRTP_MASTER_KEY_SALT_LEN;
std::string server_master_salt(reinterpret_cast<char*>(material + offset), SRTP_MASTER_KEY_SALT_LEN);
recv_key = client_master_key + client_master_salt;
send_key = server_master_key + server_master_salt;
if (role_ == SrsDtlsRoleClient) {
recv_key = server_master_key + server_master_salt;
send_key = client_master_key + client_master_salt;
} else {
recv_key = client_master_key + client_master_salt;
send_key = server_master_key + server_master_salt;
}
return err;
}

@ -62,6 +62,22 @@ public:
// @global config object.
extern SrsDtlsCertificate* _srs_rtc_dtls_certificate;
// @remark: play the role of DTLS_CLIENT, will send handshake
// packet first.
enum SrsDtlsRole {
SrsDtlsRoleClient,
SrsDtlsRoleServer
};
// @remark: DTLS_10 will all be ignored, and only DTLS1_2 will be accepted,
// DTLS_10 Support will be completely removed in M84 or later.
// TODO(https://bugs.webrtc.org/10261).
enum SrsDtlsVersion {
SrsDtlsVersionAuto = -1,
SrsDtlsVersion1_0,
SrsDtlsVersion1_2
};
class ISrsDtlsCallback
{
public:
@ -85,19 +101,26 @@ private:
BIO* bio_out;
ISrsDtlsCallback* callback;
bool handshake_done;
// @remark: dtls_role_ default value is DTLS_SERVER.
SrsDtlsRole role_;
// @remark: dtls_version_ default value is SrsDtlsVersionAuto.
SrsDtlsVersion version_;
public:
SrsDtls(ISrsDtlsCallback* callback);
virtual ~SrsDtls();
public:
srs_error_t initialize(SrsRequest* r);
srs_error_t do_handshake();
srs_error_t initialize(std::string role, std::string version);
// As DTLS client, start handshake actively, send the ClientHello packet.
srs_error_t start_active_handshake();
// When got DTLS packet, may handshake packets or application data.
// @remark When we are passive(DTLS server), we start handshake when got DTLS packet.
srs_error_t on_dtls(char* data, int nb_data);
srs_error_t get_srtp_key(std::string& recv_key, std::string& send_key);
private:
SSL_CTX* build_dtls_ctx();
srs_error_t handshake();
srs_error_t do_handshake();
};
class SrsSRTP

@ -34,6 +34,13 @@
#include <map>
const std::string kTWCCExt = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01";
struct SrsSessionConfig
{
public:
std::string dtls_role;
std::string dtls_version;
};
class SrsSessionInfo
{
public:
@ -212,6 +219,7 @@ public:
int64_t end_time_;
SrsSessionInfo session_info_;
SrsSessionConfig session_config_;
std::vector<std::string> groups_;
std::string group_policy_;

@ -323,16 +323,6 @@ srs_error_t SrsRtcServer::create_session(
}
}
std::string cid = _srs_context->get_id();
SrsRtcSession* session = new SrsRtcSession(this);
if ((err = session->initialize(source, req, publish, username, cid)) != srs_success) {
srs_freep(session);
return srs_error_wrap(err, "init");
}
map_username_session.insert(make_pair(username, session));
*psession = session;
local_sdp.set_ice_ufrag(local_ufrag);
local_sdp.set_ice_pwd(local_pwd);
local_sdp.set_fingerprint_algo("sha-256");
@ -348,10 +338,22 @@ srs_error_t SrsRtcServer::create_session(
}
}
SrsRtcSession* session = new SrsRtcSession(this);
session->set_remote_sdp(remote_sdp);
// We must setup the local SDP, then initialize the session object.
session->set_local_sdp(local_sdp);
session->set_state(WAITING_STUN);
std::string cid = _srs_context->get_id();
// Before session initialize, we must setup the local SDP.
if ((err = session->initialize(source, req, publish, username, cid)) != srs_success) {
srs_freep(session);
return srs_error_wrap(err, "init");
}
map_username_session.insert(make_pair(username, session));
*psession = session;
return err;
}

Loading…
Cancel
Save