Commit 4d97ca04 authored by Martin Storsjö's avatar Martin Storsjö

rtpproto: Check the source IP if one single source has been specified

If another peer is sending unicast packets to the same port that
we are listening on, those packets can end up being received despite
using source specific multicast. For those cases, manually check the
source address of received packets against the intended source address.

This only handles the case when the source list is one single IP
address for now, which probably is the most common case.

Based on a patch by Ed Torbett.
Signed-off-by: 's avatarMartin Storsjö <martin@martin.st>
parent 336353de
......@@ -42,7 +42,8 @@
typedef struct RTPContext {
URLContext *rtp_hd, *rtcp_hd;
int rtp_fd, rtcp_fd;
int rtp_fd, rtcp_fd, ssm;
struct sockaddr_storage ssm_addr;
} RTPContext;
/**
......@@ -75,6 +76,44 @@ int ff_rtp_set_remote_url(URLContext *h, const char *uri)
return 0;
}
static struct addrinfo* rtp_resolve_host(const char *hostname, int port,
int type, int family, int flags)
{
struct addrinfo hints = { 0 }, *res = 0;
int error;
char service[16];
snprintf(service, sizeof(service), "%d", port);
hints.ai_socktype = type;
hints.ai_family = family;
hints.ai_flags = flags;
if ((error = getaddrinfo(hostname, service, &hints, &res))) {
res = NULL;
av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error));
}
return res;
}
static int compare_addr(const struct sockaddr_storage *a,
const struct sockaddr_storage *b)
{
if (a->ss_family != b->ss_family)
return 1;
if (a->ss_family == AF_INET) {
return (((const struct sockaddr_in *)a)->sin_addr.s_addr !=
((const struct sockaddr_in *)b)->sin_addr.s_addr);
}
#if defined(IPPROTO_IPV6)
if (a->ss_family == AF_INET6) {
const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr;
const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr;
return memcmp(s6_addr_a, s6_addr_b, 16);
}
#endif
return 1;
}
/**
* add option to url of the form:
......@@ -178,7 +217,20 @@ static int rtp_open(URLContext *h, const char *uri, int flags)
connect = strtol(buf, NULL, 10);
}
if (av_find_info_tag(buf, sizeof(buf), "sources", p)) {
struct addrinfo *sourceaddr = NULL;
av_strlcpy(sources, buf, sizeof(sources));
/* Try resolving the IP if only one IP is specified - we don't
* support manually checking more than one IP. */
if (!strchr(sources, ','))
sourceaddr = rtp_resolve_host(sources, 0,
SOCK_DGRAM, AF_UNSPEC,
AI_NUMERICHOST);
if (sourceaddr) {
s->ssm = 1;
memcpy(&s->ssm_addr, sourceaddr->ai_addr, sourceaddr->ai_addrlen);
freeaddrinfo(sourceaddr);
}
}
}
......@@ -238,6 +290,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue;
return AVERROR(EIO);
}
if (s->ssm && compare_addr(&from, &s->ssm_addr))
continue;
break;
}
/* then RTP */
......@@ -251,6 +305,8 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size)
continue;
return AVERROR(EIO);
}
if (s->ssm && compare_addr(&from, &s->ssm_addr))
continue;
break;
}
} else if (n < 0) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment