Added RTMPS listening port support

This commit is contained in:
Thulinma 2024-04-08 13:11:59 +02:00
parent 8fd4f29b06
commit 78a30e212e
4 changed files with 156 additions and 0 deletions

View file

@ -807,6 +807,51 @@ static void my_debug(void *ctx, int level, const char *file, int line, const cha
fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str);
fflush((FILE *)ctx);
}
/// Takes a just-accepted socket and SSL-ifies it.
bool Socket::Connection::sslAccept(mbedtls_ssl_config * sslConf, mbedtls_ctr_drbg_context * dbgCtx){
int ret;
server_fd = new mbedtls_net_context;
mbedtls_net_init(server_fd);
server_fd->fd = getSocket();
ssl = new mbedtls_ssl_context;
mbedtls_ssl_init(ssl);
if ((ret = mbedtls_ctr_drbg_reseed(dbgCtx, (const unsigned char *)"child", 5)) != 0){
FAIL_MSG("Could not reseed");
close();
return false;
}
// Set up the SSL connection
if ((ret = mbedtls_ssl_setup(ssl, sslConf)) != 0){
FAIL_MSG("Could not set up SSL connection");
close();
return false;
}
// Inform mbedtls how we'd like to use the connection (uses default bio handlers)
// We tell it to use non-blocking IO here
mbedtls_net_set_nonblock(server_fd);
Blocking = false;
mbedtls_ssl_set_bio(ssl, server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
// do the SSL handshake
while ((ret = mbedtls_ssl_handshake(ssl)) != 0){
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
char error_buf[200];
mbedtls_strerror(ret, error_buf, 200);
WARN_MSG("Could not handshake, SSL error: %s (%d)", error_buf, ret);
close();
return false;
}else{
Util::sleep(20);
}
}
sslConnected = true;
HIGH_MSG("Started SSL connection handler");
return true;
}
#endif
/// Create a new TCP Socket. This socket will (try to) connect to the given host/port right away.

View file

@ -144,6 +144,9 @@ namespace Socket{
void open(std::string hostname, int port, bool nonblock, bool with_ssl = false); // Open TCP connection.
void open(std::string adres, bool nonblock = false); // Open Unix connection.
void open(int write, int read); // Open from two existing file descriptors.
#ifdef SSL
bool sslAccept(mbedtls_ssl_config * sslConf, mbedtls_ctr_drbg_context * dbgCtx);
#endif
void close(); ///< Close connection.
void drop(); ///< Close connection without shutdown.
void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).

View file

