From 4ded03de918fc2dfcc25c6720f0e345acf04eb33 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 9 May 2014 10:24:50 -0400 Subject: [PATCH] implement media-handover and strict-source logic --- daemon/call.c | 102 +++++++++++++++++++++++++++++++++--------------- daemon/call.h | 7 ++++ daemon/sdp.c | 2 + utils/ng-client | 4 +- 4 files changed, 83 insertions(+), 32 deletions(-) diff --git a/daemon/call.c b/daemon/call.c index 50f83947a..1920de75f 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -262,6 +262,7 @@ static const struct mediaproxy_srtp __mps_null = { static void call_destroy(struct call *); static void unkernelize(struct packet_stream *); +static void __stream_unkernelize(struct packet_stream *ps); @@ -288,6 +289,18 @@ static void stream_fd_closed(int fd, void *p, uintptr_t u) { +INLINE void __mp_address_translate(struct mp_address *o, const struct endpoint *ep) { + if (IN6_IS_ADDR_V4MAPPED(&ep->ip46)) { + o->family = AF_INET; + o->u.ipv4 = ep->ip46.s6_addr32[3]; + } + else { + o->family = AF_INET6; + memcpy(o->u.ipv6, &ep->ip46, sizeof(o->u.ipv6)); + } + o->port = ep->port; +} + /* called with in_lock held */ void kernelize(struct packet_stream *stream) { struct mediaproxy_target_info mpt; @@ -306,8 +319,7 @@ void kernelize(struct packet_stream *stream) { if (!stream->sfd) goto no_kernel; - ilog(LOG_DEBUG, "Kernelizing media stream with local port %u", - stream->sfd->fd.localport); + ilog(LOG_INFO, "Kernelizing media stream"); sink = packet_stream_sink(stream); if (!sink) { @@ -326,28 +338,33 @@ void kernelize(struct packet_stream *stream) { ZERO(mpt); + if (PS_ISSET(stream, STRICT_SOURCE) || PS_ISSET(stream, MEDIA_HANDOVER)) { + mutex_lock(&stream->out_lock); + __mp_address_translate(&mpt.expected_src, &stream->endpoint); + mutex_unlock(&stream->out_lock); + if (PS_ISSET(stream, STRICT_SOURCE)) + mpt.src_mismatch = MSM_DROP; + else if (PS_ISSET(stream, MEDIA_HANDOVER)) + mpt.src_mismatch = MSM_PROPAGATE; + } + mutex_lock(&sink->out_lock); mpt.target_port = stream->sfd->fd.localport; mpt.tos = cm->conf.tos; - mpt.src_addr.port = sink->sfd->fd.localport; - mpt.dst_addr.port = sink->endpoint.port; mpt.rtcp_mux = MEDIA_ISSET(stream->media, RTCP_MUX); mpt.dtls = MEDIA_ISSET(stream->media, DTLS); mpt.stun = PS_ISSET(stream, STUN); - if (IN6_IS_ADDR_V4MAPPED(&sink->endpoint.ip46)) { - mpt.src_addr.family = AF_INET; + __mp_address_translate(&mpt.dst_addr, &sink->endpoint); + + mpt.src_addr.family = mpt.dst_addr.family; + mpt.src_addr.port = sink->sfd->fd.localport; + + if (mpt.src_addr.family == AF_INET) mpt.src_addr.u.ipv4 = cm->conf.ipv4; - mpt.dst_addr.family = AF_INET; - mpt.dst_addr.u.ipv4 = sink->endpoint.ip46.s6_addr32[3]; - } - else { - mpt.src_addr.family = AF_INET6; + else memcpy(mpt.src_addr.u.ipv6, &cm->conf.ipv6, sizeof(mpt.src_addr.u.ipv6)); - mpt.dst_addr.family = AF_INET6; - memcpy(mpt.dst_addr.u.ipv6, &sink->endpoint.ip46, sizeof(mpt.src_addr.u.ipv6)); - } stream->handler->in->kernel(&mpt.decrypt, stream); stream->handler->out->kernel(&mpt.encrypt, sink); @@ -615,37 +632,55 @@ static int stream_packet(struct stream_fd *sfd, str *s, struct sockaddr_in6 *fsi mutex_lock(&stream->in_lock); use_cand: + /* we're OK to (potentially) use the source address of this packet as destination + * in the other direction. */ + /* if the other side hasn't been signalled yet, just forward the packet */ if (!PS_ISSET(stream, FILLED)) goto forward; + /* do not pay attention to source addresses of incoming packets for asymmetric streams */ if (MEDIA_ISSET(media, ASYMMETRIC)) PS_SET(stream, CONFIRMED); - if (PS_ISSET(stream, CONFIRMED)) + /* if we have already updated the endpoint in the past ... */ + if (PS_ISSET(stream, CONFIRMED)) { + /* see if we need to compare the source address with the known endpoint */ + if (PS_ISSET(stream, STRICT_SOURCE) || PS_ISSET(stream, MEDIA_HANDOVER)) { + endpoint.ip46 = fsin->sin6_addr; + endpoint.port = ntohs(fsin->sin6_port); + mutex_lock(&stream->out_lock); + + int tmp = memcmp(&endpoint, &stream->endpoint, sizeof(endpoint)); + if (tmp && PS_ISSET(stream, MEDIA_HANDOVER)) { + /* out_lock remains locked */ + ilog(LOG_INFO, "Peer address changed to %s", addr); + __stream_unkernelize(stream); + goto update_addr; + } + + mutex_unlock(&stream->out_lock); + + if (tmp && PS_ISSET(stream, STRICT_SOURCE)) { + stream->stats.errors++; + goto drop; + } + } goto kernel_check; + } + /* wait at least 3 seconds after last signal before committing to a particular + * endpoint address */ if (!call->last_signal || poller_now <= call->last_signal + 3) - goto peerinfo; + goto update_peerinfo; - ilog(LOG_DEBUG, "Confirmed peer information for port %u - %s", - sfd->fd.localport, addr); + ilog(LOG_INFO, "Confirmed peer address as %s", addr); PS_SET(stream, CONFIRMED); update = 1; -peerinfo: - /* - if (!stun_ret && !stream->codec && s->len >= 2) { - cc = s->s[1]; - cc &= 0x7f; - if (cc < G_N_ELEMENTS(rtp_codecs)) - stream->codec = rtp_codecs[cc] ? : "unknown"; - else - stream->codec = "unknown"; - } - */ - +update_peerinfo: mutex_lock(&stream->out_lock); +update_addr: endpoint = stream->endpoint; stream->endpoint.ip46 = fsin->sin6_addr; stream->endpoint.port = ntohs(fsin->sin6_port); @@ -1513,8 +1548,11 @@ static int __init_streams(struct call_media *A, struct call_media *B, const stru a->rtp_sink = b; PS_SET(a, RTP); - if (sp) + if (sp) { __fill_stream(a, &sp->rtp_endpoint, port_off); + bf_copy_same(&a->ps_flags, &sp->sp_flags, + SHARED_FLAG_STRICT_SOURCE | SHARED_FLAG_MEDIA_HANDOVER); + } if (__init_stream(a)) return -1; @@ -1561,6 +1599,8 @@ static int __init_streams(struct call_media *A, struct call_media *B, const stru __fill_stream(a, &sp->rtp_endpoint, port_off + 1); PS_SET(a, IMPLICIT_RTCP); } + bf_copy_same(&a->ps_flags, &sp->sp_flags, + SHARED_FLAG_STRICT_SOURCE | SHARED_FLAG_MEDIA_HANDOVER); } if (__init_stream(a)) return -1; diff --git a/daemon/call.h b/daemon/call.h index 3a1e3a2ce..cc809906c 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -77,6 +77,8 @@ struct call_monologue; #define SHARED_FLAG_SETUP_ACTIVE 0x00000020 #define SHARED_FLAG_SETUP_PASSIVE 0x00000040 #define SHARED_FLAG_ICE 0x00000080 +#define SHARED_FLAG_STRICT_SOURCE 0x00000100 +#define SHARED_FLAG_MEDIA_HANDOVER 0x00000200 /* struct stream_params */ #define SP_FLAG_NO_RTCP 0x00010000 @@ -88,6 +90,8 @@ struct call_monologue; #define SP_FLAG_SETUP_ACTIVE SHARED_FLAG_SETUP_ACTIVE #define SP_FLAG_SETUP_PASSIVE SHARED_FLAG_SETUP_PASSIVE #define SP_FLAG_ICE SHARED_FLAG_ICE +#define SP_FLAG_STRICT_SOURCE SHARED_FLAG_STRICT_SOURCE +#define SP_FLAG_MEDIA_HANDOVER SHARED_FLAG_MEDIA_HANDOVER /* struct packet_stream */ #define PS_FLAG_RTP 0x00010000 @@ -101,6 +105,8 @@ struct call_monologue; #define PS_FLAG_NO_KERNEL_SUPPORT 0x00800000 #define PS_FLAG_HAS_HANDLER 0x01000000 #define PS_FLAG_FINGERPRINT_VERIFIED 0x02000000 +#define PS_FLAG_STRICT_SOURCE SHARED_FLAG_STRICT_SOURCE +#define PS_FLAG_MEDIA_HANDOVER SHARED_FLAG_MEDIA_HANDOVER /* struct call_media */ #define MEDIA_FLAG_INITIALIZED 0x00010000 @@ -320,6 +326,7 @@ struct callmaster { u_int16_t lastport; BIT_ARRAY_DECLARE(ports_used, 0x10000); + /* XXX rework these */ mutex_t statspslock; struct stats statsps; /* per second stats, running timer */ mutex_t statslock; diff --git a/daemon/sdp.c b/daemon/sdp.c index 5a582fc77..31add8b5b 100644 --- a/daemon/sdp.c +++ b/daemon/sdp.c @@ -987,6 +987,8 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, struct sdp_ng_flags *fl memcpy(sp->direction, flags->directions, sizeof(sp->direction)); sp->desired_family = flags->address_family; bf_xset(&sp->sp_flags, SP_FLAG_ASYMMETRIC, flags->asymmetric); + bf_xset(&sp->sp_flags, SP_FLAG_STRICT_SOURCE, flags->strict_source); + bf_xset(&sp->sp_flags, SP_FLAG_MEDIA_HANDOVER, flags->media_handover); /* a=crypto */ attr = attr_get_by_id(&media->attributes, ATTR_CRYPTO); diff --git a/utils/ng-client b/utils/ng-client index 6c41531bb..bac3c32d6 100755 --- a/utils/ng-client +++ b/utils/ng-client @@ -33,6 +33,8 @@ GetOptions( 'address-family=s' => \$options{'address family'}, 'force' => \$options{'force'}, 'v|verbose' => \$options{'verbose'}, + 'strict-source' => \$options{'strict source'}, + 'media-handover' => \$options{'media handover'}, ) or die; my $cmd = shift(@ARGV) or die; @@ -42,7 +44,7 @@ my %packet = (command => $cmd); for my $x (split(',', 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family')) { defined($options{$x}) and $packet{$x} = $options{$x}; } -for my $x (split(',', 'trust address,symmetric,asymmetric,force')) { +for my $x (split(',', 'trust address,symmetric,asymmetric,force,strict source,media handover')) { defined($options{$x}) and push(@{$packet{flags}}, $x); } for my $x (split(',', 'origin,session connection')) {