1
0
Fork 0
mirror of https://github.com/ossrs/srs.git synced 2025-02-12 11:21:52 +00:00

Fix #1445, limit the createStream recursive depth. 3.0.70

This commit is contained in:
winlin 2019-12-11 17:56:31 +08:00
parent 41a9f15626
commit 4f298134af
7 changed files with 327 additions and 9 deletions

View file

@ -145,6 +145,7 @@ For previous versions, please read:
## V3 changes
* v3.0, 2019-12-11, Fix [#1445][bug #1445], limit the createStream recursive depth. 3.0.70
* v3.0, 2019-12-11, For [#1042][bug #1042], cover RTMP handshake protocol.
* v3.0, 2019-12-11, Fix [#1229][bug #1229], fix the security risk in logger. 3.0.69
* v3.0, 2019-12-11, For [#1229][bug #1229], fix the security risk in HDS. 3.0.69
@ -1515,6 +1516,7 @@ Winlin
[bug #1501]: https://github.com/ossrs/srs/issues/1501
[bug #1229]: https://github.com/ossrs/srs/issues/1229
[bug #1042]: https://github.com/ossrs/srs/issues/1042
[bug #1445]: https://github.com/ossrs/srs/issues/1445
[bug #xxxxxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxxxxx
[exo #828]: https://github.com/google/ExoPlayer/pull/828

View file

@ -27,7 +27,7 @@
// The version config.
#define VERSION_MAJOR 3
#define VERSION_MINOR 0
#define VERSION_REVISION 69
#define VERSION_REVISION 70
// The macros generated by configure script.
#include <srs_auto_headers.hpp>

View file

@ -177,7 +177,8 @@
#define ERROR_HTTP_HIJACK 2052
#define ERROR_RTMP_MESSAGE_CREATE 2053
#define ERROR_RTMP_PROXY_EXCEED 2054
//
#define ERROR_RTMP_CREATE_STREAM_DEPTH 2055
//
// The system control message,
// It's not an error, but special control logic.
//

View file

@ -200,9 +200,9 @@ string srs_generate_stream_with_query(string host, string vhost, string stream,
// Remove the start & when param is empty.
srs_string_trim_start(query, "&");
// Prefix query with ?.
if (!srs_string_starts_with(query, "?")) {
if (!query.empty() && !srs_string_starts_with(query, "?")) {
url += "?";
}

View file

@ -2538,7 +2538,7 @@ srs_error_t SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type,
SrsAutoFree(SrsPacket, pkt);
if (dynamic_cast<SrsCreateStreamPacket*>(pkt)) {
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name, duration);
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, 3, type, stream_name, duration);
}
if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
return identify_fmle_publish_client(dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);
@ -2909,9 +2909,13 @@ srs_error_t SrsRtmpServer::start_flash_publish(int stream_id)
return err;
}
srs_error_t SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, string& stream_name, srs_utime_t& duration)
srs_error_t SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, int depth, SrsRtmpConnType& type, string& stream_name, srs_utime_t& duration)
{
srs_error_t err = srs_success;
if (depth <= 0) {
return srs_error_new(ERROR_RTMP_CREATE_STREAM_DEPTH, "create stream recursive depth");
}
if (true) {
SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(req->transaction_id, stream_id);
@ -2952,7 +2956,7 @@ srs_error_t SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket*
return identify_flash_publish_client(dynamic_cast<SrsPublishPacket*>(pkt), type, stream_name);
}
if (dynamic_cast<SrsCreateStreamPacket*>(pkt)) {
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name, duration);
return identify_create_stream_client(dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, depth-1, type, stream_name, duration);
}
if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
return identify_haivision_publish_client(dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);

View file

@ -775,7 +775,7 @@ public:
return protocol->expect_message<T>(pmsg, ppacket);
}
private:
virtual srs_error_t identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name, srs_utime_t& duration);
virtual srs_error_t identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, int depth, SrsRtmpConnType& type, std::string& stream_name, srs_utime_t& duration);
virtual srs_error_t identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
virtual srs_error_t identify_haivision_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name);
virtual srs_error_t identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, std::string& stream_name);

View file

@ -1594,12 +1594,323 @@ VOID TEST(ProtoStackTest, ServerCommandMessage)
SrsCommonMessage* msg = NULL;
SrsSetWindowAckSizePacket* pkt = NULL;
HELPER_EXPECT_SUCCESS(p.expect_message(&msg, &pkt));
HELPER_ASSERT_SUCCESS(p.expect_message(&msg, &pkt));
EXPECT_EQ(1024, pkt->ackowledgement_window_size);
srs_freep(msg);
srs_freep(pkt);
}
}
// Response ConnectApp.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
SrsRequest req;
req.objectEncoding = 3.0;
const char* ip = "1.2.3.4";
HELPER_EXPECT_SUCCESS(r.response_connect_app(&req, ip));
if (true) {
MockBufferIO tio;
tio.in_buffer.append(&io.out_buffer);
SrsProtocol p(&tio);
// In order to receive and decode the response,
// we have to send out a ConnectApp request.
if (true) {
SrsConnectAppPacket* pkt = new SrsConnectAppPacket();
HELPER_EXPECT_SUCCESS(p.send_and_free_packet(pkt, 0));
}
SrsCommonMessage* msg = NULL;
SrsConnectAppResPacket* pkt = NULL;
HELPER_ASSERT_SUCCESS(p.expect_message(&msg, &pkt));
SrsAmf0Any* prop = pkt->info->get_property("objectEncoding");
ASSERT_TRUE(prop && prop->is_number());
EXPECT_EQ(3.0, prop->to_number());
prop = pkt->info->get_property("data");
ASSERT_TRUE(prop && prop->is_ecma_array());
SrsAmf0EcmaArray* arr = prop->to_ecma_array();
prop = arr->get_property("srs_server_ip");
ASSERT_TRUE(prop && prop->is_string());
EXPECT_STREQ("1.2.3.4", prop->to_str().c_str());
srs_freep(msg);
srs_freep(pkt);
}
}
// Response ConnectApp rejected.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
const char* desc = "Rejected";
r.response_connect_reject(NULL, desc);
if (true) {
MockBufferIO tio;
tio.in_buffer.append(&io.out_buffer);
SrsProtocol p(&tio);
SrsCommonMessage* msg = NULL;
SrsCallPacket* pkt = NULL;
HELPER_ASSERT_SUCCESS(p.expect_message(&msg, &pkt));
SrsAmf0Any* prop = pkt->arguments;
ASSERT_TRUE(prop && prop->is_object());
prop = prop->to_object()->get_property(StatusDescription);
ASSERT_TRUE(prop && prop->is_string());
EXPECT_STREQ(desc, prop->to_str().c_str());
srs_freep(msg);
srs_freep(pkt);
}
}
// Response OnBWDone
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
HELPER_EXPECT_SUCCESS(r.on_bw_done());
EXPECT_TRUE(io.out_length() > 0);
}
// Set peer chunk size.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
HELPER_EXPECT_SUCCESS(r.set_chunk_size(1024));
if (true) {
MockBufferIO tio;
tio.in_buffer.append(&io.out_buffer);
SrsProtocol p(&tio);
SrsCommonMessage* msg = NULL;
HELPER_EXPECT_SUCCESS(p.recv_message(&msg));
srs_freep(msg);
EXPECT_EQ(1024, p.in_chunk_size);
}
}
}
VOID TEST(ProtoStackTest, ServerRedirect)
{
srs_error_t err;
// Redirect without response.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
SrsRequest req;
req.app = "live";
req.stream = "livestream";
string host = "target.net";
int port = 8888;
bool accepted = false;
HELPER_EXPECT_SUCCESS(r.redirect(&req, host, port, accepted));
if (true) {
MockBufferIO tio;
tio.in_buffer.append(&io.out_buffer);
SrsProtocol p(&tio);
SrsCommonMessage* msg = NULL;
SrsCallPacket* pkt = NULL;
HELPER_ASSERT_SUCCESS(p.expect_message(&msg, &pkt));
SrsAmf0Any* prop = pkt->arguments;
ASSERT_TRUE(prop && prop->is_object());
prop = prop->to_object()->get_property("ex");
ASSERT_TRUE(prop && prop->is_object());
SrsAmf0Object* ex = prop->to_object();
prop = ex->get_property("code");
ASSERT_TRUE(prop && prop->is_number());
EXPECT_EQ(302, prop->to_number());
prop = ex->get_property("redirect");
ASSERT_TRUE(prop && prop->is_string());
EXPECT_STREQ("rtmp://target.net:8888/live/livestream", prop->to_str().c_str());
srs_freep(msg);
srs_freep(pkt);
}
}
// Redirect with response.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
if (true) {
MockBufferIO tio;
SrsProtocol p(&tio);
SrsCallPacket* call = new SrsCallPacket();
call->command_name = "redirected";
call->command_object = SrsAmf0Any::object();
call->arguments = SrsAmf0Any::str("OK");
HELPER_EXPECT_SUCCESS(p.send_and_free_packet(call, 0));
io.in_buffer.append(&tio.out_buffer);
}
SrsRequest req;
req.app = "live";
req.stream = "livestream";
string host = "target.net";
int port = 8888;
bool accepted = false;
HELPER_EXPECT_SUCCESS(r.redirect(&req, host, port, accepted));
EXPECT_TRUE(accepted);
if (true) {
MockBufferIO tio;
tio.in_buffer.append(&io.out_buffer);
SrsProtocol p(&tio);
SrsCommonMessage* msg = NULL;
SrsCallPacket* pkt = NULL;
HELPER_ASSERT_SUCCESS(p.expect_message(&msg, &pkt));
SrsAmf0Any* prop = pkt->arguments;
ASSERT_TRUE(prop && prop->is_object());
prop = prop->to_object()->get_property("ex");
ASSERT_TRUE(prop && prop->is_object());
SrsAmf0Object* ex = prop->to_object();
prop = ex->get_property("code");
ASSERT_TRUE(prop && prop->is_number());
EXPECT_EQ(302, prop->to_number());
prop = ex->get_property("redirect");
ASSERT_TRUE(prop && prop->is_string());
EXPECT_STREQ("rtmp://target.net:8888/live/livestream", prop->to_str().c_str());
srs_freep(msg);
srs_freep(pkt);
}
}
}
VOID TEST(ProtoStackTest, ServerIdentify)
{
srs_error_t err;
// Identify failed.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
string stream_name;
SrsRtmpConnType tp;
srs_utime_t duration = 0;
HELPER_EXPECT_FAILED(r.identify_client(1, tp, stream_name, duration));
}
// Identify by CreateStream, Play.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
if (true) {
MockBufferIO tio;
SrsProtocol p(&tio);
SrsCreateStreamPacket* call = new SrsCreateStreamPacket();
HELPER_EXPECT_SUCCESS(p.send_and_free_packet(call, 0));
SrsPlayPacket* play = new SrsPlayPacket();
play->stream_name = "livestream";
play->duration = 100;
HELPER_EXPECT_SUCCESS(p.send_and_free_packet(play, 0));
io.in_buffer.append(&tio.out_buffer);
}
string stream_name;
SrsRtmpConnType tp;
srs_utime_t duration = 0;
HELPER_EXPECT_SUCCESS(r.identify_client(1, tp, stream_name, duration));
EXPECT_EQ(SrsRtmpConnPlay, tp);
EXPECT_STREQ("livestream", stream_name.c_str());
EXPECT_EQ(100000, duration);
}
// Identify by CreateStream, CreateStream, CreateStream, Play.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
if (true) {
MockBufferIO tio;
SrsProtocol p(&tio);
for (int i = 0; i < 3; i++) {
SrsCreateStreamPacket* call = new SrsCreateStreamPacket();
HELPER_EXPECT_SUCCESS(p.send_and_free_packet(call, 0));
}
SrsPlayPacket* play = new SrsPlayPacket();
play->stream_name = "livestream";
play->duration = 100;
HELPER_EXPECT_SUCCESS(p.send_and_free_packet(play, 0));
io.in_buffer.append(&tio.out_buffer);
}
string stream_name;
SrsRtmpConnType tp;
srs_utime_t duration = 0;
HELPER_EXPECT_SUCCESS(r.identify_client(1, tp, stream_name, duration));
EXPECT_EQ(SrsRtmpConnPlay, tp);
EXPECT_STREQ("livestream", stream_name.c_str());
EXPECT_EQ(100000, duration);
}
// For N*CreateStream and N>3, it should fail.
// Identify by CreateStream, CreateStream, CreateStream, Play.
if (true) {
MockBufferIO io;
SrsRtmpServer r(&io);
if (true) {
MockBufferIO tio;
SrsProtocol p(&tio);
for (int i = 0; i < 4; i++) {
SrsCreateStreamPacket* call = new SrsCreateStreamPacket();
HELPER_EXPECT_SUCCESS(p.send_and_free_packet(call, 0));
}
io.in_buffer.append(&tio.out_buffer);
}
string stream_name;
SrsRtmpConnType tp;
srs_utime_t duration = 0;
HELPER_EXPECT_FAILED(r.identify_client(1, tp, stream_name, duration));
}
}