Linux 版 (精华区)
发信人: tcpip (俺的昵称改了), 信区: Linux
标 题: IP防火链--4
发信站: 哈工大紫丁香 (Fri Sep 3 16:26:40 1999), 转信
4. IP 防火链
本节描述你建立包过滤器时需要知道的知识.
4.1 包是如何通过过滤器的
核心开始时亦启动了三个规则表, 这些表就叫防火链或链. 三个链叫进入(input), 外
出(output), 中转(forward). 当一个包进来时(是说从网卡进来的), 核心使用进入链
来决定它的命运. 如果它通过了, 那么核心将决定包下一步该发往何处(这一步叫路由
). 假如它是送往另一台机器的, 核心就运用中转链. 最后, 一个包发送出去之前, 核
心就应用外出链.
一个链就是一个规则(rules)表. 规则的意思是: 如果包头符合规则的定义, 就按预先
的设定对包做某种处理. 如果包与此规则不相符, 就与下一个规则比较. 最后, 假如没
有用于比较的规则了, 那么核心按预定的策略决定该做什么. 在安全防护系统中, 策略
通常告诉核心拒绝或丢弃此包.
下面是一个包进入一台机器的完整路径.
----------------------------------------------------------------
| ACCEPT/ lo interface |
v REDIRECT |
--> C --> S --> ______ --> D --> ~~~~ --> local? -----> _______ -->
h -> a |input | e {Routing } __|____ |output |ACCEPT
e | n |Chain | m {Decision} |forward|---->|Chain |
c | i |______| a ~~~~ |Chain | ^ |_______|
k | t | s | ^ |_______| | |
s | y | q | | | | |
u | | v e v | | | v
m | | DENY/ r Local Process v | DENY/
| | v REJECT a | DENY/ | REJECT
| |DENY d | REJECT |
v | e -------+---------------------
DENY| |
------------------------------
这儿是每一步的详细描述:
Checksum:
测试包在传输中是否有误. 如果有误, 把包丢弃.
Sanity:
每个防火链都有包的正常性检查, 但是进入链是最重要的. 一些畸形的包会把
规则检查搞糊度, 这些包在此被丢弃(假如发生此 种情况, 会在系统记录中写入
一个信息).
input chain:
这是防火链的第一个检查站. 如果包不被丢弃或拒绝, 则继续.
Demasquerade:
假如此包是事前发出的伪装的包的回复, 它被恢复, 并且跳过外出链检查. 假
如你不使用伪装, 你可从思想上取消图的此部分.
Routing decision:
通过路由表检查目的地, 来决定此包送给本地还是中转到远程机器.
Local process:
它是一个运行的进程, 接收经过路由判断后过来的包, 并把它发送出去.
lo interface:
假如包是由一个本地进程为另一个本地进程产生的, 它们将通过外出链的'lo'
接口, 然后返回进入链的'lo'接口. 'lo'接口通常叫本地 环路接口.
local:
假如包不是由本地进程产生的, 那么将进入中转链, 否则进入外出链.
forward chain:
任何包试图从本机到达其它的机器, 都必需被中转链检查.
output chain:
外出链在包外出之前检查它们.
使用 ipchains.
首先请检查 ipchains 版本是否符合要求:
$ ipchains --version
ipchains 1.3.8, 27-Oct-1998
ipchains 有一个详细的手册 (man ipchains), 如果你想知道细节问题, 请看程序接口
(man 4 ipfw), 或者看 2.1.X 核心代码中的 net/ipv4/ip_fw.c 文件.
另外有一份快速参考卡片.
你可以用 ipchains 做许多不同的事. 首先是管理整个链集合. 核心以三个内置的链
input, output 和 forward 启动, 这三个链不能被删除.
1.建立一个新的链 (-N).
2.删除一个空的链 (-X).
3.改变内置链的策略 (-P).
4.对一个链中的所有规则列表 (-L).
5.把一个链中的所有规则清空 (-F).
6.把一个链的所有规则的计数器置零 (-Z).
管理一个链中的规则的几个方法:
1.在一个链中增加一个规则 (-A).
2.在一个链中的某个位置插入一个规则 (-I).
3.替换一个链中某个位置的一个规则 (-R).
4.删除一个链中某个位置的一个规则 (-D).
5.删除一个链中第一个匹配的规则 (-D).
伪装的操作只有几个.
1.列表当前的伪装连接 (-M -L).
2.设置伪装的超时值 (-M -S). (注意: 请看 I我为什么不能设置伪装的超时值!)
.
最后的功能, 也许是最有用的, 是让你检查, 一个特定的包通过一个特定的链时会发生
什么.
在一个规则上操作.
使用 ipchains, 实际上就是熟练地操作规则. 通常, 你将使用添加(-A)和删除命令(-
D). 其它命令是它们的简单扩充.
每个规则指定了遇到某些包时该如何处理它们(一个目标). 例如: 你想丢弃从 127.0.
0.1 IP 地址来的所有的 ICMP 包. 对于此中情况规则中的协议必须是 ICMP, 源地址必
须是 127.0.0.1, 我们的目标是"丢弃".
地址 127.0.0.1 是"本地环路"接口, 即使没有真正的网络连接也存在. 你可以用 'pi
ng' 程序产生这样的包, (它简单的送一个类型为8的 ICMP, 乐意服务的主机将返回一
个类型为0的 ICMP包). 这在测试是有用.
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
64 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.2 ms
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.2/0.2/0.2 ms
# ipchains -A input -s 127.0.0.1 -p icmp -j DENY
# ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1): 56 data bytes
--- 127.0.0.1 ping statistics ---
1 packets transmitted, 0 packets received, 100% packet loss
#
在这, 你可以看到第一个 ping 成功了('-c 1 是告诉 ping 只产生一个包).
然后, 我们在'input'链中增加了一个规则, 对于从 127.0.0.1 来的('-s 127.0.0.1'
), 协议是 ICMP, ('-p ICMP') 的包, 我们将丢弃('-j DENY').
然后测试我们的新规则, 使用第二个 ping. 程序由于等一个永远也不会来的包, 所以
显示结果会有一个停顿.
我们可以用两钟方法中的任何一钟删除此规则. 首先我们知道它是链中的唯一规则, 我
们可以使用编号删除, 输入:
# ipchains -D input 1
#
来删除进入链的编号1规则.
第二条路是 -A 命令的镜象, 但是用 -D 代替 -A. 当你不愿意去数繁多的规则时, 这
是一个有用的方法. 这种情况下, 我们使用:
# ipchains -D input -s 127.0.0.1 -p icmp -j DENY
#
-D (-I, -R) 的语法与 -A 完全相同. 当在一个链中有多个相同的规则时, 只有第一个
被删除.
过滤器说明.
我们已经看到用 '-p' 指定协议, '-s' 指定源头地址, 但是还有其它参数, 可以让我
们用来指定包的特征. 下面是详尽的说明.
指定源头和目的 IP 地址.
有四中方法指定源头(-s)和目的(-d) IP 地址. 最常用的方法是使用全称, 比如 'loc
alhost' 或 'www.linuxhq.com'. 第二中方法是指定 IP 地址, 如 '127.0.0.1'.
第三种和第四种方法是指定 IP 地址集, 比如 '199.95.207.0/24' '199.95.207.0/25
5.255.255.0'. 这两种方式都指定了从 192.95.207.0 到 192.95.207.255 的所有 IP
地址; '/'后的数字表示 IP 地址的哪部分(或'位')被指定. 默认是 '/32' 或 '255.
255.255.255' (与所有 IP 地址匹配). 完全指定所有 IP 地址用'/0'. 象这样:
# ipchains -A input -s 0/0 -j DENY
#
这很少使用, 上面的结果同没有指定 '-s' 一样了.
否定指定.
许多参数, 包括 '-s' 和 '-d' 能有它们自己的参数, 在地址之前用 '!'(读 'not')参
数, 来匹配不等于给定地址的地址, 例如: ' -s ! localhost' 匹配所有不是从 loca
lhost 来的包.
协议指定.
用 '-p' 来指定协议. 协议可以用编号(假如你知道 IP 的数字化协议值)或名字'TCP'
, 'UDP', 'ICMP'. 大小写无关, 'tcp' 与 'TCP' 一样.
协议名前面可以加前缀 '!', 来否定它, 比如: ' -p ! TCP'.
UDP 和 TCP 端口的指定.
对于特殊的 TCP 和 UDP 协议, 还有额外的参数可以指定, 即它们的端口号, 或端口的
范围(但是请看下面的 处理片段 ). 范围用 ':' 表示, 比如 '6000:6010', 它包含从
6000到6010的11个端口, 如果没有下限, 默认是0. 如果没有上限, 默认是 65535. 所
以指定1024以下端口来的 TCP 连接, 表示为 '-p TCP -s 0.0.0.0/0 :1023'. 端口号
也可以用名字指定,如 'WWW'.
端口指定也可以用'!'参数来否定它. 所以指定除了 WWW 外的其它 TCP 端口, 可以这
样做:
-p TCP -d 0.0.0.0/0 ! www
请仔细看, 领悟它们, 很重要
-p TCP -d ! 192.168.1.1 www
-p TCP -d 192.168.1.1 ! www
上面两个是截然不同的
第一个指定了送到除 192.168.1.1 外的任何机器的 WWW 端口的 TCP 包.第二个定义了
到 192.168.1.1 的任何端口的 TCP 连接, 除了 WWW 端口外.
最后, 此例表示不是 WWW 端口, 并且不是 192.168.1.1:
-p TCP -d ! 192.168.1.1 ! www
指定 ICMP 类型和代码.
ICMP 也可以有参数, 但是它没有端口,(ICMP 有类型和代码)它们有不同的含义.
你能在'-s'参数后放它们的 ICMP 名字来指定(使用 ipchains -h icmp 来列出这些名
字). 或使用 ICMP 类型和代码的数字编号, 类型跟在 '-s' 后, 代码跟在 '-d' 后.
ICMP 名相当长: 你只需输入足够长的字母能区分它们即可.
这有一点常用的 ICMP 包的介绍.
Number Name Required by
0 echo-reply ping
3 destination-unreachable Any TCP/UDP traffic.
5 redirect routing if not running routing daem
on 8 echo-request ping
11 time-exceeded traceroute
注意: 目前, ICMP 名的前面不能用'!'.
绝对不能封闭 ICMP 类型 3 的信息!(看下面的 ICMP Packets )
指定一个接口.
The `-i' option specifies the name of an interface to match. An interface i
s the physical device the packet came in on, or is going out on. You can us
e the ifconfig command to list the interfaces which are `up' (ie. working a
t the moment).
用 '-i' 参数指定接口名字. 接口是包进进出出的物理设备. 你可以使用 ifconfig 命
令看哪些接口目前在工作.
用于包进入(包通过进入链 )的接口被认为是进入接口, 同样地, 用于包外出(包通过外
出链)的接口被认为是外出接口. 用于包中转的接口也被认为是外出接口; 这是我随心
所欲的决定.
指定一个目前不存在的接口是完全合法的. 规则直到此接口工作时, 才起作用. 这种指
定是非常有用, 对于 PPP 及其类似的连接.
作为一个特例, 一个结尾是'+'的接口将适合所有此类接口(无论它们是否工作). 例如
: 设定一个规则适合所有的 PPP 连接, 可以用 -i ppp+来指定接口.
接口可以使用否定符'!'来匹配不是指定接口来的包.
仅指定 TCP SYN 包.
有时希望 TCP 连接是单方向的, 不是其它的. 例如: 你也许想连接一个外部的 WWW 服
务器, 但不想接收来自外部服务器的连接.
不成熟的做法是阻止来自外部服务器的 TCP 包进入. 但不幸的是, TCP 连接时需要包
进入双方才能正常工作.
解决的办法是仅阻止请求连接的包. 这些包叫 SYN(从技术上说, 这些包被设置了 SYN
标志, FIN 和 ACK 标志被取消, 但是我们叫它们为 SYN包). 仅阻止这些包, 我们可
以停止它们连接的企图.
'-y' 标志用于此: 它仅对 TCP 协议有效. 例如, 指定从 192.168.1.1 来的连接:
-p TCP -s 192.168.1.1 -y
此参数可以使用 '!' 否定参数, 意味着除了请求连接外的所有包.
处理片段.
有时, 一个过于大的包无法一次传输. 当这种情况发生时, 包被分解成片段, 作为多个
包传送. 片段传送完成后, 再将片段合成为原来的包.
片段产生的问题是, 上面的指定中的一些(个别的, 源端口, 目的端口, ICMP 类型, I
CMP 代码, TCP SYN 标志)需要系统核心看一下包的开始部分, 以得到信息, 但这些信
息只包含在包分解后的第一个片段中.
假如你的机器是与外部网相连的唯一通道, 你可以告诉 Linux 核心合并经过它的片段
, 在编译核心时回答 IP: always defragment set to 'y'. 这将使问题简单化.
否则, 理解过滤器如何对待片段是相当重要的. 所有过滤器在包中找信息, 但包中没有
, 它便判断包不符合规则. 这意味第一个片段象其它包一样通过, 第二个及其以后的不
能通过. 这样的话, 规则 -p TCP -s 192.168.1.1 www 便永远不能匹配这些片段(除第
一个外). -p TCP -s192.168.1.1 ! www 也不能.
然而, 你可以为第二个及后续片段包指定一个特别标准, 使用 '-f'.明显的, 用它来指
定 TCP 或 UDP 端口, ICMP 类型, ICMP 代码 或 TCP SYN 是不合法的.
可以在它前面使用否定符'!', 来指定一个规则不适用于第二个及其后续的片段包.
通常, 让第二个和后续的片段通过是安全的, 由于过滤器已经拒绝了第一个片段, 这样
可以防止片段重新组合, 然而, 现已知道靠简单的发送片段可以导致机器死机. 如何做
, 你自己看吧.
需要注意的: 过滤器把畸变的包(TCP, UDP 和 ICMP 包太短, 以致于过滤器无法读端口
, 代码 和类型)与片段包一样看待. 只有 TCP 片段包在位置8开始, 可以被防火墙拒绝
.
下面的规则拒绝发往 192.168.1.1 的任何片段包.
# ipchains -A output -f -D 192.168.1.1 -j DENY
#
过滤器作用的结果.
现在我们知道如何使用规则去匹配一个包. 当一个包符合一个规则时, 会发生:
1.此规则的字节计数器会按包的大小(包头和全部数据)增加.
2.那个规则的包计数器会增加.
3.假如规则需要, 包会被记录下来.
4.假如规则需要, 包的服务类型会被改变.
5.假如规则需要, 包会被标记(2.0版本核心不会).
6.会检查规则的目标来决定下一步如何处理此包.
由于多样性, 我会按重要性记录下这些包的地址.
指定一个目标.
目标(target)用来告诉核心当一个包符合规则时如何处理它. 用'-j'来指定规则的目标
.
最简单的情况是不指定目标. 这种类型的规则(通常叫记数规则)常用来做某种类型包的
简单记数. 无论规则匹配与否, 核心将继续检查此链中的下一个的规则. 例如, 对从1
92.168.1.1来的包记数:
# ipchains -A input -s 192.168.1.1
#
(使用 'ipchains -L -v' 加上各个规则, 可以显示它们的字节和包的联合计数器的数
值).
可以指定六种目标. 头三个, 接受(ACCEPT), 拒绝(REJECT)和丢弃(DENY)是最常用的.
接受通常让包通过. DENY 扔掉包就象没有受到过一样. 拒绝也把包扔掉, 但(假如它不
是 ICMP 包)产生一个 ICMP 回复来告诉发包者, 目的地址无法到达.
下一个, MASQ 告诉核心伪装此包. 想让它起作用, 编译核心时必需让 IP Masqueradi
ng 起作用. 想详细了解这些, 请看 Masquerading-HOWTO 和 附录ipchains和 ipfwad
m 的不同之处. 只有包通过中转链时此目标才起作用.
另一个重要的目标指定是 REDIRECT, 它告诉核心把无论应送到何处的包改送到一个本
地端口. 只有 TCP 和 UDP 协议可以使用此指定. 任意用 '-j REDIRECT' 指定一个端
口(名字或编号)可以使送往此的包被重定向到某个特殊的端口, 即使它被标记为送到其
它端口. 此目标只在输入链有效.
最后的一个目标指定是 RETURN, 它跳过它下面的所有规则, 直到链的末尾.(看下面的
策略设定)
任何其它的目标指定表示一个用户自定义的链(在下面的 在整个链上操作 中描述). 包
将在那个链中通过. 假如那个链没有决定此包的命运, 那么在那个链中的传输就完成了
, 包将通过当前链的下一个规则.
下面有两个链: input(内建) 和 test(自定义)
`input' `Test'
---------------------------- ----------------------------
| Rule1: -p ICMP -j REJECT | | Rule1: -s 192.168.1.1 |
|--------------------------| |--------------------------|
| Rule2: -p TCP -j Test | | Rule2: -d 192.168.1.1 |
|--------------------------| ----------------------------
| Rule3: -p UDP -j DENY |
----------------------------
假设包从 192.168.1.1 来, 到 1.2.3.4. 它进入进入链, 被规则1检测 - 不符合. 符
合规则2, 规则2的目标是 test, 所以下一个规则是 test 的开始. 包符合test 中的规
则1, 但它没有指定目标, 所以下一个规则被检查, 不符合. 就到了此链的末尾. 便返
回进入链, 规则2被检查过了, 我们检查规则3, 但它亦不符合.
所以包的路径是:
v __________________________
`input' | / `Test' v
------------------------|--/ -----------------------|----
| Rule1 | /| | Rule1 | |
|-----------------------|/-| |----------------------|---|
| Rule2 / | | Rule2 | |
|--------------------------| -----------------------v----
| Rule3 /--+___________________________/
------------------------|---
v
看 如何组织你的防火墙规则 学习使用有效的自定义链.
记录包.
这是包匹配一个规则的副产品; 你可以用'-f'标志来指示把符合规则的包记录下来. 对
于通常的包你不会这样做, 但当你查找特殊问题时它很有用(看 man klogd or man dm
esg).
熟练运用服务类型.
在 IP 包头中有四个位难得使用, 它们叫服务类型(TOS)位. 它们影响如何对待包; 这
四个位是最小延时"Minimum Delay", 最大吞吐量"MaximumThroughput", 最大可靠程度
"Maximum Reliability" and 最小费用"Minimum Cost".
Especially the "Minimum Delay" is important for me. I switch it on f
or "interactive" packets in my upstream (Linux) router. I'm behind a 33k6 m
odem link. Linux prioritizes packets in 3 queues. This way I get acceptable
interactive performance while doing bulk downloads at the same time.
(It could even be better if there wasn't such a big queue in the serial dr
iver, but latency is kept down 1.5 seconds now).
最小延时对我特别重要. 我在路由器(Linux)上打开它, 使它与包相互作用. 我
在一个 33K6的猫后面. Linux 按优先把包分为3个队列. 用这种方法, 当我在同
一时间下载大量数据时得到了满意的性能.
The most common use is to set telnet & ftp control connections to "Minimum
Delay" and FTP data to "Maximum Throughput". This would be done as follows:
最常用的是把 telnet 和 ftp 的控制连接设为最小延时和把 FTP 数据设为最大吞吐量
. 这样做:
ipchains -A output -p tcp -d 0.0.0.0/0 telnet -t 0x01 0x10
ipchains -A output -p tcp -d 0.0.0.0/0 ftp -t 0x01 0x10
ipchains -A output -p tcp -s 0.0.0.0/0 ftp-data -t 0x01 0x08
'-t'标志有两个额外参数, 以16进制表示. 这些参数综合设置 TOS 位: 第一个掩码与
当前的 TOS 位'与'(AND)操作. 第二个与 TOS 位'异或'(XOR)操作. 如果这些太难理解
, 使用下表:
TOS Name Value Typical Uses
Minimum Delay 0x01 0x10 ftp, telnet
Maximum Throughput 0x01 0x08 ftp-data
Maximum Reliability 0x01 0x04 snmp
Minimum Cost 0x01 0x02 nntp
Andi Kleen说,. 对于使用猫和ISDN的用户调整 TOS 是有必要的, 它们原来的数值太大
, 调为 4-10 比较好. 对于2.0的用户需要一个补丁来修改它,对于2.1它是 ifconfig
的标志位.
所以, 操作 TOS对用猫连接的用户有很大好处, 在你的 /etc/ppp/ip-up 脚本中运行
'ifconfig $1 txqueuelen'. 使用什么数值依赖与你的猫的速度和猫的内置缓存; 这有
建议:
最佳数值需要试验得到. 假如路由器中的队列太短会丢包. 等等.
标记一个包.
对 Alexey Kuznetsov 的新的服务质量(QOS)的完成有用. 此项对2.1及以后的版本此作
用. 对2.0不起作用. 译者注: 通过把包标记来分等级, 不同的等级有不同的优先传送
权.
对全部链操作.
ipchains 一个非常有用的特色是有能力把关联的规则放到链中. 链可以起任何名字,
只有不与内置的链或目标冲突即可. 我建议避开大写的符号, 因为我将在未来的功能中
使用它们. 链名可以长达8个字符.
建立一个新链.
让我们建立一个新链. 我叫它 test.
# ipchains -N test
#
这是如此简单. 现在你可以按照上面讲的向链中增加规则了.
删除一个链.
删除同样简单.
# ipchains -X test
#
删除链必须满足两个条件: 它们是空的(看下面的 Flushing a Chain), 并且不是任何
规则的目标. 但你不能删除3个内置链中的任何一个.
清空一个链.
使用'-F'命令可以清除一个链中的所有规则.
# ipchains -F forward
#
假如你不指定链, 那么所有链都将被清空.
对链执行列表操作.
使用'-L'命令可以显示一个链中的所有规则.
# ipchains -L input
Chain input (refcnt = 1): (policy ACCEPT)
target prot opt source destination p
orts ACCEPT icmp ----- anywhere anywhere
any # ipchains -L test
Chain test (refcnt = 0):
target prot opt source destination p
orts DENY icmp ----- localnet/24 anywhere
any #
上面 test 链中的'refcnt'表示把 test 作为目标的规则的个数, 在删除此链时, 它必
须是零(并且此链是空的).
假如省略链名, 所有的链都将被列表, 即使是空的.
'-L'有三个可选项. '-n'(数值)项非常有用, 它阻止 ipchains 去查找 IP 地址, 假如
你的DNS没有正确设置, 或你已经过滤掉了 DNS 请求, 这将造成很大延时. 它还会导致
端口用数字而不是名字被显示出来.
'-V'选项显示规则的所有详细信息, 如包和字节计数器, TOS 掩码, 接口, 和包标记.
用其它的方法这些项都会被忽略. 例如:
# ipchains -v -L input
Chain input (refcnt = 1): (policy ACCEPT)
pkts bytes target prot opt tosa tosx ifname mark s
ource destination ports 10 840 ACCEPT
icmp ----- 0xFF 0x00 lo anywhere anywhe
re any
注意: 包和字节计数器显示时使用后缀 'K', 'M', 'G' 来表示1000 1,000,000 和 1,
000,000,000. 不管数值多大, 使用 '-x' 标志(展开数字)可以完全显示它们.
重置(清零)计数器.
重置计数器是一项有用的功能. 使用 '-Z' 选项来实现. 例如:
# ipchains -v -L input
Chain input (refcnt = 1): (policy ACCEPT)
pkts bytes target prot opt tosa tosx ifname mark s
ource destination ports 10 840 ACCEPT
icmp ----- 0xFF 0x00 lo anywhere anywhe
re any # ipchains -Z input
# ipchains -v -L input
Chain input (refcnt = 1): (policy ACCEPT)
pkts bytes target prot opt tosa tosx ifname mark s
ource destination ports 0 0 ACCEPT
icmp ----- 0xFF 0x00 lo anywhere anywhe
re any #
但有时你想在重置计数器前知道它们的值. 在上面的例子中, 一些包可能在执行 '-L'
和 '-Z' 命令之间通过. 由于此, 你可以同时使用 '-L'和 '-Z' 命令, 读计数器的同
时重置它们. 不幸的是, 假如你这样做, 你不能只操作一个链, 你不得不列表和清零所
有的链.
# ipchains -L -v -Z
Chain input (policy ACCEPT):
pkts bytes target prot opt tosa tosx ifname mark s
ource destination ports 10 840 ACCEPT
icmp ----- 0xFF 0x00 lo anywhere anywhe
re any
Chain forward (refcnt = 1): (policy ACCEPT)
Chain output (refcnt = 1): (policy ACCEPT)
Chain test (refcnt = 0):
0 0 DENY icmp ----- 0xFF 0x00 ppp0 l
ocalnet/24 anywhere any # ipchains -L -v
Chain input (policy ACCEPT):
pkts bytes target prot opt tosa tosx ifname mark s
ource destination ports 10 840 ACCEPT
icmp ----- 0xFF 0x00 lo anywhere anywhe
re any
Chain forward (refcnt = 1): (policy ACCEPT)
Chain output (refcnt = 1): (policy ACCEPT)
Chain test (refcnt = 0):
0 0 DENY icmp ----- 0xFF 0x00 ppp0 l
ocalnet/24 anywhere any #
设定策略.
我们在上面讨论指定一个目标时忽略了当一个包符合最后的内置链时会发生什么. 在这
种情况下, 由链的策略决定包的命运. 只有内置链(input, output 和 fowward)有策略
, 原因是当包通过了一个自定义链时, 会接着回到先前的链并在其中通过.
策略可以是前四个指定的目标: ACCEPT(接收), DENY(丢弃), REJECT(拒绝) 或 MASQ(
伪装). MASQ 只在 'forward'(中转)链中合法.
注意: 当一个包符合一个内置链中的规则时, 可以使用 RETURN(返回)来明确的把链策
略当作目标.
伪装操作.
有几个参数用来调整 IP 伪装操作.
IP 伪装操作命令是 '-M', 它可以和 '-L' 连用对当前的伪装连接列表, 或与 '-S' 连
用来设置伪装参数.
'-L' 命令能和 '-n'(用数字代替主机名和端口名来显示) 或'v'(假使你正好注意, 以
连续数值显示伪装连接的 deltas)连用.
'-S' 后跟三个以秒表示的超时值: TCP sessions, FIN 包到后的 TCP sessions, 和对
于 UDP 包的. 假如你不想改变这些值, 给个 '0' 值即可.
默认值在 '/usr/include/net/ip_masp.h' 文件中, 目前分别是 15分, 2分和 5分.
由于 FTP 的原因, 经常改变的是第一个值. (看下面的 恶梦般的 FTP).
设置超时中遇到问题请看 我不能设置伪装超时!
检查一个包.
有时你想知道一个确定的包进入机器后会发生什么事情, 比如调试防火链时. ipchain
s 的 '-C' 命令提供与核心检查真实包完全相同的程序来让你做这件事.
你可以指定让哪个链来检测包, 把链的名字放在 '-C' 参数后即可. 鉴于核心总是从
input, output 或 forward 链开始, 特许你从需要测试的链开始.
包的细节用与设置防火墙规则相同的语法设定. 在个别时, 包的协议('-p'), 源地址(
'-s'), 目的地址('-d'), 和接口('-i') 必须有. 假如协议是 TCP或 UDP, 那么必须指
定一个源地址和一个目的端口, 对于 ICMP 协议必须指定类型和代码. (除非使用了 '
-f' 标志指定了一个片段规则, 在那种情况下这些选项是不合法的).
假如协议是 TCP (并且没有 '-f' 标志), 可以使用 '-y' 标志设置包的 SYN 位.
这有一个例子, 测试一个 TCP SYN 包, 它从 192.168.1.1 端口 60000 到 192.168.1
.2 www 端口, 进入 eth0 接口, 进入 'input' 链. (这是一个与 WWW 建立连接的典型
例子)
# ipchains -C input -p tcp -y -i eth0 -s 192.168.1.1 60000 -d 192.16
8.1.2 www packet accepted
#
立即复合规则和监视发生的事.
有时一个单命令行能影响多个规则. 有两种做法. 第一, 假如你设置一个能解析为多个
IP 地址(使用 DNS)的主机名, ipchains 将如同你对多个地址都设置了命令一样发生
作用.
假如主机名'www.foo.com'解析为三个 IP 地址, 主机名'www.bar.com'解析为两个 IP
地址, 那么命令 'ipchains -A input -j reject -s www.bar.com -d www.foo.com'
将在 input 链中追加6条规则.
另一种办法事用双向作用标志('-b'). 这个标志使 ipchains 象你输入命令两次一样工
作, 第二次是把 '-s' 和 '-d' 参数颠倒. 所以, 不转发 到192.168.1.1 或 从192.1
68.1.1 来的包,可以使用以下命令:
# ipchains -b -A forward -j reject -s 192.168.1.1
#
就我本人而言, 不太喜欢 '-b' 选项; 如果你想方便, 看下面的 使用 ipchains-save
保存设置.
'-b' 选项可以和 insert ('-I'), delete ('-D'), append ('-A') 和 check ('-c')
命令联用.
另一个有用的标志是 '-v'(verbose), 它显示出对于你的命令, ipchains 是如何响应
的. 假如你使用的命令可以影响多个规则, 它是很有用的. 例如: 检查 192.168.1.1
与 192.168.1.2 之间片段的情况:
# ipchains -v -b -C input -p tcp -f -s 192.168.1.1 -d 192.168.1.2 -i
lo tcp opt ---f- tos 0xFF 0x00 via lo 192.168.1.1 -> 192.16
8.1.2 * -> * packet accepted
tcp opt ---f- tos 0xFF 0x00 via lo 192.168.1.2 -> 192.168.1
.1 * -> * packet accepted
#
4.2 实用举例
我有一个拨号连接(-i ppp0). 每次拨号后读取新闻(-p TCP -s news.virtual.net.au
nntp)和邮件(-p TCP -s mail.virtual.net.au pop-3). 定期使用 Debian 的 FTP 方
式更新我的机器(-p TCP -y -s ftp.debian.org.au ftp-data). 当这些完成后使用我
的 ISP 的代理服务访问 Web (-p TCP -d proxy.virtual.net.au 8080), 但是厌恶 d
oubleclick.net (-p TCP -y -d199.95.207.0/24 & -p TCP -y -d 199.95.208.0/24)
.
当我在线的时候不介意人们 FTP 我的机器(-p TCP -d $LOCALIP ftp), 但不想让外边
的人伪装成我的内部网的 IP 地址(-s 192.168.1.0/24). 这通常叫 IP 欺骗, 在 2.1
.x 核心和上面讲的中有一个好办法来防止它: 看 我如何建立 IP 欺骗防护?.
因为我的内部网中没有其它机器, 这些设置相当简单.
我不想让任何内部进程连接到 doubleclick.net:
# ipchains -A output -d 199.95.207.0/24 -j REJECT
# ipchains -A output -d 199.95.208.0/24 -j REJECT
#
现在设定外出包的优先权(与设置进入包的优先权有许多不同). 由于我有这些规则的清
晰的编号, 可以把它们放到一个单一链中,叫 ppp-out.
# ipchains -N ppp-out
# ipchains -A output -i ppp0 -j ppp-out
#
设置 Web 访问和 telnet 为最小延时.
# ipchains -A ppp-out -p TCP -d proxy.virtual.net.au 8080 -t 0x01 0x
10 # ipchains -A ppp-out -p TCP -d 0.0.0.0 telnet -t 0x01 0x10
#
设置 ftp data, nntp, pop-3 为最低费用:
# ipchains -A ppp-out -p TCP -d 0.0.0.0/0 ftp-data -t 0x01 0x02
# ipchains -A ppp-out -p TCP -d 0.0.0.0/0 nntp -t 0x01 0x02
# ipchains -A ppp-out -p TCP -d 0.0.0.0/0 pop-3 -t 0x01 0x02
#
对于进入 ppp0 的包有一些小限制: 让我们建立一个叫 'ppp-in' 的链:
# ipchains -N ppp-in
# ipchains -A input -i ppp0 -j ppp-in
#
现在, 不让自称地址为 192.168.1.* 的包进入 ppp0, 我们记录和丢弃它们:
# ipchains -A ppp-in -s 192.168.1.0/24 -l -j DENY
#
我只允许 DNS 的 UDP 包(我运行一个缓存命名服务器, 它把所有请求转送到 203.29.
16.1, 所以我只接收从它们来的 DNS 响应)、进入的 ftp连接, 和返回的 ftp-data 进
入(只能在 1023 口以上, 在 6000左右没有 X11 端口).
# ipchains -A ppp-in -p UDP -s 203.29.16.1 -d $LOCALIP dns -j ACCEPT
# ipchains -A ppp-in -p TCP -s 0.0.0.0/0 ftp-data -d $LOCALIP 1024:5
999 -j ACCEPT # ipchains -A ppp-in -p TCP -s 0.0.0.0/0 ftp-data -d $L
OCALIP 6010: -j ACCEPT # ipchains -A ppp-in -p TCP -d $LOCALIP ftp -j
ACCEPT #
最后, 允许本地包:
# ipchains -A input -i lo -j ACCEPT
#
现在, 默认的输入链(input)策略是丢弃(DENY), 所以其它类型的包将被扔掉:
# ipchains -P input DENY
#
注: 我不会以此顺序设置我的链, 因为当我设置的时候包可以进来. 安全的方法是首先
设置策略为丢弃, 然后再插入规则. 当然, 如果你的规则请求 DNS 来解析主机名, 会
出问题的.
使用 ipchains-save 保存设置.
当你按照自己的意图设置了防火链后, 在下次试图记住这些命令再来一次, 是很麻烦的
.
ipchains-save 脚本可以读你当前的链设置并把它们存到一个文件中. 等一会, 解释
ipchains-restore 如何工作.
ipchains-save 能保存单个链, 或所有链(假如不指定链名). 唯一的选项是 '-v', 它
输出保存的规则到标准错误输出(stderr). input, output and forward 链的策略也被
保存.
$ ipchains-save > my_firewall
Saving `input'.
Saving `output'.
Saving `forward'.
Saving `ppp-in'.
Saving `ppp-out'.
$
使用 ipchains-restore.
ipchains-restore 按照 ipchains-save 保存的恢复链. 它能带两个选项: '-v'显示加
入的每个链. '-f' 按下面描述的方式强行刷新存在的自定义链.
假如 ipchains-restore 检查到一个自定义链在 输入链(input) 中已经存在, ipchai
ns-restore 将提示你是否刷新此链(清除所有规则)或跳过对此链的恢复. 假如你在命
令行指定了 '-f', 将不再提示你; 链将被刷新.
运行这个脚本, 你必须是 root; 它使用 ipchains 去尝试恢复这些规则.
例如:
# ipchains-restore < my_firewall
Restoring `input'.
Restoring `output'.
Restoring `forward'.
Restoring `ppp-in'.
Chain `ppp-in' already exists. Skip or flush? [S/f]? s
Skipping `ppp-in'.
Restoring `ppp-out'.
Chain `ppp-out' already exists. Skip or flush? [S/f]? f
Flushing `ppp-out'.
#
--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: bin@mtlab.hit.edu.cn]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:423.163毫秒