SRTP daemon<>kernel tie-in

git.mgm/mediaproxy-ng/github/master
Richard Fuchs 13 years ago
parent 02176fcb0f
commit 97f9c3d398

@ -123,6 +123,60 @@ const char *transport_protocol_strings[__PROTO_LAST] = {
static int __k_null(struct mediaproxy_srtp *s, struct streamrelay *r);
static int __k_srtp_encrypt(struct mediaproxy_srtp *s, struct streamrelay *r);
static int __k_srtp_decrypt(struct mediaproxy_srtp *s, struct streamrelay *r);
static int call_avp2savp_rtp(str *s, struct streamrelay *r);
static int call_savp2avp_rtp(str *s, struct streamrelay *r);
static int call_avp2savp_rtcp(str *s, struct streamrelay *r);
static int call_savp2avp_rtcp(str *s, struct streamrelay *r);
static int call_avpf2avp_rtcp(str *s, struct streamrelay *r);
static int call_avpf2savp_rtcp(str *s, struct streamrelay *r);
static int call_savpf2avp_rtcp(str *s, struct streamrelay *r);
static int call_savpf2savp_rtcp(str *s, struct streamrelay *r);
static const struct streamhandler __sh_noop = {
.kernel_decrypt = __k_null,
.kernel_encrypt = __k_null,
};
static const struct streamhandler __sh_rtp_avp2savp = {
.rewrite = call_avp2savp_rtp,
.kernel_decrypt = __k_null,
.kernel_encrypt = __k_srtp_encrypt,
};
static const struct streamhandler __sh_rtp_savp2avp = {
.rewrite = call_savp2avp_rtp,
.kernel_decrypt = __k_srtp_decrypt,
.kernel_encrypt = __k_null,
};
static const struct streamhandler __sh_rtcp_avp2savp = {
.rewrite = call_avp2savp_rtcp,
};
static const struct streamhandler __sh_rtcp_savp2avp = {
.rewrite = call_savp2avp_rtcp,
};
static const struct streamhandler __sh_rtcp_avpf2avp = {
.rewrite = call_avpf2avp_rtcp,
};
static const struct streamhandler __sh_rtcp_avpf2savp = {
.rewrite = call_avpf2savp_rtcp,
};
static const struct streamhandler __sh_rtcp_savpf2avp = {
.rewrite = call_savpf2avp_rtcp,
};
static const struct streamhandler __sh_rtcp_savpf2savp = {
.rewrite = call_savpf2savp_rtcp,
};
static const struct mediaproxy_srtp __mps_null = {
.cipher = MPC_NULL,
.hmac = MPH_NULL,
};
static void call_destroy(struct call *);
@ -161,7 +215,7 @@ void kernelize(struct callstream *c) {
int i, j;
struct peer *p, *pp;
struct streamrelay *r, *rp;
struct kernel_stream ks;
struct mediaproxy_target_info mpt;
struct callmaster *cm = c->call->callmaster;
if (cm->conf.kernelfd < 0 || cm->conf.kernelid == -1)
@ -169,7 +223,7 @@ void kernelize(struct callstream *c) {
mylog(LOG_DEBUG, LOG_PREFIX_C "Kernelizing RTP streams", LOG_PARAMS_C(c->call));
ZERO(ks);
ZERO(mpt);
for (i = 0; i < 2; i++) {
p = &c->peers[i];
@ -184,29 +238,40 @@ void kernelize(struct callstream *c) {
if (is_addr_unspecified(&r->peer_advertised.ip46)
|| !r->fd.fd_family || !r->peer_advertised.port)
continue;
goto no_kernel_stream;
if (!r->handler->kernel_decrypt
|| !r->handler->kernel_encrypt)
goto no_kernel_stream;
ks.local_port = r->fd.localport;
ks.tos = cm->conf.tos;
ks.src.port = rp->fd.localport;
ks.dest.port = r->peer.port;
mpt.target_port = r->fd.localport;
mpt.tos = cm->conf.tos;
mpt.src_addr.port = rp->fd.localport;
mpt.dst_addr.port = r->peer.port;
if (IN6_IS_ADDR_V4MAPPED(&r->peer.ip46)) {
ks.src.family = AF_INET;
ks.src.ipv4 = cm->conf.ipv4;
ks.dest.family = AF_INET;
ks.dest.ipv4 = r->peer.ip46.s6_addr32[3];
mpt.src_addr.family = AF_INET;
mpt.src_addr.ipv4 = cm->conf.ipv4;
mpt.dst_addr.family = AF_INET;
mpt.dst_addr.ipv4 = r->peer.ip46.s6_addr32[3];
}
else {
ks.src.family = AF_INET6;
ks.src.ipv6 = cm->conf.ipv6;
ks.dest.family = AF_INET6;
ks.dest.ipv6 = r->peer.ip46;
mpt.src_addr.family = AF_INET6;
memcpy(mpt.src_addr.ipv6, &cm->conf.ipv6, sizeof(mpt.src_addr.ipv6));
mpt.dst_addr.family = AF_INET6;
memcpy(mpt.dst_addr.ipv6, &r->peer.ip46, sizeof(mpt.src_addr.ipv6));
}
r->handler->kernel_decrypt(&mpt.decrypt, r);
r->handler->kernel_encrypt(&mpt.encrypt, r);
ZERO(r->kstats);
kernel_add_stream(cm->conf.kernelfd, &ks, 0);
kernel_add_stream(cm->conf.kernelfd, &mpt, 0);
continue;
no_kernel_stream:
r->no_kernel_support = 1;
}
p->kernelized = 1;
@ -216,10 +281,7 @@ void kernelize(struct callstream *c) {
static int __dummy_stream_handler(str *s, struct streamrelay *r) {
return 0;
}
static int call_avpf2avp(str *s, struct streamrelay *r) {
static int call_avpf2avp_rtcp(str *s, struct streamrelay *r) {
return rtcp_avpf2avp(s);
}
static int call_avp2savp_rtp(str *s, struct streamrelay *r) {
@ -260,25 +322,76 @@ static int call_savpf2savp_rtcp(str *s, struct streamrelay *r) {
}
static stream_handler determine_handler(struct streamrelay *in) {
if (in->peer.protocol == in->peer_advertised.protocol)
goto dummy;
if (in->peer_advertised.protocol == PROTO_UNKNOWN)
goto dummy;
static int __k_null(struct mediaproxy_srtp *s, struct streamrelay *r) {
*s = __mps_null;
return 0;
}
static int __k_srtp_crypt(struct mediaproxy_srtp *s, struct crypto_context *c) {
*s = (struct mediaproxy_srtp) {
.cipher = c->crypto_suite->kernel_cipher,
.hmac = c->crypto_suite->kernel_hmac,
.mki = c->mki,
.mki_len = c->mki_len,
.last_index = c->s_l,
.auth_tag_len = c->crypto_suite->srtp_auth_tag,
};
memcpy(s->master_key, c->master_key, c->crypto_suite->master_key_len);
memcpy(s->master_salt, c->master_salt, c->crypto_suite->master_salt_len);
return 0;
}
static int __k_srtp_encrypt(struct mediaproxy_srtp *s, struct streamrelay *r) {
return __k_srtp_crypt(s, &r->crypto.out);
}
static int __k_srtp_decrypt(struct mediaproxy_srtp *s, struct streamrelay *r) {
return __k_srtp_crypt(s, &r->other->crypto.in);
}
static const struct streamhandler *determine_handler_rtp(struct streamrelay *in) {
switch (in->peer.protocol) {
case PROTO_UNKNOWN:
goto dummy;
case PROTO_RTP_AVP:
case PROTO_RTP_AVPF:
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVP:
case PROTO_RTP_AVPF:
return NULL;
case PROTO_RTP_SAVP:
case PROTO_RTP_SAVPF:
return &__sh_rtp_avp2savp;
default:
abort();
}
case PROTO_RTP_SAVP:
case PROTO_RTP_SAVPF:
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVP:
case PROTO_RTP_AVPF:
return &__sh_rtp_savp2avp;
case PROTO_RTP_SAVPF:
case PROTO_RTP_SAVP:
return NULL;
default:
abort();
}
default:
abort();
}
}
static const struct streamhandler *determine_handler_rtcp(struct streamrelay *in) {
switch (in->peer.protocol) {
case PROTO_RTP_AVP:
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVPF:
goto dummy;
return NULL;
case PROTO_RTP_SAVP:
case PROTO_RTP_SAVPF:
return in->rtcp ? call_avp2savp_rtcp
: call_avp2savp_rtp;
return &__sh_rtcp_avp2savp;
default:
abort();
@ -288,11 +401,10 @@ static stream_handler determine_handler(struct streamrelay *in) {
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVP:
case PROTO_RTP_AVPF:
return in->rtcp ? call_savp2avp_rtcp
: call_savp2avp_rtp;
return &__sh_rtcp_savp2avp;
case PROTO_RTP_SAVPF:
goto dummy;
return NULL;
default:
abort();
@ -301,17 +413,14 @@ static stream_handler determine_handler(struct streamrelay *in) {
case PROTO_RTP_AVPF:
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVP:
if (!in->rtcp)
goto dummy;
return call_avpf2avp;
return &__sh_rtcp_avpf2avp;
case PROTO_RTP_SAVP:
return in->rtcp ? call_avpf2savp_rtcp
: call_avp2savp_rtp;
return &__sh_rtcp_avpf2savp;
case PROTO_RTP_SAVPF:
return in->rtcp ? call_avp2savp_rtcp
: call_avp2savp_rtp;
return &__sh_rtcp_avp2savp;
default:
abort();
}
@ -319,17 +428,13 @@ static stream_handler determine_handler(struct streamrelay *in) {
case PROTO_RTP_SAVPF:
switch (in->peer_advertised.protocol) {
case PROTO_RTP_AVP:
return in->rtcp ? call_savpf2avp_rtcp
: call_savp2avp_rtp;
return &__sh_rtcp_savpf2avp;
case PROTO_RTP_AVPF:
return in->rtcp ? call_savp2avp_rtcp
: call_savp2avp_rtp;
return &__sh_rtcp_savp2avp;
case PROTO_RTP_SAVP:
if (!in->rtcp)
goto dummy;
return call_savpf2savp_rtcp;
return &__sh_rtcp_savpf2savp;
default:
abort();
@ -338,9 +443,28 @@ static stream_handler determine_handler(struct streamrelay *in) {
default:
abort();
}
}
static const struct streamhandler *determine_handler(struct streamrelay *in) {
const struct streamhandler *ret;
if (in->peer.protocol == in->peer_advertised.protocol)
goto dummy;
if (in->peer.protocol == PROTO_UNKNOWN)
goto dummy;
if (in->peer_advertised.protocol == PROTO_UNKNOWN)
goto dummy;
if (in->rtcp)
ret = determine_handler_rtcp(in);
else
ret = determine_handler_rtp(in);
if (!ret)
goto dummy;
return ret;
dummy:
return __dummy_stream_handler;
return &__sh_noop;
}
/* called with r->up (== cs) locked */
@ -392,7 +516,8 @@ static int stream_packet(struct streamrelay *sr_incoming, str *s, struct sockadd
if (!sr_incoming->handler)
sr_incoming->handler = determine_handler(sr_incoming);
handler_ret = sr_incoming->handler(s, sr_incoming);
if (sr_incoming->handler->rewrite)
handler_ret = sr_incoming->handler->rewrite(s, sr_incoming);
use_cand:
if (p_incoming->confirmed || !p_incoming->filled || sr_incoming->idx != 0)
@ -424,7 +549,7 @@ peerinfo:
update = 1;
if (sr_incoming->handler != __dummy_stream_handler)
if (sr_incoming->no_kernel_support)
goto forward;
if (p_incoming->confirmed && p_outgoing->confirmed && p_outgoing->filled)
@ -1592,6 +1717,7 @@ static void unkernelize(struct peer *p) {
for (i = 0; i < 2; i++) {
r = &p->rtps[i];
kernel_del_stream(p->up->call->callmaster->conf.kernelfd, r->fd.localport);
r->no_kernel_support = 0;
}
p->kernelized = 0;

@ -93,7 +93,12 @@ struct udp_fd {
};
struct streamrelay;
typedef int (*stream_handler)(str *, struct streamrelay *);
struct mediaproxy_srtp;
struct streamhandler {
int (*rewrite)(str *, struct streamrelay *);
int (*kernel_decrypt)(struct mediaproxy_srtp *, struct streamrelay *);
int (*kernel_encrypt)(struct mediaproxy_srtp *, struct streamrelay *);
};
struct streamrelay {
struct udp_fd fd;
@ -105,10 +110,11 @@ struct streamrelay {
struct stats stats;
struct stats kstats;
time_t last;
stream_handler handler;
const struct streamhandler *handler;
struct crypto_context_pair crypto;
int stun:1;
int rtcp:1;
int no_kernel_support:1;
};
struct relays_cache {
struct udp_fd relays_A[16];

@ -5,6 +5,8 @@
#include <openssl/hmac.h>
#include <glib.h>
#include "xt_MEDIAPROXY.h"
#include "str.h"
#include "aux.h"
#include "rtp.h"
@ -37,8 +39,8 @@ const struct crypto_suite crypto_suites[] = {
.session_salt_len = 14,
.srtp_lifetime = 1ULL << 48,
.srtcp_lifetime = 1ULL << 31,
.cipher = CIPHER_AES_CM,
.mac = MAC_HMAC_SHA1,
.kernel_cipher = MPC_AES_CM,
.kernel_hmac = MPH_HMAC_SHA1,
.srtp_auth_tag = 10,
.srtcp_auth_tag = 10,
.srtp_auth_key_len = 20,
@ -60,8 +62,8 @@ const struct crypto_suite crypto_suites[] = {
.session_salt_len = 14,
.srtp_lifetime = 1ULL << 48,
.srtcp_lifetime = 1ULL << 31,
.cipher = CIPHER_AES_CM,
.mac = MAC_HMAC_SHA1,
.kernel_cipher = MPC_AES_CM,
.kernel_hmac = MPH_HMAC_SHA1,
.srtp_auth_tag = 4,
.srtcp_auth_tag = 10,
.srtp_auth_key_len = 20,
@ -81,8 +83,8 @@ const struct crypto_suite crypto_suites[] = {
.session_salt_len = 14,
.srtp_lifetime = 1ULL << 48,
.srtcp_lifetime = 1ULL << 31,
.cipher = CIPHER_AES_F8,
.mac = MAC_HMAC_SHA1,
.kernel_cipher = 0,
.kernel_hmac = MPH_HMAC_SHA1,
.srtp_auth_tag = 10,
.srtcp_auth_tag = 10,
.srtp_auth_key_len = 20,

@ -8,22 +8,6 @@
/* XXX get rid of the enums and replace with struct pointers? */
enum cipher {
CIPHER_UNKNOWN = 0,
CIPHER_AES_CM,
CIPHER_AES_F8,
__CIPHER_LAST
};
enum mac {
MAC_UNKNOWN = 0,
MAC_HMAC_SHA1,
__MAC_LAST
};
struct crypto_context;
struct rtp_header;
struct rtcp_packet;
@ -49,8 +33,8 @@ struct crypto_suite {
unsigned long long int
srtp_lifetime,
srtcp_lifetime;
enum cipher cipher;
enum mac mac;
int kernel_cipher;
int kernel_hmac;
crypto_func_rtp encrypt_rtp,
decrypt_rtp;
crypto_func_rtcp encrypt_rtcp,

@ -7,10 +7,12 @@
#include <fcntl.h>
#include <unistd.h>
#include <glib.h>
#include <errno.h>
#include "xt_MEDIAPROXY.h"
#include "aux.h"
#include "log.h"
@ -72,50 +74,36 @@ fail:
}
static void addr_copy(struct mp_address *mp, struct ip_port *ap) {
mp->family = ap->family;
mp->port = ap->port;
switch (mp->family) {
case AF_INET:
mp->ipv4 = ap->ipv4;
break;
case AF_INET6:
memcpy(mp->ipv6, &ap->ipv6, 16);
break;
default:
/* XXX panic */
break;
}
}
int kernel_add_stream(int fd, struct kernel_stream *info, int update) {
int kernel_add_stream(int fd, struct mediaproxy_target_info *mti, int update) {
struct mediaproxy_message msg;
int ret;
ZERO(msg);
msg.cmd = update ? MMG_UPDATE : MMG_ADD;
msg.target.target_port = info->local_port;
addr_copy(&msg.target.src_addr, &info->src);
addr_copy(&msg.target.dst_addr, &info->dest);
addr_copy(&msg.target.mirror_addr, &info->mirror);
msg.target.tos = info->tos;
msg.target.decrypt.cipher = MPC_NULL;
msg.target.decrypt.hmac = MPH_NULL;
msg.target.encrypt.cipher = MPC_NULL;
msg.target.encrypt.hmac = MPH_NULL;
return write(fd, &msg, sizeof(msg)) <= 0 ? -1 : 0;
msg.target = *mti;
ret = write(fd, &msg, sizeof(msg));
if (ret > 0)
return 0;
mylog(LOG_ERROR, "Failed to push relay stream to kernel: %s", strerror(errno));
return -1;
}
int kernel_del_stream(int fd, u_int16_t p) {
struct mediaproxy_message msg;
int ret;
ZERO(msg);
msg.cmd = MMG_DEL;
msg.target.target_port = p;
return write(fd, &msg, sizeof(msg)) <= 0 ? -1 : 0;
ret = write(fd, &msg, sizeof(msg));
if (ret > 0)
return 0;
mylog(LOG_ERROR, "Failed to delete relay stream from kernel: %s", strerror(errno));
return -1;
}

@ -10,30 +10,14 @@
struct ip_port {
int family;
union {
u_int32_t ipv4;
struct in6_addr ipv6;
};
u_int16_t port;
};
struct kernel_stream {
u_int16_t local_port;
struct ip_port src;
struct ip_port dest;
struct ip_port mirror;
unsigned char tos;
};
struct mediaproxy_target_info;
int kernel_create_table(unsigned int);
int kernel_open_table(unsigned int);
int kernel_add_stream(int, struct kernel_stream *, int);
int kernel_add_stream(int, struct mediaproxy_target_info *, int);
int kernel_del_stream(int, u_int16_t);
GList *kernel_list(unsigned int);

@ -809,18 +809,29 @@ static void proc_list_addr_print(struct seq_file *f, const char *s, const struct
}
}
static void proc_list_crypto_print(struct seq_file *f, struct mp_crypto_context *c, struct mediaproxy_srtp *s) {
seq_printf(f, " cipher: %s\n", c->cipher ? c->cipher->name : "<null>");
seq_printf(f, " MKI: %llu length %u\n", (unsigned long long) s->mki, s->mki_len);
seq_printf(f, " HMAC: %s\n", c->hmac ? c->hmac->name : "<null>");
seq_printf(f, " auth tag length: %u\n", s->auth_tag_len);
}
static int proc_list_show(struct seq_file *f, void *v) {
struct mediaproxy_target *g = v;
unsigned long flags;
spin_lock_irqsave(&g->stats_lock, flags);
seq_printf(f, "port %5u:\n", g->target.target_port);
proc_list_addr_print(f, "src", &g->target.src_addr);
proc_list_addr_print(f, "dst", &g->target.dst_addr);
proc_list_addr_print(f, "mirror", &g->target.mirror_addr);
spin_lock_irqsave(&g->stats_lock, flags);
seq_printf(f, " stats: %20llu bytes, %20llu packets, %20llu errors\n",
g->stats.bytes, g->stats.packets, g->stats.errors);
spin_unlock_irqrestore(&g->stats_lock, flags);
seq_printf(f, " SRTP in:\n");
proc_list_crypto_print(f, &g->decrypt, &g->target.decrypt);
seq_printf(f, " SRTP out:\n");
proc_list_crypto_print(f, &g->encrypt, &g->target.encrypt);
target_push(g);

Loading…
Cancel
Save