TT#146201 refactor rtpengine46()

Change-Id: Ie49ba654c5e6f15227b4db8cd4588c0ae366e87b
pull/1657/head
Richard Fuchs 4 years ago
parent 77689a0b8c
commit 694a8dd47c

@ -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;

Loading…
Cancel
Save