Merge pull request #241 from minfree123/tk4/master

add iptables target WH and DNATLB
This commit is contained in:
frankjpliu 2022-08-08 15:08:10 +08:00 committed by GitHub
commit 42d6bf3ee2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 261 additions and 0 deletions

View File

@ -299,6 +299,27 @@ config IP_NF_TARGET_TTL
(e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_TARGET_HL.
config IP_NF_TARGET_WH
tristate "Write target ip:port into tcp option header"
default m
help
This option adds WH to iptables, for write target ip:port info into
tcp option header before dnat , it's used in the traffic proxy scenario,
eg: iptables -t mangle -A OUTPUT -p tcp --dst 10.1.0.0/255.255.255.0 -j WH
If unsure, say N.
config IP_NF_TARGET_DNATLB
tristate "Support DNAT to multiple dest, with weight support"
depends on NF_NAT
default m
help
modify from iptables DNAT, support multiple dest,with weight specified.
eg: iptables -t nat -A OUTPUT -p tcp --dst 10.1.0.0/255.255.255.0 --dport 4001 -j DNATLB
--to-destination 192.168.0.1:4001:10 --to-destination 192.168.0.1:4002:20
If unsure, say N.
# raw + specific targets
config IP_NF_RAW
tristate 'raw table support (required for NOTRACK/TRACE)'

View File

@ -50,6 +50,8 @@ obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
obj-$(CONFIG_IP_NF_TARGET_SYNPROXY) += ipt_SYNPROXY.o
obj-$(CONFIG_IP_NF_TARGET_WH) += ipt_WH.o
obj-$(CONFIG_IP_NF_TARGET_DNATLB) += ipt_DNATLB.o
# generic ARP tables
obj-$(CONFIG_IP_NF_ARPTABLES) += arp_tables.o

View File

@ -0,0 +1,133 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
* (C) 2011 Patrick McHardy <kaber@trash.net>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat.h>
#define MAX_DST_SIZE 10
struct nf_nat_ipv4_range_weight {
unsigned int flags;
__be32 min_ip;
__be32 max_ip;
union nf_conntrack_man_proto min;
union nf_conntrack_man_proto max;
unsigned short weight;
};
struct nf_nat_ipv4_range_weight_multi {
unsigned int size;
struct nf_nat_ipv4_range_weight range[MAX_DST_SIZE];
};
static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
{
return nf_ct_netns_get(par->net, par->family);
}
static void xt_nat_destroy(const struct xt_tgdtor_param *par)
{
nf_ct_netns_put(par->net, par->family);
}
static void xt_nat_convert_range(struct nf_nat_range2 *dst,
const struct nf_nat_ipv4_range_weight *src)
{
memset(&dst->min_addr, 0, sizeof(dst->min_addr));
memset(&dst->max_addr, 0, sizeof(dst->max_addr));
memset(&dst->base_proto, 0, sizeof(dst->base_proto));
dst->flags = src->flags;
dst->min_addr.ip = src->min_ip;
dst->max_addr.ip = src->max_ip;
dst->min_proto = src->min;
dst->max_proto = src->max;
}
static unsigned int get_random_number(void)
{
unsigned int rand_num;
get_random_bytes(&rand_num, sizeof(unsigned int));
return rand_num;
}
static const struct nf_nat_ipv4_range_weight *
get_range_lb(const struct nf_nat_ipv4_range_weight_multi *mr)
{
int i = 0;
unsigned int weight_acc = 0;
unsigned int weight_mod = 0;
unsigned int rand_num = 0;
for (i = 0; i < mr->size; i++) {
weight_acc += mr->range[i].weight;
}
rand_num = get_random_number();
weight_mod = rand_num % weight_acc;
weight_acc = 0;
for (i = 0; i < mr->size; i++) {
weight_acc += mr->range[i].weight;
if (weight_mod <= weight_acc) {
return &mr->range[i];
}
}
return NULL;
}
static unsigned int xt_dnat_target_v0(struct sk_buff *skb,
const struct xt_action_param *par)
{
const struct nf_nat_ipv4_range_weight_multi *mr = par->targinfo;
struct nf_nat_range2 range;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
const struct nf_nat_ipv4_range_weight *range_weight;
ct = nf_ct_get(skb, &ctinfo);
WARN_ON(!(ct != NULL &&
(ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)));
range_weight = get_range_lb(mr);
if (range_weight == NULL) {
return 0;
}
xt_nat_convert_range(&range, range_weight);
return nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
}
static struct xt_target xt_nat_target_reg __read_mostly = {
.name = "DNATLB",
//.revision = 0,
.checkentry = xt_nat_checkentry_v0,
.destroy = xt_nat_destroy,
.target = xt_dnat_target_v0,
.targetsize = sizeof(struct nf_nat_ipv4_range_weight_multi),
.family = NFPROTO_IPV4,
.table = "nat",
.hooks = (1 << NF_INET_LOCAL_OUT),
.me = THIS_MODULE,
};
static int __init
xt_nat_init(void)
{
return xt_register_target(&xt_nat_target_reg);
}
static void __exit
xt_nat_exit(void)
{
xt_unregister_target(&xt_nat_target_reg);
}
module_init(xt_nat_init);
module_exit(xt_nat_exit);
MODULE_LICENSE("GPL");

103
net/ipv4/netfilter/ipt_WH.c Normal file
View File

@ -0,0 +1,103 @@
#include <linux/version.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat.h>
/*
* add to mangle table,int OUTPUT phase put target ip,port info into tcp option
*/
static unsigned int write_target_to_tcp_options(struct sk_buff *skb)
{
struct iphdr *iph;
struct tcphdr *tcph;
char new_head[120];
int hdr_len;
char option_addr[8];
uint32_t tmp_ip;
uint16_t tmp_port;
int data_len;
char *d;
iph = ip_hdr(skb);
tcph = (struct tcphdr *)skb_transport_header(skb);
if (skb->data[0] != 0x45 || iph->protocol != 0x06) {
//no ipv4 and tcp packetjust ignore
return 0;
}
if (tcph->syn != 1) {
//not first packetno need to modify header
return 0;
}
if (skb_headroom(skb) < 22) {
return 0;
}
hdr_len = (iph->ihl + tcph->doff) * 4;
memcpy(new_head, skb->data, hdr_len);
tmp_ip = htonl(iph->daddr);
tmp_port = htons(tcph->dest);
option_addr[0] = 0xfd;
option_addr[1] = 0x08;
memcpy(option_addr + 2, &tmp_ip, 4);
memcpy(option_addr + 6, &tmp_port, 2);
memcpy(new_head + hdr_len, option_addr, 8);
d = new_head;
skb_pull(skb, hdr_len);
skb_push(skb, hdr_len + 8);
memcpy(skb->data, new_head, hdr_len + 8);
skb->transport_header = skb->transport_header - 8;
skb->network_header = skb->network_header - 8;
iph = ip_hdr(skb); //update iph point to new ip header
iph->tot_len = htons(skb->len);
iph->check = 0; //re-calculate ip checksum
iph->check = ip_fast_csum(iph, iph->ihl);
tcph = (struct tcphdr *)skb_transport_header(skb);
tcph->doff = tcph->doff + 2;
tcph->check = 0;
data_len = (skb->len - iph->ihl * 4); //tcp segment length
tcph->check =
csum_tcpudp_magic(iph->saddr, iph->daddr, data_len,
iph->protocol,
csum_partial((char *)tcph, data_len, 0));
skb->ip_summed = CHECKSUM_UNNECESSARY;
return 0;
}
static unsigned int xt_wh_target(struct sk_buff *skb,
const struct xt_action_param *par)
{
write_target_to_tcp_options(skb);
return NF_ACCEPT;
}
static struct xt_target xt_wh_target_reg __read_mostly = {
.name = "WH",
// .revision = 1,
.target = xt_wh_target,
.targetsize = sizeof(int),
.table = "mangle",
.family = NFPROTO_IPV4,
.hooks = (1 << NF_INET_LOCAL_OUT),
.me = THIS_MODULE,
};
static int __init xt_nat_init(void)
{
return xt_register_target(&xt_wh_target_reg);
}
static void __exit xt_nat_exit(void)
{
xt_unregister_target(&xt_wh_target_reg);
}
module_init(xt_nat_init);
module_exit(xt_nat_exit);
MODULE_LICENSE("GPL");

View File

@ -1369,6 +1369,8 @@ CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_TARGET_ECN=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_TARGET_WH=m
CONFIG_IP_NF_TARGET_DNATLB=m
CONFIG_IP_NF_RAW=m
# CONFIG_IP_NF_SECURITY is not set
CONFIG_IP_NF_ARPTABLES=m