Linux防火墙netfilter的编程接口libiptc简介

本文作者:admin       点击: 2007-06-07 00:00
前言:
libiptc库是Linux防火墙netfilter的一个编程接口,可以使用libiptc库来查询、修改、增加、删除netfilter的规则、策略等。大家熟知的防火墙管理工具iptables也是利用libiptc来实现配置管理的。在应用程序中我们也可以利用libiptc库完成对Linux防火墙的配置管理功能,从而达到与防火墙的联动效果。比如,用户认证系统可以在用户认证后使用libiptc库动态开通其网络访问权力;而在用户下线后动态关闭其网络访问权力。
目前对于libiptc库的介绍资料主要是Leonardo Balliache整理的《Querying libiptc HOWTO》,该文档详细介绍了libiptc库的安装方法和库函数中查询函数的使用方法。美中不足的是该文档没有介绍增加、删除规则的方法。笔者通过阅读源码和试验初步摸索出使用libiptc库增加、删除防火墙规则的基本方法,在此整理出来供大家参考。

基本概念

使用libiptc库的目的是处理防火墙的规则,规则是隶属于表(table)和链(chain)的。规则可以划分为基本部分、匹配部分以及目标部分。如下:
例一、 iptables-A FORWARD-s 192.168.3.2 -p tcp-dport 80-j ACCEPT
上例中,表是filter(默认),链是 FORWARD,-dport 80是规则的匹配部分,而-j ACCEPT是规则的目标部分。在libiptc库中,表和链都是以字符串形式表示的;规则是用多个数据结构来描述。规则的三个主要部分(基本部分、匹配部分以及目标部分)分别对应着相应的数据结构:struct ipt_entry、struct  ipt_entry_match 、struct  ipt_entry_target 。
将上述规则转换为对应的libiptc库的程序,大体如下:
1、 使用iptc_init函数对表filter进行初始化,获取该表的句柄
h = iptc_init(“filter”);  //针对filter表获取表句柄h
2、 构造规则(包括匹配和目标部分)
//定义ipt_entry_target描述-j ACCEPT
//定义ipt_entry_match描述-dport 80
//定义ipt_entry 描述-s 192.168.3.2 -p tcp ;并且把上述的匹配和目标都组合进来
     ……
3、 调用iptc_append_entry或iptc_insert_entry函数,在filter表FORWARD链中添加该规则
iptc_append_entry(“FORWARD”,&e,&h);
由于netfilter防火墙是可扩展的,描述其规则的数据结构也因此是可扩展的。使用libiptc库的主要技巧就是掌握动态构造这些数据结构的方法。下面我们介绍规则的基本描述方法。
        
主要数据结构

libiptc库的主要数据结构就是描述规则的结构。具体而言是ipt_entry、ipt_entry_target、ipt_entry_match 三个主体结构以及它们引用的一些描述细节信息结构。这些结构的定义主要在iptables.h文件中。
结构ipt_entry是防火墙规则的载体,除了记录规则的基本信息以外还集成封装了规则的匹配部分以及目标部分。其定义如下:
对于上述例子,该规则的基本信息“-s 192.168.3.2  -p tcp ”在属性ip中描述;匹配信息“-p tcp —dport 80”以及目标信息“-j ACCEPT”需要动态构造然后依次附加到elems位置;属性target_offset和next_offset用来将目标部分的位置明确标识出来。
属性ip是一个ipt_ip类型的结构,用来记录源ip地址、源接口、目的ip地址、目的接口等基本信息。其定义如下:
填写本结构时有特殊的要求:需要设置相应的标志。比如下:
● 填写源ip信息ip.src时,需要填写ip.smsk属性(否则系统不理会ip.src的信息)。正常情况下,ip.smsk填写子网掩码信息,如果没有子网掩码信息时,可取值 -1 ;
● 填写接口信息ip.iniface时,需要填写ip.iniface_mask属性。对应iniface名字字符(包括null结尾)的位置都设置为0xff。
● 协议proto属性,取值可参见/etc/protocols文件里各协议的编号值。
结构ipt_entry_target描述防火墙规则的目标部分,其简化定义如下:
上述结构中变长Data部分的内容是与防火墙模块相关的。对于filter表,内置目标(ACCEPT、DROP等)或者自定义链目标的data部分长度为IPT_ALIGN(sizeof(int)),内容为0 。但是对于nat表等,data部分也是变长的结构,需要根据实际规则构造。
结构 ipt_entry_match 描述防火墙规则的匹配部分,其逻辑定义如下:
与ipt_entry结构一样,ipt_entry_match结构本身也需要额外的扩展来进一步描述match的细节信息(在data部分)。对于上述例子 -dport 80 而言,需要结构ipt_tcp来描述tcp协议端口范围信息。结构ipt_tcp的定义如下:
上述结构中,描述tcp端口时必须用范围的方式描述。对于例子的-p tcp —dport 80 ,描述的伪代码:
spts[0] = 0;
spts[1] = 0xffff; 
dpts[0] = 80 ; 
dpts[1] = 80 
可以看出,不同的match内容对应不同的结构。在使用libiptc库时需要根据规则的种类来找出相应的匹配结构。

