A example of NF_IP_PRE_ROUTING module(转载)
来源:互联网 发布:云南旅游攻略 知乎 编辑:程序博客网 时间:2024/05/16 02:31
1、 要做什么 - 在netfilter Hook点注册一个自己的Hook函数,截取每一个数据包
- 读取文件,获取IP列表
- Ip匹配
- 是否进行重定向的工作,是否丢弃等
2、netfilter结构以及HOOK点的选择
Fig.1 Hook Point of netfilter
[选择]NF_IP_PRE_ROUTING(local process所发送的包不在限制之列)
3、NF_IP_PRE_ROUTING下优先级的选择
Hook点的Hook函数依照优先级一次执行。
2.6Kernel下(2.4Kernel下自己查询)PREROUTING的HOOK操作主要有(依优先级大小):
(1) .hook = ip_sabotage .priority = NF_IP_PRI_FIRST
丢弃skb结构中设置桥参数但没有相关桥标志的包
(2) .hook = ip_conntrack_defrag .priority = NF_IP_PRI_CONNTRACK_ DEFRAG //(-400)
完成分片重组,之后处理过程中的包都是非分片包,直到包要送出本机
(3) .hook = ipt_hook .priority = NF_IP_PRI_RAW //(-300)
raw表,提供对收到的数据包在连接跟踪前进行处理的手段
(4) .hook = ip_conntrack_in .priority = NF_IP_PRI_CONNTRACK //(-200)
完成连接跟踪,为每个skb找到所属连接(ESTABLISHED, REPLY)或新建连接(NEW, RELATED)
(5) .hook = ipt_route_hook .priority = NF_IP_PRI_MANGLE //(-150)
mangle表,提供对收到的数据包进行修改的处理
(6) .hook = ip_nat_in .priority = NF_IP_PRI_NAT_DST //(-100)
对刚收到的本机skb包进行目的NAT操作,只对NEW包处理
(7) .hook = ing_hook .priority = NF_IP_PRI_FILTER + 1 //(1)
对进入本机的skb包进行排队处理,Qos操作
[选择] .priority = NF_IP_PRI_CONNTRACK + 1(暂定)。 经过ip_conntrack_in之后,就可以判断连接状态,这样在进行IP匹配之前,可以判断这个状态,进一步减少要进行IP匹配包的数量4、总体程序框架设计
数据结构与全局变量
struct ip_hash_data { char *ip_str; }; typedef struct ip_hash_data *ip_hash_elem; struct ip_hash_entry { ip_hash_elem elem; struct ip_hash_entry *next; }; typedef struct ip_hash_entry *ip_hash_table; struct global_param { ip_hash_table *ipt_install; ip_hash_table *ipt_update; int ip_num_install; int ip_num_update; struct ip_hash_data data_install[4999]; struct ip_hash_data data_update[4999]; }; 调用ip_hash_create创建2个空hash链表ipt_install 和 ipt_update 调用2次fileread模块填充2个hash链表 调用rising_ip_match模块进行过滤匹配以及后续处理 static struct nf_hook_ops ip_match_ops = { .hook = ip_match, //主函数 .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_IP_PRE_ROUTING, .priority = NF_IP_PRE_CONNTRACK + 1, }; static int __init init(void) { int ret; ret = nf_register_hook(ip_match_ops); //注册自己的Hook函数 if(ret < 0) goto cleanup_hook; return ret; cleanup_hook: nf_unregister_hook(ip_match_ops) return ret; } module_init(init); ... file_read() static int fileread(const char *filename, ip_hash_table **ipt) 根据filename读取文件获取ip列表 调用hash模块的ip_hash_insert插入hash元素 (1) int packet_judge(struct sk_buff **pskb) 在匹配IP列表匹配之前,先允许通过一些没必要IP匹配的包: 从外网卡进来的包,不是IP包,包状态不是NEW的包 (2) int is_in_ip_list(struct sk_buff **pskb, ip_hash_table *ipt,) 调用ip_hash_find查找源IP是否在hash链表中 (3) void ip_redirection(struct sk_buff **pskb, char *ip_str) 针对NEW包完成重定向功能,包目的地址改成ip_str static unsigned int ip_match( unsigned int hook, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { int ret; ret = get_list_from_server(); if(ret < 0) { printk(KERN_NOTICE “cannot get list from server.”); return NF_DROP; //拒绝所有包通过 } //让一些不用IP匹配的包通过,比如不是IP包,或者是ESTABLISHED的包,或者从外网卡发送过来的包。 ret = packet_judge(); if (ret == 0) return NF_ACCEPT; //进行IP匹配 if(is_in_install_list) { if(is_in_update_list) return NF_ACCEPT; //允许通过 else ip_redirection(); //转向update页面 } else ip_redirection(); //转向安装页面 return NF_ACCEPT; } 有这么几种选择: Ø 可以在应用层写一个程序,接受ip_list并写入文件ip_list_install,ip_list_update。而在内核里只要用sys_read()进行简单的文件读取。 Ø 在内核中使用常用的socket函数完成ip_list的获取。比如调用bind(),可以用sys_socketcall(SYS_BIND, args)替代。 Ø 使用kernel socket lib完成ip_list的获取。常用的函数比如 sock_create_kern(), send_msg()等。 Ø 使用内核线程(没有mm域,会造成竞争以及并发的问题,不推荐使用) Ø 自己构建TCP包,依葫芦画瓢构建SYN ACK的数据结构sk_buff以及TCP DATA,再用dev_queue_xmit()发送出去(该方法着眼于具体的包,有很多可以改进的地方,比如可以与服务器商定,在含有ip_list的包中,sk_buff的数据区域的最前面多加一些信息用于判断这个包是否位含有ip_list的包) 问题:一个程序的kernel内核栈一般为8KB,而一个IP占4个byte,即使4000个也占有16KB。 static int packet_judge(struct sk_buff **pskb) { //在sk_buff中包含有三个union,分别为传输层、网络层和链路层的头,可以通 //过判断这些头部进行这些数据包的率选。 //当然,还可以通过sk_buff的其他部分进行判断,比如成员struct nf_ct_info //*nfct 判断IP包的连接状态是否为ESTABLISHED //再比如判断是哪个网卡接受过来的包,判断是内网卡还是外网卡 // 等等 } IP的匹配无论放在核内还是核外都是一件很耗资源的事情(建议放在内核外面,不然会拖慢内核效率) 由于IP列表包含的IP数量多,一项一项地匹配是意见效率不高的事情,改进的一些想法有(留待进一步讨论): Ø hash表:一种用空间换取时间的方法,因为对于机器而言,用数组下标找寻数据是很快的方法,而hash表的作用就是把散列的数据用数组的形式进行存储。 Ø 其他方法(未及多想) static int ip_redirection(struct sk_buff **pskb, u_int_32_t ip) { //修改sk_buff中ip头的daddr,指定目的地址 (*pskb)->nh.iph->daddr = ip; //? } 注1:替代inet_addr和inet_itoa unsigned long inet_addr_my(char *ip_str); char *inet_itoa_my(unsigned long ip_num); char *iota(unsigned long num); 注2:对sk_buff理解的差异:在这个插入点上,即使时TCP包,我发现(*pskb)->h.th->dest并没有得到我想要的目的端口,而只能通过struct tcphdr *tcph = (struct tcphdr *)((*pskb)->nh.iph + (*pskb)->nh.iph->ihl)来获取tcph的数据 init()(example, 2.6 kernel 下, 2.4 kernel改变不大)
ip_match()
get_list_from_server()
packet_judge()
is_in_install_list(), is_in_update_list()
ip_redirecton()
- A example of NF_IP_PRE_ROUTING module(转载)
- A example of NF_IP_PRE_ROUTING module(转载)
- A example of NF_IP_PRE_ROUTING module(转载)
- A example of NF_IP_PRE_ROUTING module PART_1(转载)
- A example of Log4c
- A example of pointer
- OpenERP Server Developers Documentation (Openerp服务器开发文档)之 Module 之 Example of module creation
- A wrong example of pointer
- A good example of equals()
- Module Example
- SQL: A example of creating a procedure
- a simple example of Ado.net
- A example of "Connect to ArcIMS"
- A example of "Connect to ArcSDE"
- Sun DefaultColorPhone : A programming example of TouchScreen.
- A Simple Example of Weak Ref Cursor
- A Example of Factory Method for Java
- Example of a SysTray App in Win32
- Ext.tree如何创建树以及动态加载树
- 跟我一起走进WPF的世界之一学了WPF能做什么?
- Servlet生命周期
- Windows环境下hadoop安装——ssh配置
- weblogic servlet关于war包
- A example of NF_IP_PRE_ROUTING module(转载)
- 信息摘要算法-CRC(循环冗余校验)
- 实例化bean的三种方式
- A example of NF_IP_PRE_ROUTING module(转载)
- 《转载》android context 与内存泄露
- Hadoop RPC 实例
- OpenMP模式下多线程文件操作(二)
- s3c2440地址空间的分配(转)
- 工厂方法模式与抽象工厂模式的区别