From 2d583e8cfa7bdfc4094829128e9f8091bef1f43c Mon Sep 17 00:00:00 2001 From: Rolf Ahrenberg Date: Wed, 15 Sep 2010 17:37:20 +0300 Subject: [PATCH] Refactored multicast source address validation. --- HISTORY | 4 ++-- README | 3 +++ protocolext.c | 2 +- protocolhttp.c | 6 +++--- protocoludp.c | 31 ++++++++++++++++++++----------- protocoludp.h | 1 + socket.c | 41 ++++++++++++++++++++++------------------- socket.h | 11 +++++++---- 8 files changed, 59 insertions(+), 40 deletions(-) diff --git a/HISTORY b/HISTORY index c228811..9d9b8fb 100644 --- a/HISTORY +++ b/HISTORY @@ -142,11 +142,11 @@ VDR Plugin 'iptv' Revision History - Updated for vdr-1.7.15. -2010-09-12: Version 0.4.3 +2010-09-15: Version 0.4.3 - Renamed Sid scanner to section id scanner and added experimental Tid/Nid support into it. -- Added validation for source addresses of socket data. +- Added optional source address validation for UDP protocol. - Fixed audio pid detection in pid scanner. - Changed ProvidesChannel() to set the need of detaching receivers due to VDR's channel selection mechanism. diff --git a/README b/README index c0d4bfd..290d7c0 100644 --- a/README +++ b/README @@ -161,6 +161,9 @@ Notes: - EIT scanning functionality can be disabled for all IPTV channels by applying the "disable_eitscan" patch to the VDR. +- Source address validation can be enabled for UDP protocol separated by + adding the source address after a ';' character: "U=239.192.0.1;239.192.0.2" + Acknowledgements: - The IPTV section filtering code is derived from Linux kernel. diff --git a/protocolext.c b/protocolext.c index b065635..955d6c2 100644 --- a/protocolext.c +++ b/protocolext.c @@ -109,7 +109,7 @@ bool cIptvProtocolExt::Open(void) if (!strlen(*scriptFile)) return false; // Create the listening socket - OpenSocket(INADDR_LOOPBACK, socketPort); + OpenSocket(socketPort); // Execute the external script ExecuteScript(); isActive = true; diff --git a/protocolhttp.c b/protocolhttp.c index 5b7a8ec..7416ae0 100644 --- a/protocolhttp.c +++ b/protocolhttp.c @@ -19,10 +19,10 @@ #include "protocolhttp.h" cIptvProtocolHttp::cIptvProtocolHttp() +: streamAddr(NULL), + streamPath(strdup("/")) { debug("cIptvProtocolHttp::cIptvProtocolHttp()\n"); - streamAddr = strdup(""); - streamPath = strdup("/"); } cIptvProtocolHttp::~cIptvProtocolHttp() @@ -59,7 +59,7 @@ bool cIptvProtocolHttp::Connect(void) } // Ensure that socket is valid - OpenSocket(sockAddr.sin_addr.s_addr, socketPort); + OpenSocket(socketPort); int err = connect(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr)); // Non-blocking sockets always report in-progress error when connected diff --git a/protocoludp.c b/protocoludp.c index 6e54838..e688c45 100644 --- a/protocoludp.c +++ b/protocoludp.c @@ -19,9 +19,10 @@ #include "socket.h" cIptvProtocolUdp::cIptvProtocolUdp() +: streamAddr(strdup("")), + sourceAddr(strdup("")) { debug("cIptvProtocolUdp::cIptvProtocolUdp()\n"); - streamAddr = strdup(""); } cIptvProtocolUdp::~cIptvProtocolUdp() @@ -31,6 +32,7 @@ cIptvProtocolUdp::~cIptvProtocolUdp() cIptvProtocolUdp::Close(); // Free allocated memory free(streamAddr); + free(sourceAddr); } bool cIptvProtocolUdp::JoinMulticast(void) @@ -39,7 +41,7 @@ bool cIptvProtocolUdp::JoinMulticast(void) // Check that stream address is valid if (!isActive && !isempty(streamAddr)) { // Ensure that socket is valid - OpenSocket(inet_addr(streamAddr), socketPort); + OpenSocket(socketPort, isempty(sourceAddr) ? INADDR_ANY : inet_addr(sourceAddr)); // Join a new multicast group struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr(streamAddr); @@ -59,7 +61,7 @@ bool cIptvProtocolUdp::DropMulticast(void) // Check that stream address is valid if (isActive && !isempty(streamAddr)) { // Ensure that socket is valid - OpenSocket(inet_addr(streamAddr), socketPort); + OpenSocket(socketPort, isempty(sourceAddr) ? INADDR_ANY : inet_addr(sourceAddr)); // Drop the multicast group struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = inet_addr(streamAddr); @@ -100,14 +102,21 @@ bool cIptvProtocolUdp::Set(const char* Location, const int Parameter, const int { debug("cIptvProtocolUdp::Set(): Location=%s Parameter=%d Index=%d\n", Location, Parameter, Index); if (!isempty(Location)) { - // Drop the multicast group - DropMulticast(); - // Update stream address and port - streamAddr = strcpyrealloc(streamAddr, Location); - socketPort = Parameter; - // Join a new multicast group - JoinMulticast(); - } + // Drop the multicast group + DropMulticast(); + // Update stream address and port + streamAddr = strcpyrealloc(streamAddr, Location); + char *p = strstr(streamAddr, ";"); + if (p) { + sourceAddr = strcpyrealloc(sourceAddr, p + 1); + *p = 0; + } + else + sourceAddr = strcpyrealloc(sourceAddr, ""); + socketPort = Parameter; + // Join a new multicast group + JoinMulticast(); + } return true; } diff --git a/protocoludp.h b/protocoludp.h index ed33872..1d35f53 100644 --- a/protocoludp.h +++ b/protocoludp.h @@ -15,6 +15,7 @@ class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf { private: char* streamAddr; + char* sourceAddr; private: bool JoinMulticast(void); diff --git a/socket.c b/socket.c index 1ccef56..62c67a1 100644 --- a/socket.c +++ b/socket.c @@ -20,11 +20,10 @@ cIptvSocket::cIptvSocket() : socketDesc(-1), socketPort(0), - inetAddr(INADDR_NONE), isActive(false) { debug("cIptvSocket::cIptvSocket()\n"); - memset(&sockAddr, 0, sizeof(sockAddr)); + memset(&sockAddr, '\0', sizeof(sockAddr)); } cIptvSocket::~cIptvSocket() @@ -34,7 +33,7 @@ cIptvSocket::~cIptvSocket() CloseSocket(); } -bool cIptvSocket::OpenSocket(const in_addr_t InetAddr, const int Port, const bool isUdp) +bool cIptvSocket::OpenSocket(const int Port, const bool isUdp) { debug("cIptvSocket::OpenSocket()\n"); // If socket is there already and it is bound to a different port, it must @@ -43,9 +42,6 @@ bool cIptvSocket::OpenSocket(const in_addr_t InetAddr, const int Port, const boo debug("cIptvSocket::OpenSocket(): Socket tear-down\n"); CloseSocket(); } - // inetAddr must be set after CloseSocket() - if (inetAddr != InetAddr) - inetAddr = InetAddr; // Bind to the socket if it is not active already if (socketDesc < 0) { int yes = 1; @@ -65,7 +61,7 @@ bool cIptvSocket::OpenSocket(const in_addr_t InetAddr, const int Port, const boo ERROR_IF_FUNC(setsockopt(socketDesc, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0, "setsockopt(IP_PKTINFO)", CloseSocket(), return false); // Bind socket - memset(&sockAddr, 0, sizeof(sockAddr)); + memset(&sockAddr, '\0', sizeof(sockAddr)); sockAddr.sin_family = AF_INET; sockAddr.sin_port = htons((uint16_t)(Port & 0xFFFF)); sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); @@ -87,13 +83,13 @@ void cIptvSocket::CloseSocket(void) close(socketDesc); socketDesc = -1; socketPort = 0; - inetAddr = INADDR_NONE; memset(&sockAddr, 0, sizeof(sockAddr)); } } // UDP socket class cIptvUdpSocket::cIptvUdpSocket() +: sourceAddr(INADDR_ANY) { debug("cIptvUdpSocket::cIptvUdpSocket()\n"); } @@ -103,10 +99,18 @@ cIptvUdpSocket::~cIptvUdpSocket() debug("cIptvUdpSocket::~cIptvUdpSocket()\n"); } -bool cIptvUdpSocket::OpenSocket(const in_addr_t InetAddr, const int Port) +bool cIptvUdpSocket::OpenSocket(const int Port, const in_addr_t SourceAddr) { debug("cIptvUdpSocket::OpenSocket()\n"); - return cIptvSocket::OpenSocket(InetAddr, Port, true); + sourceAddr = SourceAddr; + return cIptvSocket::OpenSocket(Port, true); +} + +void cIptvUdpSocket::CloseSocket(void) +{ + debug("cIptvUdpSocket::CloseSocket()\n"); + sourceAddr = INADDR_ANY; + cIptvSocket::CloseSocket(); } int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) @@ -137,15 +141,16 @@ int cIptvUdpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) // Read data from socket if (isActive && socketDesc && BufferAddr && (BufferLen > 0)) len = (int)recvmsg(socketDesc, &msgh, MSG_DONTWAIT); - if (len < 0) - return -1; - else if (len > 0) { + ERROR_IF_RET(len < 0, "recvmsg()", return -1); + if (len > 0) { // Process auxiliary received data and validate source address - for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { + for (cmsg = CMSG_FIRSTHDR(&msgh); (sourceAddr != INADDR_ANY) && (cmsg != NULL); cmsg = CMSG_NXTHDR(&msgh, cmsg)) { if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) { struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg); - if (i->ipi_addr.s_addr != inetAddr) + if (i->ipi_addr.s_addr != sourceAddr) { + //debug("Discard packet due to invalid source address: %s", inet_ntoa(i->ipi_addr)); return 0; + } } } if (BufferAddr[0] == TS_SYNC_BYTE) @@ -193,10 +198,10 @@ cIptvTcpSocket::~cIptvTcpSocket() debug("cIptvTcpSocket::~cIptvTcpSocket()\n"); } -bool cIptvTcpSocket::OpenSocket(const in_addr_t InetAddr, const int Port) +bool cIptvTcpSocket::OpenSocket(const int Port) { debug("cIptvTcpSocket::OpenSocket()\n"); - return cIptvSocket::OpenSocket(InetAddr, Port, false); + return cIptvSocket::OpenSocket(Port, false); } int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) @@ -213,7 +218,5 @@ int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) if (isActive && socketDesc && BufferAddr && (BufferLen > 0)) len = (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT, (struct sockaddr *)&sockAddr, &addrlen); - //if (inetAddr != sockAddr.sin_addr.s_addr) - // return -1; return len; } diff --git a/socket.h b/socket.h index 170b4d7..0abae60 100644 --- a/socket.h +++ b/socket.h @@ -14,12 +14,11 @@ class cIptvSocket { protected: int socketDesc; int socketPort; - in_addr_t inetAddr; struct sockaddr_in sockAddr; bool isActive; protected: - bool OpenSocket(const in_addr_t InetAddr, const int Port, const bool isUdp); + bool OpenSocket(const int Port, const bool isUdp); void CloseSocket(void); public: @@ -28,11 +27,15 @@ public: }; class cIptvUdpSocket : public cIptvSocket { +private: + in_addr_t sourceAddr; + public: cIptvUdpSocket(); virtual ~cIptvUdpSocket(); virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen); - bool OpenSocket(const in_addr_t InetAddr, const int Port); + bool OpenSocket(const int Port, const in_addr_t SourceAddr = INADDR_ANY); + void CloseSocket(void); }; class cIptvTcpSocket : public cIptvSocket { @@ -40,7 +43,7 @@ public: cIptvTcpSocket(); virtual ~cIptvTcpSocket(); virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen); - bool OpenSocket(const in_addr_t InetAddr, const int Port); + bool OpenSocket(const int Port); }; #endif // __IPTV_SOCKET_H