From 01c5c22a1c4986bee291daae8a939886ce42fb83 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Tue, 12 Apr 2016 10:46:13 -0400 Subject: [PATCH] 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) (cherry picked from commit 2e5e2ec1b9be5366b2153a14190af657439aaefe) --- daemon/call.c | 44 ++++++++++++++++++++++++++++++++++++++++++- daemon/call.h | 2 ++ daemon/main.c | 10 ++++++++-- daemon/media_socket.c | 35 +++++++++++++++++++++++++++++++++- daemon/media_socket.h | 5 +++-- daemon/sdp.c | 3 ++- daemon/socket.c | 21 +++++++++++++++++++++ daemon/socket.h | 6 ++++++ 8 files changed, 119 insertions(+), 7 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index d00cc5e55..cb43db8de 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -58,6 +58,7 @@ const struct transport_protocol transport_protocols[] = { .rtp = 1, .srtp = 0, .avpf = 0, + .tcp = 0, }, [PROTO_RTP_SAVP] = { .index = PROTO_RTP_SAVP, @@ -65,6 +66,7 @@ const struct transport_protocol transport_protocols[] = { .rtp = 1, .srtp = 1, .avpf = 0, + .tcp = 0, }, [PROTO_RTP_AVPF] = { .index = PROTO_RTP_AVPF, @@ -72,6 +74,7 @@ const struct transport_protocol transport_protocols[] = { .rtp = 1, .srtp = 0, .avpf = 1, + .tcp = 0, }, [PROTO_RTP_SAVPF] = { .index = PROTO_RTP_SAVPF, @@ -79,6 +82,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, @@ -86,6 +90,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, @@ -93,6 +98,7 @@ const struct transport_protocol transport_protocols[] = { .rtp = 1, .srtp = 1, .avpf = 1, + .tcp = 0, }, [PROTO_UDPTL] = { .index = PROTO_UDPTL, @@ -100,6 +106,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) @@ -1566,6 +1606,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, @@ -2240,7 +2282,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; diff --git a/daemon/call.h b/daemon/call.h index 9894f3730..3c36d5cf3 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -91,6 +91,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 */ @@ -222,6 +223,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[]; diff --git a/daemon/main.c b/daemon/main.c index b43e1d9cd..1560dc88b 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -216,7 +216,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; @@ -513,10 +515,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(); clock_gettime(CLOCK_REALTIME, &ts); srandom(ts.tv_sec ^ ts.tv_nsec); @@ -690,6 +695,7 @@ int main(int argc, char **argv) { struct main_context ctx; int idx=0; + early_init(); options(&argc, &argv); init_everything(); create_everything(&ctx); diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 8a5cc27cd..e1683f304 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -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]); @@ -1335,7 +1366,9 @@ out: if (ret == 0 && update) ret = 1; +#if RTP_LOOP_PROTECT done: +#endif if (unk) __stream_unconfirm(stream); mutex_unlock(&stream->in_lock); diff --git a/daemon/media_socket.h b/daemon/media_socket.h index 44277dfca..abdac21ae 100644 --- a/daemon/media_socket.h +++ b/daemon/media_socket.h @@ -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 *); diff --git a/daemon/sdp.c b/daemon/sdp.c index 34f684849..d9f1de447 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -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) { diff --git a/daemon/socket.c b/daemon/socket.c index 951195e8b..1660afef9 100644 --- a/daemon/socket.c +++ b/daemon/socket.c @@ -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"); } diff --git a/daemon/socket.h b/daemon/socket.h index aff67bb63..dc7458b27 100644 --- a/daemon/socket.h +++ b/daemon/socket.h @@ -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