荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Lg (创造人生的传奇), 信区: Linux
标  题: linux下防火墙的编程实现(一)[转载]
发信站: BBS 荔园晨风站 (Sun May 28 13:54:24 2000), 站内信件

【 以下文字转载自 Hacker 讨论区 】
【 原文由 bstone 所发表 】
linux下防火墙的编程实现(一)

发布日期: 2000-5-18
内容:
------------------------------------------------------------------------
--------

--- 摘自<<绿盟月刊>>第九期

◆ linux下防火墙的编程实现一

作者:flag<flag@isbase.com>
主页:http://www.isbase.com
日期:2000-05-10

前言

    linux自带了ipchains作为自己的防火墙工具。现在有很多文章介绍如何使用
ipchains来把
linux机器配置成防火墙,但好像很少有文章介绍ipchains是如何实现的,也就是说
linux是如何
实现防火墙功能的。linux确实有自己的做法,它定义了针对防火墙实现的自己的
接口库,在内
核中的ip层上实现了防火墙。下面的文字是我从编程的角度对linux防火墙的一些
理解。

一·ipchains简介

    ipchains是linux的防火墙配置工具,以前叫ipfwadm,版本的更新非常快,现
在的版本号是
1.3.9。我们网站上的安全文摘中有一篇《ipchains参数介绍》,介绍了ipchains
的用法,请大
家参考。它的特点是定义了三条链,分别为ipput,forward和output链,然后对链
进行操作,如
添加删除等。它的功能很强,允许用户作很细的规则定义。本文目的不是介绍
ipchains的用法,
这段就请大家自己看书了。

二·linux防火墙实现分析

    1·基础知识

     tcp/ip协议处理进入的报文是把接口进入的报文放在一个缓冲区中,由ip进
程处理。在ip
层进行选路,决定包是路由还是发给某个套接口去处理。对于出去的报文,先有套
接口把报文
放在缓冲区中,ip进程再进行处理,决定从那个接口发送。这些工作是内核完成是TCPIP
协议处理包文的过程。

    2·linux防火墙分析

     linux防火墙是写在内核中的,具体是写在ip协议的中,ipchains只是一个命
令行程序,它
的作用是把我们写出的规则表达成系统认识的结构然后传给内核。 这是linux自己
做的工作,因
为在通用的套接口编程中可没有。

static int ipfwc_init()
{
ipfwc_fn = ipfwc_init;
init = 1;
return ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) != -1);
}
     大家可以看到这是起了一个原始套接口,但请注意socket的第三个参数,第
三个参数在创建
原始套接口时不为0,为一个常值,代表协议名,告诉系统此套接口接受什么协议
的包。具体由RFC
定义,在linux实现时,此常量定义在<netinet/in.h>中。但本文所用的
IPPROTO_RAW代表的常量是255,
在RFC中的定义是保留项,linux就利用了此保留项。当用IPPROTO_RAW起了套接口
后;

static int
do_setsockopt(int cmd, const void *data, int length)
{
return setsockopt(sockfd, IPPROTO_IP, cmd, (char *)data, length) != -1;

}

     setsockopt可以设置套接口选项,在这里,它被用来向系统传递特定的结构
,它的意义就是,
linux定义了一个接口库,这个库容许我们对内核进行操作,达到过滤包的目的。
这样的实现大大
简化了ipchains的工作,并且使得防火墙的效率很高。
三·一个例子

    为了验证上面的看法,我提供一个小例子,

#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <linux/if.h>
typedef char ip_chainlabel[9];

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 */
};
struct ip_fwuser
{
        struct ip_fw ipfw;
        ip_chainlabel label;
};
struct ipfwuser fwc_rule;
        ip_chainlabel fwc_label;
};

main(int argc,char **argv)
{
        static struct ip_fwchange new ;
        struct ip_fwchange *new1;
        const char *srcpts=NULL,*dstpts=NULL;
        static int sockfd = -1;
        new1=&new;
      if (argc!=2)
       {
        printf("usage: <ipaddress>\n");
        exit(1);
       }
        if((sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))==-1)
         {
          printf("init error!\n");
          exit(1);
         }
        memcpy(new.fwc_rule.label,"DENY",sizeof(new.fwc_rule.label));
        memcpy(new.fwc_label, "input", sizeof(new.fwc_label));
        if(inet_aton(argv[1],&new.fwc_rule.ipfw.fw_src.s_addr)==0)
         {
          printf("aton err!\n");
          exit(1);
         }
        new.fwc_rule.ipfw.fw_smsk.s_addr=0xffffffff;
        new.fwc_rule.ipfw.fw_dst.s_addr=0x00000000;
        new.fwc_rule.ipfw.fw_dmsk.s_addr=0x00000000;
        new.fwc_rule.ipfw.fw_spts[0]=0;
        new.fwc_rule.ipfw.fw_spts[1]=0xFFFF;
        new.fwc_rule.ipfw.fw_dpts[0]=0;
        new.fwc_rule.ipfw.fw_dpts[1]=0xFFFF;
        if(setsockopt(sockfd,IPPROTO_IP,64,&new,sizeof(new))==-1)
         perror("setsockopt err!");
        else
         printf("ok!\n");
exit(1);
}
为了大家方便,我把用到的结构列了出来,这些结构是系统定义的。对照上面所说
,我先起了个
第三个参数为IPPROTO_RAW的原始套接口,然后开始打包,源地址设为argv的参数
,源地址掩码
设为255.255.255.255,目的地址和目的地址掩码均不限,源端口和目的端口均设
为0-65535。
规则设为"DENY",链设为“input",大家看到结构中还有很多项可以设置,这里都省
略了。setsockopt
的第三项64为系统定义的常量,意思是"append",具体的定义大家可以参考
ipfw(4)。这个例子的
意思就是禁止命令行参数的ip地址的包进入linux的机器。小程序在radhat 6.1上
编译通过,大家
可以拿自己的ip地址做试验,但要在root权限下运行,因为设置原始套接口要
root权限。运行后你
就连不上你的linux服务器了。最方便的解决办法就是在root下运行ipchains -F。
大家看得出来
这个小程序实现的就是ipchains的部分功能。
    有了这种方法,我们可以自己做个界面就是防火墙了。不过那样不好用,局限
性太大。因为最
多可以做一个图形界面,比ipchains易用。如果要想实现自己的一些想法,就必须
改动内核。那么
内核是怎么处理我们传进去的规则的?咱们下期再谈。



    参考资料:Richard.Stevens的经典
              ipchains 1.3.9 源代码
              linux 2.2.12 ipv4源代码




--
 Welcome to http://192.168.28.98


※ 来源:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.28.106]
--
※ 转载:·BBS 荔园晨风站 bbs.szu.edu.cn·[FROM: 192.168.63.241]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店