那位做过防火墙软件?能否给点提示?(5分)

  • 主题发起人 主题发起人 billrobin
  • 开始时间 开始时间
B

billrobin

Unregistered / Unconfirmed
GUEST, unregistred user!
那位做过防火墙软件?能否给点提示?
 
这篇文章可能有些帮助,是linux下的
  作 者: 赵泽良等
一、 从程序设计角度看Linux网络
  编写防火墙程序并不一定要求对Linux网络内核有多么深刻的理解,只是需要明白在
网络内核中有这样一种机制,那就是内核可以自动调用用户编写的防火墙程序,并根据
这个防火墙程序返回的结果来决定对网络收发数据报的处理策略。这一点可以从图1中
看出。
  二、 怎样将自己编写的防火墙程序登记到内核中
我们已经知道内核在网络层中自动调用用户编写的防火墙程序。但有一个前提条件就是用
户必须正确地将自己编写的防火墙程序登记到内核中。关于Linux内核驱动程序的编写方
法,可参见本刊第四期中《Linux设备驱动程序设计实例》一文。
内核中提供了防火墙的登记和卸载函数,分别是register_firewall和
unregister_firewall,参见firewall.c。
1、 register_firewall
  函数原型如下:
  int register_firewall(int pf,struct firewall_ops *fw)
  返回值:0代表成功,小于0表示不成功。
  参数:
  * 协议标志pf,主要的取值及其代表的协议如下:
  2代表Ipv4协议,4代表IPX协议,10代表Ipv6协议等。
  * 参数结构fw定义如下:
  struct firewall_ops{
  struct firewall_ops *next;
  int (*fw_forward)(struct firewall_ops *this, int pf,
  struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
  int (*fw_input)(struct firewall_ops *this, int pf,
  struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
  int (*fw_output)(struct firewall_ops *this, int pf,
  struct device *dev, void *phdr, void *arg, struct sk_buff **pskb);
  int fw_pf;
  int fw_priority;
  };
  结构中next的域将由内核来修改,使其指向下一个防火墙模块。
  fw_pf域为协议标志,含义同上。
  fw_priority指定优先级,一般应大于0。
  fw_input、fw_output、fw_forward是用户编写的防火墙函数模块,
在接收到网络报和发送网络报时内核将调用这些模块,后面将详细讨论。
2、 unregister_firewall
  unregister_firewall的原型说明与调用方法同register_firewall。
三、 防火墙函数模块的设计
1、 防火墙函数模块的返回值
  返回值是至关重要的,内核将根据它来决定对网络数据报采取的处理策略。主要返回
值及意义如下:
  0和1 通知内核忽略该网络报。
  -1 通知内核忽略该网络报,并发送不可达到的网络控制报(ICMP报文)。
  2 通知内核认可该网络报。
2、 各模块函数的入口参数
  * 参数this
  指向register_firewall中的fw参数结构。
  * 参数pf
  含义同register_firewall中的pf参数。
  * 参数dev
  dev是指向数据结构device的指针。在Linux系统中,每一个网络设备都是用device数
据结构来描述的。在系统引导期间,网络设备驱动程序向Linux登记设备信息,如设备名、
设备的I/O基地址、设备中断号、网卡的48位硬件地址等,device数据结构中包括这些设备
信息以及设备服务函数的地址。关于device结构的详细信息可参见netdevice.h头文件。
  * 参数phdr
  该参数指向链路层数据报报头首址。
  * 参数arg
  利用这个参数可以向内核传递信息,如重定向时的端口号。
  * 参数pskb
  此参数是指向sk_buff结构指针的指针。在Linux中,所有网络数据的发送和接收都
用sk_buff数据结构表示。在sk_buff数据结构中包含有对应设备结构的device地址、传
输层、网络层、链路层协议头地址等。关于sk_buff的定义可参见skbuff.h头文件。
  3、防火墙程序示例
  下面给出一个简单防火墙程序。在这里假设读者对以太协议、IP协议、TCP协议等
常用协议有一定的了解。用命令行"gcc -Wall -O2 -c MyFirewall.c"进行编译,再用
insmod命令加载程序后,系统将只响应外部网络用TCP协议的80端口所进行的访问。要让
系统恢复原有功能,则可用rmmod命令卸载该程序,
源代码见网站www.pccomputing.com.cn上的同名文章。

  // MyFirewall.c 2000年3月7日编写
  #ifndef __KERNEL__
  # define __KERNEL__ //按内核模块编译
  #endif
  #ifndef MODULE
  # define MODULE //按设备驱动程序模块编译
  #endif
  #include //最基本的内核模块头文件
  #include
  #include //最基本的内核模块头文件
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #define SOL_ICMP 1
  #define PERMIT_PORT 80 //只允许访问TCP的80端口
int zzl_input(struct firewall_ops *this,int pf,struct device *dev,
  void *phdr,void *arg,struct sk_buff **pskb)
  {//每当收到一个网络报时,此函数将被内核调用
  struct tcphdr *tcph;
//TCP的头指针
  struct iphdr *iph;
//IP头指针
  struct sk_buff *skb=*pskb;
  if (skb->protocol==htons(ETH_P_ARP)){
  printk("/nPermit a ARP Packet");
  return FW_ACCEPT;//允许地址解析协议报
  }
  if(skb->protocol==htons(ETH_P_RARP)){
  printk("/nPermit a RARP Packet");
  return FW_ACCEPT;//允许反向地址解析协议报
  }
  if(skb->protocol==htons(ETH_P_IP))
  {
  iph=skb->nh.iph;
  if (iph->protocol==SOL_ICMP)
  {
  printk("/nPermit a ICMP Packet");
  return FW_ACCEPT;//允许网络控制报
  }
  if(iph->protocol==SOL_TCP){
  tcph=skb->h.th;
  if(tcph->dest==PERMIT_PORT){
  printk("/nPermit a valid access");
  return FW_ACCEPT;//允许对TCP端口80的访问
  }
  }
  }
  return FW_REJECT;//禁止对本计算机的所有其它访问
  }
  int zzl_output(struct firewall_ops *this,int pf,struct device *dev,
  void *phdr,void *arg,struct sk_buff **pskb)
  {//程序编写方法同zzl_input函数模块
  printk("/nzzl_output is called ");
  return FW_SKIP;
  }
  int zzl_foreward(struct firewall_ops *this,int pf,struct device *dev,
  void *phdr,void *arg,struct sk_buff **pskb)
  {//程序编写方法同zzl_input函数模块
  printk("/nzzl_foreward is called ");
  return FW_SKIP;
  }
  struct firewall_ops zzl_ops=
  {
  NULL,
  zzl_foreward,
  zzl_input,
  zzl_output,
  PF_INET,
  01
  };
  int init_module(void)
  {
  if(register_firewall(PF_INET,&zzl_ops)!=0)
  {
  printk("/nunable register firewall");
  return -1;
  }
  printk("/nzzl_ops=%p",&zzl_ops);
  return 0;
  }
  void cleanup_module(void)
  {
  printk("unload/n");
  unregister_firewall(PF_INET,&zzl_ops);
  }
 
用http协议就可,对大多数来说.
 
接受答案了.
 
后退
顶部