新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     计算机科学论坛     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 操作系统研究。UEFI
    [返回] 中文XML论坛 - 专业的XML技术讨论区计算机理论与工程『 操作系统原理 』 → [转帖]linux防火墙实现技术比较 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 7419 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: [转帖]linux防火墙实现技术比较 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     longshentailang 帅哥哟,离线,有人找我吗?
      
      
      威望:1
      等级:计算机学士学位
      文章:325
      积分:2990
      门派:XML.ORG.CN
      注册:2006/6/20

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给longshentailang发送一个短消息 把longshentailang加入好友 查看longshentailang的个人资料 搜索longshentailang在『 操作系统原理 』的所有贴子 引用回复这个贴子 回复这个贴子 查看longshentailang的博客楼主
    发贴心情 [转帖]linux防火墙实现技术比较


    一 前言
    此文是在aka(www.aka.org.cn)的一次讲座稿【12】基础之上修改而成(催稿,没办法),着重阐述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


    2.4内核中的防火墙系统不是2.2的简单增强,而是一次完全的重写,在结构上发生了非常大的变化。相比2.2的内核,2.4的检测点变为了五个。

    在每个检测点上登记了需要处理的函数(通过nf_register_hook()保存在全局变量nf_hooks中),当到达此检测点的时候,实现登记的函数按照一定的优先级来执行。严格的从概念上将,netfilter便是这么一个框架,你可以在适当的位置上登记一些你需要的处理函数,正式代码中已经登记了许多处理函数(在代码中搜nf_register_hook的调用),如在NF_IP_FORWARD点上登记了装发的包过滤功能。你也可以登记自己的处理函数,具体例子可参看【8】与【10】。

    3.3 FW1
    FW1是chekpoint推出的用于2.2内核的防火墙。由于其发布的模组文件带了大量的调试信息,可以从反汇编的代码中窥探到到许多实现细节。
    FW1通过dev_add_pack的办法加载输入过滤函数,如果对这个函数不熟悉,请参看【14】。但是此处有个问题:在net_bh()中,传往网络层的skbuff是克隆的,即
    skb2=skb_clone(skb, GFP_ATOMIC);
    if(skb2)
    pt_prev->func(skb2, skb->dev, pt_prev);
    这样的话如果你想丢弃此包的话,光将其free掉是不够的,因为它只是其中的一份拷贝而已。
    FW1是怎么解决这个问题的呢?见下面的代码(从汇编代码翻译成的C程序):

    packet_type *fw_type_list=NULL;

    static struct packet_type fw_ip_packet_type =
    {
    __constant_htons(ETH_P_IP),
    NULL, /* All devices */
    fw_filterin,
    NULL,
    NULL, /* next */
    };

    fwinstallin(int isinstall )
    {
    packet_type *temp;

    /*安装*/
    if(isinstall==0){
    dev_add_pack(&fw_ip_packet_type);
    fw_type_list = fw_ip_packet_type->next;

    for(temp = fw_type_list; temp; temp=temp->temp)
    dev_remove_pack(temp);
    }
    /*卸载*/
    else {
    dev_remove_pack(&fw_ip_packet_type);

    for(temp = fw_ip_packet_type; temp; temp=temp->next)
    dev_add_pack(temp);
    }
    }


       收藏   分享  
    顶(0)
      




    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/12/30 17:15:00
     
     longshentailang 帅哥哟,离线,有人找我吗?
      
      
      威望:1
      等级:计算机学士学位
      文章:325
      积分:2990
      门派:XML.ORG.CN
      注册:2006/6/20

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给longshentailang发送一个短消息 把longshentailang加入好友 查看longshentailang的个人资料 搜索longshentailang在『 操作系统原理 』的所有贴子 引用回复这个贴子 回复这个贴子 查看longshentailang的博客2
    发贴心情 

    不难看出,FW1把ip_packet_type歇载掉了,然后自己在自己的处理函数(fw_filterin)中调ip_recv。

    输出的挂载和lkm的手法一样,更改dev->hard_start_xmit。dev结构在2.2版本的发展过程中变了一次,为了兼容FW1对这点也做了处理(通过检查版本号来取偏移)。

    还有一款linux下的防火墙产品WebGuard(http://www.gennet.com.tw/b5/csub_webguard.html)采用的手法与FW1其非常类似。有兴趣的人可以自行研究一下。


    四 规则

    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
    未作分析。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/12/30 17:16:00
     
     longshentailang 帅哥哟,离线,有人找我吗?
      
      
      威望:1
      等级:计算机学士学位
      文章:325
      积分:2990
      门派:XML.ORG.CN
      注册:2006/6/20

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给longshentailang发送一个短消息 把longshentailang加入好友 查看longshentailang的个人资料 搜索longshentailang在『 操作系统原理 』的所有贴子 引用回复这个贴子 回复这个贴子 查看longshentailang的博客3
    发贴心情 

    五 与应用层的交互

    5.0 综述

    防火墙除了内核里的功能以外,还需要在应用层有相应的的配置工具,如添加修改规则等,这就涉及如何与内核通信的问题。
    内核模块有三种办法与进程打交道:首先是系统调用,缺点是必须添加新的系统调用或修改原有的,造成对内核代码原有结构的变换;第二种办法是通过设备文件(/dev目录下的文件),不必修改编译原有的代码,但在使用之前要先用mknod命令产生一个这样的设备;第三个办法便是使用proc文件系统。

    5.1 ipchains
    由于ipchains是已经是内核的正式一部分,它采用了修改系统调用的办法来添加修改命令,采用的办法就是扩展setsockopt系统调用:
    int setsockopt (int socket, IPPROTO_IP, int command, void *data, int length)

    man ipfw可以获得这方面的细节。

    ipchains应用程序首先要需要建立一个raw socket(libipfwc.c),然后在之上调用setsockopt。
    sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)

    调用顺序:
    ipchains在应用层调用setsockopt,进入内核:
    --->sys_socketcall(net/socket.c)
    --->sys_setsockopt(net/socket.c)
    --->inet_setsockopt(net/ipv4/af_inet.c)
    --->sock_setsockopt(net/core/sock.c)
    --->raw_setsockopt(net/ipv4/raw.c)
    --->ip_setsockopt(net/ipv4/ip_sockglue.c)
    --->ip_fw_ctl(net/ipv4/ip_fw.c)

    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基本相同。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/12/30 17:17:00
     
     longshentailang 帅哥哟,离线,有人找我吗?
      
      
      威望:1
      等级:计算机学士学位
      文章:325
      积分:2990
      门派:XML.ORG.CN
      注册:2006/6/20

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给longshentailang发送一个短消息 把longshentailang加入好友 查看longshentailang的个人资料 搜索longshentailang在『 操作系统原理 』的所有贴子 引用回复这个贴子 回复这个贴子 查看longshentailang的博客4
    发贴心情 

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

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

    >Linux内核技术
    >herze (stranger ) 01/15/01 02:54 PM
    >高手指点:PPP的发送函数在那里?
    >在Linux内核2.4.0中对于PPP数据包已经打好的包,内核中的ppp_generic.c文件中发送的流程好像如下
    >用到了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
    >思路这样 [re: herze]
    >内核中常有这样的类似处理,查找这种函数指针的一个好办法,就是找那种结构的实例,对于你的问题,就是找
    >ppp_channel_ops,最终会找到async_ops(ppp_async.c)和sync_ops(ppp_synctty.c),没看过这块的
    >具体代码,不敢多说,但思路如此。

    九 后记
    尽管此文中是在【12】的基础之上完成的,但是在内容上并未完全包括前者,感兴趣的朋友在那篇文章上可能能找到一些有趣的原始信息。由于时间关系,本文在此主题上的探讨仍显粗浅,对此只能说抱歉了。

    十 参考文献
    【1】了解Check Point FW-1状态表
    http://magazine.nsfocus.com/detail.asp?id=538
    【2】A Stateful Inspection of FireWall-1
    http://www.dataprotect.com/bh2000/
    【3】Linux IPCHAINS-HOWTO
    http://www.linuxdoc.org
    【4】防火墙新生代:Stateful-inspection
    http://www.liuxuan.com/safe/anquan/html/firewall/04.htm
    【5】netfilter站点上的文档
    http://netfilter.kernelnotes.org
    【6】Application Gateways and Stateful Inspection:A Brief Note Comparing and Contrasting
    http://www.avolio.com/apgw+spf.html
    【7】Internet Firewalls:Frequently Asked Questions
    http://www.interhack.net/pubs/fwfaq
    【8】Writing a Module for netfilter
    http://www.linux-mag.com/2000-06/gear_01.html
    【9】ipchains的源代码分析
    http://www.lisoleg.net/lisoleg/network/ipchains.zip
    【10】内核防火墙netfilter入门
    http://magazine.nsfocus.com/detail.asp?id=637
    【11】Check Point Firewall-1 on Linux, Part Two
    http://www.securityfocus.com/frames/?focus=linux&content=/focus/linux/articles/checkpoint2.html
    【12】防火墙技术分析讲义
    http://bj.aka.org.cn/Lectures/003/Lecture-3.1.1/Lecture-3.1.1/firewall.txt
    【13】IP分片重组的分析和常见碎片攻击 v0.2
    http://magazine.nsfocus.com/detail.asp?id=584
    【14】利用LLKM处理网络通信---对抗IDS、Firewall
    http://security.nsfocus.com/showQueryL.asp?libID=43

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2006/12/30 17:19:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 操作系统原理 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2025/5/12 13:57:01

    本主题贴数4,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    78.125ms