|
|
|
@ -3542,6 +3542,22 @@ out: |
|
|
|
return err; |
|
|
|
} |
|
|
|
|
|
|
|
// returns: -1 = no SSRCs were given, -2 = SSRCs were given but SSRC not found |
|
|
|
static int target_find_ssrc(struct rtpengine_target *g, uint32_t ssrc) { |
|
|
|
int ssrc_idx; |
|
|
|
|
|
|
|
if (unlikely(!g->target.ssrc[0])) |
|
|
|
return -1; |
|
|
|
|
|
|
|
for (ssrc_idx = 0; ssrc_idx < RTPE_NUM_SSRC_TRACKING; ssrc_idx++) { |
|
|
|
if (!g->target.ssrc[ssrc_idx]) |
|
|
|
break; |
|
|
|
if (g->target.ssrc[ssrc_idx] == ssrc) |
|
|
|
return ssrc_idx; |
|
|
|
} |
|
|
|
return -2; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -4033,7 +4049,7 @@ static uint64_t packet_index(struct re_crypto_context *c, |
|
|
|
uint32_t roc; |
|
|
|
uint32_t v; |
|
|
|
|
|
|
|
if (ssrc_idx == -1) |
|
|
|
if (ssrc_idx < 0) |
|
|
|
ssrc_idx = 0; |
|
|
|
|
|
|
|
seq = ntohs(rtp->seq_num); |
|
|
|
@ -4075,7 +4091,7 @@ static void update_packet_index(struct re_crypto_context *c, |
|
|
|
{ |
|
|
|
unsigned long flags; |
|
|
|
|
|
|
|
if (ssrc_idx == -1) |
|
|
|
if (ssrc_idx < 0) |
|
|
|
ssrc_idx = 0; |
|
|
|
|
|
|
|
spin_lock_irqsave(&c->lock, flags); |
|
|
|
@ -4456,6 +4472,24 @@ static inline int is_muxed_rtcp(struct sk_buff *skb) { |
|
|
|
return 0; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
static inline int is_stun(struct rtpengine_target *g, unsigned int datalen, unsigned char *skb_data) { |
|
|
|
uint32_t *u32; |
|
|
|
if (!g->target.stun) |
|
|
|
return 0; |
|
|
|
if (datalen < 28) |
|
|
|
return 0; |
|
|
|
if ((datalen & 0x3)) |
|
|
|
return 0; |
|
|
|
u32 = (void *) skb_data; |
|
|
|
if (u32[1] != htonl(0x2112A442UL)) /* magic cookie */ |
|
|
|
return 0; |
|
|
|
if ((u32[0] & htonl(0xc0000003UL))) /* zero bits required by rfc */ |
|
|
|
return 0; |
|
|
|
u32 = (void *) &skb_data[datalen - 8]; |
|
|
|
if (u32[0] != htonl(0x80280004UL)) /* required fingerprint attribute */ |
|
|
|
return 0; |
|
|
|
return 1; // probably STUN |
|
|
|
} |
|
|
|
|
|
|
|
static inline int is_dtls(struct sk_buff *skb) { |
|
|
|
if (skb->len < 1) |
|
|
|
@ -4651,7 +4685,6 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, |
|
|
|
int rtp_pt_idx = -2; |
|
|
|
int ssrc_idx = -1; |
|
|
|
unsigned int datalen, pllen, datalen_out; |
|
|
|
uint32_t *u32; |
|
|
|
struct rtp_parsed rtp, rtp2; |
|
|
|
ssize_t offset; |
|
|
|
uint64_t pkt_idx; |
|
|
|
@ -4672,7 +4705,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, |
|
|
|
|
|
|
|
datalen = ntohs(uh->len); |
|
|
|
if (datalen < sizeof(*uh)) |
|
|
|
goto skip2; |
|
|
|
goto out_no_target; |
|
|
|
datalen -= sizeof(*uh); |
|
|
|
DBG("udp payload = %u\n", datalen); |
|
|
|
skb_trim(skb, datalen); |
|
|
|
@ -4682,14 +4715,14 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, |
|
|
|
|
|
|
|
g = get_target(t, dst); |
|
|
|
if (!g) |
|
|
|
goto skip2; |
|
|
|
goto out_no_target; |
|
|
|
|
|
|
|
// all our outputs filled? |
|
|
|
_r_lock(&g->outputs_lock, flags); |
|
|
|
if (g->outputs_unfilled) { |
|
|
|
// pass to application |
|
|
|
_r_unlock(&g->outputs_lock, flags); |
|
|
|
goto skip1; |
|
|
|
goto out; |
|
|
|
} |
|
|
|
_r_unlock(&g->outputs_lock, flags); |
|
|
|
|
|
|
|
@ -4697,124 +4730,97 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, |
|
|
|
DBG("target decrypt hmac and cipher are %s and %s", g->decrypt.hmac->name, |
|
|
|
g->decrypt.cipher->name); |
|
|
|
|
|
|
|
if (!g->target.stun) |
|
|
|
goto not_stun; |
|
|
|
if (datalen < 28) |
|
|
|
goto not_stun; |
|
|
|
if ((datalen & 0x3)) |
|
|
|
goto not_stun; |
|
|
|
u32 = (void *) skb->data; |
|
|
|
if (u32[1] != htonl(0x2112A442UL)) /* magic cookie */ |
|
|
|
goto not_stun; |
|
|
|
if ((u32[0] & htonl(0xc0000003UL))) /* zero bits required by rfc */ |
|
|
|
goto not_stun; |
|
|
|
u32 = (void *) &skb->data[datalen - 8]; |
|
|
|
if (u32[0] != htonl(0x80280004UL)) /* required fingerprint attribute */ |
|
|
|
goto not_stun; |
|
|
|
|
|
|
|
/* probably stun, pass to application */ |
|
|
|
goto skip1; |
|
|
|
if (is_stun(g, datalen, skb->data)) |
|
|
|
goto out; |
|
|
|
|
|
|
|
not_stun: |
|
|
|
// source checks; |
|
|
|
if (g->target.src_mismatch == MSM_IGNORE) |
|
|
|
goto src_check_ok; |
|
|
|
if (!memcmp(&g->target.expected_src, src, sizeof(*src))) |
|
|
|
goto src_check_ok; |
|
|
|
if (g->target.src_mismatch == MSM_PROPAGATE) |
|
|
|
goto skip1; |
|
|
|
/* MSM_DROP */ |
|
|
|
error_nf_action = NF_DROP; |
|
|
|
errstr = "source address mismatch"; |
|
|
|
goto skip_error; |
|
|
|
|
|
|
|
src_check_ok: |
|
|
|
; // source ignored |
|
|
|
else if (!memcmp(&g->target.expected_src, src, sizeof(*src))) |
|
|
|
; // source matched |
|
|
|
else if (g->target.src_mismatch == MSM_PROPAGATE) |
|
|
|
goto out; // source mismatched, pass to userspace |
|
|
|
else { |
|
|
|
/* MSM_DROP */ |
|
|
|
error_nf_action = NF_DROP; |
|
|
|
errstr = "source address mismatch"; |
|
|
|
goto out_error; |
|
|
|
} |
|
|
|
|
|
|
|
if (g->target.dtls && is_dtls(skb)) |
|
|
|
goto skip1; |
|
|
|
goto out; |
|
|
|
if (g->target.non_forwarding && !g->target.do_intercept) { |
|
|
|
if (g->target.blackhole) |
|
|
|
goto do_stats; // and drop |
|
|
|
goto skip1; // pass to userspace |
|
|
|
goto out; // pass to userspace |
|
|
|
} |
|
|
|
|
|
|
|
// RTP processing |
|
|
|
rtp.ok = 0; |
|
|
|
if (!g->target.rtp) |
|
|
|
goto not_rtp; |
|
|
|
|
|
|
|
if (g->target.rtcp_mux && is_muxed_rtcp(skb)) |
|
|
|
goto skip1; |
|
|
|
if (g->target.rtp) { |
|
|
|
if (g->target.rtcp_mux && is_muxed_rtcp(skb)) |
|
|
|
goto out; // pass to userspace |
|
|
|
|
|
|
|
parse_rtp(&rtp, skb); |
|
|
|
if (!rtp.ok) { |
|
|
|
if (g->target.rtp_only) |
|
|
|
goto skip1; |
|
|
|
goto not_rtp; |
|
|
|
parse_rtp(&rtp, skb); |
|
|
|
if (!rtp.ok && g->target.rtp_only) |
|
|
|
goto out; // pass to userspace |
|
|
|
} |
|
|
|
if (rtp.ok) { |
|
|
|
// RTP ok |
|
|
|
rtp_pt_idx = rtp_payload_type(rtp.header, &g->target, &g->last_pt); |
|
|
|
|
|
|
|
rtp_pt_idx = rtp_payload_type(rtp.header, &g->target, &g->last_pt); |
|
|
|
|
|
|
|
// Pass to userspace if SSRC has changed. |
|
|
|
// Look for matching SSRC index if any SSRC were given |
|
|
|
if (likely(g->target.track_ssrc)) { |
|
|
|
// Pass to userspace if SSRC has changed. |
|
|
|
// Look for matching SSRC index if any SSRC were given |
|
|
|
ssrc_idx = target_find_ssrc(g, rtp.header->ssrc); |
|
|
|
errstr = "SSRC mismatch"; |
|
|
|
for (ssrc_idx = 0; ssrc_idx < RTPE_NUM_SSRC_TRACKING; ssrc_idx++) { |
|
|
|
if (g->target.ssrc[ssrc_idx] == rtp.header->ssrc) |
|
|
|
goto found_ssrc; |
|
|
|
} |
|
|
|
ssrc_idx = -1; |
|
|
|
goto skip_error; |
|
|
|
found_ssrc:; |
|
|
|
} |
|
|
|
if (ssrc_idx == -2) |
|
|
|
goto out_error; |
|
|
|
|
|
|
|
pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header, ssrc_idx); |
|
|
|
errstr = "SRTP authentication tag mismatch"; |
|
|
|
if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp, &pkt_idx, ssrc_idx)) |
|
|
|
goto skip_error; |
|
|
|
pkt_idx = packet_index(&g->decrypt, &g->target.decrypt, rtp.header, ssrc_idx); |
|
|
|
errstr = "SRTP authentication tag mismatch"; |
|
|
|
if (srtp_auth_validate(&g->decrypt, &g->target.decrypt, &rtp, &pkt_idx, ssrc_idx)) |
|
|
|
goto out_error; |
|
|
|
|
|
|
|
// only forward packets of known/passthrough payload types? |
|
|
|
if (g->target.pt_filter && rtp_pt_idx < 0) |
|
|
|
goto skip1; |
|
|
|
// if RTP, only forward packets of known/passthrough payload types |
|
|
|
if (g->target.pt_filter && rtp_pt_idx < 0) |
|
|
|
goto out; |
|
|
|
|
|
|
|
errstr = "SRTP decryption failed"; |
|
|
|
err = srtp_decrypt(&g->decrypt, &g->target.decrypt, &rtp, &pkt_idx); |
|
|
|
if (err < 0) |
|
|
|
goto skip_error; |
|
|
|
if (err == 1) |
|
|
|
update_packet_index(&g->decrypt, &g->target.decrypt, pkt_idx, ssrc_idx); |
|
|
|
errstr = "SRTP decryption failed"; |
|
|
|
err = srtp_decrypt(&g->decrypt, &g->target.decrypt, &rtp, &pkt_idx); |
|
|
|
if (err < 0) |
|
|
|
goto out_error; |
|
|
|
if (err == 1) |
|
|
|
update_packet_index(&g->decrypt, &g->target.decrypt, pkt_idx, ssrc_idx); |
|
|
|
|
|
|
|
skb_trim(skb, rtp.header_len + rtp.payload_len); |
|
|
|
skb_trim(skb, rtp.header_len + rtp.payload_len); |
|
|
|
|
|
|
|
if (g->target.rtp_stats && ssrc_idx != -1) |
|
|
|
rtp_stats(g, &rtp, ktime_to_us(skb->tstamp), rtp_pt_idx, ssrc_idx); |
|
|
|
if (g->target.rtp_stats && ssrc_idx != -1) |
|
|
|
rtp_stats(g, &rtp, ktime_to_us(skb->tstamp), rtp_pt_idx, ssrc_idx); |
|
|
|
|
|
|
|
DBG("packet payload decrypted as %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x...\n", |
|
|
|
rtp.payload[0], rtp.payload[1], rtp.payload[2], rtp.payload[3], |
|
|
|
rtp.payload[4], rtp.payload[5], rtp.payload[6], rtp.payload[7], |
|
|
|
rtp.payload[8], rtp.payload[9], rtp.payload[10], rtp.payload[11], |
|
|
|
rtp.payload[12], rtp.payload[13], rtp.payload[14], rtp.payload[15], |
|
|
|
rtp.payload[16], rtp.payload[17], rtp.payload[18], rtp.payload[19]); |
|
|
|
DBG("packet payload decrypted as %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x...\n", |
|
|
|
rtp.payload[0], rtp.payload[1], rtp.payload[2], rtp.payload[3], |
|
|
|
rtp.payload[4], rtp.payload[5], rtp.payload[6], rtp.payload[7], |
|
|
|
rtp.payload[8], rtp.payload[9], rtp.payload[10], rtp.payload[11], |
|
|
|
rtp.payload[12], rtp.payload[13], rtp.payload[14], rtp.payload[15], |
|
|
|
rtp.payload[16], rtp.payload[17], rtp.payload[18], rtp.payload[19]); |
|
|
|
} |
|
|
|
|
|
|
|
not_rtp: |
|
|
|
if (g->target.do_intercept) { |
|
|
|
DBG("do_intercept is set\n"); |
|
|
|
stream = get_stream_lock(NULL, g->target.intercept_stream_idx); |
|
|
|
if (!stream) |
|
|
|
goto no_intercept; |
|
|
|
packet = kzalloc(sizeof(*packet), GFP_ATOMIC); |
|
|
|
if (!packet) |
|
|
|
goto intercept_done; |
|
|
|
packet->skbuf = intercept_skb_copy(skb, src); |
|
|
|
if (!packet->skbuf) |
|
|
|
goto no_intercept_free; |
|
|
|
add_stream_packet(stream, packet); |
|
|
|
goto intercept_done; |
|
|
|
|
|
|
|
no_intercept_free: |
|
|
|
free_packet(packet); |
|
|
|
intercept_done: |
|
|
|
stream_put(stream); |
|
|
|
if (stream) { |
|
|
|
packet = kzalloc(sizeof(*packet), GFP_ATOMIC); |
|
|
|
if (packet) { |
|
|
|
packet->skbuf = intercept_skb_copy(skb, src); |
|
|
|
if (packet->skbuf) |
|
|
|
add_stream_packet(stream, packet); |
|
|
|
else |
|
|
|
free_packet(packet); |
|
|
|
} |
|
|
|
stream_put(stream); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
no_intercept: |
|
|
|
// output |
|
|
|
for (i = 0; i < g->target.num_destinations; i++) { |
|
|
|
struct rtpengine_output *o = &g->outputs[i]; |
|
|
|
@ -4931,12 +4937,12 @@ do_stats: |
|
|
|
|
|
|
|
return NF_DROP; |
|
|
|
|
|
|
|
skip_error: |
|
|
|
out_error: |
|
|
|
log_err("x_tables action failed: %s", errstr); |
|
|
|
atomic64_inc(&g->stats_in.errors); |
|
|
|
skip1: |
|
|
|
out: |
|
|
|
target_put(g); |
|
|
|
skip2: |
|
|
|
out_no_target: |
|
|
|
kfree_skb(skb); |
|
|
|
table_put(t); |
|
|
|
return error_nf_action; |
|
|
|
|