PktFilter使用参考
tombkeeper@whitecell.org
/* 这份文档主要是基于PktFilter 所附带的PktFilter.pdf,修正了一些原文的错误,增 加了一些我自己的使用经验。
我喜欢这个防火墙主要是因为资源占用比较少,UNIX风格,没有图形界面,没有讨厌的 的系统托盘图标。
和IP Filter一样,这个防火墙不是为对安全一无所知或者略有所知的人设计的,要打 算使用它请确定你了解TCP/IP 协议等基础知识。如果对程序有问题,请写信问程序作 者:Jean-Baptiste.Marchand@hsc.fr。如果对使用有问题,也请写信问作者。我对这 份文档、规则生成脚本、修改过的程序不提供任何支持。 */
PktFilter是一个运行在Windows 2000/XP/2003上的包过滤防火墙。
PktFilter自己并没有实现网络过滤驱动,事实上它是系统本身包过滤机制的一个配置 界面。Windows 2000以上的操作系统都有一个IpFilterDriver 服务,但是系统本身却 没有提供好用的配置界面。
因为是调用系统自身的机制,所以PktFilter工作得很稳定,占用资源也较少,但也正 因为如此,PktFilter的功能实现也受限于系统。
PktFilter的规则语法其实是IP Filter4的一个子集。可以参考http://www.ipfilter.org/。
---------- 安装使用: ----------
为PktFilter创建一个目录,将pktfltsrv.exe和pktctl.exe拷贝进来。
创建规则文件。大家可以根据下面介绍的语法自己编写规则。如果把PktFilter安装在 一台作为网关的机器上,并编写相应的规则,那么PktFilter 可以很好地作为一个网 络防火墙工作。
如果只是用来保护个人计算机,不需要设置太复杂的规则,那么你可以使用我写的脚本 rulesbuild.cmd。只需设置文件开头的一些变量,就可以迅速地生成一个规则。
安装启动服务: C:\PktFilter> pktfltsrv -i "C:\PktFilter\PktFilter.conf" "C:\PktFilter\PktFilter.log"
C:\PktFilter> net start pktfilter
------------- 过滤规则介绍: -------------
全局选项 option small_frags, 拒绝太小的的分片包,默认small_frags是指小于16 bytes的 分片包。这个值可以通过建立注册表 HKLM\SYSTEM\CurrentControlSet\Services\IpFilterDriver\FragmentThreshold 来设定。 strong_host, 这个文档里面没说,但是程序支持,MSDN的解释是 “Causes a check of the destination address of incoming packets.” check_frags,这个文档里面没说,但是程序支持,MSDN的解释是 “Causes a check of the fragments from the cache.” 过滤动作 pass, 允许 block, 阻塞
方向 in, 进来的 out, 出去的
协议 proto, 包括: tcp, TCP 协议 udp, UDP 协议 icmp, ICMP 协议 [number], 指定其他的IP协议号 [empty], 所有协议
源地址 from [addr], 指定一个IPv4地址 from [subnet/mask],指定一个网络
源端口(仅限TCP/UDP协议) port [表达式] [端口号] 表达式包括: = >= > <= < >< 端口范围
目标地址 to [addr], 指定一个IPv4地址 to [subnet/mask],指定一个网络
目标端口(仅限TCP/UDP协议) port [表达式] [端口号] 表达式包括: = >= > <= < >< 端口范围
ICMP类型和代码 icmp-type [type] icmp-code [code]
TCP连接建立 established, 阻塞只有SYN标志位而没有ACK标志位的TCP包,放在规则末尾表示 只允许连接建立后的TCP包通过。
----- 例子: -----
# drop packets composed of small fragments option small_frags on eth0 # default behavior = deny everything block in on eth0 all block out on eth0 all # allow DNS resolution to our nameserver pass out on eth0 proto udp from 192.168.1.1 port > 1023 to 192.168.1.254 port = 53 pass in on eth0 proto udp from 192.168.1.254 port = 53 to 192.168.1.1 port > 1023 # allow inbound ICMP traffic (ping) pass in on eth0 proto icmp from any to 192.168.1.1 icmp-type echo pass out on eth0 proto icmp from 192.168.1.1 type echo-rep to any # allow RDP (Terminal Services) administration from our administration subnet pass in on eth0 proto tcp from 10.42.42.0/24 port > 1024 to 192.168.1.1 port = 3389 pass out on eth0 proto tcp from 192.168.1.1 port = 3389 to 10.42.42.0/24 port > 1024 established
------------- 过滤规则参考: -------------
过滤规则由全局选项(global-option)和普通规则(normal-rule)组成。
全局选项的语法: "option" global_option iface
现在支持的global-option只有"small_frags"。
普通规则的语法: action [in-out] iface [proto_spec] ip [proto-options]
action = "pass" | "block" in-out = "in" | "out" iface = "on" ifname digit ifname = "eth*" | "ppp" | "sl" | "lo" | "tr" | "fd" proto_spec = "proto" [proto] proto = "tcp" | "udp" | "icmp" | "any" | ip_proto ip_proto = decnumber decnumber = digit [decnumber] ip = "all" | "from" ip-addr [port-comp | port-range] "to" ip-addr [port-comp | port-range] ip-addr = "any" | ip-dotted-addr [ip-mask] ip-dotted-addr = host-num "." host-num "." host-num "." host-num host-num = digit [digit [digit]] ip-mask = "/" ip-addr | decnumber port-comp = "port" comparator decnumber comparator = ">" | ">=" | "<" | "<=" | "=" port-range = "port" decnumber "><" decnumber proto-options = "icmp-type" icmp-type ["code" icmp-code] | "established" icmp-type = "echorep" | "unreach" | "squench" | "redir" | "echo" | "router_adv"| "router_sol" | "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" | "inforep" | "maskreq" | "maskrep" icmp-code = decnumber
----------------- pktctl命令的用法: -----------------
pktctl有两种用法:命令行模式和交互模式。pktctl -i进入交互模式。
列出网络接口: C:\> pktctl -I eth0: (3Com EtherLink PCI): 192.168.0.1
加载规则文件: C:\> pktctl -f rules.txt pktctl> source rules.txt
先清除所有已加载的规则再加载规则文件: C:\> pktctl -F rules.txt pktctl> reload rules.txt
手工临时添加一条规则: C:\> pktctl -a "pass in on eth0 from 10.0.0.42 to any" pktctl> pass in on eth0 proto udp from 10.0.0.42 to any
列出指定接口上的规则: C:\> pktcl -l eth0 pktcl> list on eth0
列出指定接口上的规则和规则号: option: C:\> pktcl -L eth0 pktcl> List on eth0 在删除规则的时候需要指定规则号。
删除规则: C:\> pktctl -d 2 eth0
删除指定接口上的所有规则: C:\> pktctl -Fa eth0 pktctl> flush on eth0
删除所有接口上的所有规则: C:\> pktctl -Fa all C:\> pktctl -Fa pktctl> flush on all
显示过滤情况的统计数据: C:\> pktctl -s eth0 pktctl> stats on eth0
显示过滤情况的详细统计数据: C:\> pktctl -S eth0 pktctl> Stats on eth0
---------------------- pktfltsrv的命令行选项: ---------------------- -i "path_to_rules_file" "path_to_log_file" -u: uninstalls the service.
一些问题:
1、在Windows XP + SP1 上不能记录日志。 这是XP的问题,SP1 iphlpapi.dll的PfSetLogBuffer函数工作不正常。(这个问题是PktFilter邮件列表上的)
2、添加某些格式不正确的规则时可导致服务崩溃。
3、因为只有SDK的WinBase.h才定义了INVALID_SET_FILE_POINTER。所以编译pktfltsrv的时候需要在 VS的tools--options里面把SDK的include目录放到最前面。我现在的机器没有安装SDK, 是把以前的安装目录copy过来用的,所以需要手工设。我不记得直接安装SDK后是否会直接用SDK的文件覆盖VC的文件, 如果那样的话,可能就不需要多此一举了。
4、在Windows 2000 Pro版本上未必能够运行,我没试验,只是MSND谈到那些函数的时候总是说: “Included in Windows 2000 Server and Windows .NET Server.”
5、pktctl.exe -l命令列规则的时候适配器和协议两个字段之间没有空格,我给加了一个。filter_stats.c/70行。 可能作者没留神少了一句,所以ICMP类型和状态码不能记录下来,加上了。logging.c/187行。 不能记录ttl,tcp窗口值等信息,加上了。 有些记录格式我看着不习惯,改了。
6、程序实现原理可以参考: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/rras/rras/packet_filtering_reference.asp
附:规则生成脚本:
@echo off
echo # 规则由PktFilter 规则生成脚本 RulesBuild.cmd v0.1 生成 echo # tombkeeper@whitecell.org echo.
setlocal
rem 不打算填写内容的变量就让它空着,
rem 指定要要设置规则的网络接口: set interface=eth0
rem 指定要生成的规则文件: set rules_file=PktFilter.conf
rem 指定本机IP,这里只考虑了一个IP的情况: set local_ip=192.168.0.1
rem 指定信任的IP,注意!来自这些IP的访问将完全不受防火墙控制。多个IP之间用逗号分隔: set trust_ip=192.168.0.2,192.168.0.3
rem 指定网关,某些网关会设置会定时ping主机: set gateway=192.168.0.254
rem 指定qq服务器,多个IP之间用逗号分隔: set qq_server=219.133.40.15
rem 是否要使用主动模式ftp: set ftp_active=true
rem 是否要访问DNS: set dns=true
rem 是否要访问tftp: set tftp=true
rem 是否要访问snmp: set snmp=true
rem 是否要使用msn直接文件传输: set msn=true
rem 是否要使用QQ: set qq=true
rem 是否使用金山毒霸在线升级: set kav=true
rem 是否使用netbios: set netbios=true
rem 其它要开放的TCP端口,多个端口之间用逗号分隔: set other_tcp=
echo ##################################################################################### echo # 全局规则 echo ##################################################################################### echo.
echo # 丢掉小的分片包 echo option small_frags on %interface% echo.
echo # 默认阻塞所有进出数据 echo block in on %interface% all echo block out on %interface% all echo.
echo # 允许 %local_ip% 发起向任意地址的TCP连接 echo pass out on %interface% proto tcp from %local_ip% port 1 ^>^< 65535 to any port 1 ^>^< 65535 echo pass in on %interface% proto tcp from any port 1 ^>^< 65535 to %local_ip% port 1 ^>^< 65535 established echo.
:trust_ip if "%trust_ip%"=="" goto tcp echo # 设置信任主机 %trust_ip% 可完全访问 %local_ip% for %%I in (%trust_ip%,) do echo pass in on %interface% from %%I to %local_ip% && echo pass out on %interface% from %local_ip% to %%I rem %trust_ip%后面加一个逗号是考虑只有一个%trust_ip%时候的情况 echo.
:tcp echo ##################################################################################### echo # TCP 规则 echo ##################################################################################### echo.
:ftp_active if not "%ftp_active%"=="true" goto msn echo # 开放TCP 20 ,FTP 主动模式 echo pass in on %interface% proto tcp from any port = 20 to %local_ip% port ^> 1023 echo.
:msn if not "%msn%"=="true" goto other_tcp echo # 开放TCP 6890 - 6900,允许MSN直接传输文件 echo pass in on %interface% proto tcp from any port ^> 1023 to %local_ip% port 6890 ^>^< 6900 echo.
:other_tcp if "%other_tcp%"=="" goto udp echo # 其他要开放的TCP 端口:%other_tcp% for %%I in (%other_tcp%,) do echo pass in on %interface% proto tcp from any port ^> 1023 to %local_ip% port = %%I echo.
:udp echo ##################################################################################### echo # UDP 规则 echo ##################################################################################### echo.
:dns if not "%dns%"=="true" goto snmp echo # 访问DNS服务 echo pass out on %interface% proto udp from %local_ip% port ^> 1023 to any port = 53 echo pass in on %interface% proto udp from any port = 53 to %local_ip% port ^> 1023 echo.
:snmp if not "%snmp%"=="true" goto tftp echo # 访问snmp服务 echo pass out on %interface% proto udp from %local_ip% port ^> 1023 to any port = 161 echo pass in on %interface% proto udp from any port = 161 to %local_ip% port ^> 1023 echo.
:tftp if not "%tftp%"=="true" goto netbios echo # 访问tftp服务 echo pass out on %interface% proto udp from %local_ip% port ^> 1023 to any port = 69 echo pass in on %interface% proto udp from any port = 69 to %local_ip% port ^> 1023 echo.
:netbios if not "%netbios%"=="true" goto kav echo # 访问netbios-ns(UDP 137) netbios-dgm(UDP 138)服务 echo pass out on %interface% proto udp from any port = 137 to any port = 137 echo pass in on %interface% proto udp from any port = 137 to any port = 137 echo pass out on %interface% proto udp from any port = 138 to any port = 138 echo pass in on %interface% proto udp from any port = 138 to any port = 138 echo.
:kav if not "%kav%"=="true" goto qq echo # 访问金山毒霸升级验证端口 echo pass out on %interface% proto udp from %local_ip% port ^> 1023 to any port = 6868 echo pass in on %interface% proto udp from any port = 6868 to %local_ip% port ^> 1023 echo.
:qq if not "%qq%"=="true" goto icmp echo # 使用udp方式访问QQ for %%I in (%qq_server%,) do echo pass out on %interface% proto udp from %local_ip% port = 6000 to %%I port = 8000 && echo pass in on %interface% proto udp from %%I port = 8000 to %local_ip% port = 6000 rem %qq_server%后面加一个逗号是考虑只有一个%qq_server%时候的情况 echo.
:icmp echo ##################################################################################### echo # ICMP 规则 echo ##################################################################################### echo.
:ping echo # %local_ip% 可以 ping 任意地址 echo pass out on %interface% proto icmp from %local_ip% to any icmp-type echo echo pass in on %interface% proto icmp from any to %local_ip% icmp-type echorep echo.
:gateway if "%gateway"=="" goto write echo # 网关可以ping %local_ip% echo pass in on %interface% proto icmp from %gateway% to %local_ip% icmp-type echo echo pass out on %interface% proto icmp from %local_ip% to %gateway% icmp-type echorep
:write call %0 1> %rules_file% 2>nul @echo off rem 用这种方法写文件就不用每行后面都重定向而多次执行写操作,速度快,便于维护。 rem 用call或者cmd /c都可以,写入一次后会因为文件被另起的cmd进程占用而出错退出。 rem 如果不用call而直接在批处理中调用,则命令是在同一个cmd进程中执行,会出现死循环。 rem 事实上这种写法更适用于在交互脚本中指定要写的文件, rem 譬如前面设定变量的过程就可以用set /p 来分别从控制台上取得。
endlocal
@echo on |