TT#146201 refactor kernel packet sending function

Change-Id: I008a7fd8c53da3ef00316189ea69b65afa6789e2
pull/1657/head
Richard Fuchs 4 years ago
parent 694a8dd47c
commit b48ebebd59

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

Loading…
Cancel
Save