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