detect and ignore when local endpoints are advertised by remote clients

fixes #65

this also obsoletes the old loop detection

Change-Id: I850d81500c45828af2c4d50d80278ec2d599c2a0
(cherry picked from commit 3254278cfd55167fb881cc665328744183773728)
pull/269/head
Richard Fuchs 9 years ago
parent 44d993c919
commit 2e5e2ec1b9

@ -59,6 +59,7 @@ const struct transport_protocol transport_protocols[] = {
.rtp = 1,
.srtp = 0,
.avpf = 0,
.tcp = 0,
},
[PROTO_RTP_SAVP] = {
.index = PROTO_RTP_SAVP,
@ -66,6 +67,7 @@ const struct transport_protocol transport_protocols[] = {
.rtp = 1,
.srtp = 1,
.avpf = 0,
.tcp = 0,
},
[PROTO_RTP_AVPF] = {
.index = PROTO_RTP_AVPF,
@ -73,6 +75,7 @@ const struct transport_protocol transport_protocols[] = {
.rtp = 1,
.srtp = 0,
.avpf = 1,
.tcp = 0,
},
[PROTO_RTP_SAVPF] = {
.index = PROTO_RTP_SAVPF,
@ -80,6 +83,7 @@ const struct transport_protocol transport_protocols[] = {
.rtp = 1,
.srtp = 1,
.avpf = 1,
.tcp = 0,
},
[PROTO_UDP_TLS_RTP_SAVP] = {
.index = PROTO_UDP_TLS_RTP_SAVP,
@ -87,6 +91,7 @@ const struct transport_protocol transport_protocols[] = {
.rtp = 1,
.srtp = 1,
.avpf = 0,
.tcp = 0,
},
[PROTO_UDP_TLS_RTP_SAVPF] = {
.index = PROTO_UDP_TLS_RTP_SAVPF,
@ -94,6 +99,7 @@ const struct transport_protocol transport_protocols[] = {
.rtp = 1,
.srtp = 1,
.avpf = 1,
.tcp = 0,
},
[PROTO_UDPTL] = {
.index = PROTO_UDPTL,
@ -101,6 +107,7 @@ const struct transport_protocol transport_protocols[] = {
.rtp = 0,
.srtp = 0,
.avpf = 0,
.tcp = 0,
},
};
const int num_transport_protocols = G_N_ELEMENTS(transport_protocols);
@ -1490,6 +1497,39 @@ static int get_algorithm_num_ports(GQueue *streams, char *algorithm) {
return algorithm_ports;
}
static void __endpoint_loop_protect(struct stream_params *sp, struct call_media *media) {
struct intf_address intf_addr;
struct packet_stream *ps;
/* check if the advertised endpoint is one of our own addresses. this can
* happen by mistake, or it's expected when ICE is in use and passthrough
* mode is enabled (in particular when using ICE=force-relay). ignore such
* an endpoint and revert to what we had before. */
intf_addr.type = socktype_udp;
// if (other_media->protocol && other_media->protocol->tcp)
// intf_addr.type = socktype_tcp;
intf_addr.addr = sp->rtp_endpoint.address;
if (!is_local_endpoint(&intf_addr, sp->rtp_endpoint.port))
return;
if (media->streams.head) {
ps = media->streams.head->data;
sp->rtp_endpoint = ps->advertised_endpoint;
ps = ps->rtcp_sibling;
if (ps)
sp->rtcp_endpoint = ps->advertised_endpoint;
else
ZERO(sp->rtcp_endpoint);
}
else
ZERO(sp->rtp_endpoint);
ilog(LOG_DEBUG, "Detected local endpoint advertised by remote client. "
"Ignoring and reverting to %s",
endpoint_print_buf(&sp->rtp_endpoint));
}
/* called with call->master_lock held in W */
int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
const struct sdp_ng_flags *flags)
@ -1565,6 +1605,8 @@ int monologue_offer_answer(struct call_monologue *other_ml, GQueue *streams,
&& other_media->protocol && other_media->protocol->rtp)
media->protocol = flags->transport_protocol;
__endpoint_loop_protect(sp, other_media);
if (sp->rtp_endpoint.port) {
/* copy parameters advertised by the sender of this message */
bf_copy_same(&other_media->media_flags, &sp->sp_flags,
@ -2253,7 +2295,7 @@ int call_stream_address46(char *o, struct packet_stream *ps, enum stream_address
&& !is_trickle_ice_address(&sink->advertised_endpoint))
l += sprintf(o + l, "%s", ifa_addr->addr.family->unspec_string);
else
l += sprintf(o + l, "%s", sockaddr_print_buf(&ifa->advertised_address));
l += sprintf(o + l, "%s", sockaddr_print_buf(&ifa->advertised_address.addr));
*len = l;
return ifa_addr->addr.family->af;

@ -93,6 +93,7 @@ enum call_type {
#define RTP_BUFFER_TAIL_ROOM 512
#define RTP_BUFFER_SIZE (MAX_RTP_PACKET_SIZE + RTP_BUFFER_HEAD_ROOM + RTP_BUFFER_TAIL_ROOM)
#define RTP_LOOP_PROTECT 0 // disable
#ifndef RTP_LOOP_PROTECT
#define RTP_LOOP_PROTECT 28 /* number of bytes */
#define RTP_LOOP_PACKETS 2 /* number of packets */
@ -224,6 +225,7 @@ struct transport_protocol {
int rtp:1; /* also set to 1 for SRTP */
int srtp:1;
int avpf:1;
int tcp:1;
};
extern const struct transport_protocol transport_protocols[];

@ -219,7 +219,9 @@ static struct intf_config *if_addr_parse(char *s) {
ifa = g_slice_alloc0(sizeof(*ifa));
ifa->name = name;
ifa->local_address.addr = addr;
ifa->advertised_address = adv;
ifa->local_address.type = socktype_udp;
ifa->advertised_address.addr = adv;
ifa->advertised_address.type = ifa->local_address.type;
ifa->port_min = port_min;
ifa->port_max = port_max;
@ -518,10 +520,13 @@ static void make_OpenSSL_thread_safe(void) {
}
static void early_init() {
socket_init(); // needed for socktype_udp
}
static void init_everything() {
struct timespec ts;
socket_init();
log_init();
recording_fs_init(spooldir);
clock_gettime(CLOCK_REALTIME, &ts);
@ -699,6 +704,7 @@ int main(int argc, char **argv) {
struct main_context ctx;
int idx=0;
early_init();
options(&argc, &argv);
init_everything();
create_everything(&ctx);

@ -225,6 +225,7 @@ static GQueue *__interface_list_for_family(sockfamily_t *fam);
static GHashTable *__logical_intf_name_family_hash;
static GHashTable *__intf_spec_addr_type_hash;
static GHashTable *__local_intf_addr_type_hash; // hash of lists
static GQueue __preferred_lists_for_family[__SF_LAST];
static __thread unsigned int selection_index = 0;
@ -422,6 +423,32 @@ static int __addr_type_eq(const void *a, const void *b) {
return sockaddr_eq(&A->addr, &B->addr) && A->type == B->type;
}
static void __insert_local_intf_addr_type(const struct intf_address *addr, const struct local_intf *intf) {
GList *l;
l = g_hash_table_lookup(__local_intf_addr_type_hash, addr);
l = g_list_prepend(l, (void *) intf);
g_hash_table_replace(__local_intf_addr_type_hash, (void *) addr, l);
}
int is_local_endpoint(const struct intf_address *addr, unsigned int port) {
GList *l;
const struct local_intf *intf;
const struct intf_spec *spec;
l = g_hash_table_lookup(__local_intf_addr_type_hash, addr);
if (!l)
return 0;
while (l) {
intf = l->data;
spec = intf->spec;
if (spec->port_pool.min <= port && spec->port_pool.max >= port)
return 1;
l = l->next;
}
return 0;
}
static GQueue *__interface_list_for_family(sockfamily_t *fam) {
return &__preferred_lists_for_family[fam->idx];
}
@ -461,7 +488,10 @@ static void __interface_append(struct intf_config *ifa, sockfamily_t *fam) {
ifc->spec = spec;
ifc->logical = lif;
g_hash_table_insert(lif->addr_hash, (void *) &ifc->spec->local_address, ifc);
g_hash_table_insert(lif->addr_hash, &spec->local_address, ifc);
__insert_local_intf_addr_type(&spec->local_address, ifc);
__insert_local_intf_addr_type(&ifc->advertised_address, ifc);
}
void interfaces_init(GQueue *interfaces) {
@ -473,6 +503,7 @@ void interfaces_init(GQueue *interfaces) {
/* init everything */
__logical_intf_name_family_hash = g_hash_table_new(__name_family_hash, __name_family_eq);
__intf_spec_addr_type_hash = g_hash_table_new(__addr_type_hash, __addr_type_eq);
__local_intf_addr_type_hash = g_hash_table_new(__addr_type_hash, __addr_type_eq);
for (i = 0; i < G_N_ELEMENTS(__preferred_lists_for_family); i++)
g_queue_init(&__preferred_lists_for_family[i]);
@ -1367,7 +1398,9 @@ out:
if (ret == 0 && update)
ret = 1;
#if RTP_LOOP_PROTECT
done:
#endif
if (unk)
__stream_unconfirm(stream);
mutex_unlock(&stream->in_lock);

@ -37,7 +37,7 @@ struct intf_address {
struct intf_config {
str name;
struct intf_address local_address;
sockaddr_t advertised_address;
struct intf_address advertised_address;
unsigned int port_min, port_max;
};
struct intf_spec {
@ -46,7 +46,7 @@ struct intf_spec {
};
struct local_intf {
struct intf_spec *spec;
sockaddr_t advertised_address;
struct intf_address advertised_address;
unsigned int unique_id; /* starting with 0 - serves as preference */
const struct logical_intf *logical;
str ice_foundation;
@ -74,6 +74,7 @@ struct logical_intf *get_logical_interface(const str *name, sockfamily_t *fam, i
struct local_intf *get_interface_address(const struct logical_intf *lif, sockfamily_t *fam);
struct local_intf *get_any_interface_address(const struct logical_intf *lif, sockfamily_t *fam);
void interfaces_exclude_port(unsigned int port);
int is_local_endpoint(const struct intf_address *addr, unsigned int port);
//int get_port(socket_t *r, unsigned int port, const struct local_intf *lif, const struct call *c);
//void release_port(socket_t *r, const struct local_intf *);

@ -1029,7 +1029,8 @@ void sdp_free(GQueue *sessions) {
}
static int fill_endpoint(struct endpoint *ep, const struct sdp_media *media, struct sdp_ng_flags *flags,
struct network_address *address, long int port) {
struct network_address *address, long int port)
{
struct sdp_session *session = media->session;
if (!flags->trust_address) {

@ -106,6 +106,12 @@ static struct socket_family __socket_families[__SF_LAST] = {
};
socktype_t *socktype_udp;
static int __ip4_addr_parse(sockaddr_t *dst, const char *src) {
if (inet_pton(AF_INET, src, &dst->u.ipv4) == 1)
return 0;
@ -599,6 +605,19 @@ socktype_t *get_socket_type(const str *s) {
}
return NULL;
}
socktype_t *get_socket_type_c(const char *s) {
int i;
socktype_t *tp;
for (i = 0; i < G_N_ELEMENTS(__socket_types); i++) {
tp = &__socket_types[i];
if (!strcmp(s, tp->name))
return tp;
if (!strcmp(s, tp->name_uc))
return tp;
}
return NULL;
}
@ -608,4 +627,6 @@ void socket_init(void) {
for (i = 0; i < __SF_LAST; i++)
__socket_families[i].idx = i;
socktype_udp = get_socket_type_c("udp");
}

@ -89,6 +89,11 @@ struct socket {
extern socktype_t *socktype_udp;
#include "aux.h"
@ -236,6 +241,7 @@ INLINE int ipv46_any_convert(endpoint_t *ep) {
socktype_t *get_socket_type(const str *s);
socktype_t *get_socket_type_c(const char *s);
#endif

Loading…
Cancel
Save