@ -21,7 +21,19 @@ const char * trackType(char ID){
namespace Mist{
#ifdef SSL
bool sslEnabled = false;
mbedtls_entropy_context OutRTMP::entropy;
mbedtls_ctr_drbg_context OutRTMP::ctr_drbg;
mbedtls_ssl_config OutRTMP::sslConf;
mbedtls_x509_crt OutRTMP::srvcert;
mbedtls_pk_context OutRTMP::pkey;
#endif
OutRTMP::OutRTMP(Socket::Connection &conn) : Output(conn){
#ifdef SSL
if (sslEnabled){myConn.sslAccept(&sslConf, &ctr_drbg);}
#endif
lastSilence = 0;
hasSilence = false;
lastAudioInserted = 0;
@ -90,6 +102,74 @@ namespace Mist{
}
}
#ifdef SSL
/// Listens for HTTPS requests, accepting them and connecting them to a HTTP socket
void OutRTMP::listener(Util::Config &conf, int (*callback)(Socket::Connection &S)){
// No cert or key? Non-SSL mode.
if (config->getOption("cert", true).size() < 2 || config->getOption("key", true).size() < 2){
INFO_MSG("No cert or key set, regular RTMP mode");
Output::listener(conf, callback);
return;
}
INFO_MSG("Cert and key set, RTMPS mode");
sslEnabled = true;
// Declare and set up all required mbedtls structures
int ret;
mbedtls_ssl_config_init(&sslConf);
mbedtls_entropy_init(&entropy);
mbedtls_pk_init(&pkey);
mbedtls_x509_crt_init(&srvcert);
mbedtls_ctr_drbg_init(&ctr_drbg);
// seed the rng
if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const unsigned char *)APPNAME, strlen(APPNAME))) != 0){
FAIL_MSG("Could not seed the random number generator!");
}
// Read certificate chain(s) from cmdline option(s)
JSON::Value certs = config->getOption("cert", true);
jsonForEach(certs, it){
if (it->asStringRef().size()){// Ignore empty entries (default is empty)
ret = mbedtls_x509_crt_parse_file(&srvcert, it->asStringRef().c_str());
if (ret != 0){
WARN_MSG("Could not load any certificates from file: %s", it->asStringRef().c_str());
}
}
}
// Read key from cmdline option
ret = mbedtls_pk_parse_keyfile(&pkey, config->getString("key").c_str(), 0);
if (ret != 0){
FAIL_MSG("Could not load any keys from file: %s", config->getString("key").c_str());
return;
}
if ((ret = mbedtls_ssl_config_defaults(&sslConf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0){
FAIL_MSG("SSL config defaults failed");
return;
}
mbedtls_ssl_conf_rng(&sslConf, mbedtls_ctr_drbg_random, &ctr_drbg);
mbedtls_ssl_conf_ca_chain(&sslConf, srvcert.next, NULL);
if ((ret = mbedtls_ssl_conf_own_cert(&sslConf, &srvcert, &pkey)) != 0){
FAIL_MSG("SSL config own certificate failed");
return;
}
Output::listener(conf, callback);
// Free all the mbedtls structures
mbedtls_x509_crt_free(&srvcert);
mbedtls_pk_free(&pkey);
mbedtls_ssl_config_free(&sslConf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
}
#endif
void OutRTMP::startPushOut(const char *args){
myConn.close();
@ -277,6 +357,22 @@ namespace Mist{
capa["optional"]["maxkbps"]["short"] = "K";
capa["optional"]["maxkbps"]["default"] = 0;
capa["optional"]["maxkbps"]["type"] = "uint";
#ifdef SSL
capa["optional"]["cert"]["name"] = "Certificate";
capa["optional"]["cert"]["help"] = "(Root) certificate(s) file(s) to append to chain";
capa["optional"]["cert"]["option"] = "--cert";
capa["optional"]["cert"]["short"] = "C";
capa["optional"]["cert"]["default"] = "";
capa["optional"]["cert"]["type"] = "str";
capa["optional"]["key"]["name"] = "Key";
capa["optional"]["key"]["help"] = "Private key for SSL";
capa["optional"]["key"]["option"] = "--key";
capa["optional"]["key"]["short"] = "k";
capa["optional"]["key"]["default"] = "";
capa["optional"]["key"]["type"] = "str";
#endif
cfg->addConnectorOptions(1935, capa);
config = cfg;
config->addStandardPushCapabilities(capa);

View file

@ -19,6 +19,9 @@ namespace Mist{
static bool listenMode();
void requestHandler();
bool onFinish();
#ifdef SSL
static void listener(Util::Config &conf, int (*callback)(Socket::Connection &S));
#endif
protected:
std::string streamOut; ///< When pushing out, the output stream name
@ -52,6 +55,15 @@ namespace Mist{
void sendLoopedAudio(uint64_t untilTimestamp);
// Gets the next ADTS frame in AAC file. Loops if EOF reached
void calcNextFrameInfo();
#ifdef SSL
// TLS-related
static mbedtls_entropy_context entropy;
static mbedtls_ctr_drbg_context ctr_drbg;
static mbedtls_ssl_config sslConf;
static mbedtls_x509_crt srvcert;
static mbedtls_pk_context pkey;
#endif
};
}// namespace Mist