博威---云架构决胜云计算

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 2084|回复: 2

linux防火墙实现技术比较(1)

[复制链接]
发表于 2007-7-21 15:35:44 | 显示全部楼层 |阅读模式
linux防火墙实现技术比较(1)


  

一 前言

此文着重阐述linux下的防火墙的不同实现之间的区别,以ipchains, iptables, checkpoint FW1为例。

二 基本概念

2.0

在进入正题之前,我将花少许篇幅阐述一些基本概念。尽管防火墙的术语这些年基本上没有太大的变化,但是如果你以前只看过90年代初的一些文献的话,有些概念仍然会让你混淆。此处只列出一些最实用的,它们不是准确的定义,我只是尽可能的让它们便于理解而已。

2.1 包过滤:

防火墙的一类。80年代便有论文来描述这种系统。传统的包过滤功能在路由器上常可看到,而专门的防火墙系统一般在此之上加了功能的扩展,如状态检测等。它通过检查单个包的地址,协议,端口等信息来决定是否允许此数据包通过。

2.2 代理:

防火墙的一类。工作在应用层,特点是两次连接(browser与proxy之间,proxy与web server之间)。如果对原理尚有疑惑,建议用sniffer抓一下包。代理不在此文的讨论范围之内。

2.3 状态检测:

又称动态包过滤,是在传统包过滤上的功能扩展,最早由checkpoint提出。传统的包过滤在遇到利用动态端口的协议时会发生困难,如ftp。你事先无法知道哪些端口需要打开,而如果采用原始的静态包过滤,又希望用到的此服务的话,就需要实现将所有可能用到的端口打开,而这往往是个非常大的范围,会给安全带来不必要的隐患。而状态检测通过检查应用程序信息(如ftp的PORT和PASS命令),来判断此端口是否允许需要临时打开,而当传输结束时,端口又马上恢复为关闭状态。

2.4 DMZ非军事化区:

为了配置管理方便,内部网中需要向外提供服务的服务器往往放在一个单独的网段,这个网段便是非军事化区。防火墙一般配备三块网卡,在配置时一般分别分别连接内部网,internet和DMZ。

2.5

由于防火墙地理位置的优越(往往处于网络的关键出口上),防火墙一般附加了NAT,地址伪装和VPN等功能,这些不在本文的讨论范围。

三 检测点

3.0 综述

包过滤需要检查IP包,因此它工作在网络层,截获IP包,并与用户定义的规则做比较。

3.1 ipchains

摘自【3】

----------------------------------------------------------------

| ACCEPT/ lo interface |

v REDIRECT _______ |

--> C --> S --> ______ --> D --> ~~~~~~~~ -->|forward|----> _______ -->

h a |input | e {Routing } |Chain | |output |ACCEPT

e n |Chain | m {Decision} |_______| --->|Chain |

c i |______| a ~~~~~~~~ | | ->|_______|

k t | s | | | | |

s y | q | v | | |

u | v e v DENY/ | | v

m | DENY/ r Local Process REJECT | | DENY/

| v REJECT a | | | REJECT

| DENY d --------------------- |

v e -----------------------------

DENY

总体来说,分为输入检测,输出检测和转发检测。但具体到代码的时候,输出检测实际分散到了几处(不同的上层协议走IP层的不同的流程):

UDP/RAW/ICMP报文:ip_build_xmit

TCP报文:ip_queue_xmit

转发的包:ip_forward

其它:ip_build_and_send_pkt

正如ipchains项目的负责人Rusty Russell所说,在开始ipchians不久,便发现选择的检测点位置错了,最终只能暂时将错就错。一个明显的问题是转发的包在此结构中必须经过三条链的匹配。地址伪装功能与防火墙模块牵扯过于紧密,如果不详细了解其原理的话,配置规则很容易出错。

此部分详细的分析可参见我早期的一份文章【9】。



3.2 iptables

A Packet Traversing the Netfilter System:

--->PRE------>[ROUTE]--->FWD---------->POST------>

Conntrack | Filter ^ NAT (Src)

Mangle | | Conntrack

NAT (Dst) | [ROUTE]

(QDisc) v |

IN Filter OUT Conntrack

| Conntrack ^ Mangle

| | NAT (Dst)

v | Filter
 楼主| 发表于 2007-7-21 15:37:20 | 显示全部楼层
linux防火墙实现技术比较(2)


四 规则


4.0 综述

4.1 ipchains

man ipfw可以看到这一段的详细解释。关键数据结构如下:

规则链用ip_chain结构来表示,缺省有input,ouptput,forward三条链。在配置规则的时候,也可以添加新的链。每条链事实上就是一组相关的规则,以链表的形式存储。

