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