Browse Source

Merge branch 'marcantonio-ssrc-seq'

pull/114/head
Richard Fuchs 11 years ago
parent
commit
6001a4411e
8 changed files with 169 additions and 62 deletions
  1. +8
    -0
      daemon/aux.c
  2. +2
    -0
      daemon/aux.h
  3. +5
    -3
      daemon/call.c
  4. +39
    -3
      daemon/crypto.h
  5. +59
    -29
      daemon/rtp.c
  6. +34
    -25
      kernel-module/xt_RTPENGINE.c
  7. +1
    -0
      kernel-module/xt_RTPENGINE.h
  8. +21
    -2
      tests/simulator-ng.pl

+ 8
- 0
daemon/aux.c View File

@ -212,3 +212,11 @@ int g_tree_find_all_cmp(void *k, void *v, void *d) {
g_queue_push_tail(q, v);
return FALSE;
}
unsigned int uint32_hash(const void *p) {
const u_int32_t *a = p;
return *a;
}
int uint32_eq(const void *a, const void *b) {
const u_int32_t *A = a, *B = b;
return (*A == *B) ? TRUE : FALSE;
}

+ 2
- 0
daemon/aux.h View File

@ -67,6 +67,8 @@ INLINE void strdupfree(char **, const char *);
char *get_thread_buf(void);
unsigned int in6_addr_hash(const void *p);
int in6_addr_eq(const void *a, const void *b);
unsigned int uint32_hash(const void *p);
int uint32_eq(const void *a, const void *b);


+ 5
- 3
daemon/call.c View File