struct ip_chain

{

ip_chainlabel label; /* Defines the label for each block */

struct ip_chain *next; /* Pointer to next block */

struct ip_fwkernel *chain; /* Pointer to first rule in block */

__u32 refcount; /* Number of refernces to block */

int policy; /* Default rule for chain. Only *

* used in built in chains */

struct ip_reent reent[0]; /* Actually several of these */

};

每条规则用一个ip_fwkernel结构表示:

struct ip_fwkernel

{

struct ip_fw ipfw;

struct ip_fwkernel *next; /* where to go next if current

* rule doesn't match */

struct ip_chain *branch; /* which branch to jump to if

* current rule matches */

int simplebranch; /* Use this if branch == NULL */

struct ip_counters counters[0]; /* Actually several of these */

};

ip_fwkernel中的一个重要部分就是ip_fw,用来表示待匹配的数据包消息:

struct ip_fw

{

struct in_addr fw_src, fw_dst; /* Source and destination IP addr */

struct in_addr fw_smsk, fw_dmsk; /* Mask for src and dest IP addr */

__u32 fw_mark; /* ID to stamp on packet */

__u16 fw_proto; /* Protocol, 0 = ANY */

__u16 fw_flg; /* Flags word */

__u16 fw_invflg; /* Inverse flags */

__u16 fw_spts[2]; /* Source port range. */

__u16 fw_dpts[2]; /* Destination port range. */

__u16 fw_redirpt; /* Port to redirect to. */

__u16 fw_outputsize; /* Max amount to output to

NETLINK */

char fw_vianame[IFNAMSIZ]; /* name of interface "via" */

__u8 fw_tosand, fw_tosxor; /* Revised packet priority */

};

2.2内核中网络包与规则的实际匹配在ip_fw_check中进行。


4.2 iptables

一条规则分为三部分:

struct ipt_entry file://主要用来匹配IP头

struct ip_match file://额外的匹配(tcp头,mac地址等)

struct ip_target file://除缺省的动作外(如ACCEPT,DROP),可以增加新的(如REJECT)。

man iptable:

>A firewall rule specifies criteria for a packet, and a

>target. If the packet does not match, the next rule in

>the chain is the examined; if it does match, then the next

>rule is specified by the value of the target, which can be

>the name of a user-defined chain, or one of the special

>values ACCEPT, DROP, QUEUE, or RETURN.

2.4内核中网络包与规则的实际匹配在ip_do_table中进行。这段代码的流程在

netfilter hacking howto 4.1.3描述的非常清楚。

简化代码如下:

/* Returns one of the generic firewall policies, like NF_ACCEPT. */

unsigned int

ipt_do_table(struct sk_buff **pskb,

unsigned int hook,

const struct net_device *in,

const struct net_device *out,

struct ipt_table *table,

void *userdata)

{

struct ipt_entry *e;

struct ipt_entry_target *t;

unsigned int verdict = NF_DROP;

table_base = (void *)table->private->entries

+ TABLE_OFFSET(table->private,

cpu_number_map(smp_processor_id()));

e = get_entry(table_base, table->private->hook_entry[hook]);

...

ip_packet_match(ip, indev, outdev, &e->ip, offset);

...

IPT_MATCH_ITERATE(e, do_match, *pskb, in, out, offset, protohdr, datalen, &hotdrop)

...

t = ipt_get_target(e);

...

verdict = t->u.kernel.target->target(pskb, hook, in, out, t->data, userdata);//非标准的target走这一步

...

return verdict;

}

流程:

--->NF_HOOK();(/include/linux/netfilter.h)

--->nf_hook_slow;(/net/core/netfilter.c)

--->nf_iterate();(/net/core/netfilter.c)

--->然后运行登记的函数;如果你希望有一套ipt_entry结构规则,并将它放到table里,你此时便可调用ipt_do_table来匹配。

在2.4内核中,规则本身也是可扩展的,体现可自己定义并添加新的ip_match和ip_target上。

4.2 FW1

未作分析。
 楼主| 发表于 2007-7-21 15:38:04 | 显示全部楼层
5.2 iptables

原理同ipchains, 但内部命令格式作了大幅简化。详见nf_setsockopt()。


5.3 FW1

FW1 登记了一个字符设备,通过它来进行用户空间与内核空间的交互。相关代码(从汇编代码翻译成的C程序)如下:

static unsigned int fw_major=0;

static struct file_operations fw_fops=

