荔园在线

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

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


发信人: Chair (银发), 信区: Linux
标  题: LINUX FIREWALL设计
发信站: 荔园晨风BBS站 (Sun Feb  3 10:33:49 2002), 转信


发信人: szhunter (无聊人士), 信区: Linux
标  题: Linux防火墙程序设计
发信站: BBS 一网情深站 (Sat Feb  2 13:51:24 2002), 转信

http://www.lslnet.com/linux/docs/linux-2808.htm

Linux防火墙程序设计
蓝森林 http://www.lslnet.com 2000年6月12日 12:59
作 者: 赵泽良等
赵泽良 穆华俊
今年二月上旬,Yahoo、eBay、CNN.com、Amazon、Buy.com和E*Trade等著名商业网
站连
续遭到黑客攻击,造成了数以十亿美元的损失,向世人再一次敲响了网络并不安全
的警
钟。防火墙作为一种网络或系统之间强制实行访问控制的机制,是确保网络安全的
重要
手段。目前社会上各种商业产品的防火墙非常多,功能也大都很强。我们暂且不管
这些
防火墙产品的价格如何,由于它们在开发设计过程中注重的是产品的通用性、兼容
性,
考虑更多的是市场和利润,因此对于某些特殊的应用就不一定很合适。如果用户能
根据
自己的实际需要,将防火墙设计的一般理论和方法与自己系统的具体实践相结合,
设计
一些小而精、精而强的防火墙程序,则往往可以发挥出比花大价钱买来的通用型防
火墙
更好的作用。
由于篇幅所限,本文不可能对防火墙的一般理论和结构进行深入的讨论,因此仅以
Linu
x系统为例,具体说明防火墙程序的设计方法。
一、 从程序设计角度看Linux网络
编写防火墙程序并不一定要求对Linux网络内核有多么深刻的理解,只是需要明白
在网络
编写防火墙程序并不一定要求对Linux网络内核有多么深刻的理解,只是需要明白
在网络
内核中有这样一种机制,那就是内核可以自动调用用户编写的防火墙程序,并根据
这个
防火墙程序返回的结果来决定对网络收发数据报的处理策略。这一点可以从图1中
看出。

二、 怎样将自己编写的防火墙程序登记到内核中
我们已经知道内核在网络层中自动调用用户编写的防火墙程序。但有一个前提条件
就是
用户必须正确地将自己编写的防火墙程序登记到内核中。关于Linux内核驱动程序
的编写
方法,可参见本刊第四期中《Linux设备驱动程序设计实例》一文。
内核中提供了防火墙的登记和卸载函数,分别是register_firewall和
unregister_fire
wall,参见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,
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
* 参数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
上的同
原有功能,则可用rmmod命令卸载该程序,源代码见网站www.pccomputing.com.cn
上的同
名文章。
//   MyFirewall.c    2000年3月7日编写
#ifndef __KERNEL__
#  define __KERNEL__  //按内核模块编译
#endif
#ifndef MODULE
#  define MODULE  //按设备驱动程序模块编译
#endif
#include <linux/module.h> //最基本的内核模块头文件
#include <linux/sched.h>
#include <linux/kernel.h> //最基本的内核模块头文件
#include <linux/netdevice.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/if.h>
#include <linux/in.h>
#include <linux/firewall.h>
#define SOL_ICMP 1
#define PERMIT_PORT 80  //只允许访问TCP的80端口
int zzl_input(struct firewall_ops *this,int pf,struct device *dev,
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){
  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=
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);
 zzl_output,
}
(作者地址:北京市北三环中路四号750房 100720 收稿日期:2000.3.13)

--
※ 来源:.BBS 一网情深站 bbs.szptt.net.cn.[FROM: 218.17.67.169]

--


             岁岁年年朝朝暮暮

                     点点滴滴晃晃悠悠

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 203.93.19.1]


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

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