添加一个规则

libiptc库提供了iptc_insert_entry、iptc_append_entry两个函数。可以在指定位置上增加一个规则,也可以在链尾附加一个规则。如前所述,使用这些函数的关键问题就是描述规则。以下介绍常见规则的描述方法。
规则一: iptables -A INPUT -i eth0 -p icmp -j DROP
本规则中没有匹配部分,只有目标。以下为上例中规则部分的描述代码。
需要说明的是:上述的目标描述方法适合filter表的标准内置目标(ACCEPT、DROP)也适合目标为用户自定义链名的情况。
规则二:iptables -A FORWARD -s 192.168.3.2  -p tcp  --dport 80  -j ACCEPT
本规则多了tcp的匹配部分 -p tcp -dport 80。需要专门描述。
本规则的代码片断为:
本段代码中增加了匹配的描述,可以看到在ipt_entry结构的末尾首先附加匹配条件的描述,其后是目标部分的描述。ipt_entry中属性target_offset记录着目标部分的起始位置而属性next_offset记录着目标的结束位置。
     
删除一个规则

Libiptc库提供了删除链、规则的接口。删除规则,有多种模式:可以清空链内的所有规则;可以指定规则号来删除该编号对应的规则;也可以根据规则内容删除该规则。
命令一、iptables -D INPUT  1   删除规则号为1的规则
函数iptc_delete_num_entry函数可以按规则号删除指定的规则。需要注意的是在使用iptables命令时规则号是从1开始计数的;但是在调用libiptc库函数时规则号是从0开始计数的。
命令二:iptables -D FORWARD -s 192.168.3.2  -p tcp  --dport 80  -j ACCEPT
本命令根据规则内容来删除相应的规则。
函数iptc_delete_entry根据规则内容删除一个规则。使用此函数时与增加规则一样需要先定义ipt_entry结构来描述规则内容,然后调用iptc_delete_entry函数。
规则描述部分与上一节中增加该规则的描述方法一样,只是最后调用的是删除函数,如下:
此外,也可以用iptc_flush_entries可以清空指定链的规则,实现类似iptables -F INPUT的功能。
查询已有规则
libiptc库查询的方法主要是遍历:指定一个表,可以便利这个表内的链;指定一个链,可以遍历这个链内的规则。
具体方法是使用iptc_first_rule函数获取特定链的第一个规则;然后使用iptc_next_rule依次获取后面的规则。获取规则后,可以用上面介绍的内容得到规则的细节信息。
     
结语

libiptc库的函数都比较直观,使用此库的主要困难是描述规则。规则主要分为基本部分、匹配部分、目标部分。它们都是变长的结构。在实际编程中主要是根据具体的防火墙规则来构造相应的匹配、目标等数据结构。由于篇幅所限本文只介绍了基本的构造方法,以给大家提供一个入门的参考。由于没有官方资料参考再加上笔者能力有限,文中内容有不足之处还请读者指正。
文中的代码的测试环境:linux2.6.11.12内核,iptables-1.3.7版本 ,intel平台。