{

NULL, /* lseek */

fw_read, /* read */

fw_write, /* write */

NULL, /* readdir */

fw_poll, /* poll */

fw_ioctl, /* ioctl */

NULL, /* mmap */

fw_open, /* open */

NULL, /* flush */

fw_release /* release */

NULL, /* fsync */

};

int init_module()

{

...

/*man register_chrdev

On success, register_chrdev returns 0 if major is a number

other then 0, otherwise Linux will choose a major number and

return the chosen value.*/

if(fw_major=register_chrdev(UNNAMED_MAJOR, “fw”, &fw_fops))

return -1;

...

}

void cleanup_module()

{

...

unregister_chrdev(fw_major, "fw");

...

}

fw_ioctl()用来做配置工作。

六 碎片的处理

6.0 综述

关于分片重组的实现可参看【13】。

6.1 ipchains

在2.2内核中除非设置了alway_defrag,否则包过滤模块不会对经过的包进行重组。它采用的办法是只看第一片,因为只有这一片中有完整的头信息,而后序的分片一律允许通过。为了防止分片欺骗(比如第一片极小,把传输层信息放到了第二片中),对这种正常情况中不可能出现的包做了而外的处理(太小的分片会被丢弃)。

6.2 iptables

在2.4内核有些变化,如果启动了conncetion track,所有到达防火墙的碎片都会重组,这点在以后可能会变化,正如howto 中说的,现在考虑的还只是功能的完备性,效率还要在以后的版本中改进。检测点也有了变化,输入检测在改在重组之后。

6.3 FW1

FW1对分片也做了额外处理,但目前尚未对其实现做仔细的分析。



七 状态检测

7.0 综述

基于状态的检测对管理规则提出了非常大的方便,现在已成了防火墙的一项基本要求。但目的明确之后,其实现可以选择多种不同的方法。

7.1 ipchains

ipchains本身不能完成状态检测,但有几份pacth为它做了一下这方面的补充,采用的是简单的动态添加规则的办法,这是作者对其的介绍:

> I believe it does exactly what I want: Installing a temporary

> "backward"-rule to let packets in as a response to an

> outgoing request.

7.2 iptables

在2.4内核中,基于状态的检测已经实现,利用的是connection track模块。此模块检查所有到来的数据包,将得到的状态(enum ip_conntrack_status)保留在sk_buff结构中(即skb->nfct,可通过ip_conntrack_get()得到)。

在规则中要指明状态信息(作为一个ipt_match),既实际上仍是比较每一条规则。从效率上,这种处理方式感觉不如下面FW1采用的方式好。

7.3 FW1

这段的代码没有做分析,但有一些文章通过黑箱操作的办法“猜测“出了它的实现原理,如【1】。除规则表以外,FW1另外维护一份状态表。当一个新的连接发生的时候,FW1与规则表配备,如果允许通过的话,则在状态表中建立相应表项。以后的数据过来的时候首先匹配状态表,如果它属于一个连接,便允许通过,而不再检查规则表。

草草看了一下BSD下的防火墙ipfilter的howto,感觉它的实现与FW1基本相同。

八 函数指针的问题

许多初读内核的人对函数指针的应用很不适应,在netfilter中更是用的非常广泛。大量register函数的应用,使得netfilter非常的模块化,但是给初学者带来的问题也不小。

这里是linuxforum上的一份帖子,如果看代码时对函数指针的指向总是糊里糊涂的话,可借鉴一下这个思路(当然关键还是要找到指针初始化的地方):

>Linux内核技术

>herze (stranger ) 01/15/01 02:54 PM

>高手指点:PPP的发送函数在那里?

>在Linux内核2.4.0中对于PPP数据包已经打好的包,内核中的ppp_generic.c文件中发送的流程好像如下

>ppp_file_write()->ppp_xmit_process()->ppp_push()(可能也由其它的发送流程,但是最后都是

>用到了ppp_push())这个函数,而这个函数调用了一个struct channel中struct ppp_channel中的

>struct ppp_channel_ops 中的一个函数指针

>int (*start_xmit)(struct ppp_channel *, struct sk_buff *)来进行发送的,但是下面我就不明白了。

>虽然在drivers/char/cyclades.c和drivers/char/serial167.c中找到了

>start_xmit( struct cyclades_port *info )但是函数说明都不相同。

>请教:

>int (*start_xmit)(struct ppp_channel *, struct sk_buff *)

>到底这个函数指针是指到了什么地方?

>是不是和具体的硬件有关,但是我怎么在内核中找不到对应的函数?

>Linux内核技术

>yawl (stranger ) 01/15/01 11:31 PM
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|boway Inc. ( 冀ICP备10011147号 )

GMT+8, 2024-5-4 17:27 , Processed in 0.089084 second(s), 16 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表