1
0
mirror of https://github.com/rofafor/vdr-plugin-iptv.git synced 2023-10-10 13:37:03 +02:00

Refactored multicast source address validation.

This commit is contained in:
Rolf Ahrenberg 2010-09-15 17:37:20 +03:00
parent b0dba49fbc
commit 2d583e8cfa
8 changed files with 59 additions and 40 deletions

View File

@ -142,11 +142,11 @@ VDR Plugin 'iptv' Revision History
- Updated for vdr-1.7.15. - 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 - Renamed Sid scanner to section id scanner and added
experimental Tid/Nid support into it. 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. - Fixed audio pid detection in pid scanner.
- Changed ProvidesChannel() to set the need of detaching - Changed ProvidesChannel() to set the need of detaching
receivers due to VDR's channel selection mechanism. receivers due to VDR's channel selection mechanism.

3
README
View File

@ -161,6 +161,9 @@ Notes:
- EIT scanning functionality can be disabled for all IPTV channels by applying - EIT scanning functionality can be disabled for all IPTV channels by applying
the "disable_eitscan" patch to the VDR. 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: Acknowledgements:
- The IPTV section filtering code is derived from Linux kernel. - The IPTV section filtering code is derived from Linux kernel.

View File

@ -109,7 +109,7 @@ bool cIptvProtocolExt::Open(void)
if (!strlen(*scriptFile)) if (!strlen(*scriptFile))
return false; return false;
// Create the listening socket // Create the listening socket
OpenSocket(INADDR_LOOPBACK, socketPort); OpenSocket(socketPort);
// Execute the external script // Execute the external script
ExecuteScript(); ExecuteScript();
isActive = true; isActive = true;

View File

@ -19,10 +19,10 @@
#include "protocolhttp.h" #include "protocolhttp.h"
cIptvProtocolHttp::cIptvProtocolHttp() cIptvProtocolHttp::cIptvProtocolHttp()
: streamAddr(NULL),
streamPath(strdup("/"))
{ {
debug("cIptvProtocolHttp::cIptvProtocolHttp()\n"); debug("cIptvProtocolHttp::cIptvProtocolHttp()\n");
streamAddr = strdup("");
streamPath = strdup("/");
} }
cIptvProtocolHttp::~cIptvProtocolHttp() cIptvProtocolHttp::~cIptvProtocolHttp()
@ -59,7 +59,7 @@ bool cIptvProtocolHttp::Connect(void)
} }
// Ensure that socket is valid // Ensure that socket is valid
OpenSocket(sockAddr.sin_addr.s_addr, socketPort); OpenSocket(socketPort);
int err = connect(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr)); int err = connect(socketDesc, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
// Non-blocking sockets always report in-progress error when connected // Non-blocking sockets always report in-progress error when connected

View File

@ -19,9 +19,10 @@
#include "socket.h" #include "socket.h"
cIptvProtocolUdp::cIptvProtocolUdp() cIptvProtocolUdp::cIptvProtocolUdp()
: streamAddr(strdup("")),
sourceAddr(strdup(""))
{ {
debug("cIptvProtocolUdp::cIptvProtocolUdp()\n"); debug("cIptvProtocolUdp::cIptvProtocolUdp()\n");
streamAddr = strdup("");
} }
cIptvProtocolUdp::~cIptvProtocolUdp() cIptvProtocolUdp::~cIptvProtocolUdp()
@ -31,6 +32,7 @@ cIptvProtocolUdp::~cIptvProtocolUdp()
cIptvProtocolUdp::Close(); cIptvProtocolUdp::Close();
// Free allocated memory // Free allocated memory
free(streamAddr); free(streamAddr);
free(sourceAddr);
} }
bool cIptvProtocolUdp::JoinMulticast(void) bool cIptvProtocolUdp::JoinMulticast(void)
@ -39,7 +41,7 @@ bool cIptvProtocolUdp::JoinMulticast(void)
// Check that stream address is valid // Check that stream address is valid
if (!isActive && !isempty(streamAddr)) { if (!isActive && !isempty(streamAddr)) {
// Ensure that socket is valid // Ensure that socket is valid
OpenSocket(inet_addr(streamAddr), socketPort); OpenSocket(socketPort, isempty(sourceAddr) ? INADDR_ANY : inet_addr(sourceAddr));
// Join a new multicast group // Join a new multicast group
struct ip_mreq mreq; struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr); mreq.imr_multiaddr.s_addr = inet_addr(streamAddr);
@ -59,7 +61,7 @@ bool cIptvProtocolUdp::DropMulticast(void)
// Check that stream address is valid // Check that stream address is valid
if (isActive && !isempty(streamAddr)) { if (isActive && !isempty(streamAddr)) {
// Ensure that socket is valid // Ensure that socket is valid
OpenSocket(inet_addr(streamAddr), socketPort); OpenSocket(socketPort, isempty(sourceAddr) ? INADDR_ANY : inet_addr(sourceAddr));
// Drop the multicast group // Drop the multicast group
struct ip_mreq mreq; struct ip_mreq mreq;
mreq.imr_multiaddr.s_addr = inet_addr(streamAddr); 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); debug("cIptvProtocolUdp::Set(): Location=%s Parameter=%d Index=%d\n", Location, Parameter, Index);
if (!isempty(Location)) { if (!isempty(Location)) {
// Drop the multicast group // Drop the multicast group
DropMulticast(); DropMulticast();
// Update stream address and port // Update stream address and port
streamAddr = strcpyrealloc(streamAddr, Location); streamAddr = strcpyrealloc(streamAddr, Location);
socketPort = Parameter; char *p = strstr(streamAddr, ";");
// Join a new multicast group if (p) {
JoinMulticast(); sourceAddr = strcpyrealloc(sourceAddr, p + 1);
} *p = 0;
}
else
sourceAddr = strcpyrealloc(sourceAddr, "");
socketPort = Parameter;
// Join a new multicast group
JoinMulticast();
}
return true; return true;
} }

