diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index f17b40211..49861bb50 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -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)' diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 7c497c781..d7fa63957 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -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 diff --git a/net/ipv4/netfilter/ipt_DNATLB.c b/net/ipv4/netfilter/ipt_DNATLB.c new file mode 100644 index 000000000..bcc169f35 --- /dev/null +++ b/net/ipv4/netfilter/ipt_DNATLB.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * (C) 2011 Patrick McHardy + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +#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"); diff --git a/net/ipv4/netfilter/ipt_WH.c b/net/ipv4/netfilter/ipt_WH.c new file mode 100644 index 000000000..90502e96d --- /dev/null +++ b/net/ipv4/netfilter/ipt_WH.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include +#include +/* + * 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 packet,just ignore + return 0; + } + if (tcph->syn != 1) { + //not first packet,no 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"); diff --git a/package/default/config.default b/package/default/config.default index 504771275..0caa419de 100644 --- a/package/default/config.default +++ b/package/default/config.default @@ -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