diff --git a/daemon/call.c b/daemon/call.c index af0efc7bc..12a18c1c6 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -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; diff --git a/daemon/call.h b/daemon/call.h index 7474491c7..61242c58b 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -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[]; diff --git a/daemon/main.c b/daemon/main.c index 2a95a4ec5..e136aaed2 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -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); diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 9c798e8f5..676cc9446 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]); @@ -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); 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