|
|
|
@ -33,6 +33,7 @@ MODULE_LICENSE("GPL"); |
|
|
|
|
|
|
|
|
|
|
|
#define MAX_ID 64 /* - 1 */ |
|
|
|
#define MAX_SKB_TAIL_ROOM (128 + 20) |
|
|
|
|
|
|
|
#define MIPF "%i:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x:%u" |
|
|
|
#define MIPP(x) (x).family, \ |
|
|
|
@ -1552,23 +1553,23 @@ static int parse_rtp(struct rtp_parsed *rtp, struct sk_buff *skb) { |
|
|
|
memset(rtp, 0, sizeof(*rtp)); |
|
|
|
|
|
|
|
if (skb->len < sizeof(*rtp->header)) |
|
|
|
return -1; |
|
|
|
goto error; |
|
|
|
rtp->header = (void *) skb->data; |
|
|
|
if ((rtp->header->v_p_x_cc & 0xc0) != 0x80) /* version 2 */ |
|
|
|
return -1; |
|
|
|
goto error; |
|
|
|
rtp->header_len = sizeof(*rtp->header); |
|
|
|
|
|
|
|
/* csrc list */ |
|
|
|
rtp->header_len += (rtp->header->v_p_x_cc & 0xf) * 4; |
|
|
|
if (skb->len < rtp->header_len) |
|
|
|
return -1; |
|
|
|
goto error; |
|
|
|
rtp->payload = skb->data + rtp->header_len; |
|
|
|
rtp->payload_len = skb->len - rtp->header_len; |
|
|
|
|
|
|
|
if ((rtp->header->v_p_x_cc & 0x10)) { |
|
|
|
/* extension */ |
|
|
|
if (rtp->payload_len < sizeof(*ext)) |
|
|
|
return -1; |
|
|
|
goto error; |
|
|
|
ext = (void *) rtp->payload; |
|
|
|
ext_len = 4 + ntohs(ext->length) * 4; |
|
|
|
if (rtp->payload_len < ext_len) |
|
|
|
@ -1580,6 +1581,10 @@ static int parse_rtp(struct rtp_parsed *rtp, struct sk_buff *skb) { |
|
|
|
DBG("rtp header parsed, payload length is %u\n", rtp->payload_len); |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
error: |
|
|
|
memset(rtp, 0, sizeof(*rtp)); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
/* XXX shared code */ |
|
|
|
@ -1623,31 +1628,13 @@ static u_int64_t packet_index(struct mp_crypto_context *c, |
|
|
|
return index; |
|
|
|
} |
|
|
|
|
|
|
|
static int srtp_auth_validate(struct mp_crypto_context *c, |
|
|
|
static int srtp_hash(unsigned char *hmac, |
|
|
|
struct mp_crypto_context *c, |
|
|
|
struct mediaproxy_srtp *s, struct rtp_parsed *r, |
|
|
|
u_int64_t pkt_idx) |
|
|
|
{ |
|
|
|
unsigned char *auth_tag; |
|
|
|
unsigned char hmac[20]; |
|
|
|
struct shash_desc *dsc; |
|
|
|
u_int32_t roc; |
|
|
|
|
|
|
|
if (s->hmac == MPH_NULL) |
|
|
|
return 0; |
|
|
|
if (!c->hmac) |
|
|
|
return 0; |
|
|
|
if (!c->shash) |
|
|
|
return -1; |
|
|
|
|
|
|
|
if (r->payload_len < s->auth_tag_len) |
|
|
|
return -1; |
|
|
|
|
|
|
|
r->payload_len -= s->auth_tag_len; |
|
|
|
auth_tag = r->payload + r->payload_len; |
|
|
|
|
|
|
|
if (r->payload_len < s->mki_len) |
|
|
|
return -1; |
|
|
|
r->payload_len -= s->mki_len; |
|
|
|
struct shash_desc *dsc; |
|
|
|
|
|
|
|
if (!s->auth_tag_len) |
|
|
|
return 0; |
|
|
|
@ -1677,20 +1664,108 @@ static int srtp_auth_validate(struct mp_crypto_context *c, |
|
|
|
hmac[8], hmac[9], hmac[10], hmac[11], |
|
|
|
hmac[12], hmac[13], hmac[14], hmac[15], |
|
|
|
hmac[16], hmac[17], hmac[18], hmac[19]); |
|
|
|
DBG("packet auth tag %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
error: |
|
|
|
kfree(dsc); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
/* XXX shared code */ |
|
|
|
static void rtp_append_mki(struct rtp_parsed *r, struct mediaproxy_srtp *c) { |
|
|
|
u_int32_t mki_part; |
|
|
|
unsigned char *p; |
|
|
|
|
|
|
|
if (!c->mki_len) |
|
|
|
return; |
|
|
|
|
|
|
|
p = r->payload + r->payload_len; |
|
|
|
memset(p, 0, c->mki_len); |
|
|
|
if (c->mki_len > 4) { |
|
|
|
mki_part = (c->mki & 0xffffffff00000000ULL) >> 32; |
|
|
|
mki_part = htonl(mki_part); |
|
|
|
if (c->mki_len < 8) |
|
|
|
memcpy(p, ((char *) &mki_part) + (8 - c->mki_len), c->mki_len - 4); |
|
|
|
else |
|
|
|
memcpy(p + (c->mki_len - 8), &mki_part, 4); |
|
|
|
} |
|
|
|
mki_part = (c->mki & 0xffffffffULL); |
|
|
|
mki_part = htonl(mki_part); |
|
|
|
if (c->mki_len < 4) |
|
|
|
memcpy(p, ((char *) &mki_part) + (4 - c->mki_len), c->mki_len); |
|
|
|
else |
|
|
|
memcpy(p + (c->mki_len - 4), &mki_part, 4); |
|
|
|
|
|
|
|
r->payload_len += c->mki_len; |
|
|
|
} |
|
|
|
|
|
|
|
static int srtp_authenticate(struct mp_crypto_context *c, |
|
|
|
struct mediaproxy_srtp *s, struct rtp_parsed *r, |
|
|
|
u_int64_t pkt_idx) |
|
|
|
{ |
|
|
|
unsigned char hmac[20]; |
|
|
|
|
|
|
|
if (!r->header) |
|
|
|
return 0; |
|
|
|
if (s->hmac == MPH_NULL) |
|
|
|
return 0; |
|
|
|
if (!c->hmac) |
|
|
|
return 0; |
|
|
|
if (!c->shash) |
|
|
|
return -1; |
|
|
|
|
|
|
|
if (srtp_hash(hmac, c, s, r, pkt_idx)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
rtp_append_mki(r, s); |
|
|
|
|
|
|
|
memcpy(r->payload + r->payload_len, hmac, s->auth_tag_len); |
|
|
|
r->payload_len += s->auth_tag_len; |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int srtp_auth_validate(struct mp_crypto_context *c, |
|
|
|
struct mediaproxy_srtp *s, struct rtp_parsed *r, |
|
|
|
u_int64_t pkt_idx) |
|
|
|
{ |
|
|
|
unsigned char *auth_tag; |
|
|
|
unsigned char hmac[20]; |
|
|
|
|
|
|
|
if (s->hmac == MPH_NULL) |
|
|
|
return 0; |
|
|
|
if (!c->hmac) |
|
|
|
return 0; |
|
|
|
if (!c->shash) |
|
|
|
return -1; |
|
|
|
|
|
|
|
if (r->payload_len < s->auth_tag_len) |
|
|
|
return -1; |
|
|
|
|
|
|
|
r->payload_len -= s->auth_tag_len; |
|
|
|
auth_tag = r->payload + r->payload_len; |
|
|
|
|
|
|
|
if (r->payload_len < s->mki_len) |
|
|
|
return -1; |
|
|
|
r->payload_len -= s->mki_len; |
|
|
|
|
|
|
|
if (!s->auth_tag_len) |
|
|
|
return 0; |
|
|
|
|
|
|
|
DBG("packet auth tag %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", |
|
|
|
auth_tag[0], auth_tag[1], auth_tag[2], auth_tag[3], |
|
|
|
auth_tag[4], auth_tag[5], auth_tag[6], auth_tag[7], |
|
|
|
auth_tag[8], auth_tag[9], auth_tag[10], auth_tag[11], |
|
|
|
auth_tag[12], auth_tag[13], auth_tag[14], auth_tag[15], |
|
|
|
auth_tag[16], auth_tag[17], auth_tag[18], auth_tag[19]); |
|
|
|
auth_tag[8], auth_tag[9]); |
|
|
|
|
|
|
|
if (srtp_hash(hmac, c, s, r, pkt_idx)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
if (memcmp(auth_tag, hmac, s->auth_tag_len)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
error: |
|
|
|
kfree(dsc); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1729,6 +1804,8 @@ static inline int srtp_encrypt(struct mp_crypto_context *c, |
|
|
|
struct mediaproxy_srtp *s, struct rtp_parsed *r, |
|
|
|
u_int64_t pkt_idx) |
|
|
|
{ |
|
|
|
if (!r->header) |
|
|
|
return 0; |
|
|
|
if (!c->cipher->encrypt) |
|
|
|
return 0; |
|
|
|
return c->cipher->encrypt(c, s, r, pkt_idx); |
|
|
|
@ -1819,6 +1896,10 @@ not_rtp: |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
err = send_proxy_packet(skb, &g->target.src_addr, &g->target.dst_addr, g->target.tos); |
|
|
|
|
|
|
|
spin_lock_irqsave(&g->stats_lock, flags); |
|
|
|
@ -1857,17 +1938,12 @@ static unsigned int mediaproxy4(struct sk_buff *oskb, const struct xt_action_par |
|
|
|
struct sk_buff *skb; |
|
|
|
struct iphdr *ih; |
|
|
|
struct mediaproxy_table *t; |
|
|
|
int headroom; |
|
|
|
|
|
|
|
t = get_table(pinfo->id); |
|
|
|
if (!t) |
|
|
|
goto skip; |
|
|
|
|
|
|
|
headroom = MAX_HEADER - sizeof(*ih); |
|
|
|
if (skb_headroom(oskb) >= headroom) |
|
|
|
skb = skb_copy(oskb, GFP_ATOMIC); |
|
|
|
else |
|
|
|
skb = skb_copy_expand(oskb, headroom, 0, GFP_ATOMIC); |
|
|
|
skb = skb_copy_expand(oskb, MAX_HEADER, MAX_SKB_TAIL_ROOM, GFP_ATOMIC); |
|
|
|
if (!skb) |
|
|
|
goto skip3; |
|
|
|
|
|
|
|
@ -1899,17 +1975,12 @@ static unsigned int mediaproxy6(struct sk_buff *oskb, const struct xt_action_par |
|
|
|
struct sk_buff *skb; |
|
|
|
struct ipv6hdr *ih; |
|
|
|
struct mediaproxy_table *t; |
|
|
|
int headroom; |
|
|
|
|
|
|
|
t = get_table(pinfo->id); |
|
|
|
if (!t) |
|
|
|
goto skip; |
|
|
|
|
|
|
|
headroom = MAX_HEADER - sizeof(*ih); |
|
|
|
if (skb_headroom(oskb) >= headroom) |
|
|
|
skb = skb_copy(oskb, GFP_ATOMIC); |
|
|
|
else |
|
|
|
skb = skb_copy_expand(oskb, headroom, 0, GFP_ATOMIC); |
|
|
|
skb = skb_copy_expand(oskb, MAX_HEADER, MAX_SKB_TAIL_ROOM, GFP_ATOMIC); |
|
|
|
if (!skb) |
|
|
|
goto skip3; |
|
|
|
|
|
|
|
|