View File

@ -15,6 +15,7 @@
class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf { class cIptvProtocolUdp : public cIptvUdpSocket, public cIptvProtocolIf {
private: private:
char* streamAddr; char* streamAddr;
char* sourceAddr;
private: private:
bool JoinMulticast(void); bool JoinMulticast(void);

View File

@ -20,11 +20,10 @@
cIptvSocket::cIptvSocket() cIptvSocket::cIptvSocket()
: socketDesc(-1), : socketDesc(-1),
socketPort(0), socketPort(0),
inetAddr(INADDR_NONE),
isActive(false) isActive(false)
{ {
debug("cIptvSocket::cIptvSocket()\n"); debug("cIptvSocket::cIptvSocket()\n");
memset(&sockAddr, 0, sizeof(sockAddr)); memset(&sockAddr, '\0', sizeof(sockAddr));
} }
cIptvSocket::~cIptvSocket() cIptvSocket::~cIptvSocket()
@ -34,7 +33,7 @@ cIptvSocket::~cIptvSocket()
CloseSocket(); 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"); debug("cIptvSocket::OpenSocket()\n");
// If socket is there already and it is bound to a different port, it must // 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"); debug("cIptvSocket::OpenSocket(): Socket tear-down\n");
CloseSocket(); CloseSocket();
} }
// inetAddr must be set after CloseSocket()
if (inetAddr != InetAddr)
inetAddr = InetAddr;
// Bind to the socket if it is not active already // Bind to the socket if it is not active already
if (socketDesc < 0) { if (socketDesc < 0) {
int yes = 1; 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)", ERROR_IF_FUNC(setsockopt(socketDesc, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0, "setsockopt(IP_PKTINFO)",
CloseSocket(), return false); CloseSocket(), return false);
// Bind socket // Bind socket
memset(&sockAddr, 0, sizeof(sockAddr)); memset(&sockAddr, '\0', sizeof(sockAddr));
sockAddr.sin_family = AF_INET; sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons((uint16_t)(Port & 0xFFFF)); sockAddr.sin_port = htons((uint16_t)(Port & 0xFFFF));
sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
@ -87,13 +83,13 @@ void cIptvSocket::CloseSocket(void)
close(socketDesc); close(socketDesc);
socketDesc = -1; socketDesc = -1;
socketPort = 0; socketPort = 0;
inetAddr = INADDR_NONE;
memset(&sockAddr, 0, sizeof(sockAddr)); memset(&sockAddr, 0, sizeof(sockAddr));
} }
} }
// UDP socket class // UDP socket class
cIptvUdpSocket::cIptvUdpSocket() cIptvUdpSocket::cIptvUdpSocket()
: sourceAddr(INADDR_ANY)
{ {
debug("cIptvUdpSocket::cIptvUdpSocket()\n"); debug("cIptvUdpSocket::cIptvUdpSocket()\n");
} }
@ -103,10 +99,18 @@ cIptvUdpSocket::~cIptvUdpSocket()
debug("cIptvUdpSocket::~cIptvUdpSocket()\n"); 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"); 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) 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 // Read data from socket
if (isActive && socketDesc && BufferAddr && (BufferLen > 0)) if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
len = (int)recvmsg(socketDesc, &msgh, MSG_DONTWAIT); len = (int)recvmsg(socketDesc, &msgh, MSG_DONTWAIT);
if (len < 0) ERROR_IF_RET(len < 0, "recvmsg()", return -1);
return -1; if (len > 0) {
else if (len > 0) {
// Process auxiliary received data and validate source address // 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)) { if ((cmsg->cmsg_level == SOL_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
struct in_pktinfo *i = (struct in_pktinfo *)CMSG_DATA(cmsg); 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; return 0;
}
} }
} }
if (BufferAddr[0] == TS_SYNC_BYTE) if (BufferAddr[0] == TS_SYNC_BYTE)
@ -193,10 +198,10 @@ cIptvTcpSocket::~cIptvTcpSocket()
debug("cIptvTcpSocket::~cIptvTcpSocket()\n"); 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"); debug("cIptvTcpSocket::OpenSocket()\n");
return cIptvSocket::OpenSocket(InetAddr, Port, false); return cIptvSocket::OpenSocket(Port, false);
} }
int cIptvTcpSocket::Read(unsigned char* BufferAddr, unsigned int BufferLen) 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)) if (isActive && socketDesc && BufferAddr && (BufferLen > 0))
len = (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT, len = (int)recvfrom(socketDesc, BufferAddr, BufferLen, MSG_DONTWAIT,
(struct sockaddr *)&sockAddr, &addrlen); (struct sockaddr *)&sockAddr, &addrlen);
//if (inetAddr != sockAddr.sin_addr.s_addr)
// return -1;
return len; return len;
} }

View File

@ -14,12 +14,11 @@ class cIptvSocket {
protected: protected:
int socketDesc; int socketDesc;
int socketPort; int socketPort;
in_addr_t inetAddr;
struct sockaddr_in sockAddr; struct sockaddr_in sockAddr;
bool isActive; bool isActive;
protected: 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); void CloseSocket(void);
public: public:
@ -28,11 +27,15 @@ public:
}; };
class cIptvUdpSocket : public cIptvSocket { class cIptvUdpSocket : public cIptvSocket {
private:
in_addr_t sourceAddr;
public: public:
cIptvUdpSocket(); cIptvUdpSocket();
virtual ~cIptvUdpSocket(); virtual ~cIptvUdpSocket();
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen); 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 { class cIptvTcpSocket : public cIptvSocket {
@ -40,7 +43,7 @@ public:
cIptvTcpSocket(); cIptvTcpSocket();
virtual ~cIptvTcpSocket(); virtual ~cIptvTcpSocket();
virtual int Read(unsigned char* BufferAddr, unsigned int BufferLen); 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 #endif // __IPTV_SOCKET_H