diff -Naur crtmpserver-1.0~dfsg/applications/flvplayback/include/rtmpappprotocolhandler.h crtmpserver-1.0_mod/applications/flvplayback/include/rtmpappprotocolhandler.h --- crtmpserver-1.0~dfsg/applications/flvplayback/include/rtmpappprotocolhandler.h 2012-03-18 13:43:18.000000000 +0400 +++ crtmpserver-1.0_mod/applications/flvplayback/include/rtmpappprotocolhandler.h 2017-10-11 21:13:27.089849662 +0300 @@ -34,6 +34,10 @@ virtual bool ProcessInvokeGeneric(BaseRTMPProtocol *pFrom, Variant &request); + // to check schema and swf name + virtual bool ProcessInvokeConnect(BaseRTMPProtocol *pFrom, + Variant &request); + virtual bool ValidateRequest(Variant &request); private: bool ProcessGetAvailableFlvs(BaseRTMPProtocol *pFrom, Variant &request); bool ProcessInsertMetadata(BaseRTMPProtocol *pFrom, Variant &request); diff -Naur crtmpserver-1.0~dfsg/applications/flvplayback/src/rtmpappprotocolhandler.cpp crtmpserver-1.0_mod/applications/flvplayback/src/rtmpappprotocolhandler.cpp --- crtmpserver-1.0~dfsg/applications/flvplayback/src/rtmpappprotocolhandler.cpp 2012-03-18 13:43:18.000000000 +0400 +++ crtmpserver-1.0_mod/applications/flvplayback/src/rtmpappprotocolhandler.cpp 2017-10-11 23:45:36.529694557 +0300 @@ -19,6 +19,7 @@ #ifdef HAS_PROTOCOL_RTMP +#include "common.h" #include "rtmpappprotocolhandler.h" #include "protocols/rtmp/basertmpprotocol.h" #include "protocols/rtmp/messagefactories/messagefactories.h" @@ -27,6 +28,95 @@ #include "streaming/streamstypes.h" using namespace app_flvplayback; + +//=== +// Moiseenko Andrey's security checks for local and remote IPs +static unsigned GetMaskByNum(int Num) +{ + if (!Num) + { + return 0; + } + return ~ ((1 << (32 - Num)) - 1); +} +static bool CheckIp(string ip, const char * fn) +{ + const char * pip = ip.c_str(); + unsigned xx[4] = { 0, 0, 0, 0 }; + sscanf(pip, "%d.%d.%d.%d", &xx[0], &xx[1], &xx[2], &xx[3]); + unsigned Ip = (((((xx[0] << 8) | xx[1]) << 8) | xx[2]) << 8) | xx[3]; + fprintf(stderr, "%d.%d.%d.%d %08x\n", xx[0], xx[1], xx[2], xx[3], Ip); + FILE * f = fopen(fn, "rb"); + if (f) + { + char Buffer[256]; + while(fgets(Buffer, (int)sizeof(Buffer) - 1, f)) + { + int l = strlen(Buffer); + while(l > 0 && (Buffer[l - 1] == '\r' || Buffer[l - 1] == '\n')) + { + Buffer[--l] = 0; + } + if (Buffer[0] == ';' || Buffer[0] == '#' || Buffer[0] == 0) + { + continue; + } + pip = Buffer; + unsigned cmp_ip = 0, x; + for (int i = 0; i < 4; i++) + { + x = 0; + sscanf(pip, "%d", &x); + fprintf(stderr, "%d.\n", x); + cmp_ip = (cmp_ip << 8) | x; + while(*pip >= '0' && *pip <= '9') pip++; + if (*pip == '.' || *pip == '/') pip++; + } + x = 32; + sscanf(pip, "%d", &x); + fprintf(stderr, "/%d\n", x); + x = GetMaskByNum((int)x); + fprintf(stderr, "%08x&%08x (%08x) == %08x&%08x (%08x) ?\n", cmp_ip, x, (cmp_ip & x), Ip, x, (Ip & x)); + if ((cmp_ip & x) == (Ip & x)) + { + fclose(f); + return true; + } + } + fclose(f); + } + return false; +} +static bool CheckUrl(string url, const char * fn) +{ + const char * purl = url.c_str(); + FILE * f = fopen(fn, "rb"); + if (f) + { + char Buffer[512]; + while(fgets(Buffer, (int)sizeof(Buffer) - 1, f)) + { + int l = strlen(Buffer); + while(l > 0 && (Buffer[l - 1] == '\r' || Buffer[l - 1] == '\n')) + { + Buffer[--l] = 0; + } + if (Buffer[0] == ';' || Buffer[0] == '#' || Buffer[0] == 0) + { + continue; + } + if (!strcmp(purl, Buffer) || !strcmp(Buffer, "*")) + { + fclose(f); + return true; + } + } + fclose(f); + } + return false; +} +//=== + RTMPAppProtocolHandler::RTMPAppProtocolHandler(Variant &configuration) : BaseRTMPAppProtocolHandler(configuration) { @@ -48,6 +138,199 @@ } } +// adding functions for filter validations +bool RTMPAppProtocolHandler::ProcessInvokeConnect(BaseRTMPProtocol *pFrom, Variant &request) { + + // check white remote ip + if (pFrom->GetType() == PT_INBOUND_RTMP) + { + //INFO("// pFrom->GetType() == PT_INBOUND_RTMP"); + IOHandler *pIOHandler = pFrom->GetIOHandler(); + /*if (pIOHandler) + { + INFO("// pIOHandler != NULL, ->GetType() = %d (%d?, %d?)", (int)pIOHandler->GetType(), (int)IOHT_TCP_CARRIER, (int)IOHT_UDP_CARRIER); + } + else + { + INFO("// pIOHandler == NULL"); + }*/ + if (pIOHandler && (pIOHandler->GetType() == IOHT_TCP_CARRIER || pIOHandler->GetType() == IOHT_UDP_CARRIER)) + { + int fd = pIOHandler->GetInboundFd(); + + struct sockaddr_in s; + socklen_t len; + memset(&s, 0, sizeof(s)); + len = sizeof(s); + if (getpeername(fd, (struct sockaddr *)&s, &len)) + { + //Error("getpeername()"); + } + else + { + unsigned long RemoteIp = (unsigned long)(s.sin_addr.s_addr); + int RemotePort = ntohs(s.sin_port); + unsigned char * pucIp = (unsigned char *)&RemoteIp; + string strIp = format("%hhu.%hhu.%hhu.%hhu", + (uint8_t) pucIp[0], + (uint8_t) pucIp[1], + (uint8_t) pucIp[2], + (uint8_t) pucIp[3]); + RemoteIp = ntohl(RemoteIp); + //if (RemoteIp == 0xc2b11453 /*194.177.20.83*/) + //if (strIp == "194.177.20.83") + // Moiseenko Andrey's security checks for remote IPs + if (CheckIp(strIp, "/etc/crtmpserver/remote_ip.txt")) + { + INFO("// PT_INBOUND_RTMP is from white ip: remote IP:Port=%s:%d", STR(strIp), RemotePort); + return BaseRTMPAppProtocolHandler::ProcessInvokeConnect(pFrom, request); + } + else + { + INFO("// PT_INBOUND_RTMP is from not white remote IP:Port=%s:%d, check next...", STR(strIp), RemotePort); + } + } + } + } + + //1. Get the request params + if (M_INVOKE_PARAMS(request).MapSize() < 1) { + FATAL("Invalid request"); + return false; + } + Variant connectParameters = M_INVOKE_PARAM(request, 0); + + if (_authMethod != "") { + //we have adobe auth enabled + string flashVer = connectParameters[RM_INVOKE_PARAMS_CONNECT_FLASHVER]; + if (!_configuration[CONF_APPLICATION_AUTH][CONF_APPLICATION_AUTH_ENCODER_AGENTS].HasKey(flashVer)) { + //this connection will not be authenticated, so we will try to validate the URI's + if (!ValidateRequest(request)) { + FATAL("Invalid connect request"); + return false; + } + } + } else { + //we don't have adobe auth enabled at all. We will try to validate the URI's + if (!ValidateRequest(request)) { + FATAL("Invalid connect request"); + return false; + } + } + + return BaseRTMPAppProtocolHandler::ProcessInvokeConnect(pFrom, request); +} + +bool RTMPAppProtocolHandler::ValidateRequest(Variant &request) { + //TODO: Validate the various URI's inside the request here + //0. Dump the request on console, just to see its structure + FINEST("Initial request:\n%s", STR(request.ToString())); + + //1. Get the connect params from the connect invoke + Variant connectParams = M_INVOKE_PARAM(request, 0); + + //2. This should be a key-value map + if (connectParams != V_MAP) { + FATAL("Incorrect invoke params:\n%s", STR(request.ToString())); + return false; + } + + //3. Let's extract few values. Make sure we extract them using non-case-sensitive keys + Variant tcUrl = connectParams.GetValue(RM_INVOKE_PARAMS_CONNECT_TCURL, false); + + //If you are sure about case-sensitive settings, you can extract it directly like this + Variant swfUrl = connectParams[RM_INVOKE_PARAMS_CONNECT_SWFURL]; + //Variant tcUrl = connectParams[RM_INVOKE_PARAMS_CONNECT_TCURL]; + Variant pageUrl = connectParams[RM_INVOKE_PARAMS_CONNECT_PAGEURL]; + + + //4. Do some validation on them. + + if (pageUrl != V_STRING) { + FATAL("Incorrect " RM_INVOKE_PARAMS_CONNECT_PAGEURL ": %s", STR(request.ToString())); + return false; + //return true; + } + + if (tcUrl != V_STRING) { + FATAL("Incorrect " RM_INVOKE_PARAMS_CONNECT_TCURL ":\n%s", STR(request.ToString())); + return false; + //return true; + } + + string rawURI; + URI uri; + if (!URI::FromString(pageUrl, true, uri)) { + FATAL("Unable to parse the uri %s", STR(rawURI)); + return false; + } + + // as proto we are going to validate rtmp/rtmpe + // added if/elseif/else and INFO like Andriy suggested + INFO("Connect schema is %s", STR((string) tcUrl)); + if (CheckUrl((string)tcUrl, "/etc/crtmpserver/tc_url.txt")) + { + } + else + { + FATAL("Incorrect " RM_INVOKE_PARAMS_CONNECT_TCURL ": %s", STR(request.ToString())); + return false; + } + /* + if (((string) tcUrl) != "rtmp://media.bfy.ro/livestream") { + INFO("Connect schema is %s", STR((string) tcUrl)); + } else if (((string) tcUrl) != "rtmpe://media.bfy.ro/livestream") { + INFO("Connect schema is %s", STR((string) tcUrl)); + } + else { + FATAL("Incorrect " RM_INVOKE_PARAMS_CONNECT_TCURL ": %s", STR(request.ToString())); + return false; + } + */ + // we use our static flowplayer which is always on the same address + // added if/elseif/else and INFO like Andriy suggested + INFO("Flash player address is %s", STR((string) swfUrl)); + if (CheckUrl((string)swfUrl, "/etc/crtmpserver/swf_url.txt")) + { + } + else + { + FATAL("Incorrect " RM_INVOKE_PARAMS_CONNECT_SWFURL ": %s", STR(request.ToString())); + return false; + } + /* + if (((string) swfUrl) != "http://www.a-queens.ro/flowplayer/flowplayer-3.2.5.swf") { + INFO("Flash player address is %s", STR((string) swfUrl)); + } else if (((string) swfUrl) != "http://www.a-queens.ro/player.swf") { + INFO("Flash player address is %s", STR((string) swfUrl)); + } + else { + FATAL("Incorrect " RM_INVOKE_PARAMS_CONNECT_SWFURL ": %s", STR(request.ToString())); + return false; + } + */ + + // ip which resolve our calling webpage(s)/website(s) + // added if/elseif/else and INFO like Andriy suggested + string _ip = uri.ip(); + // Moiseenko Andrey's security checks for local IPs + if (CheckIp(_ip, "/etc/crtmpserver/local_ip.txt")) + //if (_ip == "194.177.20.83") + { + INFO("Stream calling webpage is %s", STR((string) pageUrl)); + INFO("stream Calling webpage IP is %s", STR(_ip)); + } + else + { + INFO("!! Stream calling webpage is %s", STR((string) pageUrl)); + FATAL("!! stream Calling webpage IP is %s", STR(_ip)); + //FATAL("Incorrect " RM_INVOKE_PARAMS_CONNECT_PAGEURL ": %s", STR(request.ToString())); + return false; + } + + return true; +} + bool RTMPAppProtocolHandler::ProcessGetAvailableFlvs(BaseRTMPProtocol *pFrom, Variant &request) { Variant parameters; parameters.PushToArray(Variant()); diff -Naur crtmpserver-1.0~dfsg/debian/crtmpserver.install crtmpserver-1.0_mod/debian/crtmpserver.install --- crtmpserver-1.0~dfsg/debian/crtmpserver.install 2013-06-22 19:09:08.000000000 +0400 +++ crtmpserver-1.0_mod/debian/crtmpserver.install 2017-10-11 21:41:11.611077568 +0300 @@ -1,4 +1,8 @@ debian/crtmpserver-scripts/crtmpserver.lua etc/crtmpserver debian/crtmpserver-scripts/log_appenders.lua etc/crtmpserver +debian/crtmpserver-scripts/local_ip.txt etc/crtmpserver +debian/crtmpserver-scripts/remote_ip.txt etc/crtmpserver +debian/crtmpserver-scripts/tc_url.txt etc/crtmpserver +debian/crtmpserver-scripts/swf_url.txt etc/crtmpserver usr/sbin/crtmpserver diff -Naur crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/local_ip.txt crtmpserver-1.0_mod/debian/crtmpserver-scripts/local_ip.txt --- crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/local_ip.txt 1970-01-01 03:00:00.000000000 +0300 +++ crtmpserver-1.0_mod/debian/crtmpserver-scripts/local_ip.txt 2017-10-11 21:58:39.709222872 +0300 @@ -0,0 +1,5 @@ +; /etc/local_ip.txt: just local server's IP enabled +; Sample: +127.0.0.1 +0.0.0.0/0 +;10.7.52.97 diff -Naur crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/remote_ip.txt crtmpserver-1.0_mod/debian/crtmpserver-scripts/remote_ip.txt --- crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/remote_ip.txt 1970-01-01 03:00:00.000000000 +0300 +++ crtmpserver-1.0_mod/debian/crtmpserver-scripts/remote_ip.txt 2017-10-11 21:58:55.169193293 +0300 @@ -0,0 +1,7 @@ +; /etc/remote_ip.txt: white list remote IPs for translation and connect from +; high priority, if passed then local IPs and urls are not checked +; +; if not exist then urls and local ip are checking next +; Sample: +;185.189.1.2 +;37.78.53.97 diff -Naur crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/swf_url.txt crtmpserver-1.0_mod/debian/crtmpserver-scripts/swf_url.txt --- crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/swf_url.txt 1970-01-01 03:00:00.000000000 +0300 +++ crtmpserver-1.0_mod/debian/crtmpserver-scripts/swf_url.txt 2017-10-11 19:51:52.000000000 +0300 @@ -0,0 +1,4 @@ +; /etc/swf_url.txt: allowed Flash player address (swf's urls) or * +; Sample: +;http://maasoftware.ru/ref/tarantinov/starominskaya/TarantinovFLV3.swf +* diff -Naur crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/tc_url.txt crtmpserver-1.0_mod/debian/crtmpserver-scripts/tc_url.txt --- crtmpserver-1.0~dfsg/debian/crtmpserver-scripts/tc_url.txt 1970-01-01 03:00:00.000000000 +0300 +++ crtmpserver-1.0_mod/debian/crtmpserver-scripts/tc_url.txt 2017-10-11 19:51:52.000000000 +0300 @@ -0,0 +1,4 @@ +; /etc/tc_url.txt: allowed tc urls (Connect schema) or * +; Sample: +;rtmp://starominskaya.biz/flvplayback +*