编写iptables模块实现不连续IP地址的DNAT-POOL

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

               

1.背景

路由应用-使用路由实现负载流量均衡》的第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.
在相对老的内核中,使用iptables时,可以配置多个to-destination选项来支持不连续IP的pool配置,可是到了2.6.11以及之后,内核不再支持不连续IP地址的pool配置了。具体的原因还得从Changelog中寻找,在2.6.11-rc1的Changelog中有如下描述:
[PATCH] Remove NAT to multiple ranges
The NAT code has the concept of multiple ranges: you can say "map this connection onto IP 192.168.1.2 - 192.168.1.4, 192.168.1.7 ports 1024-65535, and 192.168.1.10".  I implemented this because we could.
But it's not actually *used* by many (any?) people, and you can    approximate this by a random match (from patch-o-matic) if you really
want to.  It adds complexity to the code.

可见,没有人用的东西是不必再继续存在下去的。作者建议使用Netfilter的非正式补丁patch-o-matic的形式进行支持,可是事情远没有那么麻烦,如果有上网寻找现成方案的时间,自己写一个pool的实现也是很快的。

2.实现一个新功能的步骤

Linux的防火墙和NAT完全是由Netfilter机制实现的,然而具体的策略却需要一个用户态程序配置进内核的Netfilter,一个很流行可能也是唯一在使用的用户态工具就是iptables。iptables负责接收并检查用户的配置,然后将其传到内核,内核接收后会将策略配置在内核的内存中,至此iptables的配置任务完成。因此要实现一个新的功能,必然首先需要编写一个内核模块用于支持机制,然后还需要一个iptables模块呼应之,用于配置策略。
     总的来说,Netfilter的工作方式为:在特定的HOOK点执行多条rule,每一条rule对于每一个数据包执行多个match,多个match都匹配后,执行该rule的target。每一条rule都要显式绑定于一个table和一个HOOK点。
     对于实现一个IP地址pool,用于DNAT的时候从中选择目的IP地址,很明显是一个target要做的。因此,我们要做的就是实现一个新的target。对于实现一个新的match,本文不讨论,它的实现过程和实现一个target几乎一模一样。

2.1.编写一个内核模块

2.1.1.定义并注册一个xt_target结构体

这是必须的要求,内核为每一个协议族(family)保留了一个target链表,新定义的xt_target根据其family注册在特定的链表上。

2.1.2.实现xt_target的target函数

该回调函数实现了动作逻辑,也就是说,匹配完成后要执行一个target,具体如何执行就要看该回调函数如何定义。内核并没有对此函数的实现有任何限制,理论上可以在其中实现一切。

2.1.3.定义xt_target的targetsize字段

为了提高target定位的效率,高一些版本的内核要求xt_target强制长度,该长度表示“用户策略”数据结构的总长度。

2.1.4.定义xt_target的table,hooks,family字段

Netfilter要求每一个match以及每一个target都显式绑定在一个HOOK上,如果需要用户态进程比如iptables呼应,还需要显式绑定于一个table。

2.2.编写一个iptables模块

iptables是一个用户态防火墙应用程序,其全部实现由extension来完成,这个机制类似于插件机制,你可以很方便的扩展iptables的功能。
     iptables是高度模块化的,它的几乎所有的功能都在模块中被实现,比如一个很简单的配置项:-p tcp,-p说明它是一个match,而tcp则是该match的一个模块,对于-p这个match,其它可选的模块还有udp,icmp等等,在iptables结构中,模块和模块名称是高度相关的,iptables的所有模块都安装于/usr/local/lib/xtables/(具体机器的iptables模块安装位置可能与此不同),比如对于-p tcp来讲,需要的模块就是/usr/local/lib/xtables/libxt_tcp.so,同名的源代码位于iptables-$version/extensions目录的libxt_tcp.c。
     如果想实现一个新的iptables模块,无疑需要比葫芦画瓢地编写一个类似的文件

2.2.1.定义并注册一个xtables_target结构体

这件事情和内核态的注册xt_target是对应的,然而这个用户态的xtables_target只是为了通知内核配置策略,而不像内核的xt_target那样永存。一旦iptables命令返回,这个用户态的target结构体即被释放。

2.2.2.实现xtables_target的x6_parse回调函数

这个回调函数很核心,它将iptables的配置参数转化为要传给内核的策略配置。

2.2.3.定义x6_options数组

该数组的每一项表示一个配置选项,比如--to-destination中的to-destination就是x6_options中的一个成员字段。

2.2.4.实现save回调函数用于iptables-save时的显示

如果不希望被备份,则不需要实现此函数。

2.2.5.用户态size和内核态targetsize的对应

内核在接收用户态iptables等程序配置的target的时候,要进行size匹配验证,如果size不一致将会拒绝这个配置,因此iptables的xtables_target结构体的size一定要和内核态xt_target结构体的targetsize一致。这个验证在2.6.18以后的内核中是强制的,之所以如此是因为在内核中netfilter的match以及target是在一块连续内核排列的,正是有这些size才能断定哪里是match以及target的边界。

3.POOL的实现

理解了原理之后,我们发现实现POOL是多么简单的一件事。

3.1.实现POOL target的内核态模块

以下是对应的内核模块ipt_POOL.ko的源代码 ipt_POOL.c
/* 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 100struct ip_addr_pool {
            unsigned int size;        __be32 ips[MAX];};static bool pool_check(const struct xt_tgchk_param *par){        //TODO        return true;}static unsigned intpool_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];      
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值