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.
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.

3
README
View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

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

View File

@ -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;
}

View File

@ -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