Hello, Maintainers. I have a look more to patching code and have fix machine-depending host byte order in remote ip calculation.
So patch5.txt is a new version of patch. And I have a question about how is it possible to send this fix to a bug tracking system due to patch maa_crtmpserver_security_path.diff created by "dpkg-source -commit" is not including /etc/crtmpserver/*txt files, only manual patch5.txt is including. -- Best regards, Moiseenko Andrey, e-mail: supp...@maasoftware.ru web: http://www.maasoftware.ru ---------- forwarded letter ---------- От: JSK MaaSoftware <supp...@maasoftware.ru> К: Debian Multimedia Maintainers <pkg-multimedia-maintainers@lists.alioth.debian.org> А также к: Время создания: Wed, 11 Oct 2017 22:25:11 +0300 Тема: Moiseenko Andrey's crtmpserver security patch Прикрепленные файлы: maa_crtmpserver_security_path.diff, patch4.txt Hello, Maintainers! I have found a security problem in crtmpserver in December 2015, still exists. The problem is any rtmp streams generators like web cams, ffmpeg, etc can send they stream to you crtmpserver server anonymously and playback it. It can be a problem for you due to anybody can use your server for video streaming not for your sites nor your application. To solve the problem i create a patch based on code found by google for connect schema name and swf name check. And I have my additions to check remote (source) and local IP addresses of connection to allow to translate rtmp from certain static IPs. I am novice in open source commit, and just have to read 4 configs from hard coding dir /etc/crtmpserver (local_ip.txt, remote_ip.txt, tc_url.txt, swf_url.txt). I am trying to build modified source (Thank for Sebastian Ramacher for Bug#878211: crtmpserver can not be compilled from source - answered how to compile crtmpserver from Debian source). "dpkg-source -commit" say me: dpkg-source: info: local changes have been recorded in a new patch: crtmpserver-1.0/debian/patches/maa_crtmpserver_security_path.diff I think my path was not sent to Debian Maintainers by "dpkg-source -commit" command I am attaching my more detailed patch4.txt with /etc/crtmpserver/*txt samples generated by diff -Naur crtmpserver-1.0~dfsg crtmpserver-1.0_mod >patch4.txt Please fix me if can, about fixed path /etc/crtmpserver Waiting for code to be integrated into new versions of crtmpserver. -- Best regards, Moiseenko Andrey, e-mail: supp...@maasoftware.ru web: http://www.maasoftware.ru ---------- end of forwarded letter ----------
--- Begin Message ---Hello, Maintainers! I have found a security problem in crtmpserver in December 2015, still exists. The problem is any rtmp streams generators like web cams, ffmpeg, etc can send they stream to you crtmpserver server anonymously and playback it. It can be a problem for you due to anybody can use your server for video streaming not for your sites nor your application. To solve the problem i create a patch based on code found by google for connect schema name and swf name check. And I have my additions to check remote (source) and local IP addresses of connection to allow to translate rtmp from certain static IPs. I am novice in open source commit, and just have to read 4 configs from hard coding dir /etc/crtmpserver (local_ip.txt, remote_ip.txt, tc_url.txt, swf_url.txt). I am trying to build modified source (Thank for Sebastian Ramacher for Bug#878211: crtmpserver can not be compilled from source - answered how to compile crtmpserver from Debian source). "dpkg-source -commit" say me: dpkg-source: info: local changes have been recorded in a new patch: crtmpserver-1.0/debian/patches/maa_crtmpserver_security_path.diff I think my path was not sent to Debian Maintainers by "dpkg-source -commit" command I am attaching my more detailed patch4.txt with /etc/crtmpserver/*txt samples generated by diff -Naur crtmpserver-1.0~dfsg crtmpserver-1.0_mod >patch4.txt Please fix me if can, about fixed path /etc/crtmpserver Waiting for code to be integrated into new versions of crtmpserver. -- Best regards, Moiseenko Andrey, e-mail: supp...@maasoftware.ru web: http://www.maasoftware.ru
maa_crtmpserver_security_path.diff
Description: Binary datadiff -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 19:42:07.173819842 +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,198 @@ } } +// 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 = ntohl(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[3], + (uint8_t) pucIp[2], + (uint8_t) pucIp[1], + (uint8_t) pucIp[0]); + //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 +*
--- End Message ---
maa_crtmpserver_security_path.diff
Description: Binary data
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 +*
_______________________________________________ pkg-multimedia-maintainers mailing list pkg-multimedia-maintainers@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-multimedia-maintainers