@ -161,7 +161,6 @@ static int call_avpf2avp_rtcp(str *s, struct packet_stream *);
static int call_savpf2avp_rtcp(str *s, struct packet_stream *);
//static int call_savpf2savp_rtcp(str *s, struct packet_stream *);
/* ********** */
static const struct streamhandler_io __shio_noop = {
@ -435,6 +434,7 @@ void kernelize(struct packet_stream *stream) {
reti.src_addr.family = reti.dst_addr.family;
reti.src_addr.port = sink->sfd->fd.localport;
reti.ssrc = sink->crypto.ssrc;
ifa = g_atomic_pointer_get(&sink->media->local_address);
if (reti.src_addr.family == AF_INET)
@ -764,14 +764,16 @@ loop_ok:
mutex_lock(&out_srtp->out_lock);
/* return values are: 0 = forward packet, -1 = error/dont forward,
* 1 = forward and push update to redis */
* 1 = forward and push update to redis and kernel */
if (rwf_in)
handler_ret = rwf_in(s, in_srtp);
if (handler_ret >= 0 && rwf_out)
handler_ret += rwf_out(s, out_srtp);
if (handler_ret > 0)
if (handler_ret > 0) {
__unkernelize(stream);
update = 1;
}
mutex_unlock(&out_srtp->out_lock);
mutex_unlock(&in_srtp->in_lock);


+ 39
- 3
daemon/crypto.h View File

@ -7,6 +7,7 @@
#include <glib.h>
#include "compat.h"
#include "str.h"
#include "aux.h"
@ -86,12 +87,15 @@ struct crypto_context {
/* <from, to>? */
void *session_key_ctx[2];
GHashTable *ssrc_hash;
int have_session_key:1;
};
struct rtp_ssrc_entry {
u_int32_t ssrc;
u_int64_t index;
};
extern const struct crypto_suite crypto_suites[];
extern const int num_crypto_suites;
@ -102,7 +106,11 @@ const struct crypto_suite *crypto_find_suite(const str *);
int crypto_gen_session_key(struct crypto_context *, str *, unsigned char, int);
void crypto_dump_keys(struct crypto_context *in, struct crypto_context *out);
INLINE struct rtp_ssrc_entry *find_ssrc(u_int32_t, GHashTable *);
INLINE void add_ssrc_entry(struct rtp_ssrc_entry *, GHashTable *);
INLINE struct rtp_ssrc_entry *create_ssrc_entry(u_int32_t, u_int64_t);
INLINE void free_ssrc_table(GHashTable **);
INLINE GHashTable *create_ssrc_table(void);
INLINE int crypto_encrypt_rtp(struct crypto_context *c, struct rtp_header *rtp,
@ -136,6 +144,7 @@ INLINE void crypto_params_cleanup(struct crypto_params *p) {
}
INLINE void crypto_cleanup(struct crypto_context *c) {
crypto_params_cleanup(&c->params);
free_ssrc_table(&c->ssrc_hash);
if (!c->params.crypto_suite)
return;
if (c->params.crypto_suite->session_key_cleanup)
@ -190,4 +199,31 @@ INLINE int crypto_params_cmp(const struct crypto_params *a, const struct crypto_
INLINE struct rtp_ssrc_entry *find_ssrc(u_int32_t ssrc, GHashTable *ht) {
return g_hash_table_lookup(ht, &ssrc);
}
INLINE void add_ssrc_entry(struct rtp_ssrc_entry *ent, GHashTable *ht) {
g_hash_table_insert(ht, &ent->ssrc, ent);
}
INLINE struct rtp_ssrc_entry *create_ssrc_entry(u_int32_t ssrc, u_int64_t index) {
struct rtp_ssrc_entry *ent;
ent = g_slice_alloc(sizeof(struct rtp_ssrc_entry));
ent->ssrc = ssrc;
ent->index = index;
return ent;
}
INLINE void free_ssrc_table(GHashTable **ht) {
if (!*ht)
return;
g_hash_table_destroy(*ht);
*ht = NULL;
}
INLINE void free_ssrc_entry(void *p) {
g_slice_free1(sizeof(struct rtp_ssrc_entry), p);
}
INLINE GHashTable *create_ssrc_table(void) {
return g_hash_table_new_full(uint32_hash, uint32_eq, free_ssrc_entry, NULL);
}
#endif

+ 59
- 29
daemon/rtp.c View File

@ -137,8 +137,6 @@ error:
static u_int64_t packet_index(struct crypto_context *c, struct rtp_header *rtp) {
u_int16_t seq;
u_int64_t index;
long long int diff;
seq = ntohs(rtp->seq_num);
/* rfc 3711 section 3.3.1 */
@ -146,24 +144,24 @@ static u_int64_t packet_index(struct crypto_context *c, struct rtp_header *rtp)
c->last_index = seq;
/* rfc 3711 appendix A, modified, and sections 3.3 and 3.3.1 */
index = (c->last_index & 0xffffffff0000ULL) | seq;
diff = index - c->last_index;
if (diff >= 0) {
if (diff < 0x8000)
c->last_index = index;
else if (index >= 0x10000)
index -= 0x10000;
}
else {
if (diff >= -0x8000)
;
else {
index += 0x10000;
c->last_index = index;
}
u_int16_t s_l = (c->last_index & 0x00000000ffffULL);
u_int32_t roc = (c->last_index & 0xffffffff0000ULL) >> 16;
u_int32_t v = 0;
if (s_l < 0x8000) {
if (((seq - s_l) > 0x8000) && roc > 0)
v = (roc - 1) % 0x10000;
else
v = roc;
} else {
if ((s_l - 0x8000) > seq)
v = (roc + 1) % 0x10000;
else
v = roc;
}
return index;
c->last_index = (u_int64_t)(((v << 16) | seq) & 0xffffffffffffULL);
return c->last_index;
}
void rtp_append_mki(str *s, struct crypto_context *c) {
@ -178,29 +176,59 @@ void rtp_append_mki(str *s, struct crypto_context *c) {
s->len += c->params.mki_len;
}
static int rtp_ssrc_check(const struct rtp_header *rtp, struct crypto_context *c) {
struct rtp_ssrc_entry *cur_ssrc;
/* check last known SSRC */
if (G_LIKELY(rtp->ssrc == c->ssrc))
return 0;
if (!c->ssrc) {
c->ssrc = rtp->ssrc;
return 1;
}
/* SSRC mismatch. stash away last know info */
ilog(LOG_DEBUG, "SSRC changed, updating SRTP crypto contexts");
if (G_UNLIKELY(!c->ssrc_hash))
c->ssrc_hash = create_ssrc_table();
// Find the entry for the last SSRC.
cur_ssrc = find_ssrc(c->ssrc, c->ssrc_hash);
// If it doesn't exist, create a new entry.
if (G_UNLIKELY(!cur_ssrc)) {
cur_ssrc = create_ssrc_entry(c->ssrc, c->last_index);
add_ssrc_entry(cur_ssrc, c->ssrc_hash);
}
else
cur_ssrc->index = c->last_index;
// New SSRC, set the crypto context.
c->ssrc = rtp->ssrc;
cur_ssrc = find_ssrc(rtp->ssrc, c->ssrc_hash);
if (G_UNLIKELY(!cur_ssrc))
c->last_index = 0;
else
c->last_index = cur_ssrc->index;
return 1;
}
/* rfc 3711, section 3.3 */
int rtp_avp2savp(str *s, struct crypto_context *c) {
struct rtp_header *rtp;
str payload, to_auth;
u_int64_t index;
int ret = 0;
if (rtp_payload(&rtp, &payload, s))
return -1;
if (check_session_keys(c))
return -1;
/* SSRC is part of the crypto context and ROC must be reset when it changes */
if (G_UNLIKELY(!c->ssrc))
c->ssrc = rtp->ssrc;
else if (G_UNLIKELY(c->ssrc != rtp->ssrc)) {
c->last_index = 0;
c->ssrc = rtp->ssrc;
}
ret = rtp_ssrc_check(rtp, c);
index = packet_index(c, rtp);
/* rfc 3711 section 3.1 */
if (!c->params.session_params.unencrypted_srtp && crypto_encrypt_rtp(c, rtp, &payload, index))
return -1;
@ -213,7 +241,7 @@ int rtp_avp2savp(str *s, struct crypto_context *c) {
s->len += c->params.crypto_suite->srtp_auth_tag;
}
return 0;
return ret;
}
/* rfc 3711, section 3.3 */
@ -222,12 +250,14 @@ int rtp_savp2avp(str *s, struct crypto_context *c) {
u_int64_t index;
str payload, to_auth, to_decrypt, auth_tag;
char hmac[20];
int ret = 0;
if (rtp_payload(&rtp, &payload, s))
return -1;
if (check_session_keys(c))
return -1;
ret = rtp_ssrc_check(rtp, c);
index = packet_index(c, rtp);
if (srtp_payloads(&to_auth, &to_decrypt, &auth_tag, NULL,
c->params.session_params.unauthenticated_srtp ? 0 : c->params.crypto_suite->srtp_auth_tag,
@ -271,7 +301,7 @@ decrypt:
*s = to_auth;
return 0;
return ret;
error:
ilog(LOG_WARNING | LOG_FLAG_LIMIT, "Discarded invalid SRTP packet: authentication failed");


+ 34
- 25
kernel-module/xt_RTPENGINE.c View File

@ -1888,8 +1888,10 @@ static u_int64_t packet_index(struct re_crypto_context *c,
{
u_int16_t seq;
u_int64_t index;
long long int diff;
unsigned long flags;
u_int16_t s_l;
u_int32_t roc;
u_int32_t v;
seq = ntohs(rtp->seq_num);
@ -1900,24 +1902,26 @@ static u_int64_t packet_index(struct re_crypto_context *c,
s->last_index = seq;
/* rfc 3711 appendix A, modified, and sections 3.3 and 3.3.1 */
index = ((u_int64_t) c->roc << 16) | seq;
diff = index - s->last_index;
if (diff >= 0) {
if (diff < 0x8000)
s->last_index = index;
else if (index >= 0x10000)
index -= 0x10000;
}
else {
if (diff >= -0x8000)
;
else {
index += 0x10000;
c->roc++;
s->last_index = index;
}
s_l = (s->last_index & 0x00000000ffffULL);
roc = (s->last_index & 0xffffffff0000ULL) >> 16;
v = 0;
if (s_l < 0x8000) {
if (((seq - s_l) > 0x8000) && roc > 0)
v = (roc - 1) % 0x10000;
else
v = roc;
} else {
if ((s_l - 0x8000) > seq)
v = (roc + 1) % 0x10000;
else
v = roc;
}
index = (v << 16) | seq;
s->last_index = index;
c->roc = v;
spin_unlock_irqrestore(&c->lock, flags);
return index;
@ -2060,26 +2064,28 @@ static int srtp_auth_validate(struct re_crypto_context *c,
if (srtp_hash(hmac, c, s, r, pkt_idx))
return -1;
if (!memcmp(auth_tag, hmac, s->auth_tag_len))
goto ok;
goto ok_update;
/* or maybe we did a rollover too many */
if (pkt_idx >= 0x20000) {
pkt_idx -= 0x20000;
if (srtp_hash(hmac, c, s, r, pkt_idx))
return -1;
if (!memcmp(auth_tag, hmac, s->auth_tag_len))
goto ok;
goto ok_update;
}
/* last guess: reset ROC to zero */
pkt_idx &= 0xffff;
if (srtp_hash(hmac, c, s, r, pkt_idx))
return -1;
if (!memcmp(auth_tag, hmac, s->auth_tag_len))
goto ok;
goto ok_update;
return -1;
ok:
ok_update:
*pkt_idx_p = pkt_idx;
update_packet_index(c, s, pkt_idx);
ok:
return 0;
}
@ -2192,7 +2198,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t,
unsigned int datalen;
u_int32_t *u32;
struct rtp_parsed rtp;
u_int64_t pkt_idx = 0, pkt_idx_u;
u_int64_t pkt_idx;
skb_reset_transport_header(skb);
uh = udp_hdr(skb);
@ -2264,11 +2270,13 @@ src_check_ok:
rtp_pt_idx = rtp_payload_type(rtp.header, &g->target);
pkt_idx_u = pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header);
// Pass to userspace if SSRC has changed.
if (unlikely((g->target.ssrc) && (g->target.ssrc != rtp.header->ssrc)))
goto skip_error;
pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header);
if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp, &pkt_idx))
goto skip_error;
if (pkt_idx != pkt_idx_u)
update_packet_index(&g->decrypt, &g->target.decrypt, pkt_idx);
if (srtp_decrypt(&g->decrypt, &g->target.decrypt, &rtp, pkt_idx))
goto skip_error;
@ -2291,6 +2299,7 @@ not_rtp:
}
if (rtp.ok) {
pkt_idx = packet_index(&g->encrypt, &g->target.encrypt, rtp.header);
srtp_encrypt(&g->encrypt, &g->target.encrypt, &rtp, pkt_idx);
skb_put(skb, g->target.encrypt.mki_len + g->target.encrypt.auth_tag_len);
srtp_authenticate(&g->encrypt, &g->target.encrypt, &rtp, pkt_idx);


+ 1
- 0
kernel-module/xt_RTPENGINE.h View File

@ -82,6 +82,7 @@ struct rtpengine_target_info {
struct rtpengine_srtp decrypt;
struct rtpengine_srtp encrypt;
u_int32_t ssrc; // Expose the SSRC to userspace when we resync.
unsigned char payload_types[NUM_PAYLOAD_TYPES]; /* must be sorted */
unsigned int num_payload_types;


+ 21
- 2
tests/simulator-ng.pl View File

@ -17,7 +17,8 @@ use SRTP;
my ($NUM, $RUNTIME, $STREAMS, $PAYLOAD, $INTERVAL, $RTCP_INTERVAL, $STATS_INTERVAL)
= (1000, 30, 1, 160, 20, 5, 5);
my ($NODEL, $IP, $IPV6, $KEEPGOING, $REINVITES, $PROTOS, $DEST, $SUITES, $NOENC, $RTCPMUX, $BUNDLE, $LAZY);
my ($NODEL, $IP, $IPV6, $KEEPGOING, $REINVITES, $PROTOS, $DEST, $SUITES, $NOENC, $RTCPMUX, $BUNDLE, $LAZY,
$CHANGE_SSRC);
GetOptions(
'no-delete' => \$NODEL,
'num-calls=i' => \$NUM,
@ -38,6 +39,7 @@ GetOptions(
'rtcp-mux' => \$RTCPMUX,
'bundle' => \$BUNDLE,
'lazy-params' => \$LAZY,
'change-ssrc' => \$CHANGE_SSRC,
) or die;
($IP || $IPV6) or die("at least one of --local-ip or --local-ipv6 must be given");
@ -154,6 +156,7 @@ sub rtp_encrypt {
my ($pkt, $roc) = SRTP::encrypt_rtp(@$dctx{qw(crypto_suite rtp_session_key rtp_session_salt
rtp_session_auth_key rtp_roc rtp_mki rtp_mki_len unenc_srtp unauth_srtp)}, $r);
$roc == ($$dctx{rtp_roc} // 0) or print("ROC is now $roc\n");
$$dctx{rtp_roc} = $roc;
$NOENC{rtp_packet} = $pkt;
@ -271,9 +274,10 @@ sub rtcp_savpf {
sub rtp {
my ($ctx) = @_;
my $ssrc = $$ctx{ssrc} // ($$ctx{ssrc} = rand(2**32));
my $seq = $$ctx{rtp_seqnum};
defined($seq) or $seq = int(rand(0xfffe)) + 1;
my $hdr = pack("CCnNN", 0x80, 0x00, $seq, rand(2**32), rand(2**32));
my $hdr = pack("CCnNN", 0x80, 0x00, $seq, rand(2**32), $ssrc);
my $pack = $hdr . rand_str($PAYLOAD);
$$ctx{rtp_seqnum} = (++$seq & 0xffff);
return $pack;
@ -777,6 +781,21 @@ while (time() < $end) {
offer($c, 0, 1);
answer($c, 1, 0);
}
if ($CHANGE_SSRC && rand() < .001) {
my $c = $calls[rand(@calls)];
my $s = $$c{sides}[rand(2)];
my $st = rand($$s{num_streams});
my $d = (qw(in out))[rand(2)];
my $stc = $$s{trans_contexts}[$st];
my $ct = $$stc{$d};
if (defined($$ct{rtp_roc}) && $$stc{ssrc}) {
my $nssrc = rand(2 ** 32);
print("change SSRC from $$stc{ssrc} to $nssrc\n");
$$stc{ssrc} = $nssrc;
$$ct{roc} = 0;
}
}
}
if (!$NODEL) {


Loading…
Cancel
Save