|
|
|
@ -21,6 +21,7 @@ |
|
|
|
#include <net/ipv6.h> |
|
|
|
#include <net/tcp.h> |
|
|
|
#include <net/route.h> |
|
|
|
#include <net/ip6_route.h> |
|
|
|
#include <net/dst.h> |
|
|
|
#include <linux/proc_fs.h> |
|
|
|
#include <linux/spinlock.h> |
|
|
|
@ -91,6 +92,12 @@ MODULE_ALIAS("ip6t_RTPENGINE"); |
|
|
|
#define xt_action_param xt_target_param |
|
|
|
#endif |
|
|
|
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) |
|
|
|
#define PAR_STATE_NET(p) (p)->state->net |
|
|
|
#else |
|
|
|
#define PAR_STATE_NET(p) (p)->net |
|
|
|
#endif |
|
|
|
|
|
|
|
#if 0 |
|
|
|
#define _s_lock(l, f) do { \ |
|
|
|
printk(KERN_DEBUG "[PID %i %s:%i] acquiring lock %s\n", \ |
|
|
|
@ -3785,12 +3792,15 @@ static ssize_t proc_control_read(struct file *file, char __user *ubuf, size_t bu |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// par can be NULL |
|
|
|
static int send_proxy_packet4(struct sk_buff *skb, struct re_address *src, struct re_address *dst, |
|
|
|
unsigned char tos, const struct xt_action_param *par) |
|
|
|
{ |
|
|
|
struct iphdr *ih; |
|
|
|
struct udphdr *uh; |
|
|
|
unsigned int datalen; |
|
|
|
struct net *net; |
|
|
|
struct rtable *rt; |
|
|
|
|
|
|
|
datalen = skb->len; |
|
|
|
|
|
|
|
@ -3823,37 +3833,34 @@ static int send_proxy_packet4(struct sk_buff *skb, struct re_address *src, struc |
|
|
|
uh->check = csum_tcpudp_magic(src->u.ipv4, dst->u.ipv4, datalen, IPPROTO_UDP, csum_partial(uh, datalen, 0)); |
|
|
|
if (uh->check == 0) |
|
|
|
uh->check = CSUM_MANGLED_0; |
|
|
|
|
|
|
|
skb->protocol = htons(ETH_P_IP); |
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,9) || \ |
|
|
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,78) && LINUX_VERSION_CODE < KERNEL_VERSION(5,5,0)) || \ |
|
|
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,158) && LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)) |
|
|
|
if (ip_route_me_harder(par->state->net, par->state->sk, skb, RTN_UNSPEC)) |
|
|
|
#elif defined(RHEL_RELEASE_CODE) && LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) && \ |
|
|
|
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,4) |
|
|
|
if (ip_route_me_harder(par->state->net, par->state->sk, skb, RTN_UNSPEC)) |
|
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) |
|
|
|
if (ip_route_me_harder(par->state->net, skb, RTN_UNSPEC)) |
|
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) |
|
|
|
if (ip_route_me_harder(par->net, skb, RTN_UNSPEC)) |
|
|
|
#else |
|
|
|
if (ip_route_me_harder(skb, RTN_UNSPEC)) |
|
|
|
#endif |
|
|
|
|
|
|
|
net = NULL; |
|
|
|
if (par) |
|
|
|
net = PAR_STATE_NET(par); |
|
|
|
if (!net && current && current->nsproxy) |
|
|
|
net = current->nsproxy->net_ns; |
|
|
|
if (!net) |
|
|
|
goto drop; |
|
|
|
|
|
|
|
rt = ip_route_output(net, dst->u.ipv4, src->u.ipv4, tos, 0); |
|
|
|
if (IS_ERR(rt)) |
|
|
|
goto drop; |
|
|
|
skb_dst_drop(skb); |
|
|
|
skb_dst_set(skb, &rt->dst); |
|
|
|
|
|
|
|
if (skb_dst(skb)->error) |
|
|
|
goto drop; |
|
|
|
|
|
|
|
skb->ip_summed = CHECKSUM_NONE; |
|
|
|
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) |
|
|
|
ip_select_ident(par->state->net, skb, NULL); |
|
|
|
ip_send_check(ih); |
|
|
|
ip_local_out(par->state->net, skb->sk, skb); |
|
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) |
|
|
|
ip_select_ident(par->net, skb, NULL); |
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) |
|
|
|
ip_select_ident(net, skb, NULL); |
|
|
|
ip_send_check(ih); |
|
|
|
ip_local_out(par->net, skb->sk, skb); |
|
|
|
ip_local_out(net, skb->sk, skb); |
|
|
|
#else |
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0) |
|
|
|
ip_select_ident(par->net, skb, NULL); |
|
|
|
ip_select_ident(net, skb, NULL); |
|
|
|
#elif (LINUX_VERSION_CODE == KERNEL_VERSION(3,10,0) && RHEL_MAJOR == 7) /* CentOS 7 */ |
|
|
|
/* nothing */ |
|
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3,15,10) \ |
|
|
|
@ -3888,12 +3895,16 @@ drop: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// par can be NULL |
|
|
|
static int send_proxy_packet6(struct sk_buff *skb, struct re_address *src, struct re_address *dst, |
|
|
|
unsigned char tos, const struct xt_action_param *par) |
|
|
|
{ |
|
|
|
struct ipv6hdr *ih; |
|
|
|
struct udphdr *uh; |
|
|
|
unsigned int datalen; |
|
|
|
struct net *net; |
|
|
|
struct dst_entry *dst_entry; |
|
|
|
struct flowi6 fl6; |
|
|
|
|
|
|
|
datalen = skb->len; |
|
|
|
|
|
|
|
@ -3926,30 +3937,35 @@ static int send_proxy_packet6(struct sk_buff *skb, struct re_address *src, struc |
|
|
|
uh->check = csum_ipv6_magic(&ih->saddr, &ih->daddr, datalen, IPPROTO_UDP, csum_partial(uh, datalen, 0)); |
|
|
|
if (uh->check == 0) |
|
|
|
uh->check = CSUM_MANGLED_0; |
|
|
|
|
|
|
|
skb->protocol = htons(ETH_P_IPV6); |
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,9,9) || \ |
|
|
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(5,4,78) && LINUX_VERSION_CODE < KERNEL_VERSION(5,5,0)) || \ |
|
|
|
(LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,158) && LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)) |
|
|
|
if (ip6_route_me_harder(par->state->net, par->state->sk, skb)) |
|
|
|
#elif defined(RHEL_RELEASE_CODE) && LINUX_VERSION_CODE >= KERNEL_VERSION(4,18,0) && \ |
|
|
|
RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(8,4) |
|
|
|
if (ip6_route_me_harder(par->state->net, par->state->sk, skb)) |
|
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) |
|
|
|
if (ip6_route_me_harder(par->state->net, skb)) |
|
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) |
|
|
|
if (ip6_route_me_harder(par->net, skb)) |
|
|
|
#else |
|
|
|
if (ip6_route_me_harder(skb)) |
|
|
|
#endif |
|
|
|
|
|
|
|
net = NULL; |
|
|
|
if (par) |
|
|
|
net = PAR_STATE_NET(par); |
|
|
|
if (!net && current && current->nsproxy) |
|
|
|
net = current->nsproxy->net_ns; |
|
|
|
if (!net) |
|
|
|
goto drop; |
|
|
|
|
|
|
|
memset(&fl6, 0, sizeof(fl6)); |
|
|
|
memcpy(&fl6.saddr, src->u.ipv6, sizeof(fl6.saddr)); |
|
|
|
memcpy(&fl6.daddr, dst->u.ipv6, sizeof(fl6.daddr)); |
|
|
|
fl6.flowi6_mark = skb->mark; |
|
|
|
|
|
|
|
dst_entry = ip6_route_output(net, NULL, &fl6); |
|
|
|
if (!dst_entry) |
|
|
|
goto drop; |
|
|
|
if (dst_entry->error) { |
|
|
|
dst_release(dst_entry); |
|
|
|
goto drop; |
|
|
|
} |
|
|
|
skb_dst_drop(skb); |
|
|
|
skb_dst_set(skb, dst_entry); |
|
|
|
|
|
|
|
skb->ip_summed = CHECKSUM_NONE; |
|
|
|
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0) |
|
|
|
ip6_local_out(par->state->net, skb->sk, skb); |
|
|
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) |
|
|
|
ip6_local_out(par->net, skb->sk, skb); |
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0) |
|
|
|
ip6_local_out(net, skb->sk, skb); |
|
|
|
#else |
|
|
|
ip6_local_out(skb); |
|
|
|
#endif |
|
|
|
@ -4581,6 +4597,56 @@ static struct sk_buff *intercept_skb_copy(struct sk_buff *oskb, const struct re_ |
|
|
|
return ret; |
|
|
|
} |
|
|
|
|
|
|
|
static void proxy_packet_output_rtp(struct sk_buff *skb, struct rtpengine_output *o, |
|
|
|
int rtp_pt_idx, |
|
|
|
struct rtp_parsed *rtp, int ssrc_idx) |
|
|
|
{ |
|
|
|
unsigned int pllen; |
|
|
|
uint64_t pkt_idx; |
|
|
|
int i; |
|
|
|
|
|
|
|
if (!rtp->ok) |
|
|
|
return; |
|
|
|
|
|
|
|
// pattern rewriting |
|
|
|
if (rtp_pt_idx >= 0 && o->output.pt_output[rtp_pt_idx].replace_pattern_len) { |
|
|
|
if (o->output.pt_output[rtp_pt_idx].replace_pattern_len == 1) |
|
|
|
memset(rtp->payload, o->output.pt_output[rtp_pt_idx].replace_pattern[0], |
|
|
|
rtp->payload_len); |
|
|
|
else { |
|
|
|
for (i = 0; i < rtp->payload_len; |
|
|
|
i += o->output.pt_output[rtp_pt_idx].replace_pattern_len) |
|
|
|
memcpy(&rtp->payload[i], |
|
|
|
o->output.pt_output[rtp_pt_idx].replace_pattern, |
|
|
|
o->output.pt_output[rtp_pt_idx].replace_pattern_len); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// SSRC substitution and seq manipulation |
|
|
|
if (likely(ssrc_idx >= 0)) { |
|
|
|
rtp->header->seq_num = htons(ntohs(rtp->header->seq_num) |
|
|
|
+ o->output.seq_offset[ssrc_idx]); |
|
|
|
if (o->output.ssrc_subst && likely(o->output.ssrc_out[ssrc_idx])) |
|
|
|
rtp->header->ssrc = o->output.ssrc_out[ssrc_idx]; |
|
|
|
} |
|
|
|
|
|
|
|
// SRTP |
|
|
|
pkt_idx = packet_index(&o->encrypt, &o->output.encrypt, rtp->header, ssrc_idx); |
|
|
|
pllen = rtp->payload_len; |
|
|
|
srtp_encrypt(&o->encrypt, &o->output.encrypt, rtp, pkt_idx); |
|
|
|
srtp_authenticate(&o->encrypt, &o->output.encrypt, rtp, pkt_idx); |
|
|
|
skb_put(skb, rtp->payload_len - pllen); |
|
|
|
} |
|
|
|
|
|
|
|
static int send_proxy_packet_output(struct sk_buff *skb, struct rtpengine_target *g, |
|
|
|
int rtp_pt_idx, |
|
|
|
struct rtpengine_output *o, struct rtp_parsed *rtp, int ssrc_idx, |
|
|
|
const struct xt_action_param *par) |
|
|
|
{ |
|
|
|
proxy_packet_output_rtp(skb, o, rtp_pt_idx, rtp, ssrc_idx); |
|
|
|
return send_proxy_packet(skb, &o->output.src_addr, &o->output.dst_addr, o->output.tos, par); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -4684,7 +4750,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, |
|
|
|
int error_nf_action = XT_CONTINUE; |
|
|
|
int rtp_pt_idx = -2; |
|
|
|
int ssrc_idx = -1; |
|
|
|
unsigned int datalen, pllen, datalen_out; |
|
|
|
unsigned int datalen, datalen_out; |
|
|
|
struct rtp_parsed rtp, rtp2; |
|
|
|
ssize_t offset; |
|
|
|
uint64_t pkt_idx; |
|
|
|
@ -4845,40 +4911,7 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct rtpengine_table *t, |
|
|
|
rtp2.header = (void *) (((char *) rtp2.header) + offset); |
|
|
|
rtp2.payload = (void *) (((char *) rtp2.payload) + offset); |
|
|
|
|
|
|
|
// pattern rewriting |
|
|
|
if (rtp_pt_idx >= 0 && o->output.pt_output[rtp_pt_idx].replace_pattern_len && rtp2.ok) { |
|
|
|
if (o->output.pt_output[rtp_pt_idx].replace_pattern_len == 1) |
|
|
|
memset(rtp2.payload, o->output.pt_output[rtp_pt_idx].replace_pattern[0], |
|
|
|
rtp2.payload_len); |
|
|
|
else { |
|
|
|
for (i = 0; i < rtp2.payload_len; |
|
|
|
i += o->output.pt_output[rtp_pt_idx].replace_pattern_len) |
|
|
|
memcpy(&rtp2.payload[i], |
|
|
|
o->output.pt_output[rtp_pt_idx].replace_pattern, |
|
|
|
o->output.pt_output[rtp_pt_idx].replace_pattern_len); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (rtp2.ok) { |
|
|
|
// SSRC substitution and seq manipulation |
|
|
|
if (ssrc_idx != -1) { |
|
|
|
rtp2.header->seq_num = htons(ntohs(rtp2.header->seq_num) |
|
|
|
+ o->output.seq_offset[ssrc_idx]); |
|
|
|
if (o->output.ssrc_subst && o->output.ssrc_out[ssrc_idx]) |
|
|
|
rtp2.header->ssrc = o->output.ssrc_out[ssrc_idx]; |
|
|
|
} |
|
|
|
|
|
|
|
pkt_idx = packet_index(&o->encrypt, &o->output.encrypt, rtp2.header, ssrc_idx); |
|
|
|
pllen = rtp2.payload_len; |
|
|
|
srtp_encrypt(&o->encrypt, &o->output.encrypt, &rtp2, pkt_idx); |
|
|
|
srtp_authenticate(&o->encrypt, &o->output.encrypt, &rtp2, pkt_idx); |
|
|
|
skb_put(skb2, rtp2.payload_len - pllen); |
|
|
|
} |
|
|
|
|
|
|
|
datalen_out = skb2->len; |
|
|
|
|
|
|
|
err = send_proxy_packet(skb2, &o->output.src_addr, &o->output.dst_addr, o->output.tos, par); |
|
|
|
|
|
|
|
err = send_proxy_packet_output(skb2, g, rtp_pt_idx, o, &rtp2, ssrc_idx, par); |
|
|
|
if (err) { |
|
|
|
atomic64_inc(&g->stats_in.errors); |
|
|
|
atomic64_inc(&o->stats_out.errors); |
|
|
|
|