标签:reg dnat com 功能 net 程序 绑定 number eal
《路由应用-使用路由实现负载流量均衡》的第3.3节,并没有给出如何配置一个pool,那是因为在Linux 2.6.10之上,已经不再支持配置不连续IP地址的pool了,如果看iptables的man手册,将会得到以下信息:
In Kernels up to 2.6.10 you can add several --to-destination options. For those kernels, if you specify more than one destination address, either via an address range or multiple --to-destination options, a simple round-robin (one after another in cycle) load balancing takes place between these addresses. Later Kernels (>= 2.6.11-rc1) don‘t have the ability to NAT to multiple ranges anymore./* POOL. 将目的地址随机映射到不连续的IP地址池 */
/* (C) 2011/06/28 By ZhaoYa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_nat_rule.h>
#include <linux/netfilter_ipv4.h>
#include <linux/jiffies.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZhaoYa <marywangran@126.com>");
MODULE_DESCRIPTION("Xtables: DNAT from ip-pool");
#define MAX 100
struct ip_addr_pool {
unsigned int size;
__be32 ips[MAX];
};
static bool pool_check(const struct xt_tgchk_param *par)
{
//TODO
return true;
}
static unsigned int
pool_target(struct sk_buff *skb, const struct xt_target_param *par)
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
const struct ip_addr_pool *mr = par->targinfo;
//以时钟嘀嗒作为随机源,理由是你不知道何时数据包会过来
unsigned int indx = jiffies%(mr->size);
struct nf_nat_range newrange;
newrange.min_ip = mr->ips[indx];
newrange.max_ip = mr->ips[indx];
newrange.flags = IP_NAT_RANGE_MAP_IPS;
NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
par->hooknum == NF_INET_LOCAL_OUT);
ct = nf_ct_get(skb, &ctinfo);
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
return nf_nat_setup_info(ct, &newrange, IP_NAT_MANIP_DST);
}
static struct xt_target pool_reg __read_mostly = {
.name = "POOL",
.family = NFPROTO_IPV4,
.target = pool_target,
.targetsize = sizeof(struct ip_addr_pool),
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
.checkentry = pool_check,
.me = THIS_MODULE,
};
static int __init pool_target_init(void)
{
return xt_register_target(&pool_reg);
}
static void __exit pool_target_exit(void)
{
xt_unregister_target(&pool_reg);
}
module_init(pool_target_init);
module_exit(pool_target_exit);
/* POOL. 将目的地址随机映射到不连续的IP地址池 -用户态iptables模块*/
/* (C) 2011/06/28 By ZhaoYa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
enum {
//目前只支持一个配置
FROM_POOL = 0,
};
//最多一个池中有100个地址
#define MAX 100
struct ip_addr_pool {
unsigned int size;
u_int32_t ips[MAX];
};
struct ipt_natinfo
{
struct xt_entry_target t;
struct ip_addr_pool mr;
};
static void POOL_help(void)
{
printf(
"POOL target options:\n"
" --pool [<ipaddr>[,<ipaddr[,<...>]>]]\n");
}
static const struct xt_option_entry POOL_opts[] = {
{
.name = "pool",
.id = FROM_POOL,
.type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI
},
XTOPT_TABLEEND,
};
static struct ipt_natinfo *
set_contents(struct ipt_natinfo *info, const char *arg)
{
unsigned int size;
char *tok;
unsigned int i = 0;
size = XT_ALIGN(sizeof(struct ipt_natinfo));
info = realloc(info, size);
if (!info)
xtables_error(OTHER_PROBLEM, "Out of memory\n");
tok = strtok(arg, ",");
if (tok){
while (tok && i < MAX) {
info->mr.ips[i] = (u_int32_t)inet_addr(tok);
info->mr.size++;
tok = strtok(NULL, ",");
i ++;
}
} else {
info->mr.ips[i] = (u_int32_t)inet_addr(arg);
info->mr.size++;
}
return info;
}
static void POOL_parse(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
struct ipt_natinfo *info = (void *)(*cb->target);
int portok;
if (entry->ip.proto == IPPROTO_TCP
|| entry->ip.proto == IPPROTO_UDP
|| entry->ip.proto == IPPROTO_SCTP
|| entry->ip.proto == IPPROTO_DCCP
|| entry->ip.proto == IPPROTO_ICMP)
portok = 1;
else
portok = 0;
xtables_option_parse(cb);
switch (cb->entry->id) {
case FROM_POOL:
{
char *arg ;
arg = strdup(cb->arg);
if (arg == NULL)
xtables_error(RESOURCE_PROBLEM, "strdup");
info = set_contents(info, arg);
free(arg);
*cb->target = &(info->t);
break;
}
}
}
static void POOL_save(const void *ip, const struct xt_entry_target *target)
{
const struct ipt_natinfo *info = (const void *)target;
unsigned int i = 0;
printf(" --pool ");
for (i = 0; i < info->mr.size; i++) {
struct in_addr ia;
char *addr;
ia.s_addr = info->mr.ips[i];
addr = inet_ntoa(ia);
if (i == info->mr.size-1)
printf("%s", addr);
else
printf("%s,", addr);
}
}
static struct xtables_target pool_tg_reg = {
.name = "POOL",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct ip_addr_pool)),
.userspacesize = XT_ALIGN(sizeof(struct ip_addr_pool)),
.help = POOL_help,
.x6_parse = POOL_parse,
.save = POOL_save,
.x6_options = POOL_opts,
};
void _init(void)
{
xtables_register_target(&pool_tg_reg);
}
CC=gcc
IPTABLES_SRC=/root/iptables/iptables-1.4.12
INCLUDE=-I$(IPTABLES_SRC)/include
KERNEL_SRC=/lib/modules/`uname -r`/build
MOD=ipt_POOL.ko
all: modules libipt_POOL.so
modules: $(MOD)
ipt_POOL.ko: ipt_POOL.c
$(MAKE) -C $(KERNEL_SRC) SUBDIRS=$(PWD) modules
libipt_POOL.so: libipt_POOL.c
$(CC) $(INCLUDE) -fPIC -c libipt_POOL.c
ld -shared -o libipt_POOL.so libipt_POOL.o
clean:
-rm -f *.o *.so *.ko .*.cmd *.mod.c *.symvers *.order
install: all
cp -rf libipt_POOL.so /usr/local/lib/xtables/
cp -rf $(MOD) /lib/modules/`uname -r`/kernel/net/ipv4/netfilter/
@depmod -a
struct pool-info {
unsigned char pool_name[MAXNAMELEN];
}
#include <linux/types.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <net/netfilter/nf_nat_rule.h>
#include <linux/netfilter_ipv4.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/jiffies.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZhaoYa <marywangran@126.com>");
MODULE_DESCRIPTION("Xtables: DNAT from ip-pool");
#define MAX 100
#define MAXNAMELEN 100
#define MAXPOOL 5
struct ip_addr_pool {
unsigned char pool_name[MAXNAMELEN]; //该字段用于target中的具体POOL的查找
unsigned int size;
__be32 ips[MAX];
};
struct pool_info {
unsigned char pool_name[MAXNAMELEN];
};
//定义一个只有MAXPOOL个POOL的静态数组替代复杂的链表操作,标准的做法是用链表实现
struct ip_addr_pool gpoolset[MAXPOOL];
static bool poolset_check(const struct xt_tgchk_param *par)
{
//TODO
return true;
}
//poolset_target很简单,就是根据iptables配置的pool名称,定位一个要使用的pool,也就是一个ip_addr_pool结构体。
static unsigned int
poolset_target(struct sk_buff *skb, const struct xt_target_param *par)
{
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
struct nf_nat_range newrange;
const struct pool_info *mr = par->targinfo;
struct ip_addr_pool res = {};
unsigned int i = 0;
unsigned int indx;
//以下的循环找到根据name索引的ip_addr_pool,也就是一个POOL
for (i = 0; i < MAXPOOL; i++) {
if (!strcmp(mr->pool_name, gpoolset[i].pool_name))
res = gpoolset[i];
}
//找到POOL后,在此POOL中随机取出一个IP地址用于DNAT
indx = jiffies%(res.size);
newrange.min_ip = res.ips[indx];
newrange.max_ip = res.ips[indx];
newrange.flags = IP_NAT_RANGE_MAP_IPS;
NF_CT_ASSERT(par->hooknum == NF_INET_PRE_ROUTING ||
par->hooknum == NF_INET_LOCAL_OUT);
ct = nf_ct_get(skb, &ctinfo);
NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED));
return nf_nat_setup_info(ct, &newrange, IP_NAT_MANIP_DST);
}
static struct xt_target poolset_reg __read_mostly = {
.name = "POOLSET",
.family = NFPROTO_IPV4,
.target = poolset_target,
.targetsize = sizeof(struct pool_info),
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
.checkentry = poolset_check,
.me = THIS_MODULE,
};
struct proc_dir_entry *poolset_entry;
static ssize_t write_poolset(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
//TODO
//在这里实现将buf转换为特定pool中的IP地址
return 0;
}
static struct file_operations proc_poolset_operations = {
.write = write_poolset,
};
static int __init poolset_target_init(void)
{
unsigned int i = 0;
memset(gpoolset, 0, sizeof(gpoolset));
poolset_entry = proc_mkdir("poolset", NULL);
for (i = 0; i < MAXPOOL; i++) {
struct proc_dir_entry *entry;
char buf[100] = {0};
sprintf(buf, "%d", i);
strcpy(gpoolset[i].pool_name, buf);
entry = create_proc_entry(buf, S_IWUSR, poolset_entry);
poolset_entry->proc_fops = &proc_poolset_operations;
}
return xt_register_target(&poolset_reg);
}
static void __exit poolset_target_exit(void)
{
unsigned int i = 0;
for (i = 0; i < MAXPOOL; i++) {
remove_proc_entry(gpoolset[i].pool_name, poolset_entry);
}
xt_unregister_target(&poolset_reg);
}
module_init(poolset_target_init);
module_exit(poolset_target_exit);
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
enum {
//目前只支持一个配置
TO_POOLSET_SET = 0,
};
#define MAXNAMELEN 100
struct pool_info {
unsigned char pool_name[MAXNAMELEN];
};
struct ipt_poolsetinfo
{
struct xt_entry_target t;
struct pool_info mr;
};
static const struct xt_option_entry POOLSET_opts[] = {
{
.name = "poolset",
.id = TO_POOLSET_SET,
.type = XTTYPE_STRING,
.flags = XTOPT_MAND | XTOPT_MULTI
},
XTOPT_TABLEEND,
};
static struct ipt_poolsetinfo *
set_contents(struct ipt_poolsetinfo *info, const char *arg)
{
unsigned int size;
size = XT_ALIGN(sizeof(struct ipt_poolsetinfo));
info = realloc(info, size);
if (!info)
xtables_error(OTHER_PROBLEM, "Out of memory\n");
//内核将只需要一个名称即可,根据pool名称,内核会在poolset中定位到具体的pool
strcpy(info->mr.pool_name, arg);
return info;
}
static void POOLSET_parse(struct xt_option_call *cb)
{
const struct ipt_entry *entry = cb->xt_entry;
struct ipt_poolsetinfo *info = (void *)(*cb->target);
int portok;
if (entry->ip.proto == IPPROTO_TCP
|| entry->ip.proto == IPPROTO_UDP
|| entry->ip.proto == IPPROTO_SCTP
|| entry->ip.proto == IPPROTO_DCCP
|| entry->ip.proto == IPPROTO_ICMP)
portok = 1;
else
portok = 0;
xtables_option_parse(cb);
switch (cb->entry->id) {
case TO_POOLSET_SET:
{
char *arg ;
arg = strdup(cb->arg);
if (arg == NULL)
xtables_error(RESOURCE_PROBLEM, "strdup");
info = set_contents(info, arg);
free(arg);
*cb->target = &(info->t);
break;
}
}
}
static struct xtables_target poolset_tg_reg = {
.name = "POOLSET",
.version = XTABLES_VERSION,
.family = NFPROTO_IPV4,
.size = XT_ALIGN(sizeof(struct pool_info)),
.userspacesize = XT_ALIGN(sizeof(struct pool_info)),
.x6_parse = POOLSET_parse,
.x6_options = POOLSET_opts,
};
void _init(void)
{
xtables_register_target(&poolset_tg_reg);
}
再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow
编写iptables模块实现不连续IP地址的DNAT-POOL
标签:reg dnat com 功能 net 程序 绑定 number eal
原文地址:https://www.cnblogs.com/ksiwnhiwhs/p/10390623.html