用iptables -ADC 来指定链的规则,-A添加 -D删除 -C 修改
iptables - [RI] chain rule num rule-specification[option]
用iptables - RI 通过规则的顺序指定
iptables -D chain rule num[option]
删除指定规则
iptables -[LFZ] [chain][option]
用iptables -LFZ 链名 [选项]
iptables -[NX] chain
用 -NX 指定链
iptables -P chain target[options]
指定链的默认目标
iptables -E old-chain-name new-chain-name
-E 旧的链名 新的链名
用新的链名取代旧的链名
说明
Iptalbes 是用来设置、维护和检查Linux内核的IP包过滤规则的。
可以定义不同的表,每个表都包含几个内部的链,也能包含用户定义的链。每个链都是一个规则列表,对对应的包进行匹配:每条规则指定应当如何处理与之相匹配的包。这被称作'target'(目标),也可以跳向同一个表内的用户定义的链。
TARGETS
防火墙的规则指定所检查包的特征,和目标。如果包不匹配,将送往该链中下一条规则检查;如果匹配,那么下一条规则由目标值确定.该目标值可以是用户定义的链名,或是某个专用值,如ACCEPT[通过], DROP[删除], QUEUE[排队], 或者 RETURN[返回]。
ACCEPT 表示让这个包通过。DROP表示将这个包丢弃。QUEUE表示把这个包传递到用户空间。RETURN表示停止这条链的匹配,到前一个链的规则重新开始。如果到达了一个内建的链(的末端),或者遇到内建链的规则是RETURN,包的命运将由链准则指定的目标决定。
TABLES
当前有三个表(哪个表是当前表取决于内核配置选项和当前模块)。
-t table
这个选项指定命令要操作的匹配包的表。如果内核被配置为自动加载模块,这时若模块没有加载,(系统)将尝试(为该表)加载适合的模块。这些表如下:filter,这是默认的表,包含了内建的链INPUT(处理进入的包)、FORWORD(处理通过的包)和OUTPUT(处理本地生成的包)。nat,这个表被查询时表示遇到了产生新的连接的包,由三个内建的链构成:PREROUTING (修改到来的包)、OUTPUT(修改路由之前本地的包)、POSTROUTING(修改准备出去的包)。mangle 这个表用来对指定的包进行修改。它有两个内建规则:PREROUTING(修改路由之前进入的包)和OUTPUT(修改路由之前本地的包)。
OPTIONS
这些可被iptables识别的选项可以区分不同的种类。
COMMANDS
这些选项指定执行明确的动作:若指令行下没有其他规定,该行只能指定一个选项.对于长格式的命令和选项名,所用字母长度只要保证iptables能从其他选项中区分出该指令就行了。
-A -append
在所选择的链末添加一条或更多规则。当源(地址)或者/与 目的(地址)转换为多个地址时,这条规则会加到所有可能的地址(组合)后面。
-D -delete
从所选链中删除一条或更多规则。这条命令可以有两种方法:可以把被删除规则指定为链中的序号(第一条序号为1),或者指定为要匹配的规则。
-R -replace
从选中的链中取代一条规则。如果源(地址)或者/与 目的(地址)被转换为多地址,该命令会失败。规则序号从1开始。
-I -insert
根据给出的规则序号向所选链中插入一条或更多规则。所以,如果规则序号为1,规则会被插入链的头部。这也是不指定规则序号时的默认方式。
-L -list
显示所选链的所有规则。如果没有选择链,所有链将被显示。也可以和z选项一起使用,这时链会被自动列出和归零。精确输出受其它所给参数影响。
-F -flush
清空所选链。这等于把所有规则一个个的删除。
--Z -zero
把所有链的包及字节的计数器清空。它可以和 -L配合使用,在清空前察看计数器,请参见前文。
-N -new-chain
根据给出的名称建立一个新的用户定义链。这必须保证没有同名的链存在。
-X -delete-chain
删除指定的用户自定义链。这个链必须没有被引用,如果被引用,在删除之前你必须删除或者替换与之有关的规则。如果没有给出参数,这条命令将试着删除每个非内建的链。
-P -policy
设置链的目标规则。
-E -rename-chain
根据用户给出的名字对指定链进行重命名,这仅仅是修饰,对整个表的结构没有影响。TARGETS参数给出一个合法的目标。只有非用户自定义链可以使用规则,而且内建链和用户自定义链都不能是规则的目标。
-h Help.
帮助。给出当前命令语法非常简短的说明。
PARAMETERS
参数
以下参数构成规则详述,如用于add、delete、replace、append 和 check命令。
-p -protocal [!]protocol
规则或者包检查(待检查包)的协议。指定协议可以是tcp、udp、icmp中的一个或者全部,也可以是数值,代表这些协议中的某一个。当然也可以使用在/etc/protocols中定义的协议名。在协议名前加上"!"表示相反的规则。数字0相当于所有all。Protocol all会匹配所有协议,而且这是缺省时的选项。在和check命令结合时,all可以不被使用。
-s -source [!] address[/mask]
指定源地址,可以是主机名、网络名和清楚的IP地址。mask说明可以是网络掩码或清楚的数字,在网络掩码的左边指定网络掩码左边"1"的个数,因此,mask值为24等于255.255.255.0。在指定地址前加上"!"说明指定了相反的地址段。标志 --src 是这个选项的简写。
-d --destination [!] address[/mask]
指定目标地址,要获取详细说明请参见 -s标志的说明。标志 --dst 是这个选项的简写。
-j --jump target
-j 目标跳转
指定规则的目标;也就是说,如果包匹配应当做什么。目标可以是用户自定义链(不是这条规则所在的),某个会立即决定包的命运的专用内建目标,或者一个扩展(参见下面的EXTENSIONS)。如果规则的这个选项被忽略,那么匹配的过程不会对包产生影响,不过规则的计数器会增加。
-i -in-interface [!] [name]
i -进入的(网络)接口 [!][名称]
这是包经由该接口接收的可选的入口名称,包通过该接口接收(在链INPUT、FORWORD和PREROUTING中进入的包)。当在接口名前使用"!"说明后,指的是相反的名称。如果接口名后面加上"+",则所有以此接口名开头的接口都会被匹配。如果这个选项被忽略,会假设为"+",那么将匹配任意接口。
-o --out-interface [!][name]
-o --输出接口[名称]
这是包经由该接口送出的可选的出口名称,包通过该口输出(在链FORWARD、OUTPUT和POSTROUTING中送出的包)。当在接口名前使用"!"说明后,指的是相反的名称。如果接口名后面加上"+",则所有以此接口名开头的接口都会被匹配。如果这个选项被忽略,会假设为"+",那么将匹配所有任意接口。
[!] -f, --fragment
[!] -f --分片
这意味着在分片的包中,规则只询问第二及以后的片。自那以后由于无法判断这种把包的源端口或目标端口(或者是ICMP类型的),这类包将不能匹配任何指定对他们进行匹配的规则。如果"!"说明用在了"-f"标志之前,表示相反的意思。
OTHER OPTIONS
其他选项
还可以指定下列附加选项:
-v --verbose
-v --详细
详细输出。这个选项让list命令显示接口地址、规则选项(如果有)和TOS(Type of Service)掩码。包和字节计数器也将被显示,分别用K、M、G(前缀)表示1000、1,000,000和1,000,000,000倍(不过请参看-x标志改变它),对于添加,插入,删除和替换命令,这会使一个或多个规则的相关详细信息被打印。
-n --numeric
-n --数字
数字输出。IP地址和端口会以数字的形式打印。默认情况下,程序试显示主机名、网络名或者服务(只要可用)。
-x -exact
-x -精确
扩展数字。显示包和字节计数器的精确值,代替用K,M,G表示的约数。这个选项仅能用于 -L 命令。
--line-numbers
当列表显示规则时,在每个规则的前面加上行号,与该规则在链中的位置相对应。
MATCH EXTENSIONS
对应的扩展
iptables能够使用一些与模块匹配的扩展包。以下就是含于基本包内的扩展包,而且他们大多数都可以通过在前面加上!来表示相反的意思。
tcp
当 --protocol tcp 被指定,且其他匹配的扩展未被指定时,这些扩展被装载。它提供以下选项:
--source-port [!] [port[]]
源端口或端口范围指定。这可以是服务名或端口号。使用格式端口:端口也可以指定包含的(端口)范围。如果首端口号被忽略,默认是"0",如果末端口号被忽略,默认是"65535",如果第二个端口号大于第一个,那么它们会被交换。这个选项可以使用 --sport的别名。
--destionation-port [!] [port:[port]]
目标端口或端口范围指定。这个选项可以使用 --dport别名来代替。
--tcp-flags [!] mask comp
匹配指定的TCP标记。第一个参数是我们要检查的标记,一个用逗号分开的列表,第二个参数是用逗号分开的标记表,是必须被设置的。标记如下:SYN ACK FIN RST URG PSH ALL NONE。因此这条命令:iptables -A FORWARD -p tcp --tcp-flags SYN, ACK, FIN, RST SYN只匹配那些SYN标记被设置而ACK、FIN和RST标记没有设置的包。
[!] --syn
只匹配那些设置了SYN位而清除了ACK和FIN位的TCP包。这些包用于TCP连接初始化时发出请求;例如,大量的这种包进入一个接口发生堵塞时会阻止进入的TCP连接,而出去的TCP连接不会受到影响。这等于 --tcp-flags SYN, RST, ACK SYN。如果"--syn"前面有"!"标记,表示相反的意思。
--tcp-option [!] number
匹配设置了TCP选项的。
udp
当protocol udp 被指定,且其他匹配的扩展未被指定时,这些扩展被装载,它提供以下选项:
--source-port [!] [port:[port]]
源端口或端口范围指定。详见 TCP扩展的--source-port选项说明。
--destination-port [!] [port:[port]]
目标端口或端口范围指定。详见 TCP扩展的--destination-port选项说明。
icmp
当protocol icmp被指定,且其他匹配的扩展未被指定时,该扩展被装载。它提供以下选项:
--icmp-type [!] typename
这个选项允许指定ICMP类型,可以是一个数值型的ICMP类型,或者是某个由命令iptables -p icmp -h所显示的ICMP类型名。
mac
--mac-source [!] address
匹配物理地址。必须是XX:XX:XX:XX:XX这样的格式。注意它只对来自以太设备并进入PREROUTING、FORWORD和INPUT链的包有效。
limit
这个模块匹配标志用一个标记桶过滤器一一定速度进行匹配,它和LOG目标结合使用来给出有限的登陆数.当达到这个极限值时,使用这个扩展包的规则将进行匹配.(除非使用了"!"标记)
--limit rate
最大平均匹配速率:可赋的值有'/second', '/minute', '/hour', or '/day'这样的单位,默认是3/hour。
--limit-burst number
待匹配包初始个数的最大值:若前面指定的极限还没达到这个数值,则概数字加1.默认值为5
multiport
这个模块匹配一组源端口或目标端口,最多可以指定15个端口。只能和-p tcp 或者 -p udp 连着使用。
--source-port [port[, port]]
如果源端口是其中一个给定端口则匹配
--destination-port [port[, port]]
如果目标端口是其中一个给定端口则匹配
--port [port[, port]]
若源端口和目的端口相等并与某个给定端口相等,则匹配。
mark
这个模块和与netfilter过滤器标记字段匹配(就可以在下面设置为使用MARK标记)。
--mark value [/mask]
匹配那些无符号标记值的包(如果指定mask,在比较之前会给掩码加上逻辑的标记)。
owner
此模块试为本地生成包匹配包创建者的不同特征。只能用于OUTPUT链,而且即使这样一些包(如ICMP ping应答)还可能没有所有者,因此永远不会匹配。
--uid-owner userid
如果给出有效的user id,那么匹配它的进程产生的包。
--gid-owner groupid
如果给出有效的group id,那么匹配它的进程产生的包。
--sid-owner seessionid
根据给出的会话组匹配该进程产生的包。
state
此模块,当与连接跟踪结合使用时,允许访问包的连接跟踪状态。
--state state
这里state是一个逗号分割的匹配连接状态列表。可能的状态是:INVALID表示包是未知连接,ESTABLISHED表示是双向传送的连接,NEW表示包为新的连接,否则是非双向传送的,而RELATED表示包由新连接开始,但是和一个已存在的连接在一起,如FTP数据传送,或者一个ICMP错误。
unclean
此模块没有可选项,不过它试着匹配那些奇怪的、不常见的包。处在实验中。
tos
此模块匹配IP包首部的8位tos(服务类型)字段(也就是说,包含在优先位中)。
--tos tos
这个参数可以是一个标准名称,(用iptables -m tos -h 察看该列表),或者数值。
TARGET EXTENSIONS
iptables可以使用扩展目标模块:以下都包含在标准版中。
LOG
为匹配的包开启内核记录。当在规则中设置了这一选项后,linux内核会通过printk()打印一些关于全部匹配包的信息(诸如IP包头字段等)。
--log-level level
记录级别(数字或参看 syslog.conf(5))。
--log-prefix prefix
在纪录信息前加上特定的前缀:最多14个字母长,用来和记录中其他信息区别。
--log-tcp-sequence
记录TCP序列号。如果记录能被用户读取那么这将存在安全隐患。
--log-tcp-options
记录来自TCP包头部的选项。
--log-ip-options
记录来自IP包头部的选项。
MARK
用来设置包的netfilter标记值。只适用于mangle表。
--set-mark mark
REJECT
作为对匹配的包的响应,返回一个错误的包:其他情况下和DROP相同。
此目标只适用于INPUT、FORWARD和OUTPUT链,和调用这些链的用户自定义链。这几个选项控制返回的错误包的特性:
--reject-with type
Type可以是icmp-net-unreachable、icmp-host-unreachable、icmp-port-nreachable、icmp-proto-unreachable、 icmp-net-prohibited 或者 icmp-host-prohibited,该类型会返回相应的ICMP错误信息(默认是port-unreachable)。选项 echo-reply也是允许的;它只能用于指定ICMP ping包的规则中,生成ping的回应。最后,选项tcp-reset可以用于在INPUT链中,或自INPUT链调用的规则,只匹配TCP协议:将回应一个TCP RST包。
TOS
用来设置IP包的首部八位tos。只能用于mangle表。
--set-tos tos
你可以使用一个数值型的TOS 值,或者用iptables -j TOS -h 来查看有效TOS名列表。
MIRROR
这是一个试验示范目标,可用于转换IP首部字段中的源地址和目标地址,再传送该包,并只适用于INPUT、FORWARD和OUTPUT链,以及只调用它们的用户自定义链。
SNAT
这个目标只适用于nat表的POSTROUTING链。它规定修改包的源地址(此连接以后所有的包都会被影响),停止对规则的检查,它包含选项:
--to-source <ipaddr>;[-<ipaddr>;][:port-port]
可以指定一个单一的新的IP地址,一个IP地址范围,也可以附加一个端口范围(只能在指定-p tcp 或者-p udp的规则里)。如果未指定端口范围,源端口中512以下的(端口)会被安置为其他的512以下的端口;512到1024之间的端口会被安置为1024以下的,其他端口会被安置为1024或以上。如果可能,端口不会被修改。
--to-destiontion <ipaddr>;[-<ipaddr>;][:port-port]
可以指定一个单一的新的IP地址,一个IP地址范围,也可以附加一个端口范围(只能在指定-p tcp 或者-p udp的规则里)。如果未指定端口范围,目标端口不会被修改。
MASQUERADE
只用于nat表的POSTROUTING链。只能用于动态获取IP(拨号)连接:如果你拥有静态IP地址,你要用SNAT。伪装相当于给包发出时所经过接口的IP地址设置一个映像,当接口关闭连接会终止。这是因为当下一次拨号时未必是相同的接口地址(以后所有建立的连接都将关闭)。它有一个选项:
--to-ports <port>;[-port>;]
指定使用的源端口范围,覆盖默认的SNAT源地址选择(见上面)。这个选项只适用于指定了-p tcp或者-p udp的规则。
REDIRECT
只适用于nat表的PREROUTING和OUTPUT链,和只调用它们的用户自定义链。它修改包的目标IP地址来发送包到机器自身(本地生成的包被安置为地址127.0.0.1)。它包含一个选项:
--to-ports <port>;[<port>;]
指定使用的目的端口或端口范围:不指定的话,目标端口不会被修改。只能用于指定了-p tcp 或 -p udp的规则。
DIAGNOSTICS
诊断
不同的错误信息会打印成标准错误:退出代码0表示正确。类似于不对的或者滥用的命令行参数错误会返回错误代码2,其他错误返回代码为1。
BUGS
臭虫
Check is not implemented (yet).
检查还未完成。
COMPATIBILITY WITH IPCHAINS
与ipchains的兼容性
iptables和Rusty Russell的ipchains非常相似。主要区别是INPUT 链只用于进入本地主机的包,而OUTPUT只用于自本地主机生成的包。因此每个包只经过三个链的一个;以前转发的包会经过所有三个链。其他主要区别是 -i 引用进入接口;-o引用输出接口,两者都适用于进入FORWARD链的包。当和可选扩展模块一起使用默认过滤器表时,iptables是一个纯粹的包过滤器。这能大大减少以前对IP伪装和包过滤结合使用的混淆,所以以下选项作了不同的处理:
-j MASQ
-M -S
-M -L
在iptables中有几个不同的链。
SEE ALSO
参见
iptables-HOWTO有详细的iptables用法,对netfilter-hacking-HOWTO也有详细的本质说明。
AUTHORS
作者
一起走过的日子 回复于:2004-03-15 17:34:12
1. 简介
欢迎,亲爱的读者。
这篇文章假设你知道有关IP地址、网络地址、网络掩码、选路和DNS。如果不知道,我建议你先阅读网络概念的HowTo(Network Concepts HOWTO)。
这篇HOWTO并非一个简要的介绍(会让你发热、发毛,没有安全感),也非一个完全的原始的披露(最吃苦耐劳的人也会被搅晕,不过必定会有所斩获)。
你的网络并不安全。问题在于,必须获取快速、简洁的通讯,但又必须限于良好的、无恶意的行为,就如同在嘈杂的大戏院里,你可以高谈阔论,但是绝不能大喊:着火了!。这篇HOWTO不能解决这种问题。
(译者:所有安全都只是相对的,否则根本不会产生这种东西了)
因此,你只能决定在哪方面妥协。我想帮助你使用一些可用的工具和一些通常需要注意的漏洞,希望你将它们用在好的一面,而不是出于恶意的目的 -- 另一个同样重要的问题。
(C) 2000 Paul `Rusty' Russell. Licenced under the GNU GPL.
--------------------------------------------------------------------------------
2、 官方站点及邮件列表位置
这里有三个官方站点:
o Thanks to Filewatcher http://netfilter.filewatcher.org.
o Thanks to The Samba Team and SGI http://netfilter.samba.org.
o Thanks to Harald Welte http://netfilter.gnumonks.org.
你可以通过以下站点访问全部相关站点。
http://www.netfilter.org and http://www.iptables.org
以下是netfilter官方邮件列表
http://www.netfilter.org/contact.html#list.
--------------------------------------------------------------------------------
3.那么,什么是包过滤器?
包过滤器是这样一种软件:它检查通过的每个包的头部,然后决定如何处置它们。可以这样对待它们:丢弃(也就是说,如果这个包从未被接受,那么丢弃它),通过(也就是说,让包通过),或者更复杂的(操作)。
Linux下,包过滤内建在内核中(内核模块,或者内建),而且我们还有处理包的一些技巧,不过检查头部和处理包的一般性原则仍在这里。
--------------------------------------------------------------------------------
3.1 我为何要包过滤?
控制、安全、警戒。
控制:
当你用你的Linux服务器把你的内部网和另一个网络(就是Internet吧)连起来,你可以决定哪些通信是允许的,哪些不允许。例如,包头部包含了包的目标地址,你可以阻碍包发送到(你)确定的几个外部网络,另一个例子,我用NetScape连接到Dilbert archives。页面上有来自doubleclick.net的广告,然后NetScape浪费了我的时间愉快的下载他们。 告诉包过滤器禁止任何来自或者发往doubleclick.net地址的包,问题就解决了。(当然有更好的办法,见Junkbuster)。
安全:
当Linux服务器是混乱的Internet和你良好的、有序的网络之间唯一的东西时, 你最好能知道哪些东西可以进入你的大门。例如,你可以允许所有(包)从你的网络 发出,不过你可能会为来自外部的著名的“Ping of Death”而焦急。另一个例子,你不希望 外人telnet到你的Linux服务器,尽管所有账户都有密码。或许你只想(像绝大多数人)成为 Internet的旁观者,而非它的服务器(也可能愿意是吧)。简单的不允许任何人接入,设置 包过滤器拒绝所有进入的包(是不错的办法)。
警戒:
有时,本地网络上错误配置的机器可能会向外部喷射出大量的包。最好是当(网络中)出现任何不正常现象时,让包过滤器告诉你。这样你可能可以做点什么,或者你天生就很好奇。
--------------------------------------------------------------------------------
3.2 如何在Linux下进行包过滤?
Linux内核在其1.1系列中就有了包过滤功能。第一代,由Alan Cox 1994年移植于BSD的ipfw。这在Linux 2.0中由Jos Vos和其他人进行了加强;用户空间工具'ipfwadm'可用来控制内核过滤规则。1998年中,我在Michael Neuling的帮助下,为Linux 2.2进行了重写,推出了用户空间工具'ipchains'。最后,1999年中,基于Linux 2.4的第四代工具,'iptables',和其他内核的改写正式推出。这就是这个iptables的HOWTO文档的所在。
译者:userspace根据台湾同胞的说法,是用来区别系统内存中的适用范围的,分为核心空间和使用者空间,不必深究)
你需要包含netfilter架构的内核。netfilter是Linux中的一个通用框架,也可以插入(plug in)其他内容(如iptables模块)。也就是说你需要2.3.15及以后版本,而且在配置内核时对CONFIG_NETFILTER回答'Y'。
iptables这个工具用来和内核交互并告诉它哪些包应该过滤。除非你是程序员或者 特别好奇,否则这就是你用来控制包过滤的了。
--------------------------------------------------------------------------------
3.2.1. iptables
iptables工具向内核的包过滤表中插入和删除规则。这就意味着无论怎样设置,启动后信息都会丢失;请参看“制定永久性规则”(Making Rules Permanent)来确定如何保证下次启动这些规则能被恢复。
iptables是ipfwadm和ipchains的替代品。如果你是它们的使用者,请参看 “使用ipchains和ipfwadm”,如何轻松使用iptables。
--------------------------------------------------------------------------------
3.2.2 创建永久性规则
你当前的防火墙设置保存在内核中,所以重启后就会丢失。你可以试着用iptables-save和iptables-restore脚本来保存他们,并由一个文件恢复。
--------------------------------------------------------------------------------
4. 你算老几,凭什么玩弄我的内核?
我是Rusty Russell。Linux IP防火墙的维护者,也是一个适当的时候出现在适当的地方的coder。我写了ipchains(参见“如何在Linux下进行包过滤?”看看实际的工作其实由哪些人完成),并希望能学到足够的东西修正这次的包过滤。
WatchGuard,一个非常出色的防火墙公司,总之一堆广告,此处省略一千字……
在此,我想澄清一个误解:我不是内核专家,我了解它,是因为我的核心工作让我接触了他们:David S. Miller, Alexey Kuznetsov, Andi Kleen, Alan Cox。无论如何,他们做了最深层的工作,轮到我时,已经非常安全和容易了。
--------------------------------------------------------------------------------
5. Rusty的真正的包过滤快速指南
绝大部分人只有一个PPP连接到Internet,而且不希望有人由此进入他们的网络或者防火墙:
# 插入connection-tracking模块(如国内建在内核中就不需要)
# insmod ip_conntrack
# insmod ip_conntrack_ftp
# 对创建大量新的连接创建一个链,除非这些连接来自内部。
# iptables -N block
# iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A block -j DROP
# 由INPUT和FORWARD链跳往(刚刚创建的)那条链。
# iptables -A INPUT -j block
# iptables -A FORWARD -j block
--------------------------------------------------------------------------------
6. 包是如何穿过过滤器的
内核由'filter'表中的以下三个规则开始。这些被称为防火墙链或就叫链。这三个链分别是 INPUT、OUTPUT和FORWARD。
对于ASCII艺术迷来说,链好象这样:(注意:这与2.0和2.2内核非常不同)
译者:ASCII艺术,这里指的是利用纯ASCII文本作图
_____
Incoming / / Outgoing
-->;[Routing ]--->;|FORWARD|------->;
[Decision] /_____/ ^
| |
v ____
___ / /
/ / |OUTPUT|
|INPUT| /____/
/___/ ^
| |
---->; Local Process ----
三个圈代表上面说的三个链。当包到达图中的一个圈,那个链就检查并确定包的命运。 如果链决定DROP包,包在那里就被杀死。但是如果链决定让包ACCEPT,包就继续在图中前进。
一个链是规则的列表。每个规则都会说:'如果包头看上去像这个的话,那么就这样处理'。 如果规则和包不匹配,由链中的下一个规则处理。最后,如果再也没有要进行处理的规则了, 内核就根据链的原则(policy,有时称为默认规则)来决定应当如何做。在一个注重安全的 系统中,原则通常是让内核丢弃这个包。
1. 当一个包进入时(就是由以太网卡),内核首先检查包的目的地。这被称作“选路”。
2. 如果它就是进入本机的,包会向图中的下方移动,到达INPUT链。如果到了这里,任何等待这个包的进程都会收到它。
3. 否则,如果内核未被允许转发,或者不知道该如何转发这个包,它会被丢弃。如果允许转发,而且包的目的地是另一个网络接口(如果你有另一个的话),那么包向我们图中的右边行进,到达FORWARD链。如果允许通过(ACCEPT),它就被送了出去。
4. 最后,服务器上运行的程序可以发送网络包。这些包马上通过OUTPUT链。如果被允(ACCEPT),那么包继续向可以到达它的目的地的网络接口发送。
--------------------------------------------------------------------------------
7. 使用iptables
iptables有着非常详尽的使用手册(man iptables),而且如果你需要某个选项更详细的介绍。看看“iptables和ipchains的差别”可能对你非常有用。
使用iptables你可以做很多不同的事。开始的内建的三个链INPUT、OUTPUT和FORWARD是不能被删除的。让我们看看整个链的管理。
1. 创建一个新的链 (-N)。
2. 删除一个空链(-X)。
3.修改内建链的原则(-P)。
4. 显示链中的规则(表)(-L)。
5. 清空一个链(-F)。
6. 将链中所有规则的包和字节计数器清零(-Z)。
有几种办法操作链中的规则:
1. 向链中添加一条新规则(-A)。
2. 在链中某个位置插入一条新规则(-I)。
3. 替换某个位置的规则(-R)。
4. 删除链中某个位置的规则,或者是第一个被匹配的。(-D)。
--------------------------------------------------------------------------------
7.1. 当计算机启动后你会看到的
ptables可以作为模块,称为'iptables_filter.o,可以在第一次运行iptables时自动被装载。也可以永久性的编到内核中。
在所有iptables命令执行之前(当心:某些发布版会在初始化脚本中运行iptables),所有内建链中都没有任何规则('INPUT'、'FORWARD'和'OUTPUT'),所有链的原则都是ACCEPT。你可以在装载iptable_filter模块时,提供'forward=0'选项来修改FORWARD的默认原则。
--------------------------------------------------------------------------------
7.2. 对单个规则的操作
这是基本的包过滤:管理规则,添加(-A)和删除(-D)命令可能是最常用的。其他的(-I插入和-R替换)只是简单的扩展而已。
每个规则都有一组条件来匹配包,和如果匹配了该如何做(target)。例如,你可能希望丢弃所有来自127.0.0.1的ICMP包。这样我们的条件就是协议必须是ICMP,而且源地址必须是127.0.0.1,我们的目标是丢弃(DROP)。127.0.0.1是一个回送接口,即使你没有真正的网络连接它也会存在。你可以用ping程序生成这样的包(它简单的发送ICMP 类型8(echo request),所有愿意响应的主机都会用ICMP 类型0(echo reply)来响应)。这对于测试非常有用。
# 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
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP
# 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'链中添加(-A)一个规则,制定来自127.0.0.1('-s 127.0.0.1')的ICMP协议('-p icmp')包都将被丢弃('-j DROP')。
然后我们测试我们的规则,用第二个ping。在程序放弃等待永远不可能的响应之前,会暂停一下。
我们可以用两种办法中的任一种删除规则。首先,因为知道这是INPUT链中唯一的规则,我们用编号删除:
# iptables -D INPUT 1
删除INPUT链中的编号为1的规则
第二种办法是 -A 命令的映射,不过用-D替换-A。当你的链中规则很复杂,而你不想计算它们的编号的时候这就十分有用了。这样的话,我们可以使用:
# iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
-D的语法必须和-A(或者-I或者-R)一样精确。如果链中有多个相同的规则,只会删除第一个。
--------------------------------------------------------------------------------
7.3 过滤规格
我们已经看了,用'-p'指定协议,用'-s'指定源地址,不过还有其他选项我们可以用来指定包的特征。下面是一个详细的手册。
--------------------------------------------------------------------------------
7.3.1 指定源和目的IP地址
源('-s','--source'或'--src')和目的('-d','--destination'或'--dst')IP地址可以用四种办法指定。最常用的方法是使用全名,就像'localhost'或者'www.linuxhq.com'。第二种办法是指定IP地址,如'127.0.0.1'。
第三和第四种办法允许指定一组IP地址,就像'199.95.207.0/24'或者'199.95.207.0/255.255.255.0'。这指定了从199.95.207.0到199.95.207.255范围内的所有IP地址。'/'后面的数字说明哪部分IP地址是有效的。'32'或者'255.255.255.255‘为默认的(匹配整个IP地址)。用'/0'来指定任何IP地址,像这样:
# '-s 0/0'在这里是多余的
# iptables -A INPUT -s 0/0 -j DROP
这很少用到,这和上面出现过的不指定'-s'结果完全一样。
--------------------------------------------------------------------------------
7.3.2 反向指定
很多标记,包括'-s'(或'--source')和'-d'('--destination')标记可以在前面加上'!'标志(读作'not'),来匹配所有和给出的 NOT 的地址。例如, '-s ! localhost'匹配所有不是来自本机的包。
--------------------------------------------------------------------------------
7.3.3 协议指定
可以用'-p'(或'--protocol')指定协议。协议可以是数字(如果你知道IP的协议数值)或者像'TCP'、'UDP'或者'ICMP'这类的名称。大小写无所谓,所以'tcp'和'TCP'一样。
协议名称前可加上'!',以反向解释它,例如'-p ! TCP'将匹配所有不是TCP的包。
--------------------------------------------------------------------------------
7.3.4 接口指定
'-i'(或'--in-interface')和'-o'(或'--out-interface')选项指定匹配的接口名。接口可以是包进入的('-i')或者送出('-o')的物理设备。你可以用ifconfig命令列出当前'up'的接口。(也就是说正在工作的)。
通过INPUT链的包不会有送出接口,所以在这个链中'-o'永远不会匹配。同样,通过OUTPUT链的包也没有进入接口,这个链中的'-i'也不会被匹配。
只有通过FORWARD链的包才有进入和送出两个接口。
可以指定一个当前不存在的接口。在这个接口可用之前,规则不能匹配任何东西。这对于拨号PPP连接及类似的非常有用(通常是ppp0接口)。
一个特殊情况,接口名后面是一个'+',那就会匹配以这个字符串开头的所有接口(无论当前是否存在)。例如,指定一个匹配所有ppp接口的规则,要用到-i ppp+选项。
接口名也可以在前面插入 '!',来匹配所有与指定接口不同的包,如-i ! ppp+。
--------------------------------------------------------------------------------
7.3.5 分片指定
译者:为帮助大家理解,此处附上IP数据报的格式,摘自《Internetworking with TCP/IP》
0 4 8 16 19 24 31
版本号 首部长度 服务类型 总长度
标志符 标志 分片偏移量
寿命 协议 首部效验和
源IP地址
目的IP地址
IP选项 填充
数据
……
有时一个包太大,不可能适合所有线路。这样的话,包会被分成片,然后当作多个包发送。最终重组这些分片来重建整个包。
分片的问题是,被检查的初始片含有整个头部字段(IP+TCP,UDP和ICMP),但随后的包只有一部分头(没有附加协议字段的IP),因此,检查后面的分片的头部(就像有TCP、UDP和ICMP一样)是不可能的。
如果你在做NAT或连接追踪,那么所有分片在包过滤代码处理以前都会合并,所以你不需要为分片担心。
还请注意,到filter表中的INPUT链(或者任何由NF_IP_LOCAL_IN钩子程序钩入的表)的包实际上由核心IP栈片重组后到达。
否则,理解分片是如何被过滤规则处理的就非常重要了。任何过滤规则要求我们没有的信息,将被认为不匹配。这意味着(分片的)第一片像普通的包一样被处理。第二及后面的片则不会。因此,规则 -p TCP --sport www(指定源端口为'www')永远不会匹配一个分片(的包)(除了第一片),相反的规则 -p TCP --sport ! www也不会。
无论如何,你可以用'-f'(或'--fragment')标记指定专门处理第二及以后的分片的规则。当然也可以指定一个规则,让它不去匹配第二及以后的分片,在'-f'前加上'!'。
通常,让第二及以后的分片通过被认为是安全的,因为如果过滤处理了第一片,那么就无法在目标主机上进行重组。不过,已知的Bug是发送分片可能会轻易的让主机崩溃。你自己看着办吧。
网络高手注意:当这类检查进行时,畸形的包(防火墙读取的ICMP代码和类型过短的TCP、UDP和ICMP包)都将被丢弃。所以TCP分片从位置8开始。(译者:什么意思?大概是指IP包中的首部字段位置)
例如,下面的规则会丢弃任何发往192.168.1.1的分片。
# iptables -A OUTPUT -f -d 192.168.1.1 -j DROP
--------------------------------------------------------------------------------
7.3.6 iptables扩展:新的匹配
iptables是可扩展的,也就是包括内核和iptables工具都可以扩充新的特性。
下列部分扩展是标准的,其他的则是派生的。其他人可以做出扩展并发布给合适的人。
内核扩展一般位于内核模块子目录,诸如/lib/modules/2.4.0-test10/kernel/net/ipv4/netfilter。如果你使用了CONFIG_KMOD设置来编译内核,那么它们要求被装载,所以你不需要手工插入。
iptables程序扩展通常是位于/usr/local/lib/iptables/下的共享库,当然也可能在/lib/iptables或者/usr/lib/iptables,具体的要根据不同的发行版本来确定。
扩展有两种:新的目标,新的匹配(我们马上会谈到新的目标)。有些协议自动给出新的测试:如下所示,现有的包括TCP、UDP和ICMP。
这样,你可以在命令行中在 '-p'选项后指定新的测试,就可以载入扩展(模块)了。当允许扩展时,可以用'-m'选项装入扩展。
在选项后面('-p','-j'或者'-m')加上 '-h'或'--help'来获取扩展的帮助。
# iptables -p tcp --help
--------------------------------------------------------------------------------
7.3.6.1. TCP 扩展
如果指定了'-p tcp',那么TCP扩展将自动加载,并提供下列选项(不匹配分片)。
--tcp-flags
可附加一个'!'。有两个标志字串可以通过TCP标记来过滤。第一个标志字符串是mask:你想要测验的标志列表。第二个指出哪些将要被设置。例如:
# iptables -A INPUT --protocol tcp --tcp-flags ALL SYN,ACK -j DROP
意思是所有标志都将被测试('ALL'和'SYN, ACK,FIN,RST,URG,PSH'同义),不过只设置SYN和ACK。当然也可以用'NONE'表示无标志。
--syn
前面的'!'是可选的,是'--tcp-flags SYN, RST, ACK, SYN'的缩写
--source-port
后面可以跟一个'!',可以是单个TCP端口,或一段端口。可以是/etc/services中的端口名或者数字。端口范围格式是低端口名 : 高端口名,或者(指定大于或等于给出的端口)是端口名 + :,或者(指定小于或等于给出的端口)是: + 端口名。
--sport
就是 '--source-port'。
--destination-port
--dport
和上面类似,不过是指定匹配的目的端口(范围)。
--tcp-option
可以跟一个'!'和一个数字,匹配的是TCP选项和数字相等的包。如果试图用 这个TCP选项匹配一个没有完整的TCP包头的包,那么这个包会被自动丢弃。
--------------------------------------------------------------------------------
7.3.6.1.1. TCP标志的解释
有时只允许单向的TCP连接会很有用。例如,你可能会允许连接到外部WWW服务器,但不会允许来自那个服务器的连接。
最简单的举动可能是阻止来自那个服务器的包,可惜,TCP连接需要包双向传送(才能正常工作)。
解决办法是,只阻挡那些用来请求连接的包。这些包称为SYN包(OK,从技术上说,它们的SYN标志被设置,而没有设置RST和ACK标志,不过我们简单的称为SYN包)。通过只阻止这种包,我们就可以阻止来自那些地方的连接企图。
'--syn'标志是这样用的:只对指定了TCP协议的规则有效。例如,指定来自192.168.1.1的连接请求。
-p TCP -s 192.168.1.1 --syn
当然也可以在前面加上'!',意即所有不是初始连接的包。
--------------------------------------------------------------------------------
7.3.6.2 UDP 扩展
这些扩展在指定'-p udp'时自动加载。可以提供 '--source-port'、'--sport'、'--destination-port'和'--dport'等和TCP类似的选项。
--------------------------------------------------------------------------------
7.3.6.3 ICMP扩展
这些扩展在指定'-p icmp'时自动加载。只提供一个新的选项:
--icmp-type
可以跟'!',icmp类型名称(如'host-unreachable')或者数值(如'3'),或者数值类型/代码(如'3/3')。用'-p icmp --help'可以列出可用的icmp类型名。
--------------------------------------------------------------------------------
7.3.6.4 其他匹配的扩展
这些netfilter包中的其他扩展尚属于演示阶段,(如果安装了的话)可以用'-m'来启用。
mac
--mac-source
可以跟一个'!',后面是以太网地址,用冒号分隔的16近制表示,如`--mac-source 00:60:08:91:CC:B7'。
limit
此模块必须明确指定'-m limit'或'--match limit'。用来限制匹配的速率。就像抑制记录信息。只会匹配给定的数字/每秒(默认是每小时3个匹配,和5个触发)。可以有两个参数:
--limit
后面跟数字:指定每秒钟允许的匹配最大平均数。这个数字可以指定 明确的单位,使用'/second'、`/minute'、`/hour' 或者 `/day',或者 只写一部分(如'5/second'和'5/s'一样)。
--limit-burst
后面跟一个数字,指明在上面的limit起作用前最大的触发值。
这个匹配(项)通常和LOG目标结合起来使用,以对速率限制进行记录。 为了理解它是如何工作的,我们来看看下面这条规则,它使用默认限制参数 记录包。
# iptables -A FORWARD -m limit -j LOG
当这条规则第一次启用时,包开始被记录。实际上,由于默认触发是5,前五个包会被记录。然后,每隔20分钟再记录一次包,无论这期间有多少包到达。而且,每个不匹配包的20分钟间隔里,会恢复一个触发(值)。如果100分钟都没有包到达这个规则,那么所有触发都会恢复,回到起点。
提示:你目前不能以大于59小时的时间来创建这种规则,所以如果你设置一个平均率为一天,那么你的触发率必须小于3。
你也可以将此模块用于避免使用快速响应速率的各类拒绝服务攻击(DoS,Denial of Server)。
(译者:以下是较著名的攻击)
Syn-flood protection:
# iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
Furtive port scanner:
# iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
Ping of death:
# iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
这个模块工作原理类似于“节流阀”,以下是图示。
rate (pkt/s)
^ .---.
| / DoS /
| / /
Edge of DoS -|.....:........./....................... DoS的边界 =
= (limit * | /: /
limit-burst) | / : / .-.
| / : / / /
| / : / / /
End of DoS -|/....:..............:.../......./..../. DoS结束
= limit | : :`-' `--'
-------------+-----+--------------+------------------>; time (s)
LOGIC =>; Match | Didn't Match | Match
我们匹配由五个包触发的每秒一个包,不过每秒钟第四个包才开始进入(这个规则),进行三秒钟,然后重新开始。
<--Flood 1-->; <---Flood 2--->;
Total ^ Line __-- YNNN
Packets| Rate __-- YNNN
| mum __-- YNNN
10 | Maxi __-- Y
| __-- Y
| __-- Y
| __-- YNNN
|- YNNN
5 | Y
| Y Key: Y ->; Matched Rule
| Y N ->; Didn't Match Rule
| Y
|Y
0 +-------------------------------------------------->; Time (seconds)
0 1 2 3 4 5 6 7 8 9 10 11 12
你可以看见,前五个包是允许超过一个包/每秒(这个速率)的,然后就开始限制。 如果有一个暂停,那么另一个触发也是允许的,但不能超过规则设置的最大速率。
owner
--uid-owner userid
根据给出的有效的(数值)user id来匹配包的创建进程。
--gid-owner groupid
根据给出的有效的(数值)group id 来匹配包的创建进程。
--pid-owner processid
根据给出的process id 来匹配包的创建进程。
--sid-owner sessionid
根据给出的 session group 来匹配包的创建进程。
unclean
这是试验性模块,必须明确指定'-m unclean'或者'--match unclean'。 它对包进行各种随机判断。此模块还未通过审核,所以不要用在安全设施上。 (可能造成更糟糕的结果,它自己可能还有Bug)。没有提供选项。
--------------------------------------------------------------------------------
7.3.6.5 状态匹配
最有用的匹配标准是'state'扩展。它负责解释'ip_conntrack'模块的connection-tracking分析。 这是推荐使用的(好东东)。
通过指定'-m state'来允许附加的'--state'选项,匹配用逗号分割的状态列表('!'标志表明不符合那些状态(的状态))。
NEW
由新连接创建的包
ESTABLISHED
属于已存在连接的包(也就是说,响应的包)
RELATED
和一个已存在连接有关,但不是它的一部分的包。如ICMP错误,或者(已加载FTP模块)一个建立FTP数据连接的包。
INVALID
由于以下原因而不能被识别的包:包括内存不足和不是相应当前任何连接的ICMP错误。通常这些包会被丢弃。
这个强大的匹配扩展的一个例子:
# iptables -A FORWARD -i ppp0 -m state ! --state NEW -j DROP
--------------------------------------------------------------------------------
7.4 目标规格
现在,我们知道了如何对包进行测试,但是我们还需要告诉那些匹配的包应该如何做。这被称作规则的目标。
有两个很简单的内建目标:DROP和ACCEPT。我们已经看过了。如果包匹配的规则,其目标是这二者中的一个,那么不再考虑更多的规则了:包的命运已经决定。
除此之外有两种目标:扩展的和用户定义的链。
--------------------------------------------------------------------------------
7.4.1 用户定义链
iptables一个强大的特点是由ipchains继承来的可以让用户创建新的链,附加在三个内建的链上(INPUT、FORWARD和OUTPUT)。按照惯例,用户定义链使用小写以区分他们。(我们会在“Operations on an Entire Chains”中描述如何创建新的用户定义链)。
当包匹配的链的目标是一个用户定义链时,包就转移到用户定义链中的规则。如果 没有决定包的命运,那么包在(用户定义链)中的移动就结束了,并回到当前链的下一个规则。
搞搞ASCII艺术吧。考虑两个(笨蛋)链:INPUT(内建的)和test(用户定义的)。
`INPUT' `test'
---------------------------- ----------------------------
| Rule1: -p ICMP -j DROP | | Rule1: -s 192.168.1.1 |
|--------------------------| |--------------------------|
| Rule2: -p TCP -j test | | Rule2: -d 192.168.1.1 |
|--------------------------| ----------------------------
| Rule3: -p UDP -j DROP |
----------------------------
考虑一个由192.168.1.1到1.2.3.4的TCP包。它进入INPUT链,由Rule1检查 - 不匹配。 Rule2匹配,那么它的目标就是test,所以下一个检查由test开始。test中的第一个规则 Rule1是匹配的,但是没有指定目标,所以由第二个规则Rule2检查。结果是不匹配,而我们 到达了链的尾部。于是回到INPUT链,因为刚刚被Rule2检查,所以现在由Rule3来检查,仍然 不匹配。
所以这个包的路线是:
v __________________________
`INPUT' | / `test' v
------------------------|--/ -----------------------|----
| Rule1 | /| | Rule1 | |
|-----------------------|/-| |----------------------|---|
| Rule2 / | | Rule2 | |
|--------------------------| -----------------------v----
| Rule3 /--+___________________________/
------------------------|---
v
用户定义链可以跳转到另一个用户定义链(不过不能循环:如果发现循环,包就会被丢弃)。
--------------------------------------------------------------------------------
7.4.2 iptables扩展:新目标
其他类型的扩展是目标。目标扩展由内核模块组成,而且iptables的一个可选扩展提供了新的命令行选项。有几个扩展是包含在默认netfilter发布中的。
LOG
--log-level
跟一个级别名称或数字。合适的名字是(忽略大小写)'debug'、'info'、'notice'、'warning'、'err'、'crit'、'alert'和'emerg',相当于数字7到0。请参考syslog.conf的手册获取这些级别的说明。默认是'warning'。
--log-prefix
跟一个最多29个字符的字符串,它被写入到log信息的开始处,这样可以区别出来。
这个模块最有用的就是跟在limit match后面,这样你就不会被你的log淹没了。
REJECT
此模块和'DROP'效果一样,除了会发送一个'port unreachable'的ICMP错误报文。注意如果属于以下情况,ICMP错误报文不会发送:
o 包一开始就是ICMP错误报文,或者是未知的ICMP类型。
o 包被作为无头的分片过滤了。
o 我们已经向那里发送了太多的ICMP错误报文(参见/proc/sys/net/ipv4/icmp ratelimit)。
--------------------------------------------------------------------------------
7.4.3 特殊的内建目标
有两个特殊的内建目标:RETURN和QUEUE。
RETURN如同到达这个链的尾部:如果是内建的链的规则,那么这个链的默认规则将被执行。如果是用户定义链,当跳至这个链中的这条规则(包含RETURN)时,回到前面的链继续匹配。
QUEUE是一个特别的目标,会为用户空间进程队列这个包。要这样使用,需要两个部件:
o 一个"queue handler",处理用户空间与内核之间的机制。
o 和一个用户空间用来接收的应用程序,可能是操作,以及对包进行裁决。
IPv4 iptables的标准queue handler是 ip_queue 模块,跟随内核发布并标记为实验中。
下面是一个如何用iptables为用户空间进程队列包的快速例子:
# modprobe iptable_filter
# modprobe ip_queue
# iptables -A OUTPUT -p icmp -j QUEUE
在这个例子中,本地生成的送出ICMP包(如由ping产生)到达ip_queue模块,然后包被试图送往用户空间应用。如果没有用户空间应用在(那儿)等着,包就被丢弃了。
要写一个用户空间应用,需要libipq API。和iptables一起发布。在CVS的testsuite tools(如redirect.c)中可以找到相关例子。
可以通过这里检查ip_queue的状态:
/proc/net/ip_queue
队列的最大长度(也就是不包含返回包的送往用户空间包的数量)可以通过这里控制:
/proc/sys/net/ipv4/ip_queue_maxlen
默认队列长度是1024。一旦达到这个长度,新的包就会被丢弃,直到队列长度小于这个值。好的协议如TCP,会对丢弃的包作出拥挤的解释,而且在队列满了后会很理想的将它挡回。无论如何,如果默认值太小的话,最好是多实验以决定队列的最大长度。
--------------------------------------------------------------------------------
7.5 对整个链进行操作
iptables一个非常有用的特性是可以将链中相关的规则成组。你可以随意给链取名,不过我建议使用小写字母以避免与内建的链和目标产生冲突。链的名称最长为31个字母。
--------------------------------------------------------------------------------
7.5.1 创建新链
让我们创建一个新链。因为我是个充满想象的家伙,我叫它test。使用'-N'或'--new-chain'选项:
# iptables -N test
如此简单,现在你可以像上面说的那样放入规则了。
--------------------------------------------------------------------------------
7.5.2 删除链
删除一个链同样简单,使用 '-X'或'--delete-chain'选项。为什么是'-X'?嗯,因为所有合适的字母都已经被使用了。
# iptables -X test
有几个删除链的限制:他们必须是空的(见下面的"Flushing a Chain")而且他们不能是任何规则的目标。你也不能删除任何一个内建的链。
如果你不指定链名的话,所有可以被删除的用户定义链都将被删除。
--------------------------------------------------------------------------------
7.5.3 清空一个链
这是清除一个链中所有规则的简单方法,使用'-F' 或 '--flush'命令。
# iptables -F FORWARD
如果不指定链的话,所有链都将被清空。
--------------------------------------------------------------------------------
7.5.4 对链进行列表
用'-L'或'--list'命令,你可以列出一个链中的所有规则。
用户定义链中的'refcnt'是有多少链的规则指向了它。这个值必须为0,然后才可以删除这个链。
如果链名被忽略,所有链都将被列出,即便是空的。
'-L'可以有三个选项。'-n'(数字)选项对于阻止iptables试图查找IP地址时非常有用,因为(如果你像大多数人一样使用DNS)如果你的DNS设置不太合适的话,可能会造成长时间的停顿,或者你滤掉了DNS请求。它还会让TCP或UDP端口以数字显示。
'-v'选项显示所有规则的细节,包括饱和字节计数器,TOS比较,以及接口。否则这些值是被忽略的。
注意,报和字节计数器可以分别使用'K'、'M'或者'G'来代替1000、1,000,000 和1,000,000,000。使用'-x'(扩展数字)标志来打印整个值,不管它有多大。
--------------------------------------------------------------------------------
7.5.5 重置(清零)计数器
可以重置计数器非常有用。可以用'-Z'或'--zero'来完成。
考虑下面的:
# iptables -L FORWARD
# iptables -Z FORWARD
在上述例子中,有些包在'-L'和'-Z'命令之间通过。因此,你可以把'-L'和'-Z'一起使用,读取时就清空计数器。
--------------------------------------------------------------------------------
7.5.6 设置原则(默认规则)
我们在前面讨论包是如何通过链的时候,已经解释了当包到达内建链的尾部时会发生什么。这时,链的原则就决定包的命运。只有内建的链(INPUT、OUTPUT和FORWARD)有原则,因为如果包到达用户定义链的尾部会返回到前面的链。
原则可以是ACCEPT或DROP,例如:
# iptables -P FORWARD DROP
--------------------------------------------------------------------------------
8. 使用ipchains和ipfwadm
netflter发布中有ipchains.o和ipfwadm.o模块。把其中一个加载到你的内核(注意:他们和ip_tables.o不兼容)。然后你就可以像以前那样使用ipchains和ipfwadm了。
这在一段时间内仍然被支持。我认为合理的计算方式是 2*(替代发布 - 初始的稳定版本),超过了这个时间,就应当使用替代的稳定版本了。这意味着在Linux 2.6或2.8中对它们的支持很可能被放弃。
--------------------------------------------------------------------------------
9. NAT和包过滤的混合使用
想要做网络地址转换(参见NAT HowTo)和包过滤的已很常见。好消息是他们可以混合起来使用的,而且工作得非常好。
你可以完全忽略你的NAT,来定义你的包过滤。包过滤看见的包的源及目标是“真正”的源和目标。例如,如果你将任何发往1.2.3.4 80端口的包DNAT到10.1.1.1的8080端口。包过滤器看见的是包发往10.1.1.1的8080端口(真正的目的地),而非1.2.3.4 的80端口。同样,你可以忽略伪装:看到的是包的真实外部IP地址(如10.1.1.1),而响应的则返回到那里。
你可以使用'state'匹配扩展,使包过滤器不需要做任何额外的工作,因为无论如何,NAT都会要求连接跟踪。扩展NAT HowTo中简单的伪装例子,以禁止任何来自ppp0接口的新的连接,你可以这样:
#对送至ppp0的包进行伪装
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# 禁止由ppp0进入的新的或不合适的包
iptables -A INPUT -i ppp0 -m state --state NEW,INVALID -j DROP
iptables -A FORWARD -i ppp0 -m state --state NEW,INVALID -j DROP
# 开启IP转发
echo 1 >; /proc/sys/net/ipv4/ip_forward
--------------------------------------------------------------------------------
10. iptables和ipchains之间的差别
o 首先,内建链的名称从小写改成了大写,因为现在的INPUT和OUTPUT链只获取指向本地和本地生成的包。他们用来检查所有进入和发送的包。
o '-i'标志现在表示进入接口的意思,而且只适用于INPUT和FORWORD链。FORWORD或OUTPUT链中的规则应该将'-i'改为'-o'。
o TCP和UDP端口现在必须用--source-port或--sport(或者--destination-port/--dport)拼写,而且必须放在'-p tcp'或'-p udp'选项之后,因为TCP或UDP扩展是分别加载的。
o TCP -y 标志现在是 --syn,而且必须在'-p tcp'之后。
o DENY目标现在是DROP.
o 对单个链,可以在列出其工作同时清零。
o 清空内建链同时清除了原则计数器。
o 列出链给出的是一个计数器的微型的快照。
o REJECT和LOG现在是扩展目标,意思是他们是独立的内核模块。
o 链的名称最多可以是31个字符。
o MASQ现在是MASQUERADE而且使用不同的语法。REDRIRECT,在保留相同的名字时,也经历了语法的改变。参见NAT-HOWTO以获取配置它们的更多信息。
o -o选项不再用于将包传递给用户空间设备了(见上面的-i)。现在通过 QUEUE目标传递到用户空间。
o 很可能还有一些我也忘了。
--------------------------------------------------------------------------------
11. 对制定包过滤器的建议
在计算机安全领域中,最明智的办法是阻挡所有东西,然后对需要的开启。这通常称为“凡是没有明确允许的都是禁止的”。我建议这样做如果安全是你最关心的。
不要运行任何你不需要的服务,即使你认为你已经阻碍了对它们的访问。
如果你创建专用防火墙,开始时不运行任何东西,并阻止所有包,然后添加服务并让需要的包通过。
我强调安全:结合tcp-wrappers(对于包过滤器本身的连接),代理(通过包过滤器的连接),路由验证和包过滤。路由验证是如果包来自未预期的接口那么将被删除:例如,如果你的内部网络地址是10.1.1.0/24,而一个包的源地址是你的外部接口,那么它将被丢弃。对一个接口如ppp0来说可以这样:
# echo 1 >; /proc/sys/net/ipv4/conf/ppp0/rp_filter
或者对所有已有的或将有的接口:
# for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
# echo 1 >; $f
# done
Debian在可能的范围了将这些设为默认。如果你使用非对称路由(如你期望包来自一个其他的方向),你可能需要在这些接口上禁止这一过滤。
记录对于当工作不正常时设置防火墙非常有用,但是在一个作为产品的防火墙上,总是应当将它与'limit'匹配结合,以防止有人充斥你的记录。
我极力推荐对安全系统使用连接追踪:它虽然会造成负担,因为所有连接都被追踪。但是对于控制对你的网络的访问非常有用。如果你的内核没有自动加载而且没有内建,你需要加载'ip_conntrack.o'这个模块。如果想要精确追踪复杂的协议,你需要加载合适的相关模块(如'ip_conntrack_ftp.o')。
# iptables -N no-conns-from-ppp0
# iptables -A no-conns-from-ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A no-conns-from-ppp0 -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A no-conns-from-ppp0 -i ppp0 -m limit -j LOG --log-prefix "Bad packet from ppp0:"
# iptables -A no-conns-from-ppp0 -i ! ppp0 -m limit -j LOG --log-prefix "Bad packet not from ppp0:"
# iptables -A no-conns-from-ppp0 -j DROP
# iptables -A INPUT -j no-conns-from-ppp0
# iptables -A FORWARD -j no-conns-from-ppp0
建造一个好的防火墙超越了这个HOWTO的范围,不过我的建议是“一切从严”。请参见Security HOWTO获取更多信息,来测试和探索你的服务器。
一起走过的日子 回复于:2004-03-15 17:36:30
1. 简介
欢迎,亲爱的读者。
你将要深入迷人的(有时是令人厌烦的)NAT世界:网络地址转换,这篇HOWTO可以成为你的Linux2.4内核及其以后的准确指南。
在Linux2.4(内核版本),引入了一个叫“netfilter”的部分,专门用于拆分(mangling) (IP)包的。他上一层提供NAT,是完全依靠以前的内核制作的。
(译者注:mangle实在找不出什么合适的翻译,抱歉)
(C) 2000 Paul `Rusty' Russell. Licensed under the GNU GPL.
--------------------------------------------------------------------------------
2、 官方站点及列表位置
这里有三个官方站点:
o Thanks to Filewatcher http://netfilter.filewatcher.org.
o Thanks to The Samba Team and SGI http://netfilter.samba.org.
o Thanks to Harald Welte http://netfilter.gnumonks.org.
你可以通过以下站点访问全部相关站点。
http://www.netfilter.org and http://www.iptables.org
以下是netfilter官方邮件列表
http://www.netfilter.org/contact.html#list.
--------------------------------------------------------------------------------
2、1 什么是网络地址转换(Network Address Translation)?
通常,,网络中的(IP)包从他们的源(地址)出发(比如你家的电脑),到他们的目的地(比如www.gnumonks.org),会经过很多不同的连接(links):例如我所在澳大利亚就有19个。这些连接不会真去修改你的包:他们只是照原样传出去。
(译者注:这里的links应当认为是所有网络节点,包括主机、路由器等。通常,路由器并不是原样传送包,它至少会修改其中一点:TTL)
如果这些连接有一个做NAT,那么它(们)就会修改通过它们的包的源或者目标(地址)。正如你猜象的那样,这并非系统设计成那样的,而是NAT做了一些事情。通常进行NAT的连接(主机、服务器、路由器)会记住它是如何拆分包的,而当另一头响应的包通过时,它会对响应的包做相反的拆分,所以世界仍在运转。
(译者注:这一段的mangle应该想象为修改更合适)
--------------------------------------------------------------------------------
2、2 我为什么要NAT?
在完美的世界里,你不需要。同时,主要的理由是:
用调制解调器连接Internet
在你拨号上网时,大部分ISP只会给你一个IP地址,你可以发送你想发送的任何源地址包,但是只有响应这个(ISP给你的)地址的包才会返回。如果这种情况下你想有多台不同的机器上网(比如一个家庭网络),你就需要NAT。
这是现在NAT用得最多的功能,Linux世界的"masquerading"(伪装)非常出名,我称之为SNAT(SNAT即Source NAT,源地址转换),因为你改变了第一个包的源地址。
(译者:关于IP数据报的第一个包等内容,请参见各TCP/IP书籍)
多(重)服务器
有时你想改变进入网络中的包的目标地址(路由)。经常的,这是因为(就像上面的例子),你只有一个IP地址,但是你希望大家可以通过到那个“真实”的IP地址进入内部。如果你重写了进入包的目标地址,这样就没问题了。这种NAT在以前的Linux版本中被称为端口转发。
一个常见的变种是负载均衡,在一组机器上做映射。如果你要进行严格的比例限制, 可能需要参考Linux Virtual Server。http://linuxvirtualserver.org
透明代理
有时你可能想要经过你的Linux的包被送往本机的一个程序。这就需要用到透明代理了:代理是位于你的网络和外部世界之间的一个程序,帮助二者进行通信。之所以称为透明,是你的网络根本不知道他在和代理交谈,当然直到代理没有正常工作。
Squid可以配置为干这项工作,在以前Linux版本中它被称作重定向或者透明代理。
--------------------------------------------------------------------------------
3、 NAT的两种类型
我把NAT分为两种不同的类型:源NAT(SNAT)和目标NAT(DNAT)。(译者注:以下不再翻译SNAT和DNAT,直接用Source NAT和Destination NAT)
Source NAT是指修改第一个包的源地址:也就是说,改变连接的来源地。Source NAT会在包送出之前的最后一刻做好post-routing(动作),伪装是SNAT的一种特殊形式。
Destination NAT 是指修改第一个包的目标地址:也就是说,改变连接的目的地。Destination NAT 总是在包进入以后(马上)进行before routing(动作)。端口转发、负载均衡和透明代理都属于DNAT。
--------------------------------------------------------------------------------
4、 从2.0和2.2内核的快速转换
如果你还在为从2.0(ipfwadm)到2.2(ipchains)的转换手忙脚乱的话,很抱歉。不过这也算是个喜忧半参的消息。
首先,你可以轻松的使用ipchains和ipfwadm,就像从前一样。不过你需要安装最新发布的netfilter中的“ipchains.o”或者“ipfwadm.o”内核模块。它们是互斥的(你会被警告),而且不能和任何其他netfilter模块结合。
一旦这其中某个模块被载入,你可以像以前一样使用ipchains和ipfwadm,不过仍有以下区别:
用ipchains -M -S,或者用ipfwadm -M -s设置伪装超时不再有效。因为超时已经转移到新的NAT构架中,所以这不能做任何事。
在详细的伪装列表中,init_seq、delta和previous_delat字段始终为零。
归零和列表计数器的 -Z -L不再有效:计数器不能被归零。
这类向后兼容的部分可能和大部分连接都不能有效配合:不要在你的公司网关中使用
开发者们还要注意:
无论是否使用伪装,现在可以绑定61000 - 65095之间的端口。以前的伪装代码占用了这部分端口,因此不能使用。
尚未成文的“getsockname”,透明代理程序可以用来发现那些已不再工作的连接的真实目的地址。
尚未成文的“bind-to-foreign-address”同样还未启用:这个用于完整透明代理的设想。
--------------------------------------------------------------------------------
4、1 我只想伪装!救命!
这是绝大部分人想要的。如果你用PPP拨号上网来动态得到IP (如果你不知道,那应该就是的)你可能只想告诉你的机器,所有来自内部网络的包,要看上去同PPP连接服务器上的包一样。
# 装载NAT模块(这取代了其他的)
modprobe iptable_nat
# 在NAT表中(-t nat),路由后 POSTROUTING 加入一条规则(-A)
# 所有由ppp0送出的包(-o ppp0) 会被伪装( -j MASQUERADE)。
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# 开启IP转发
echo 1 >; /proc/sys/net/ipv4/ip_forward
注意这时你没有做任何的包过滤:如果需要,参见 the Packet Filtering HOWTO。
--------------------------------------------------------------------------------
4、2 那么ipmasqadm呢?
这个完全取决于用户,所以我不担心向后兼容的问题。你可以简单的使用“iptables -t nat”做端口转发。例如,在Linux2.2你要做:
# 在2.2内核,把指向1.2.3.4 8080端口的TCP包转到192.168.1.1的80端口
ipmasqadm portfw -a -P tcp -L 1.2.3.4 8080 -R 192.168.1.1 80
现在你可以这样:
# 2.4内核,在NAT(-t nat)表中加入一条规则,在路由之前(-A PREROUTING)指向
# 1.2.3.4(-d 1.2.3.4)8080端口(--dport 8080)的TCP包(-p tcp)目标地址(-j DNAT)
# 被重定向到 192.168.1.1的80端口(--to 192.168.1.1:80)。
iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to 192.168.1.1:80
--------------------------------------------------------------------------------
5、NAT可以控制什么
你需要创建NAT规则,以告诉内核哪些连接将被改变和如何改变。要做到这一点,我们要用到一个用处很多的iptables工具,并告诉它用指定的“-t nat”选项修改NAT表。
NAT规则表包含三个称为“链”的列表:每个规则都按顺序检查包,直到有一个匹配。其中两个被称为PREROUTING(用于Destination NAT,当包进入时检查),POSTROUTING(用于Source NAT,包离开时检查),第三个叫OUTPUT,这里可以忽略。
如果我有足够的艺术天分的话,下面的见图会准确的说明上述概念:
_____ _____
/ / / /
PREROUTING -->;[Routing ]----------------->;POSTROUTING----->;
/D-NAT/ [Decision] /S-NAT/
| ^
| |
| |
| |
| |
| |
| |
-------->; Local Process ------
上述每一点,当我们查看连接(中)的包时,如果是一个新的连接,我们查看 NAT表中相对应的链,看看需要做些什么。其结果就会作为对这个连接后面所有包 的反应。
(译者注:此处的连接是指一个HTTP会话之类的连接,而非物理上的线路、节点)
--------------------------------------------------------------------------------
5、1 用iptables做简单的选择
下面列出了iptables的一些标准选项。所有双横杠(--)的选项都是可以缩写的。只要iptables可以将它们与其他选项区分开来就够了。如果你的内核是以模块方式支持iptables的,你需要先用命令:insmod ip_tables来加载ip_tables.o
这是最重要的选项表格选择,“-t”。对所有NAT操作,你都需要使用'-t nat'以指定NAT表。其次重要的是'-A',添加一个新的规则到链的末尾(例如'-A POSTROUTING'到POSTROUTING链),或者'-I'从最开始插入一个规则(例如'-I PREROUTING')。
你可以指定你想要进行NAT的包的源(地址)('-s' 或者'--source')和目的(地址)('-d' 或 '--destination')。这两个选项可以跟单个IP地址(例如192.168.1.1),一个名字(例如www.gnumonks.org),或者一个网络地址(例如192.168.1.0/24或192.168.1.0/255.255.255.0[译者:这二者是等价的,只是表示方法不同])。
你可以指定进入或送出的匹配接口。不过能否指定取决于你想要写入规则的那个链:PREROUTING链你只能选择进入接口,POSTROUTING你只能选择送出接口。如果用错了,iptables会给出一个错误。
--------------------------------------------------------------------------------
5、2 关于应当挑选哪些包来拆分(mangle)的要点
我上面说了你可以指定源地址和目标地址。如果忽略源地址选项,那么所有源地址都会被匹配,同样,如果忽略目标地址,所有目标地址都将被匹配。
你还可以标出一个指定的协议('-p'或'--protocol'),诸如TCP或者UDP;那么只有这类协议的包会被匹配。这么做的主要原因是指定了协议,就可以增加额外的选项:指定'--source-port'源端口和'--destination-port'目的端口选项(可缩写为'-sport'和'-dport')。
这些选项让你可以只匹配那些特定源端口及目标端口的包。这些对于重定向Web请求(TCP 80或8080端口)而不影响其他包非常有用。
这些选项必须跟在'-p'选项后面(这可能会对加载该协议的连接库有一定影响)。你可以使用端口号,或者来自/etc/serverices文件的(端口)名。
所有这些你可以对一个包作出的不同选择都详细的列在那详细得可怕的使用手册中了(man iptables)。(译者注:参见iptables man page中文版)
--------------------------------------------------------------------------------
6、说说如何拆分包吧
现在我们知道如何选择我们想要拆分的包了。为完成我们的规则,我们需要准确的告诉内核我们想要它如何做。
--------------------------------------------------------------------------------
6、1 Source NAT
你想要进行Source NAT,改变连接的源地址。这在POSTROUIING链中完成,就在它将送出去的最后一刻。这是一个重要的细节,所有Linux本机上的其他任何东西(路由、包过滤)都会看见那个尚未改变的包。也意味着'-o'(送出接口)选项可用了。
用指定'-j SNAT'来进行Source NAT,'--to-source'选项指定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变源地址为1.2.3.4
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
# 改变源地址为1.2.3.4、1.2.3.5或者1.2.3.6
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
# 改变源地址为1.2.3.4,端口1-1023
# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
--------------------------------------------------------------------------------
6、1、1 伪装
Source NAT的一个特例被称作伪装。它只能被用于动态分配IP地址的情况。例如标准拨号服务(静态IP地址请用SNAT)。
你无需为IP伪装明确指定源地址。它会使用包送出的那个接口(地址)作为源地址。不过更重要的是,如果那个线路关闭了的话,连接(无论如何都会丢失了)会被忘掉,意味着启用新的IP后返回的包就会有点问题了(指那些响应掉线前发出的包的包)。
# 伪装所有由ppp0送出的东西
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
--------------------------------------------------------------------------------
6、2 Destination NAT
用于PREROUTING链,包刚刚进入的时候。意味着本机上的任何东西看见的都是“真正”的目的地(译者注:即已修改过的目的地址)。也意味着'-i'(进入接口)可用了。
用指定'-j DNAT'来进行Destination NAT,'--to-destination'选项指定定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变目标地址为5.6.7.8
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8
# 改变目标地址为5.6.7.8、5.6.7.9或5.6.7.10
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8-5.6.7.10
# 改变Web传送的目标地址为5.6.7.8,8080端口
# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to 5.6.7.8:8080
--------------------------------------------------------------------------------
6、2、1 重定向
Destination NAT的一个特例被称为重定向。它相当于对进入接口进行DNAT的简单方便的一种形式。
# 发送进入的80端口的Web传输到我们的Squid(透明)代理
# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3128
注意Squid需要被配置为透明代理。
--------------------------------------------------------------------------------
6、3 深层次的映射
还有一些可能大部分人不会用到的NAT的细节。
--------------------------------------------------------------------------------
6、3、1 一个范围内多地址的选择
如果指定了IP地址的范围,那么机器会选择当前使用最少的那个IP地址。这就实现了最俭朴的负载均衡。
--------------------------------------------------------------------------------
6、3、2 建立空的NAT映射。
你可以使用 '-j ACCEPT' 目标让连接通过,不需要NAT参与。
--------------------------------------------------------------------------------
6、3、3 标准NAT行为
默认行为是根据用户给定的内在约束规则,对连接作最小的改动。也就是除非必要 不要进行端口重映射。
--------------------------------------------------------------------------------
6、3、4 内部源端口映射
如果其他的连接覆盖了一个连接,即使这个连接不需要使用NAT,源地址转换仍会发生。考虑IP伪装,这种情况就非常普遍。
1、一个从192.168.1.1 1024端口到www.netscape.com 80端口的Web连接已建立
2、它被伪装成IP伪装服务器的IP地址(1.2.3.4)
3、IP伪装服务器试图建立一个从www.netscape.com 80端口到1.2.3.4 1024端口的Web连接(它自己的外部接口IP地址)
4、NAT代码会修改第二个连接的源地址到1025,这样两个(连接)就不会冲突了。
当这种内部源地址映射发生时,端口分为三级:
512以下的端口
512至1023之间的端口
1024以上的端口
内部端口映射决不会被映射到(除此之外的)其他种类。
--------------------------------------------------------------------------------
6、3、5 如果NAT失败会怎样?
如果无法按照用户请求的那样,为连接建一个单独的映射,(包)会被删除。这也适用于那些无法被归为任何连接的包,因为它们是畸形的,或者是主机内存溢出了。
--------------------------------------------------------------------------------
6、3、6 多重映射,重叠和冲突
你的NAT规则可以把包映射到相同的范围。NAT代码聪明到可以避免它们的冲突。因此,两条规则把192.168.1.1和192.168.1.2的源地址映射都映射到1.2.3.4是没有问题的。
而且,你可以映射到真实的、已在使用的IP地址,只要那些地址也通过这个服务器。所以如果你分配到一个网络(1.2.3.0/24),但有一个内部网络使用了这些地址,另一个使用的是私有地址192.168.1.0/24,你可以简单的NAT 192.168.1.0/24的源地址 到1.2.3.0网络,不必担心冲突。
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0/24
相同的逻辑也适用于NAT服务器本身的地址。这就是得以伪装工作的原因(由伪装后的包和来自本身的“真实”的包共享一个接口地址)。
甚至,你可以映射相同的包到许多不同的目标,它们会被共享。例如,如果你不希望映射任何东西到1.2.3.5,你可以这样做:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254
--------------------------------------------------------------------------------
6、3、7 修改本地生成的连接的目标地址
NAT代码允许你插入DNAT规则到OUTPUT链,不过这在2.4中尚未完全支持(可以使用,但必须用新的配置选项,某些测试中的代码。所以除非有人在疯狂的写这部分代码,我不相信它会很快实现)。
当前的限制是你只能修改目标地址到本机(例如'-j DNAT --to 127.0.0.1'), 不能到任何其他机器,否则相应可能不能够被正确转换。
--------------------------------------------------------------------------------
7、 特定的协议
有些协议不希望被NAT。这些协议,两种延伸必须指明:一个是协议的连接跟踪,一个是真实NAT。
在发布的netfilter中,有可用的FTP模块:ip_conntrack_ftp.o和ip_nat_ftp.o。如果你加载了任一种模块到你的内核(或者编译进去),那么任何关于FTP连接的NAT都是可行的。如果没有,那么只能使用被动FTP(passive ftp),而且如果做了一些Source NAT,它(指FTP)也许不能可靠的工作。
--------------------------------------------------------------------------------
8、 关于NAT的警告
如果你对连接做NAT,所有双向传送的包(进入和送出网络的)必须通过NAT服务器,否则NAT服务器的工作可能不可靠。特别是,连接跟踪代码重组了分片,也就意味着不光是连接跟踪不能可靠工作,甚至所有包都无法通过,因为分片被丢弃。
--------------------------------------------------------------------------------
9、 Source NAT 和路由
如果你要做SNAT,你必须注意所有机器被SNAT的包的回应都将发送到NAT服务器。例如,如果你映射了一些送出的包的源地址为1.2.3.4,那么外部的路由器必须知道发送回应包的地址到NAT服务器。可以这样做:
1、如果你对本机地址做SNAT(路由等所有事情都正常),你不需要做任何事。
2、如果你在本地LAN上做SNAT到未用地址(例如,你映射为1.2.3.99,你的1.2.3.0/24网络中未用的IP),你的NAT服务器需要像那个地址(99)一样正确响应ARP请求。最简单的办法是建立一个IP别名,例如:
# ip address add 1.2.3.99 dev eth0
3、如果你对完全不同的地址做SNAT,你必须保证被SNAT的包到达的机器会返回NAT服务器。如果NAT服务器是它们的默认网关,那么就已经行了,否则你需要发布一个路由(如果运行了路由协议)或者对每个机器手工添加路由。
--------------------------------------------------------------------------------
10、 同一个网络内的Destination NAT。
如果你要对同一个网络做端口转发,你需要确认所有以后的包和回应包都通过NAT服务器(这样它们才能被修改)。NAT代码现在(自2.4.0-test6),会屏蔽掉同组的被NAT的包送出的ICMP重定向,不过收到的服务器会继续尝试直接响应客户。(不会理解这个回应)
经典的情况是,内部人员试图访问你的“公用”Web服务器,而它实际上从公用地址(1.2.3.4)被DNAT到内部机器(192.168.1.1),例如:
# iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j DNAT --to 192.168.1.1
一种办法是运行一台内部DNS服务器,它知道你的公用(外部)Web服务器的真实的(内部)IP地址,并转发所有其他请求到外部DNS服务器。也就是说你的Web服务器能够记录真实的内部IP地址。
另一种办法是让NAT服务器映射那些连接的源地址到它自己,让服务器通过它发出响应。例如,我们可以这样做(假设NAT服务器内部IP地址是192.168.1.250):
# iptables -t nat -A POSTROUTING -d 192.168.1.1 -s 192.168.1.0/24 -p tcp --dport 80 -j SNAT --to 192.168.1.250
因为PREROUTING规则会首先运行,对内部Web服务器来说,包的去向早已确定。我们可以确定好源IP地址。
--------------------------------------------------------------------------------
11. Thanks
Thanks first to WatchGuard, and David Bonn, who believed in the netfilter idea enough to support me while I worked on it. And to everyone else who put up with my ranting as I learnt about the ugliness of NAT, especially those who read my diary.
首先感谢在我工作期间相信netfilter设想并支持我的WatchGuard和David Bonn。以及所有对NAT提出指正的朋友,尤其是读过了我的日记的。
Rusty.
一起走过的日子 回复于:2004-03-15 17:37:15
1. 简介
欢迎,亲爱的读者。
你将要深入迷人的(有时是令人厌烦的)NAT世界:网络地址转换,这篇HOWTO可以成为你的Linux2.4内核及其以后的准确指南。
在Linux2.4(内核版本),引入了一个叫“netfilter”的部分,专门用于拆分(mangling) (IP)包的。他上一层提供NAT,是完全依靠以前的内核制作的。
(译者注:mangle实在找不出什么合适的翻译,抱歉)
(C) 2000 Paul `Rusty' Russell. Licensed under the GNU GPL.
--------------------------------------------------------------------------------
2、 官方站点及列表位置
这里有三个官方站点:
o Thanks to Filewatcher http://netfilter.filewatcher.org.
o Thanks to The Samba Team and SGI http://netfilter.samba.org.
o Thanks to Harald Welte http://netfilter.gnumonks.org.
你可以通过以下站点访问全部相关站点。
http://www.netfilter.org and http://www.iptables.org
以下是netfilter官方邮件列表
http://www.netfilter.org/contact.html#list.
--------------------------------------------------------------------------------
2、1 什么是网络地址转换(Network Address Translation)?
通常,,网络中的(IP)包从他们的源(地址)出发(比如你家的电脑),到他们的目的地(比如www.gnumonks.org),会经过很多不同的连接(links):例如我所在澳大利亚就有19个。这些连接不会真去修改你的包:他们只是照原样传出去。
(译者注:这里的links应当认为是所有网络节点,包括主机、路由器等。通常,路由器并不是原样传送包,它至少会修改其中一点:TTL)
如果这些连接有一个做NAT,那么它(们)就会修改通过它们的包的源或者目标(地址)。正如你猜象的那样,这并非系统设计成那样的,而是NAT做了一些事情。通常进行NAT的连接(主机、服务器、路由器)会记住它是如何拆分包的,而当另一头响应的包通过时,它会对响应的包做相反的拆分,所以世界仍在运转。
(译者注:这一段的mangle应该想象为修改更合适)
--------------------------------------------------------------------------------
2、2 我为什么要NAT?
在完美的世界里,你不需要。同时,主要的理由是:
用调制解调器连接Internet
在你拨号上网时,大部分ISP只会给你一个IP地址,你可以发送你想发送的任何源地址包,但是只有响应这个(ISP给你的)地址的包才会返回。如果这种情况下你想有多台不同的机器上网(比如一个家庭网络),你就需要NAT。
这是现在NAT用得最多的功能,Linux世界的"masquerading"(伪装)非常出名,我称之为SNAT(SNAT即Source NAT,源地址转换),因为你改变了第一个包的源地址。
(译者:关于IP数据报的第一个包等内容,请参见各TCP/IP书籍)
多(重)服务器
有时你想改变进入网络中的包的目标地址(路由)。经常的,这是因为(就像上面的例子),你只有一个IP地址,但是你希望大家可以通过到那个“真实”的IP地址进入内部。如果你重写了进入包的目标地址,这样就没问题了。这种NAT在以前的Linux版本中被称为端口转发。
一个常见的变种是负载均衡,在一组机器上做映射。如果你要进行严格的比例限制, 可能需要参考Linux Virtual Server。http://linuxvirtualserver.org
透明代理
有时你可能想要经过你的Linux的包被送往本机的一个程序。这就需要用到透明代理了:代理是位于你的网络和外部世界之间的一个程序,帮助二者进行通信。之所以称为透明,是你的网络根本不知道他在和代理交谈,当然直到代理没有正常工作。
Squid可以配置为干这项工作,在以前Linux版本中它被称作重定向或者透明代理。
--------------------------------------------------------------------------------
3、 NAT的两种类型
我把NAT分为两种不同的类型:源NAT(SNAT)和目标NAT(DNAT)。(译者注:以下不再翻译SNAT和DNAT,直接用Source NAT和Destination NAT)
Source NAT是指修改第一个包的源地址:也就是说,改变连接的来源地。Source NAT会在包送出之前的最后一刻做好post-routing(动作),伪装是SNAT的一种特殊形式。
Destination NAT 是指修改第一个包的目标地址:也就是说,改变连接的目的地。Destination NAT 总是在包进入以后(马上)进行before routing(动作)。端口转发、负载均衡和透明代理都属于DNAT。
--------------------------------------------------------------------------------
4、 从2.0和2.2内核的快速转换
如果你还在为从2.0(ipfwadm)到2.2(ipchains)的转换手忙脚乱的话,很抱歉。不过这也算是个喜忧半参的消息。
首先,你可以轻松的使用ipchains和ipfwadm,就像从前一样。不过你需要安装最新发布的netfilter中的“ipchains.o”或者“ipfwadm.o”内核模块。它们是互斥的(你会被警告),而且不能和任何其他netfilter模块结合。
一旦这其中某个模块被载入,你可以像以前一样使用ipchains和ipfwadm,不过仍有以下区别:
用ipchains -M -S,或者用ipfwadm -M -s设置伪装超时不再有效。因为超时已经转移到新的NAT构架中,所以这不能做任何事。
在详细的伪装列表中,init_seq、delta和previous_delat字段始终为零。
归零和列表计数器的 -Z -L不再有效:计数器不能被归零。
这类向后兼容的部分可能和大部分连接都不能有效配合:不要在你的公司网关中使用
开发者们还要注意:
无论是否使用伪装,现在可以绑定61000 - 65095之间的端口。以前的伪装代码占用了这部分端口,因此不能使用。
尚未成文的“getsockname”,透明代理程序可以用来发现那些已不再工作的连接的真实目的地址。
尚未成文的“bind-to-foreign-address”同样还未启用:这个用于完整透明代理的设想。
--------------------------------------------------------------------------------
4、1 我只想伪装!救命!
这是绝大部分人想要的。如果你用PPP拨号上网来动态得到IP (如果你不知道,那应该就是的)你可能只想告诉你的机器,所有来自内部网络的包,要看上去同PPP连接服务器上的包一样。
# 装载NAT模块(这取代了其他的)
modprobe iptable_nat
# 在NAT表中(-t nat),路由后 POSTROUTING 加入一条规则(-A)
# 所有由ppp0送出的包(-o ppp0) 会被伪装( -j MASQUERADE)。
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# 开启IP转发
echo 1 >; /proc/sys/net/ipv4/ip_forward
注意这时你没有做任何的包过滤:如果需要,参见 the Packet Filtering HOWTO。
--------------------------------------------------------------------------------
4、2 那么ipmasqadm呢?
这个完全取决于用户,所以我不担心向后兼容的问题。你可以简单的使用“iptables -t nat”做端口转发。例如,在Linux2.2你要做:
# 在2.2内核,把指向1.2.3.4 8080端口的TCP包转到192.168.1.1的80端口
ipmasqadm portfw -a -P tcp -L 1.2.3.4 8080 -R 192.168.1.1 80
现在你可以这样:
# 2.4内核,在NAT(-t nat)表中加入一条规则,在路由之前(-A PREROUTING)指向
# 1.2.3.4(-d 1.2.3.4)8080端口(--dport 8080)的TCP包(-p tcp)目标地址(-j DNAT)
# 被重定向到 192.168.1.1的80端口(--to 192.168.1.1:80)。
iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to 192.168.1.1:80
--------------------------------------------------------------------------------
5、NAT可以控制什么
你需要创建NAT规则,以告诉内核哪些连接将被改变和如何改变。要做到这一点,我们要用到一个用处很多的iptables工具,并告诉它用指定的“-t nat”选项修改NAT表。
NAT规则表包含三个称为“链”的列表:每个规则都按顺序检查包,直到有一个匹配。其中两个被称为PREROUTING(用于Destination NAT,当包进入时检查),POSTROUTING(用于Source NAT,包离开时检查),第三个叫OUTPUT,这里可以忽略。
如果我有足够的艺术天分的话,下面的见图会准确的说明上述概念:
_____ _____
/ / / /
PREROUTING -->;[Routing ]----------------->;POSTROUTING----->;
/D-NAT/ [Decision] /S-NAT/
| ^
| |
| |
| |
| |
| |
| |
-------->; Local Process ------
上述每一点,当我们查看连接(中)的包时,如果是一个新的连接,我们查看 NAT表中相对应的链,看看需要做些什么。其结果就会作为对这个连接后面所有包 的反应。
(译者注:此处的连接是指一个HTTP会话之类的连接,而非物理上的线路、节点)
--------------------------------------------------------------------------------
5、1 用iptables做简单的选择
下面列出了iptables的一些标准选项。所有双横杠(--)的选项都是可以缩写的。只要iptables可以将它们与其他选项区分开来就够了。如果你的内核是以模块方式支持iptables的,你需要先用命令:insmod ip_tables来加载ip_tables.o
这是最重要的选项表格选择,“-t”。对所有NAT操作,你都需要使用'-t nat'以指定NAT表。其次重要的是'-A',添加一个新的规则到链的末尾(例如'-A POSTROUTING'到POSTROUTING链),或者'-I'从最开始插入一个规则(例如'-I PREROUTING')。
你可以指定你想要进行NAT的包的源(地址)('-s' 或者'--source')和目的(地址)('-d' 或 '--destination')。这两个选项可以跟单个IP地址(例如192.168.1.1),一个名字(例如www.gnumonks.org),或者一个网络地址(例如192.168.1.0/24或192.168.1.0/255.255.255.0[译者:这二者是等价的,只是表示方法不同])。
你可以指定进入或送出的匹配接口。不过能否指定取决于你想要写入规则的那个链:PREROUTING链你只能选择进入接口,POSTROUTING你只能选择送出接口。如果用错了,iptables会给出一个错误。
--------------------------------------------------------------------------------
5、2 关于应当挑选哪些包来拆分(mangle)的要点
我上面说了你可以指定源地址和目标地址。如果忽略源地址选项,那么所有源地址都会被匹配,同样,如果忽略目标地址,所有目标地址都将被匹配。
你还可以标出一个指定的协议('-p'或'--protocol'),诸如TCP或者UDP;那么只有这类协议的包会被匹配。这么做的主要原因是指定了协议,就可以增加额外的选项:指定'--source-port'源端口和'--destination-port'目的端口选项(可缩写为'-sport'和'-dport')。
这些选项让你可以只匹配那些特定源端口及目标端口的包。这些对于重定向Web请求(TCP 80或8080端口)而不影响其他包非常有用。
这些选项必须跟在'-p'选项后面(这可能会对加载该协议的连接库有一定影响)。你可以使用端口号,或者来自/etc/serverices文件的(端口)名。
所有这些你可以对一个包作出的不同选择都详细的列在那详细得可怕的使用手册中了(man iptables)。(译者注:参见iptables man page中文版)
--------------------------------------------------------------------------------
6、说说如何拆分包吧
现在我们知道如何选择我们想要拆分的包了。为完成我们的规则,我们需要准确的告诉内核我们想要它如何做。
--------------------------------------------------------------------------------
6、1 Source NAT
你想要进行Source NAT,改变连接的源地址。这在POSTROUIING链中完成,就在它将送出去的最后一刻。这是一个重要的细节,所有Linux本机上的其他任何东西(路由、包过滤)都会看见那个尚未改变的包。也意味着'-o'(送出接口)选项可用了。
用指定'-j SNAT'来进行Source NAT,'--to-source'选项指定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变源地址为1.2.3.4
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
# 改变源地址为1.2.3.4、1.2.3.5或者1.2.3.6
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
# 改变源地址为1.2.3.4,端口1-1023
# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
--------------------------------------------------------------------------------
6、1、1 伪装
Source NAT的一个特例被称作伪装。它只能被用于动态分配IP地址的情况。例如标准拨号服务(静态IP地址请用SNAT)。
你无需为IP伪装明确指定源地址。它会使用包送出的那个接口(地址)作为源地址。不过更重要的是,如果那个线路关闭了的话,连接(无论如何都会丢失了)会被忘掉,意味着启用新的IP后返回的包就会有点问题了(指那些响应掉线前发出的包的包)。
# 伪装所有由ppp0送出的东西
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
--------------------------------------------------------------------------------
6、2 Destination NAT
用于PREROUTING链,包刚刚进入的时候。意味着本机上的任何东西看见的都是“真正”的目的地(译者注:即已修改过的目的地址)。也意味着'-i'(进入接口)可用了。
用指定'-j DNAT'来进行Destination NAT,'--to-destination'选项指定定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变目标地址为5.6.7.8
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8
# 改变目标地址为5.6.7.8、5.6.7.9或5.6.7.10
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8-5.6.7.10
# 改变Web传送的目标地址为5.6.7.8,8080端口
# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to 5.6.7.8:8080
--------------------------------------------------------------------------------
6、2、1 重定向
Destination NAT的一个特例被称为重定向。它相当于对进入接口进行DNAT的简单方便的一种形式。
# 发送进入的80端口的Web传输到我们的Squid(透明)代理
# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3128
注意Squid需要被配置为透明代理。
--------------------------------------------------------------------------------
6、3 深层次的映射
还有一些可能大部分人不会用到的NAT的细节。
--------------------------------------------------------------------------------
6、3、1 一个范围内多地址的选择
如果指定了IP地址的范围,那么机器会选择当前使用最少的那个IP地址。这就实现了最俭朴的负载均衡。
--------------------------------------------------------------------------------
6、3、2 建立空的NAT映射。
你可以使用 '-j ACCEPT' 目标让连接通过,不需要NAT参与。
--------------------------------------------------------------------------------
6、3、3 标准NAT行为
默认行为是根据用户给定的内在约束规则,对连接作最小的改动。也就是除非必要 不要进行端口重映射。
--------------------------------------------------------------------------------
6、3、4 内部源端口映射
如果其他的连接覆盖了一个连接,即使这个连接不需要使用NAT,源地址转换仍会发生。考虑IP伪装,这种情况就非常普遍。
1、一个从192.168.1.1 1024端口到www.netscape.com 80端口的Web连接已建立
2、它被伪装成IP伪装服务器的IP地址(1.2.3.4)
3、IP伪装服务器试图建立一个从www.netscape.com 80端口到1.2.3.4 1024端口的Web连接(它自己的外部接口IP地址)
4、NAT代码会修改第二个连接的源地址到1025,这样两个(连接)就不会冲突了。
当这种内部源地址映射发生时,端口分为三级:
512以下的端口
512至1023之间的端口
1024以上的端口
内部端口映射决不会被映射到(除此之外的)其他种类。
--------------------------------------------------------------------------------
6、3、5 如果NAT失败会怎样?
如果无法按照用户请求的那样,为连接建一个单独的映射,(包)会被删除。这也适用于那些无法被归为任何连接的包,因为它们是畸形的,或者是主机内存溢出了。
--------------------------------------------------------------------------------
6、3、6 多重映射,重叠和冲突
你的NAT规则可以把包映射到相同的范围。NAT代码聪明到可以避免它们的冲突。因此,两条规则把192.168.1.1和192.168.1.2的源地址映射都映射到1.2.3.4是没有问题的。
而且,你可以映射到真实的、已在使用的IP地址,只要那些地址也通过这个服务器。所以如果你分配到一个网络(1.2.3.0/24),但有一个内部网络使用了这些地址,另一个使用的是私有地址192.168.1.0/24,你可以简单的NAT 192.168.1.0/24的源地址 到1.2.3.0网络,不必担心冲突。
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0/24
相同的逻辑也适用于NAT服务器本身的地址。这就是得以伪装工作的原因(由伪装后的包和来自本身的“真实”的包共享一个接口地址)。
甚至,你可以映射相同的包到许多不同的目标,它们会被共享。例如,如果你不希望映射任何东西到1.2.3.5,你可以这样做:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254
--------------------------------------------------------------------------------
6、3、7 修改本地生成的连接的目标地址
NAT代码允许你插入DNAT规则到OUTPUT链,不过这在2.4中尚未完全支持(可以使用,但必须用新的配置选项,某些测试中的代码。所以除非有人在疯狂的写这部分代码,我不相信它会很快实现)。
当前的限制是你只能修改目标地址到本机(例如'-j DNAT --to 127.0.0.1'), 不能到任何其他机器,否则相应可能不能够被正确转换。
--------------------------------------------------------------------------------
7、 特定的协议
有些协议不希望被NAT。这些协议,两种延伸必须指明:一个是协议的连接跟踪,一个是真实NAT。
在发布的netfilter中,有可用的FTP模块:ip_conntrack_ftp.o和ip_nat_ftp.o。如果你加载了任一种模块到你的内核(或者编译进去),那么任何关于FTP连接的NAT都是可行的。如果没有,那么只能使用被动FTP(passive ftp),而且如果做了一些Source NAT,它(指FTP)也许不能可靠的工作。
--------------------------------------------------------------------------------
8、 关于NAT的警告
如果你对连接做NAT,所有双向传送的包(进入和送出网络的)必须通过NAT服务器,否则NAT服务器的工作可能不可靠。特别是,连接跟踪代码重组了分片,也就意味着不光是连接跟踪不能可靠工作,甚至所有包都无法通过,因为分片被丢弃。
--------------------------------------------------------------------------------
9、 Source NAT 和路由
如果你要做SNAT,你必须注意所有机器被SNAT的包的回应都将发送到NAT服务器。例如,如果你映射了一些送出的包的源地址为1.2.3.4,那么外部的路由器必须知道发送回应包的地址到NAT服务器。可以这样做:
1、如果你对本机地址做SNAT(路由等所有事情都正常),你不需要做任何事。
2、如果你在本地LAN上做SNAT到未用地址(例如,你映射为1.2.3.99,你的1.2.3.0/24网络中未用的IP),你的NAT服务器需要像那个地址(99)一样正确响应ARP请求。最简单的办法是建立一个IP别名,例如:
# ip address add 1.2.3.99 dev eth0
3、如果你对完全不同的地址做SNAT,你必须保证被SNAT的包到达的机器会返回NAT服务器。如果NAT服务器是它们的默认网关,那么就已经行了,否则你需要发布一个路由(如果运行了路由协议)或者对每个机器手工添加路由。
--------------------------------------------------------------------------------
10、 同一个网络内的Destination NAT。
如果你要对同一个网络做端口转发,你需要确认所有以后的包和回应包都通过NAT服务器(这样它们才能被修改)。NAT代码现在(自2.4.0-test6),会屏蔽掉同组的被NAT的包送出的ICMP重定向,不过收到的服务器会继续尝试直接响应客户。(不会理解这个回应)
经典的情况是,内部人员试图访问你的“公用”Web服务器,而它实际上从公用地址(1.2.3.4)被DNAT到内部机器(192.168.1.1),例如:
# iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j DNAT --to 192.168.1.1
一种办法是运行一台内部DNS服务器,它知道你的公用(外部)Web服务器的真实的(内部)IP地址,并转发所有其他请求到外部DNS服务器。也就是说你的Web服务器能够记录真实的内部IP地址。
另一种办法是让NAT服务器映射那些连接的源地址到它自己,让服务器通过它发出响应。例如,我们可以这样做(假设NAT服务器内部IP地址是192.168.1.250):
# iptables -t nat -A POSTROUTING -d 192.168.1.1 -s 192.168.1.0/24 -p tcp --dport 80 -j SNAT --to 192.168.1.250
因为PREROUTING规则会首先运行,对内部Web服务器来说,包的去向早已确定。我们可以确定好源IP地址。
--------------------------------------------------------------------------------
11. Thanks
Thanks first to WatchGuard, and David Bonn, who believed in the netfilter idea enough to support me while I worked on it. And to everyone else who put up with my ranting as I learnt about the ugliness of NAT, especially those who read my diary.
首先感谢在我工作期间相信netfilter设想并支持我的WatchGuard和David Bonn。以及所有对NAT提出指正的朋友,尤其是读过了我的日记的。
Rusty.
一起走过的日子 回复于:2004-03-15 17:41:53
IPTABLES-SAVE(8)
总览
iptables-save [-c] [-t table]
说明
通过简单的语法格式把一个IP TABLE的内容转储到STDOUT(标准输出).可以
用由shell提供I/0重定向写到一个文件中
-c, --counters
输出中包括所有包和字节计数器的当前值
-t, --table tablename
仅输出指定表名的那个表,若没有指定,将输出所有可用的表
臭虫
在iptables-1.2.1发布版中还未发现
作者
Harald Welte <laforge@gnumonks.org>;
参见
iptables-restore(8), iptables(8)
The iptables-HOWTO 详述了更多的iptable用法
the NAT-HOWTO 详述了nat
the Netfilter-hacking-HOWTO 详述了本质
IPTABLES-RESTORE(8) IPTABLES-RESTORE(8)
总览
iptables-restore [-c] [-n]
说明
iptables-restore的作用是通过STDIN(标准输入)上指定的数据来恢复IP Table。
由你的shell提供的I/O重定向功能从一个文件中读取。
-c, --counters
恢复所有包和字节计数器的当前值
-n, --noflush
不删除表中以前的内容,如果没有指定(这一参数),iptables-restore会清空(删除)所有
以前表中的内容。
臭虫
在iptables-1.2.1发布版中还未发现
作者
Harald Welte <laforge@gnumonks.org>;
参见
iptables-restore(8), iptables(8)
The iptables-HOWTO 详述了更多的iptable用法
the NAT-HOWTO 详述了nat
the Netfilter-hacking-HOWTO 详述了本质
iptables - [RI] chain rule num rule-specification[option]
用iptables - RI 通过规则的顺序指定
iptables -D chain rule num[option]
删除指定规则
iptables -[LFZ] [chain][option]
用iptables -LFZ 链名 [选项]
iptables -[NX] chain
用 -NX 指定链
iptables -P chain target[options]
指定链的默认目标
iptables -E old-chain-name new-chain-name
-E 旧的链名 新的链名
用新的链名取代旧的链名
说明
Iptalbes 是用来设置、维护和检查Linux内核的IP包过滤规则的。
可以定义不同的表,每个表都包含几个内部的链,也能包含用户定义的链。每个链都是一个规则列表,对对应的包进行匹配:每条规则指定应当如何处理与之相匹配的包。这被称作'target'(目标),也可以跳向同一个表内的用户定义的链。
TARGETS
防火墙的规则指定所检查包的特征,和目标。如果包不匹配,将送往该链中下一条规则检查;如果匹配,那么下一条规则由目标值确定.该目标值可以是用户定义的链名,或是某个专用值,如ACCEPT[通过], DROP[删除], QUEUE[排队], 或者 RETURN[返回]。
ACCEPT 表示让这个包通过。DROP表示将这个包丢弃。QUEUE表示把这个包传递到用户空间。RETURN表示停止这条链的匹配,到前一个链的规则重新开始。如果到达了一个内建的链(的末端),或者遇到内建链的规则是RETURN,包的命运将由链准则指定的目标决定。
TABLES
当前有三个表(哪个表是当前表取决于内核配置选项和当前模块)。
-t table
这个选项指定命令要操作的匹配包的表。如果内核被配置为自动加载模块,这时若模块没有加载,(系统)将尝试(为该表)加载适合的模块。这些表如下:filter,这是默认的表,包含了内建的链INPUT(处理进入的包)、FORWORD(处理通过的包)和OUTPUT(处理本地生成的包)。nat,这个表被查询时表示遇到了产生新的连接的包,由三个内建的链构成:PREROUTING (修改到来的包)、OUTPUT(修改路由之前本地的包)、POSTROUTING(修改准备出去的包)。mangle 这个表用来对指定的包进行修改。它有两个内建规则:PREROUTING(修改路由之前进入的包)和OUTPUT(修改路由之前本地的包)。
OPTIONS
这些可被iptables识别的选项可以区分不同的种类。
COMMANDS
这些选项指定执行明确的动作:若指令行下没有其他规定,该行只能指定一个选项.对于长格式的命令和选项名,所用字母长度只要保证iptables能从其他选项中区分出该指令就行了。
-A -append
在所选择的链末添加一条或更多规则。当源(地址)或者/与 目的(地址)转换为多个地址时,这条规则会加到所有可能的地址(组合)后面。
-D -delete
从所选链中删除一条或更多规则。这条命令可以有两种方法:可以把被删除规则指定为链中的序号(第一条序号为1),或者指定为要匹配的规则。
-R -replace
从选中的链中取代一条规则。如果源(地址)或者/与 目的(地址)被转换为多地址,该命令会失败。规则序号从1开始。
-I -insert
根据给出的规则序号向所选链中插入一条或更多规则。所以,如果规则序号为1,规则会被插入链的头部。这也是不指定规则序号时的默认方式。
-L -list
显示所选链的所有规则。如果没有选择链,所有链将被显示。也可以和z选项一起使用,这时链会被自动列出和归零。精确输出受其它所给参数影响。
-F -flush
清空所选链。这等于把所有规则一个个的删除。
--Z -zero
把所有链的包及字节的计数器清空。它可以和 -L配合使用,在清空前察看计数器,请参见前文。
-N -new-chain
根据给出的名称建立一个新的用户定义链。这必须保证没有同名的链存在。
-X -delete-chain
删除指定的用户自定义链。这个链必须没有被引用,如果被引用,在删除之前你必须删除或者替换与之有关的规则。如果没有给出参数,这条命令将试着删除每个非内建的链。
-P -policy
设置链的目标规则。
-E -rename-chain
根据用户给出的名字对指定链进行重命名,这仅仅是修饰,对整个表的结构没有影响。TARGETS参数给出一个合法的目标。只有非用户自定义链可以使用规则,而且内建链和用户自定义链都不能是规则的目标。
-h Help.
帮助。给出当前命令语法非常简短的说明。
PARAMETERS
参数
以下参数构成规则详述,如用于add、delete、replace、append 和 check命令。
-p -protocal [!]protocol
规则或者包检查(待检查包)的协议。指定协议可以是tcp、udp、icmp中的一个或者全部,也可以是数值,代表这些协议中的某一个。当然也可以使用在/etc/protocols中定义的协议名。在协议名前加上"!"表示相反的规则。数字0相当于所有all。Protocol all会匹配所有协议,而且这是缺省时的选项。在和check命令结合时,all可以不被使用。
-s -source [!] address[/mask]
指定源地址,可以是主机名、网络名和清楚的IP地址。mask说明可以是网络掩码或清楚的数字,在网络掩码的左边指定网络掩码左边"1"的个数,因此,mask值为24等于255.255.255.0。在指定地址前加上"!"说明指定了相反的地址段。标志 --src 是这个选项的简写。
-d --destination [!] address[/mask]
指定目标地址,要获取详细说明请参见 -s标志的说明。标志 --dst 是这个选项的简写。
-j --jump target
-j 目标跳转
指定规则的目标;也就是说,如果包匹配应当做什么。目标可以是用户自定义链(不是这条规则所在的),某个会立即决定包的命运的专用内建目标,或者一个扩展(参见下面的EXTENSIONS)。如果规则的这个选项被忽略,那么匹配的过程不会对包产生影响,不过规则的计数器会增加。
-i -in-interface [!] [name]
i -进入的(网络)接口 [!][名称]
这是包经由该接口接收的可选的入口名称,包通过该接口接收(在链INPUT、FORWORD和PREROUTING中进入的包)。当在接口名前使用"!"说明后,指的是相反的名称。如果接口名后面加上"+",则所有以此接口名开头的接口都会被匹配。如果这个选项被忽略,会假设为"+",那么将匹配任意接口。
-o --out-interface [!][name]
-o --输出接口[名称]
这是包经由该接口送出的可选的出口名称,包通过该口输出(在链FORWARD、OUTPUT和POSTROUTING中送出的包)。当在接口名前使用"!"说明后,指的是相反的名称。如果接口名后面加上"+",则所有以此接口名开头的接口都会被匹配。如果这个选项被忽略,会假设为"+",那么将匹配所有任意接口。
[!] -f, --fragment
[!] -f --分片
这意味着在分片的包中,规则只询问第二及以后的片。自那以后由于无法判断这种把包的源端口或目标端口(或者是ICMP类型的),这类包将不能匹配任何指定对他们进行匹配的规则。如果"!"说明用在了"-f"标志之前,表示相反的意思。
OTHER OPTIONS
其他选项
还可以指定下列附加选项:
-v --verbose
-v --详细
详细输出。这个选项让list命令显示接口地址、规则选项(如果有)和TOS(Type of Service)掩码。包和字节计数器也将被显示,分别用K、M、G(前缀)表示1000、1,000,000和1,000,000,000倍(不过请参看-x标志改变它),对于添加,插入,删除和替换命令,这会使一个或多个规则的相关详细信息被打印。
-n --numeric
-n --数字
数字输出。IP地址和端口会以数字的形式打印。默认情况下,程序试显示主机名、网络名或者服务(只要可用)。
-x -exact
-x -精确
扩展数字。显示包和字节计数器的精确值,代替用K,M,G表示的约数。这个选项仅能用于 -L 命令。
--line-numbers
当列表显示规则时,在每个规则的前面加上行号,与该规则在链中的位置相对应。
MATCH EXTENSIONS
对应的扩展
iptables能够使用一些与模块匹配的扩展包。以下就是含于基本包内的扩展包,而且他们大多数都可以通过在前面加上!来表示相反的意思。
tcp
当 --protocol tcp 被指定,且其他匹配的扩展未被指定时,这些扩展被装载。它提供以下选项:
--source-port [!] [port[]]
源端口或端口范围指定。这可以是服务名或端口号。使用格式端口:端口也可以指定包含的(端口)范围。如果首端口号被忽略,默认是"0",如果末端口号被忽略,默认是"65535",如果第二个端口号大于第一个,那么它们会被交换。这个选项可以使用 --sport的别名。
--destionation-port [!] [port:[port]]
目标端口或端口范围指定。这个选项可以使用 --dport别名来代替。
--tcp-flags [!] mask comp
匹配指定的TCP标记。第一个参数是我们要检查的标记,一个用逗号分开的列表,第二个参数是用逗号分开的标记表,是必须被设置的。标记如下:SYN ACK FIN RST URG PSH ALL NONE。因此这条命令:iptables -A FORWARD -p tcp --tcp-flags SYN, ACK, FIN, RST SYN只匹配那些SYN标记被设置而ACK、FIN和RST标记没有设置的包。
[!] --syn
只匹配那些设置了SYN位而清除了ACK和FIN位的TCP包。这些包用于TCP连接初始化时发出请求;例如,大量的这种包进入一个接口发生堵塞时会阻止进入的TCP连接,而出去的TCP连接不会受到影响。这等于 --tcp-flags SYN, RST, ACK SYN。如果"--syn"前面有"!"标记,表示相反的意思。
--tcp-option [!] number
匹配设置了TCP选项的。
udp
当protocol udp 被指定,且其他匹配的扩展未被指定时,这些扩展被装载,它提供以下选项:
--source-port [!] [port:[port]]
源端口或端口范围指定。详见 TCP扩展的--source-port选项说明。
--destination-port [!] [port:[port]]
目标端口或端口范围指定。详见 TCP扩展的--destination-port选项说明。
icmp
当protocol icmp被指定,且其他匹配的扩展未被指定时,该扩展被装载。它提供以下选项:
--icmp-type [!] typename
这个选项允许指定ICMP类型,可以是一个数值型的ICMP类型,或者是某个由命令iptables -p icmp -h所显示的ICMP类型名。
mac
--mac-source [!] address
匹配物理地址。必须是XX:XX:XX:XX:XX这样的格式。注意它只对来自以太设备并进入PREROUTING、FORWORD和INPUT链的包有效。
limit
这个模块匹配标志用一个标记桶过滤器一一定速度进行匹配,它和LOG目标结合使用来给出有限的登陆数.当达到这个极限值时,使用这个扩展包的规则将进行匹配.(除非使用了"!"标记)
--limit rate
最大平均匹配速率:可赋的值有'/second', '/minute', '/hour', or '/day'这样的单位,默认是3/hour。
--limit-burst number
待匹配包初始个数的最大值:若前面指定的极限还没达到这个数值,则概数字加1.默认值为5
multiport
这个模块匹配一组源端口或目标端口,最多可以指定15个端口。只能和-p tcp 或者 -p udp 连着使用。
--source-port [port[, port]]
如果源端口是其中一个给定端口则匹配
--destination-port [port[, port]]
如果目标端口是其中一个给定端口则匹配
--port [port[, port]]
若源端口和目的端口相等并与某个给定端口相等,则匹配。
mark
这个模块和与netfilter过滤器标记字段匹配(就可以在下面设置为使用MARK标记)。
--mark value [/mask]
匹配那些无符号标记值的包(如果指定mask,在比较之前会给掩码加上逻辑的标记)。
owner
此模块试为本地生成包匹配包创建者的不同特征。只能用于OUTPUT链,而且即使这样一些包(如ICMP ping应答)还可能没有所有者,因此永远不会匹配。
--uid-owner userid
如果给出有效的user id,那么匹配它的进程产生的包。
--gid-owner groupid
如果给出有效的group id,那么匹配它的进程产生的包。
--sid-owner seessionid
根据给出的会话组匹配该进程产生的包。
state
此模块,当与连接跟踪结合使用时,允许访问包的连接跟踪状态。
--state state
这里state是一个逗号分割的匹配连接状态列表。可能的状态是:INVALID表示包是未知连接,ESTABLISHED表示是双向传送的连接,NEW表示包为新的连接,否则是非双向传送的,而RELATED表示包由新连接开始,但是和一个已存在的连接在一起,如FTP数据传送,或者一个ICMP错误。
unclean
此模块没有可选项,不过它试着匹配那些奇怪的、不常见的包。处在实验中。
tos
此模块匹配IP包首部的8位tos(服务类型)字段(也就是说,包含在优先位中)。
--tos tos
这个参数可以是一个标准名称,(用iptables -m tos -h 察看该列表),或者数值。
TARGET EXTENSIONS
iptables可以使用扩展目标模块:以下都包含在标准版中。
LOG
为匹配的包开启内核记录。当在规则中设置了这一选项后,linux内核会通过printk()打印一些关于全部匹配包的信息(诸如IP包头字段等)。
--log-level level
记录级别(数字或参看 syslog.conf(5))。
--log-prefix prefix
在纪录信息前加上特定的前缀:最多14个字母长,用来和记录中其他信息区别。
--log-tcp-sequence
记录TCP序列号。如果记录能被用户读取那么这将存在安全隐患。
--log-tcp-options
记录来自TCP包头部的选项。
--log-ip-options
记录来自IP包头部的选项。
MARK
用来设置包的netfilter标记值。只适用于mangle表。
--set-mark mark
REJECT
作为对匹配的包的响应,返回一个错误的包:其他情况下和DROP相同。
此目标只适用于INPUT、FORWARD和OUTPUT链,和调用这些链的用户自定义链。这几个选项控制返回的错误包的特性:
--reject-with type
Type可以是icmp-net-unreachable、icmp-host-unreachable、icmp-port-nreachable、icmp-proto-unreachable、 icmp-net-prohibited 或者 icmp-host-prohibited,该类型会返回相应的ICMP错误信息(默认是port-unreachable)。选项 echo-reply也是允许的;它只能用于指定ICMP ping包的规则中,生成ping的回应。最后,选项tcp-reset可以用于在INPUT链中,或自INPUT链调用的规则,只匹配TCP协议:将回应一个TCP RST包。
TOS
用来设置IP包的首部八位tos。只能用于mangle表。
--set-tos tos
你可以使用一个数值型的TOS 值,或者用iptables -j TOS -h 来查看有效TOS名列表。
MIRROR
这是一个试验示范目标,可用于转换IP首部字段中的源地址和目标地址,再传送该包,并只适用于INPUT、FORWARD和OUTPUT链,以及只调用它们的用户自定义链。
SNAT
这个目标只适用于nat表的POSTROUTING链。它规定修改包的源地址(此连接以后所有的包都会被影响),停止对规则的检查,它包含选项:
--to-source <ipaddr>;[-<ipaddr>;][:port-port]
可以指定一个单一的新的IP地址,一个IP地址范围,也可以附加一个端口范围(只能在指定-p tcp 或者-p udp的规则里)。如果未指定端口范围,源端口中512以下的(端口)会被安置为其他的512以下的端口;512到1024之间的端口会被安置为1024以下的,其他端口会被安置为1024或以上。如果可能,端口不会被修改。
--to-destiontion <ipaddr>;[-<ipaddr>;][:port-port]
可以指定一个单一的新的IP地址,一个IP地址范围,也可以附加一个端口范围(只能在指定-p tcp 或者-p udp的规则里)。如果未指定端口范围,目标端口不会被修改。
MASQUERADE
只用于nat表的POSTROUTING链。只能用于动态获取IP(拨号)连接:如果你拥有静态IP地址,你要用SNAT。伪装相当于给包发出时所经过接口的IP地址设置一个映像,当接口关闭连接会终止。这是因为当下一次拨号时未必是相同的接口地址(以后所有建立的连接都将关闭)。它有一个选项:
--to-ports <port>;[-port>;]
指定使用的源端口范围,覆盖默认的SNAT源地址选择(见上面)。这个选项只适用于指定了-p tcp或者-p udp的规则。
REDIRECT
只适用于nat表的PREROUTING和OUTPUT链,和只调用它们的用户自定义链。它修改包的目标IP地址来发送包到机器自身(本地生成的包被安置为地址127.0.0.1)。它包含一个选项:
--to-ports <port>;[<port>;]
指定使用的目的端口或端口范围:不指定的话,目标端口不会被修改。只能用于指定了-p tcp 或 -p udp的规则。
DIAGNOSTICS
诊断
不同的错误信息会打印成标准错误:退出代码0表示正确。类似于不对的或者滥用的命令行参数错误会返回错误代码2,其他错误返回代码为1。
BUGS
臭虫
Check is not implemented (yet).
检查还未完成。
COMPATIBILITY WITH IPCHAINS
与ipchains的兼容性
iptables和Rusty Russell的ipchains非常相似。主要区别是INPUT 链只用于进入本地主机的包,而OUTPUT只用于自本地主机生成的包。因此每个包只经过三个链的一个;以前转发的包会经过所有三个链。其他主要区别是 -i 引用进入接口;-o引用输出接口,两者都适用于进入FORWARD链的包。当和可选扩展模块一起使用默认过滤器表时,iptables是一个纯粹的包过滤器。这能大大减少以前对IP伪装和包过滤结合使用的混淆,所以以下选项作了不同的处理:
-j MASQ
-M -S
-M -L
在iptables中有几个不同的链。
SEE ALSO
参见
iptables-HOWTO有详细的iptables用法,对netfilter-hacking-HOWTO也有详细的本质说明。
AUTHORS
作者
一起走过的日子 回复于:2004-03-15 17:34:12
1. 简介
欢迎,亲爱的读者。
这篇文章假设你知道有关IP地址、网络地址、网络掩码、选路和DNS。如果不知道,我建议你先阅读网络概念的HowTo(Network Concepts HOWTO)。
这篇HOWTO并非一个简要的介绍(会让你发热、发毛,没有安全感),也非一个完全的原始的披露(最吃苦耐劳的人也会被搅晕,不过必定会有所斩获)。
你的网络并不安全。问题在于,必须获取快速、简洁的通讯,但又必须限于良好的、无恶意的行为,就如同在嘈杂的大戏院里,你可以高谈阔论,但是绝不能大喊:着火了!。这篇HOWTO不能解决这种问题。
(译者:所有安全都只是相对的,否则根本不会产生这种东西了)
因此,你只能决定在哪方面妥协。我想帮助你使用一些可用的工具和一些通常需要注意的漏洞,希望你将它们用在好的一面,而不是出于恶意的目的 -- 另一个同样重要的问题。
(C) 2000 Paul `Rusty' Russell. Licenced under the GNU GPL.
--------------------------------------------------------------------------------
2、 官方站点及邮件列表位置
这里有三个官方站点:
o Thanks to Filewatcher http://netfilter.filewatcher.org.
o Thanks to The Samba Team and SGI http://netfilter.samba.org.
o Thanks to Harald Welte http://netfilter.gnumonks.org.
你可以通过以下站点访问全部相关站点。
http://www.netfilter.org and http://www.iptables.org
以下是netfilter官方邮件列表
http://www.netfilter.org/contact.html#list.
--------------------------------------------------------------------------------
3.那么,什么是包过滤器?
包过滤器是这样一种软件:它检查通过的每个包的头部,然后决定如何处置它们。可以这样对待它们:丢弃(也就是说,如果这个包从未被接受,那么丢弃它),通过(也就是说,让包通过),或者更复杂的(操作)。
Linux下,包过滤内建在内核中(内核模块,或者内建),而且我们还有处理包的一些技巧,不过检查头部和处理包的一般性原则仍在这里。
--------------------------------------------------------------------------------
3.1 我为何要包过滤?
控制、安全、警戒。
控制:
当你用你的Linux服务器把你的内部网和另一个网络(就是Internet吧)连起来,你可以决定哪些通信是允许的,哪些不允许。例如,包头部包含了包的目标地址,你可以阻碍包发送到(你)确定的几个外部网络,另一个例子,我用NetScape连接到Dilbert archives。页面上有来自doubleclick.net的广告,然后NetScape浪费了我的时间愉快的下载他们。 告诉包过滤器禁止任何来自或者发往doubleclick.net地址的包,问题就解决了。(当然有更好的办法,见Junkbuster)。
安全:
当Linux服务器是混乱的Internet和你良好的、有序的网络之间唯一的东西时, 你最好能知道哪些东西可以进入你的大门。例如,你可以允许所有(包)从你的网络 发出,不过你可能会为来自外部的著名的“Ping of Death”而焦急。另一个例子,你不希望 外人telnet到你的Linux服务器,尽管所有账户都有密码。或许你只想(像绝大多数人)成为 Internet的旁观者,而非它的服务器(也可能愿意是吧)。简单的不允许任何人接入,设置 包过滤器拒绝所有进入的包(是不错的办法)。
警戒:
有时,本地网络上错误配置的机器可能会向外部喷射出大量的包。最好是当(网络中)出现任何不正常现象时,让包过滤器告诉你。这样你可能可以做点什么,或者你天生就很好奇。
--------------------------------------------------------------------------------
3.2 如何在Linux下进行包过滤?
Linux内核在其1.1系列中就有了包过滤功能。第一代,由Alan Cox 1994年移植于BSD的ipfw。这在Linux 2.0中由Jos Vos和其他人进行了加强;用户空间工具'ipfwadm'可用来控制内核过滤规则。1998年中,我在Michael Neuling的帮助下,为Linux 2.2进行了重写,推出了用户空间工具'ipchains'。最后,1999年中,基于Linux 2.4的第四代工具,'iptables',和其他内核的改写正式推出。这就是这个iptables的HOWTO文档的所在。
译者:userspace根据台湾同胞的说法,是用来区别系统内存中的适用范围的,分为核心空间和使用者空间,不必深究)
你需要包含netfilter架构的内核。netfilter是Linux中的一个通用框架,也可以插入(plug in)其他内容(如iptables模块)。也就是说你需要2.3.15及以后版本,而且在配置内核时对CONFIG_NETFILTER回答'Y'。
iptables这个工具用来和内核交互并告诉它哪些包应该过滤。除非你是程序员或者 特别好奇,否则这就是你用来控制包过滤的了。
--------------------------------------------------------------------------------
3.2.1. iptables
iptables工具向内核的包过滤表中插入和删除规则。这就意味着无论怎样设置,启动后信息都会丢失;请参看“制定永久性规则”(Making Rules Permanent)来确定如何保证下次启动这些规则能被恢复。
iptables是ipfwadm和ipchains的替代品。如果你是它们的使用者,请参看 “使用ipchains和ipfwadm”,如何轻松使用iptables。
--------------------------------------------------------------------------------
3.2.2 创建永久性规则
你当前的防火墙设置保存在内核中,所以重启后就会丢失。你可以试着用iptables-save和iptables-restore脚本来保存他们,并由一个文件恢复。
--------------------------------------------------------------------------------
4. 你算老几,凭什么玩弄我的内核?
我是Rusty Russell。Linux IP防火墙的维护者,也是一个适当的时候出现在适当的地方的coder。我写了ipchains(参见“如何在Linux下进行包过滤?”看看实际的工作其实由哪些人完成),并希望能学到足够的东西修正这次的包过滤。
WatchGuard,一个非常出色的防火墙公司,总之一堆广告,此处省略一千字……
在此,我想澄清一个误解:我不是内核专家,我了解它,是因为我的核心工作让我接触了他们:David S. Miller, Alexey Kuznetsov, Andi Kleen, Alan Cox。无论如何,他们做了最深层的工作,轮到我时,已经非常安全和容易了。
--------------------------------------------------------------------------------
5. Rusty的真正的包过滤快速指南
绝大部分人只有一个PPP连接到Internet,而且不希望有人由此进入他们的网络或者防火墙:
# 插入connection-tracking模块(如国内建在内核中就不需要)
# insmod ip_conntrack
# insmod ip_conntrack_ftp
# 对创建大量新的连接创建一个链,除非这些连接来自内部。
# iptables -N block
# iptables -A block -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A block -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A block -j DROP
# 由INPUT和FORWARD链跳往(刚刚创建的)那条链。
# iptables -A INPUT -j block
# iptables -A FORWARD -j block
--------------------------------------------------------------------------------
6. 包是如何穿过过滤器的
内核由'filter'表中的以下三个规则开始。这些被称为防火墙链或就叫链。这三个链分别是 INPUT、OUTPUT和FORWARD。
对于ASCII艺术迷来说,链好象这样:(注意:这与2.0和2.2内核非常不同)
译者:ASCII艺术,这里指的是利用纯ASCII文本作图
_____
Incoming / / Outgoing
-->;[Routing ]--->;|FORWARD|------->;
[Decision] /_____/ ^
| |
v ____
___ / /
/ / |OUTPUT|
|INPUT| /____/
/___/ ^
| |
---->; Local Process ----
三个圈代表上面说的三个链。当包到达图中的一个圈,那个链就检查并确定包的命运。 如果链决定DROP包,包在那里就被杀死。但是如果链决定让包ACCEPT,包就继续在图中前进。
一个链是规则的列表。每个规则都会说:'如果包头看上去像这个的话,那么就这样处理'。 如果规则和包不匹配,由链中的下一个规则处理。最后,如果再也没有要进行处理的规则了, 内核就根据链的原则(policy,有时称为默认规则)来决定应当如何做。在一个注重安全的 系统中,原则通常是让内核丢弃这个包。
1. 当一个包进入时(就是由以太网卡),内核首先检查包的目的地。这被称作“选路”。
2. 如果它就是进入本机的,包会向图中的下方移动,到达INPUT链。如果到了这里,任何等待这个包的进程都会收到它。
3. 否则,如果内核未被允许转发,或者不知道该如何转发这个包,它会被丢弃。如果允许转发,而且包的目的地是另一个网络接口(如果你有另一个的话),那么包向我们图中的右边行进,到达FORWARD链。如果允许通过(ACCEPT),它就被送了出去。
4. 最后,服务器上运行的程序可以发送网络包。这些包马上通过OUTPUT链。如果被允(ACCEPT),那么包继续向可以到达它的目的地的网络接口发送。
--------------------------------------------------------------------------------
7. 使用iptables
iptables有着非常详尽的使用手册(man iptables),而且如果你需要某个选项更详细的介绍。看看“iptables和ipchains的差别”可能对你非常有用。
使用iptables你可以做很多不同的事。开始的内建的三个链INPUT、OUTPUT和FORWARD是不能被删除的。让我们看看整个链的管理。
1. 创建一个新的链 (-N)。
2. 删除一个空链(-X)。
3.修改内建链的原则(-P)。
4. 显示链中的规则(表)(-L)。
5. 清空一个链(-F)。
6. 将链中所有规则的包和字节计数器清零(-Z)。
有几种办法操作链中的规则:
1. 向链中添加一条新规则(-A)。
2. 在链中某个位置插入一条新规则(-I)。
3. 替换某个位置的规则(-R)。
4. 删除链中某个位置的规则,或者是第一个被匹配的。(-D)。
--------------------------------------------------------------------------------
7.1. 当计算机启动后你会看到的
ptables可以作为模块,称为'iptables_filter.o,可以在第一次运行iptables时自动被装载。也可以永久性的编到内核中。
在所有iptables命令执行之前(当心:某些发布版会在初始化脚本中运行iptables),所有内建链中都没有任何规则('INPUT'、'FORWARD'和'OUTPUT'),所有链的原则都是ACCEPT。你可以在装载iptable_filter模块时,提供'forward=0'选项来修改FORWARD的默认原则。
--------------------------------------------------------------------------------
7.2. 对单个规则的操作
这是基本的包过滤:管理规则,添加(-A)和删除(-D)命令可能是最常用的。其他的(-I插入和-R替换)只是简单的扩展而已。
每个规则都有一组条件来匹配包,和如果匹配了该如何做(target)。例如,你可能希望丢弃所有来自127.0.0.1的ICMP包。这样我们的条件就是协议必须是ICMP,而且源地址必须是127.0.0.1,我们的目标是丢弃(DROP)。127.0.0.1是一个回送接口,即使你没有真正的网络连接它也会存在。你可以用ping程序生成这样的包(它简单的发送ICMP 类型8(echo request),所有愿意响应的主机都会用ICMP 类型0(echo reply)来响应)。这对于测试非常有用。
# 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
# iptables -A INPUT -s 127.0.0.1 -p icmp -j DROP
# 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'链中添加(-A)一个规则,制定来自127.0.0.1('-s 127.0.0.1')的ICMP协议('-p icmp')包都将被丢弃('-j DROP')。
然后我们测试我们的规则,用第二个ping。在程序放弃等待永远不可能的响应之前,会暂停一下。
我们可以用两种办法中的任一种删除规则。首先,因为知道这是INPUT链中唯一的规则,我们用编号删除:
# iptables -D INPUT 1
删除INPUT链中的编号为1的规则
第二种办法是 -A 命令的映射,不过用-D替换-A。当你的链中规则很复杂,而你不想计算它们的编号的时候这就十分有用了。这样的话,我们可以使用:
# iptables -D INPUT -s 127.0.0.1 -p icmp -j DROP
-D的语法必须和-A(或者-I或者-R)一样精确。如果链中有多个相同的规则,只会删除第一个。
--------------------------------------------------------------------------------
7.3 过滤规格
我们已经看了,用'-p'指定协议,用'-s'指定源地址,不过还有其他选项我们可以用来指定包的特征。下面是一个详细的手册。
--------------------------------------------------------------------------------
7.3.1 指定源和目的IP地址
源('-s','--source'或'--src')和目的('-d','--destination'或'--dst')IP地址可以用四种办法指定。最常用的方法是使用全名,就像'localhost'或者'www.linuxhq.com'。第二种办法是指定IP地址,如'127.0.0.1'。
第三和第四种办法允许指定一组IP地址,就像'199.95.207.0/24'或者'199.95.207.0/255.255.255.0'。这指定了从199.95.207.0到199.95.207.255范围内的所有IP地址。'/'后面的数字说明哪部分IP地址是有效的。'32'或者'255.255.255.255‘为默认的(匹配整个IP地址)。用'/0'来指定任何IP地址,像这样:
# '-s 0/0'在这里是多余的
# iptables -A INPUT -s 0/0 -j DROP
这很少用到,这和上面出现过的不指定'-s'结果完全一样。
--------------------------------------------------------------------------------
7.3.2 反向指定
很多标记,包括'-s'(或'--source')和'-d'('--destination')标记可以在前面加上'!'标志(读作'not'),来匹配所有和给出的 NOT 的地址。例如, '-s ! localhost'匹配所有不是来自本机的包。
--------------------------------------------------------------------------------
7.3.3 协议指定
可以用'-p'(或'--protocol')指定协议。协议可以是数字(如果你知道IP的协议数值)或者像'TCP'、'UDP'或者'ICMP'这类的名称。大小写无所谓,所以'tcp'和'TCP'一样。
协议名称前可加上'!',以反向解释它,例如'-p ! TCP'将匹配所有不是TCP的包。
--------------------------------------------------------------------------------
7.3.4 接口指定
'-i'(或'--in-interface')和'-o'(或'--out-interface')选项指定匹配的接口名。接口可以是包进入的('-i')或者送出('-o')的物理设备。你可以用ifconfig命令列出当前'up'的接口。(也就是说正在工作的)。
通过INPUT链的包不会有送出接口,所以在这个链中'-o'永远不会匹配。同样,通过OUTPUT链的包也没有进入接口,这个链中的'-i'也不会被匹配。
只有通过FORWARD链的包才有进入和送出两个接口。
可以指定一个当前不存在的接口。在这个接口可用之前,规则不能匹配任何东西。这对于拨号PPP连接及类似的非常有用(通常是ppp0接口)。
一个特殊情况,接口名后面是一个'+',那就会匹配以这个字符串开头的所有接口(无论当前是否存在)。例如,指定一个匹配所有ppp接口的规则,要用到-i ppp+选项。
接口名也可以在前面插入 '!',来匹配所有与指定接口不同的包,如-i ! ppp+。
--------------------------------------------------------------------------------
7.3.5 分片指定
译者:为帮助大家理解,此处附上IP数据报的格式,摘自《Internetworking with TCP/IP》
0 4 8 16 19 24 31
版本号 首部长度 服务类型 总长度
标志符 标志 分片偏移量
寿命 协议 首部效验和
源IP地址
目的IP地址
IP选项 填充
数据
……
有时一个包太大,不可能适合所有线路。这样的话,包会被分成片,然后当作多个包发送。最终重组这些分片来重建整个包。
分片的问题是,被检查的初始片含有整个头部字段(IP+TCP,UDP和ICMP),但随后的包只有一部分头(没有附加协议字段的IP),因此,检查后面的分片的头部(就像有TCP、UDP和ICMP一样)是不可能的。
如果你在做NAT或连接追踪,那么所有分片在包过滤代码处理以前都会合并,所以你不需要为分片担心。
还请注意,到filter表中的INPUT链(或者任何由NF_IP_LOCAL_IN钩子程序钩入的表)的包实际上由核心IP栈片重组后到达。
否则,理解分片是如何被过滤规则处理的就非常重要了。任何过滤规则要求我们没有的信息,将被认为不匹配。这意味着(分片的)第一片像普通的包一样被处理。第二及后面的片则不会。因此,规则 -p TCP --sport www(指定源端口为'www')永远不会匹配一个分片(的包)(除了第一片),相反的规则 -p TCP --sport ! www也不会。
无论如何,你可以用'-f'(或'--fragment')标记指定专门处理第二及以后的分片的规则。当然也可以指定一个规则,让它不去匹配第二及以后的分片,在'-f'前加上'!'。
通常,让第二及以后的分片通过被认为是安全的,因为如果过滤处理了第一片,那么就无法在目标主机上进行重组。不过,已知的Bug是发送分片可能会轻易的让主机崩溃。你自己看着办吧。
网络高手注意:当这类检查进行时,畸形的包(防火墙读取的ICMP代码和类型过短的TCP、UDP和ICMP包)都将被丢弃。所以TCP分片从位置8开始。(译者:什么意思?大概是指IP包中的首部字段位置)
例如,下面的规则会丢弃任何发往192.168.1.1的分片。
# iptables -A OUTPUT -f -d 192.168.1.1 -j DROP
--------------------------------------------------------------------------------
7.3.6 iptables扩展:新的匹配
iptables是可扩展的,也就是包括内核和iptables工具都可以扩充新的特性。
下列部分扩展是标准的,其他的则是派生的。其他人可以做出扩展并发布给合适的人。
内核扩展一般位于内核模块子目录,诸如/lib/modules/2.4.0-test10/kernel/net/ipv4/netfilter。如果你使用了CONFIG_KMOD设置来编译内核,那么它们要求被装载,所以你不需要手工插入。
iptables程序扩展通常是位于/usr/local/lib/iptables/下的共享库,当然也可能在/lib/iptables或者/usr/lib/iptables,具体的要根据不同的发行版本来确定。
扩展有两种:新的目标,新的匹配(我们马上会谈到新的目标)。有些协议自动给出新的测试:如下所示,现有的包括TCP、UDP和ICMP。
这样,你可以在命令行中在 '-p'选项后指定新的测试,就可以载入扩展(模块)了。当允许扩展时,可以用'-m'选项装入扩展。
在选项后面('-p','-j'或者'-m')加上 '-h'或'--help'来获取扩展的帮助。
# iptables -p tcp --help
--------------------------------------------------------------------------------
7.3.6.1. TCP 扩展
如果指定了'-p tcp',那么TCP扩展将自动加载,并提供下列选项(不匹配分片)。
--tcp-flags
可附加一个'!'。有两个标志字串可以通过TCP标记来过滤。第一个标志字符串是mask:你想要测验的标志列表。第二个指出哪些将要被设置。例如:
# iptables -A INPUT --protocol tcp --tcp-flags ALL SYN,ACK -j DROP
意思是所有标志都将被测试('ALL'和'SYN, ACK,FIN,RST,URG,PSH'同义),不过只设置SYN和ACK。当然也可以用'NONE'表示无标志。
--syn
前面的'!'是可选的,是'--tcp-flags SYN, RST, ACK, SYN'的缩写
--source-port
后面可以跟一个'!',可以是单个TCP端口,或一段端口。可以是/etc/services中的端口名或者数字。端口范围格式是低端口名 : 高端口名,或者(指定大于或等于给出的端口)是端口名 + :,或者(指定小于或等于给出的端口)是: + 端口名。
--sport
就是 '--source-port'。
--destination-port
--dport
和上面类似,不过是指定匹配的目的端口(范围)。
--tcp-option
可以跟一个'!'和一个数字,匹配的是TCP选项和数字相等的包。如果试图用 这个TCP选项匹配一个没有完整的TCP包头的包,那么这个包会被自动丢弃。
--------------------------------------------------------------------------------
7.3.6.1.1. TCP标志的解释
有时只允许单向的TCP连接会很有用。例如,你可能会允许连接到外部WWW服务器,但不会允许来自那个服务器的连接。
最简单的举动可能是阻止来自那个服务器的包,可惜,TCP连接需要包双向传送(才能正常工作)。
解决办法是,只阻挡那些用来请求连接的包。这些包称为SYN包(OK,从技术上说,它们的SYN标志被设置,而没有设置RST和ACK标志,不过我们简单的称为SYN包)。通过只阻止这种包,我们就可以阻止来自那些地方的连接企图。
'--syn'标志是这样用的:只对指定了TCP协议的规则有效。例如,指定来自192.168.1.1的连接请求。
-p TCP -s 192.168.1.1 --syn
当然也可以在前面加上'!',意即所有不是初始连接的包。
--------------------------------------------------------------------------------
7.3.6.2 UDP 扩展
这些扩展在指定'-p udp'时自动加载。可以提供 '--source-port'、'--sport'、'--destination-port'和'--dport'等和TCP类似的选项。
--------------------------------------------------------------------------------
7.3.6.3 ICMP扩展
这些扩展在指定'-p icmp'时自动加载。只提供一个新的选项:
--icmp-type
可以跟'!',icmp类型名称(如'host-unreachable')或者数值(如'3'),或者数值类型/代码(如'3/3')。用'-p icmp --help'可以列出可用的icmp类型名。
--------------------------------------------------------------------------------
7.3.6.4 其他匹配的扩展
这些netfilter包中的其他扩展尚属于演示阶段,(如果安装了的话)可以用'-m'来启用。
mac
--mac-source
可以跟一个'!',后面是以太网地址,用冒号分隔的16近制表示,如`--mac-source 00:60:08:91:CC:B7'。
limit
此模块必须明确指定'-m limit'或'--match limit'。用来限制匹配的速率。就像抑制记录信息。只会匹配给定的数字/每秒(默认是每小时3个匹配,和5个触发)。可以有两个参数:
--limit
后面跟数字:指定每秒钟允许的匹配最大平均数。这个数字可以指定 明确的单位,使用'/second'、`/minute'、`/hour' 或者 `/day',或者 只写一部分(如'5/second'和'5/s'一样)。
--limit-burst
后面跟一个数字,指明在上面的limit起作用前最大的触发值。
这个匹配(项)通常和LOG目标结合起来使用,以对速率限制进行记录。 为了理解它是如何工作的,我们来看看下面这条规则,它使用默认限制参数 记录包。
# iptables -A FORWARD -m limit -j LOG
当这条规则第一次启用时,包开始被记录。实际上,由于默认触发是5,前五个包会被记录。然后,每隔20分钟再记录一次包,无论这期间有多少包到达。而且,每个不匹配包的20分钟间隔里,会恢复一个触发(值)。如果100分钟都没有包到达这个规则,那么所有触发都会恢复,回到起点。
提示:你目前不能以大于59小时的时间来创建这种规则,所以如果你设置一个平均率为一天,那么你的触发率必须小于3。
你也可以将此模块用于避免使用快速响应速率的各类拒绝服务攻击(DoS,Denial of Server)。
(译者:以下是较著名的攻击)
Syn-flood protection:
# iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
Furtive port scanner:
# iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s -j ACCEPT
Ping of death:
# iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT
这个模块工作原理类似于“节流阀”,以下是图示。
rate (pkt/s)
^ .---.
| / DoS /
| / /
Edge of DoS -|.....:........./....................... DoS的边界 =
= (limit * | /: /
limit-burst) | / : / .-.
| / : / / /
| / : / / /
End of DoS -|/....:..............:.../......./..../. DoS结束
= limit | : :`-' `--'
-------------+-----+--------------+------------------>; time (s)
LOGIC =>; Match | Didn't Match | Match
我们匹配由五个包触发的每秒一个包,不过每秒钟第四个包才开始进入(这个规则),进行三秒钟,然后重新开始。
<--Flood 1-->; <---Flood 2--->;
Total ^ Line __-- YNNN
Packets| Rate __-- YNNN
| mum __-- YNNN
10 | Maxi __-- Y
| __-- Y
| __-- Y
| __-- YNNN
|- YNNN
5 | Y
| Y Key: Y ->; Matched Rule
| Y N ->; Didn't Match Rule
| Y
|Y
0 +-------------------------------------------------->; Time (seconds)
0 1 2 3 4 5 6 7 8 9 10 11 12
你可以看见,前五个包是允许超过一个包/每秒(这个速率)的,然后就开始限制。 如果有一个暂停,那么另一个触发也是允许的,但不能超过规则设置的最大速率。
owner
--uid-owner userid
根据给出的有效的(数值)user id来匹配包的创建进程。
--gid-owner groupid
根据给出的有效的(数值)group id 来匹配包的创建进程。
--pid-owner processid
根据给出的process id 来匹配包的创建进程。
--sid-owner sessionid
根据给出的 session group 来匹配包的创建进程。
unclean
这是试验性模块,必须明确指定'-m unclean'或者'--match unclean'。 它对包进行各种随机判断。此模块还未通过审核,所以不要用在安全设施上。 (可能造成更糟糕的结果,它自己可能还有Bug)。没有提供选项。
--------------------------------------------------------------------------------
7.3.6.5 状态匹配
最有用的匹配标准是'state'扩展。它负责解释'ip_conntrack'模块的connection-tracking分析。 这是推荐使用的(好东东)。
通过指定'-m state'来允许附加的'--state'选项,匹配用逗号分割的状态列表('!'标志表明不符合那些状态(的状态))。
NEW
由新连接创建的包
ESTABLISHED
属于已存在连接的包(也就是说,响应的包)
RELATED
和一个已存在连接有关,但不是它的一部分的包。如ICMP错误,或者(已加载FTP模块)一个建立FTP数据连接的包。
INVALID
由于以下原因而不能被识别的包:包括内存不足和不是相应当前任何连接的ICMP错误。通常这些包会被丢弃。
这个强大的匹配扩展的一个例子:
# iptables -A FORWARD -i ppp0 -m state ! --state NEW -j DROP
--------------------------------------------------------------------------------
7.4 目标规格
现在,我们知道了如何对包进行测试,但是我们还需要告诉那些匹配的包应该如何做。这被称作规则的目标。
有两个很简单的内建目标:DROP和ACCEPT。我们已经看过了。如果包匹配的规则,其目标是这二者中的一个,那么不再考虑更多的规则了:包的命运已经决定。
除此之外有两种目标:扩展的和用户定义的链。
--------------------------------------------------------------------------------
7.4.1 用户定义链
iptables一个强大的特点是由ipchains继承来的可以让用户创建新的链,附加在三个内建的链上(INPUT、FORWARD和OUTPUT)。按照惯例,用户定义链使用小写以区分他们。(我们会在“Operations on an Entire Chains”中描述如何创建新的用户定义链)。
当包匹配的链的目标是一个用户定义链时,包就转移到用户定义链中的规则。如果 没有决定包的命运,那么包在(用户定义链)中的移动就结束了,并回到当前链的下一个规则。
搞搞ASCII艺术吧。考虑两个(笨蛋)链:INPUT(内建的)和test(用户定义的)。
`INPUT' `test'
---------------------------- ----------------------------
| Rule1: -p ICMP -j DROP | | Rule1: -s 192.168.1.1 |
|--------------------------| |--------------------------|
| Rule2: -p TCP -j test | | Rule2: -d 192.168.1.1 |
|--------------------------| ----------------------------
| Rule3: -p UDP -j DROP |
----------------------------
考虑一个由192.168.1.1到1.2.3.4的TCP包。它进入INPUT链,由Rule1检查 - 不匹配。 Rule2匹配,那么它的目标就是test,所以下一个检查由test开始。test中的第一个规则 Rule1是匹配的,但是没有指定目标,所以由第二个规则Rule2检查。结果是不匹配,而我们 到达了链的尾部。于是回到INPUT链,因为刚刚被Rule2检查,所以现在由Rule3来检查,仍然 不匹配。
所以这个包的路线是:
v __________________________
`INPUT' | / `test' v
------------------------|--/ -----------------------|----
| Rule1 | /| | Rule1 | |
|-----------------------|/-| |----------------------|---|
| Rule2 / | | Rule2 | |
|--------------------------| -----------------------v----
| Rule3 /--+___________________________/
------------------------|---
v
用户定义链可以跳转到另一个用户定义链(不过不能循环:如果发现循环,包就会被丢弃)。
--------------------------------------------------------------------------------
7.4.2 iptables扩展:新目标
其他类型的扩展是目标。目标扩展由内核模块组成,而且iptables的一个可选扩展提供了新的命令行选项。有几个扩展是包含在默认netfilter发布中的。
LOG
--log-level
跟一个级别名称或数字。合适的名字是(忽略大小写)'debug'、'info'、'notice'、'warning'、'err'、'crit'、'alert'和'emerg',相当于数字7到0。请参考syslog.conf的手册获取这些级别的说明。默认是'warning'。
--log-prefix
跟一个最多29个字符的字符串,它被写入到log信息的开始处,这样可以区别出来。
这个模块最有用的就是跟在limit match后面,这样你就不会被你的log淹没了。
REJECT
此模块和'DROP'效果一样,除了会发送一个'port unreachable'的ICMP错误报文。注意如果属于以下情况,ICMP错误报文不会发送:
o 包一开始就是ICMP错误报文,或者是未知的ICMP类型。
o 包被作为无头的分片过滤了。
o 我们已经向那里发送了太多的ICMP错误报文(参见/proc/sys/net/ipv4/icmp ratelimit)。
--------------------------------------------------------------------------------
7.4.3 特殊的内建目标
有两个特殊的内建目标:RETURN和QUEUE。
RETURN如同到达这个链的尾部:如果是内建的链的规则,那么这个链的默认规则将被执行。如果是用户定义链,当跳至这个链中的这条规则(包含RETURN)时,回到前面的链继续匹配。
QUEUE是一个特别的目标,会为用户空间进程队列这个包。要这样使用,需要两个部件:
o 一个"queue handler",处理用户空间与内核之间的机制。
o 和一个用户空间用来接收的应用程序,可能是操作,以及对包进行裁决。
IPv4 iptables的标准queue handler是 ip_queue 模块,跟随内核发布并标记为实验中。
下面是一个如何用iptables为用户空间进程队列包的快速例子:
# modprobe iptable_filter
# modprobe ip_queue
# iptables -A OUTPUT -p icmp -j QUEUE
在这个例子中,本地生成的送出ICMP包(如由ping产生)到达ip_queue模块,然后包被试图送往用户空间应用。如果没有用户空间应用在(那儿)等着,包就被丢弃了。
要写一个用户空间应用,需要libipq API。和iptables一起发布。在CVS的testsuite tools(如redirect.c)中可以找到相关例子。
可以通过这里检查ip_queue的状态:
/proc/net/ip_queue
队列的最大长度(也就是不包含返回包的送往用户空间包的数量)可以通过这里控制:
/proc/sys/net/ipv4/ip_queue_maxlen
默认队列长度是1024。一旦达到这个长度,新的包就会被丢弃,直到队列长度小于这个值。好的协议如TCP,会对丢弃的包作出拥挤的解释,而且在队列满了后会很理想的将它挡回。无论如何,如果默认值太小的话,最好是多实验以决定队列的最大长度。
--------------------------------------------------------------------------------
7.5 对整个链进行操作
iptables一个非常有用的特性是可以将链中相关的规则成组。你可以随意给链取名,不过我建议使用小写字母以避免与内建的链和目标产生冲突。链的名称最长为31个字母。
--------------------------------------------------------------------------------
7.5.1 创建新链
让我们创建一个新链。因为我是个充满想象的家伙,我叫它test。使用'-N'或'--new-chain'选项:
# iptables -N test
如此简单,现在你可以像上面说的那样放入规则了。
--------------------------------------------------------------------------------
7.5.2 删除链
删除一个链同样简单,使用 '-X'或'--delete-chain'选项。为什么是'-X'?嗯,因为所有合适的字母都已经被使用了。
# iptables -X test
有几个删除链的限制:他们必须是空的(见下面的"Flushing a Chain")而且他们不能是任何规则的目标。你也不能删除任何一个内建的链。
如果你不指定链名的话,所有可以被删除的用户定义链都将被删除。
--------------------------------------------------------------------------------
7.5.3 清空一个链
这是清除一个链中所有规则的简单方法,使用'-F' 或 '--flush'命令。
# iptables -F FORWARD
如果不指定链的话,所有链都将被清空。
--------------------------------------------------------------------------------
7.5.4 对链进行列表
用'-L'或'--list'命令,你可以列出一个链中的所有规则。
用户定义链中的'refcnt'是有多少链的规则指向了它。这个值必须为0,然后才可以删除这个链。
如果链名被忽略,所有链都将被列出,即便是空的。
'-L'可以有三个选项。'-n'(数字)选项对于阻止iptables试图查找IP地址时非常有用,因为(如果你像大多数人一样使用DNS)如果你的DNS设置不太合适的话,可能会造成长时间的停顿,或者你滤掉了DNS请求。它还会让TCP或UDP端口以数字显示。
'-v'选项显示所有规则的细节,包括饱和字节计数器,TOS比较,以及接口。否则这些值是被忽略的。
注意,报和字节计数器可以分别使用'K'、'M'或者'G'来代替1000、1,000,000 和1,000,000,000。使用'-x'(扩展数字)标志来打印整个值,不管它有多大。
--------------------------------------------------------------------------------
7.5.5 重置(清零)计数器
可以重置计数器非常有用。可以用'-Z'或'--zero'来完成。
考虑下面的:
# iptables -L FORWARD
# iptables -Z FORWARD
在上述例子中,有些包在'-L'和'-Z'命令之间通过。因此,你可以把'-L'和'-Z'一起使用,读取时就清空计数器。
--------------------------------------------------------------------------------
7.5.6 设置原则(默认规则)
我们在前面讨论包是如何通过链的时候,已经解释了当包到达内建链的尾部时会发生什么。这时,链的原则就决定包的命运。只有内建的链(INPUT、OUTPUT和FORWARD)有原则,因为如果包到达用户定义链的尾部会返回到前面的链。
原则可以是ACCEPT或DROP,例如:
# iptables -P FORWARD DROP
--------------------------------------------------------------------------------
8. 使用ipchains和ipfwadm
netflter发布中有ipchains.o和ipfwadm.o模块。把其中一个加载到你的内核(注意:他们和ip_tables.o不兼容)。然后你就可以像以前那样使用ipchains和ipfwadm了。
这在一段时间内仍然被支持。我认为合理的计算方式是 2*(替代发布 - 初始的稳定版本),超过了这个时间,就应当使用替代的稳定版本了。这意味着在Linux 2.6或2.8中对它们的支持很可能被放弃。
--------------------------------------------------------------------------------
9. NAT和包过滤的混合使用
想要做网络地址转换(参见NAT HowTo)和包过滤的已很常见。好消息是他们可以混合起来使用的,而且工作得非常好。
你可以完全忽略你的NAT,来定义你的包过滤。包过滤看见的包的源及目标是“真正”的源和目标。例如,如果你将任何发往1.2.3.4 80端口的包DNAT到10.1.1.1的8080端口。包过滤器看见的是包发往10.1.1.1的8080端口(真正的目的地),而非1.2.3.4 的80端口。同样,你可以忽略伪装:看到的是包的真实外部IP地址(如10.1.1.1),而响应的则返回到那里。
你可以使用'state'匹配扩展,使包过滤器不需要做任何额外的工作,因为无论如何,NAT都会要求连接跟踪。扩展NAT HowTo中简单的伪装例子,以禁止任何来自ppp0接口的新的连接,你可以这样:
#对送至ppp0的包进行伪装
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# 禁止由ppp0进入的新的或不合适的包
iptables -A INPUT -i ppp0 -m state --state NEW,INVALID -j DROP
iptables -A FORWARD -i ppp0 -m state --state NEW,INVALID -j DROP
# 开启IP转发
echo 1 >; /proc/sys/net/ipv4/ip_forward
--------------------------------------------------------------------------------
10. iptables和ipchains之间的差别
o 首先,内建链的名称从小写改成了大写,因为现在的INPUT和OUTPUT链只获取指向本地和本地生成的包。他们用来检查所有进入和发送的包。
o '-i'标志现在表示进入接口的意思,而且只适用于INPUT和FORWORD链。FORWORD或OUTPUT链中的规则应该将'-i'改为'-o'。
o TCP和UDP端口现在必须用--source-port或--sport(或者--destination-port/--dport)拼写,而且必须放在'-p tcp'或'-p udp'选项之后,因为TCP或UDP扩展是分别加载的。
o TCP -y 标志现在是 --syn,而且必须在'-p tcp'之后。
o DENY目标现在是DROP.
o 对单个链,可以在列出其工作同时清零。
o 清空内建链同时清除了原则计数器。
o 列出链给出的是一个计数器的微型的快照。
o REJECT和LOG现在是扩展目标,意思是他们是独立的内核模块。
o 链的名称最多可以是31个字符。
o MASQ现在是MASQUERADE而且使用不同的语法。REDRIRECT,在保留相同的名字时,也经历了语法的改变。参见NAT-HOWTO以获取配置它们的更多信息。
o -o选项不再用于将包传递给用户空间设备了(见上面的-i)。现在通过 QUEUE目标传递到用户空间。
o 很可能还有一些我也忘了。
--------------------------------------------------------------------------------
11. 对制定包过滤器的建议
在计算机安全领域中,最明智的办法是阻挡所有东西,然后对需要的开启。这通常称为“凡是没有明确允许的都是禁止的”。我建议这样做如果安全是你最关心的。
不要运行任何你不需要的服务,即使你认为你已经阻碍了对它们的访问。
如果你创建专用防火墙,开始时不运行任何东西,并阻止所有包,然后添加服务并让需要的包通过。
我强调安全:结合tcp-wrappers(对于包过滤器本身的连接),代理(通过包过滤器的连接),路由验证和包过滤。路由验证是如果包来自未预期的接口那么将被删除:例如,如果你的内部网络地址是10.1.1.0/24,而一个包的源地址是你的外部接口,那么它将被丢弃。对一个接口如ppp0来说可以这样:
# echo 1 >; /proc/sys/net/ipv4/conf/ppp0/rp_filter
或者对所有已有的或将有的接口:
# for f in /proc/sys/net/ipv4/conf/*/rp_filter; do
# echo 1 >; $f
# done
Debian在可能的范围了将这些设为默认。如果你使用非对称路由(如你期望包来自一个其他的方向),你可能需要在这些接口上禁止这一过滤。
记录对于当工作不正常时设置防火墙非常有用,但是在一个作为产品的防火墙上,总是应当将它与'limit'匹配结合,以防止有人充斥你的记录。
我极力推荐对安全系统使用连接追踪:它虽然会造成负担,因为所有连接都被追踪。但是对于控制对你的网络的访问非常有用。如果你的内核没有自动加载而且没有内建,你需要加载'ip_conntrack.o'这个模块。如果想要精确追踪复杂的协议,你需要加载合适的相关模块(如'ip_conntrack_ftp.o')。
# iptables -N no-conns-from-ppp0
# iptables -A no-conns-from-ppp0 -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -A no-conns-from-ppp0 -m state --state NEW -i ! ppp0 -j ACCEPT
# iptables -A no-conns-from-ppp0 -i ppp0 -m limit -j LOG --log-prefix "Bad packet from ppp0:"
# iptables -A no-conns-from-ppp0 -i ! ppp0 -m limit -j LOG --log-prefix "Bad packet not from ppp0:"
# iptables -A no-conns-from-ppp0 -j DROP
# iptables -A INPUT -j no-conns-from-ppp0
# iptables -A FORWARD -j no-conns-from-ppp0
建造一个好的防火墙超越了这个HOWTO的范围,不过我的建议是“一切从严”。请参见Security HOWTO获取更多信息,来测试和探索你的服务器。
一起走过的日子 回复于:2004-03-15 17:36:30
1. 简介
欢迎,亲爱的读者。
你将要深入迷人的(有时是令人厌烦的)NAT世界:网络地址转换,这篇HOWTO可以成为你的Linux2.4内核及其以后的准确指南。
在Linux2.4(内核版本),引入了一个叫“netfilter”的部分,专门用于拆分(mangling) (IP)包的。他上一层提供NAT,是完全依靠以前的内核制作的。
(译者注:mangle实在找不出什么合适的翻译,抱歉)
(C) 2000 Paul `Rusty' Russell. Licensed under the GNU GPL.
--------------------------------------------------------------------------------
2、 官方站点及列表位置
这里有三个官方站点:
o Thanks to Filewatcher http://netfilter.filewatcher.org.
o Thanks to The Samba Team and SGI http://netfilter.samba.org.
o Thanks to Harald Welte http://netfilter.gnumonks.org.
你可以通过以下站点访问全部相关站点。
http://www.netfilter.org and http://www.iptables.org
以下是netfilter官方邮件列表
http://www.netfilter.org/contact.html#list.
--------------------------------------------------------------------------------
2、1 什么是网络地址转换(Network Address Translation)?
通常,,网络中的(IP)包从他们的源(地址)出发(比如你家的电脑),到他们的目的地(比如www.gnumonks.org),会经过很多不同的连接(links):例如我所在澳大利亚就有19个。这些连接不会真去修改你的包:他们只是照原样传出去。
(译者注:这里的links应当认为是所有网络节点,包括主机、路由器等。通常,路由器并不是原样传送包,它至少会修改其中一点:TTL)
如果这些连接有一个做NAT,那么它(们)就会修改通过它们的包的源或者目标(地址)。正如你猜象的那样,这并非系统设计成那样的,而是NAT做了一些事情。通常进行NAT的连接(主机、服务器、路由器)会记住它是如何拆分包的,而当另一头响应的包通过时,它会对响应的包做相反的拆分,所以世界仍在运转。
(译者注:这一段的mangle应该想象为修改更合适)
--------------------------------------------------------------------------------
2、2 我为什么要NAT?
在完美的世界里,你不需要。同时,主要的理由是:
用调制解调器连接Internet
在你拨号上网时,大部分ISP只会给你一个IP地址,你可以发送你想发送的任何源地址包,但是只有响应这个(ISP给你的)地址的包才会返回。如果这种情况下你想有多台不同的机器上网(比如一个家庭网络),你就需要NAT。
这是现在NAT用得最多的功能,Linux世界的"masquerading"(伪装)非常出名,我称之为SNAT(SNAT即Source NAT,源地址转换),因为你改变了第一个包的源地址。
(译者:关于IP数据报的第一个包等内容,请参见各TCP/IP书籍)
多(重)服务器
有时你想改变进入网络中的包的目标地址(路由)。经常的,这是因为(就像上面的例子),你只有一个IP地址,但是你希望大家可以通过到那个“真实”的IP地址进入内部。如果你重写了进入包的目标地址,这样就没问题了。这种NAT在以前的Linux版本中被称为端口转发。
一个常见的变种是负载均衡,在一组机器上做映射。如果你要进行严格的比例限制, 可能需要参考Linux Virtual Server。http://linuxvirtualserver.org
透明代理
有时你可能想要经过你的Linux的包被送往本机的一个程序。这就需要用到透明代理了:代理是位于你的网络和外部世界之间的一个程序,帮助二者进行通信。之所以称为透明,是你的网络根本不知道他在和代理交谈,当然直到代理没有正常工作。
Squid可以配置为干这项工作,在以前Linux版本中它被称作重定向或者透明代理。
--------------------------------------------------------------------------------
3、 NAT的两种类型
我把NAT分为两种不同的类型:源NAT(SNAT)和目标NAT(DNAT)。(译者注:以下不再翻译SNAT和DNAT,直接用Source NAT和Destination NAT)
Source NAT是指修改第一个包的源地址:也就是说,改变连接的来源地。Source NAT会在包送出之前的最后一刻做好post-routing(动作),伪装是SNAT的一种特殊形式。
Destination NAT 是指修改第一个包的目标地址:也就是说,改变连接的目的地。Destination NAT 总是在包进入以后(马上)进行before routing(动作)。端口转发、负载均衡和透明代理都属于DNAT。
--------------------------------------------------------------------------------
4、 从2.0和2.2内核的快速转换
如果你还在为从2.0(ipfwadm)到2.2(ipchains)的转换手忙脚乱的话,很抱歉。不过这也算是个喜忧半参的消息。
首先,你可以轻松的使用ipchains和ipfwadm,就像从前一样。不过你需要安装最新发布的netfilter中的“ipchains.o”或者“ipfwadm.o”内核模块。它们是互斥的(你会被警告),而且不能和任何其他netfilter模块结合。
一旦这其中某个模块被载入,你可以像以前一样使用ipchains和ipfwadm,不过仍有以下区别:
用ipchains -M -S,或者用ipfwadm -M -s设置伪装超时不再有效。因为超时已经转移到新的NAT构架中,所以这不能做任何事。
在详细的伪装列表中,init_seq、delta和previous_delat字段始终为零。
归零和列表计数器的 -Z -L不再有效:计数器不能被归零。
这类向后兼容的部分可能和大部分连接都不能有效配合:不要在你的公司网关中使用
开发者们还要注意:
无论是否使用伪装,现在可以绑定61000 - 65095之间的端口。以前的伪装代码占用了这部分端口,因此不能使用。
尚未成文的“getsockname”,透明代理程序可以用来发现那些已不再工作的连接的真实目的地址。
尚未成文的“bind-to-foreign-address”同样还未启用:这个用于完整透明代理的设想。
--------------------------------------------------------------------------------
4、1 我只想伪装!救命!
这是绝大部分人想要的。如果你用PPP拨号上网来动态得到IP (如果你不知道,那应该就是的)你可能只想告诉你的机器,所有来自内部网络的包,要看上去同PPP连接服务器上的包一样。
# 装载NAT模块(这取代了其他的)
modprobe iptable_nat
# 在NAT表中(-t nat),路由后 POSTROUTING 加入一条规则(-A)
# 所有由ppp0送出的包(-o ppp0) 会被伪装( -j MASQUERADE)。
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# 开启IP转发
echo 1 >; /proc/sys/net/ipv4/ip_forward
注意这时你没有做任何的包过滤:如果需要,参见 the Packet Filtering HOWTO。
--------------------------------------------------------------------------------
4、2 那么ipmasqadm呢?
这个完全取决于用户,所以我不担心向后兼容的问题。你可以简单的使用“iptables -t nat”做端口转发。例如,在Linux2.2你要做:
# 在2.2内核,把指向1.2.3.4 8080端口的TCP包转到192.168.1.1的80端口
ipmasqadm portfw -a -P tcp -L 1.2.3.4 8080 -R 192.168.1.1 80
现在你可以这样:
# 2.4内核,在NAT(-t nat)表中加入一条规则,在路由之前(-A PREROUTING)指向
# 1.2.3.4(-d 1.2.3.4)8080端口(--dport 8080)的TCP包(-p tcp)目标地址(-j DNAT)
# 被重定向到 192.168.1.1的80端口(--to 192.168.1.1:80)。
iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to 192.168.1.1:80
--------------------------------------------------------------------------------
5、NAT可以控制什么
你需要创建NAT规则,以告诉内核哪些连接将被改变和如何改变。要做到这一点,我们要用到一个用处很多的iptables工具,并告诉它用指定的“-t nat”选项修改NAT表。
NAT规则表包含三个称为“链”的列表:每个规则都按顺序检查包,直到有一个匹配。其中两个被称为PREROUTING(用于Destination NAT,当包进入时检查),POSTROUTING(用于Source NAT,包离开时检查),第三个叫OUTPUT,这里可以忽略。
如果我有足够的艺术天分的话,下面的见图会准确的说明上述概念:
_____ _____
/ / / /
PREROUTING -->;[Routing ]----------------->;POSTROUTING----->;
/D-NAT/ [Decision] /S-NAT/
| ^
| |
| |
| |
| |
| |
| |
-------->; Local Process ------
上述每一点,当我们查看连接(中)的包时,如果是一个新的连接,我们查看 NAT表中相对应的链,看看需要做些什么。其结果就会作为对这个连接后面所有包 的反应。
(译者注:此处的连接是指一个HTTP会话之类的连接,而非物理上的线路、节点)
--------------------------------------------------------------------------------
5、1 用iptables做简单的选择
下面列出了iptables的一些标准选项。所有双横杠(--)的选项都是可以缩写的。只要iptables可以将它们与其他选项区分开来就够了。如果你的内核是以模块方式支持iptables的,你需要先用命令:insmod ip_tables来加载ip_tables.o
这是最重要的选项表格选择,“-t”。对所有NAT操作,你都需要使用'-t nat'以指定NAT表。其次重要的是'-A',添加一个新的规则到链的末尾(例如'-A POSTROUTING'到POSTROUTING链),或者'-I'从最开始插入一个规则(例如'-I PREROUTING')。
你可以指定你想要进行NAT的包的源(地址)('-s' 或者'--source')和目的(地址)('-d' 或 '--destination')。这两个选项可以跟单个IP地址(例如192.168.1.1),一个名字(例如www.gnumonks.org),或者一个网络地址(例如192.168.1.0/24或192.168.1.0/255.255.255.0[译者:这二者是等价的,只是表示方法不同])。
你可以指定进入或送出的匹配接口。不过能否指定取决于你想要写入规则的那个链:PREROUTING链你只能选择进入接口,POSTROUTING你只能选择送出接口。如果用错了,iptables会给出一个错误。
--------------------------------------------------------------------------------
5、2 关于应当挑选哪些包来拆分(mangle)的要点
我上面说了你可以指定源地址和目标地址。如果忽略源地址选项,那么所有源地址都会被匹配,同样,如果忽略目标地址,所有目标地址都将被匹配。
你还可以标出一个指定的协议('-p'或'--protocol'),诸如TCP或者UDP;那么只有这类协议的包会被匹配。这么做的主要原因是指定了协议,就可以增加额外的选项:指定'--source-port'源端口和'--destination-port'目的端口选项(可缩写为'-sport'和'-dport')。
这些选项让你可以只匹配那些特定源端口及目标端口的包。这些对于重定向Web请求(TCP 80或8080端口)而不影响其他包非常有用。
这些选项必须跟在'-p'选项后面(这可能会对加载该协议的连接库有一定影响)。你可以使用端口号,或者来自/etc/serverices文件的(端口)名。
所有这些你可以对一个包作出的不同选择都详细的列在那详细得可怕的使用手册中了(man iptables)。(译者注:参见iptables man page中文版)
--------------------------------------------------------------------------------
6、说说如何拆分包吧
现在我们知道如何选择我们想要拆分的包了。为完成我们的规则,我们需要准确的告诉内核我们想要它如何做。
--------------------------------------------------------------------------------
6、1 Source NAT
你想要进行Source NAT,改变连接的源地址。这在POSTROUIING链中完成,就在它将送出去的最后一刻。这是一个重要的细节,所有Linux本机上的其他任何东西(路由、包过滤)都会看见那个尚未改变的包。也意味着'-o'(送出接口)选项可用了。
用指定'-j SNAT'来进行Source NAT,'--to-source'选项指定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变源地址为1.2.3.4
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
# 改变源地址为1.2.3.4、1.2.3.5或者1.2.3.6
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
# 改变源地址为1.2.3.4,端口1-1023
# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
--------------------------------------------------------------------------------
6、1、1 伪装
Source NAT的一个特例被称作伪装。它只能被用于动态分配IP地址的情况。例如标准拨号服务(静态IP地址请用SNAT)。
你无需为IP伪装明确指定源地址。它会使用包送出的那个接口(地址)作为源地址。不过更重要的是,如果那个线路关闭了的话,连接(无论如何都会丢失了)会被忘掉,意味着启用新的IP后返回的包就会有点问题了(指那些响应掉线前发出的包的包)。
# 伪装所有由ppp0送出的东西
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
--------------------------------------------------------------------------------
6、2 Destination NAT
用于PREROUTING链,包刚刚进入的时候。意味着本机上的任何东西看见的都是“真正”的目的地(译者注:即已修改过的目的地址)。也意味着'-i'(进入接口)可用了。
用指定'-j DNAT'来进行Destination NAT,'--to-destination'选项指定定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变目标地址为5.6.7.8
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8
# 改变目标地址为5.6.7.8、5.6.7.9或5.6.7.10
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8-5.6.7.10
# 改变Web传送的目标地址为5.6.7.8,8080端口
# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to 5.6.7.8:8080
--------------------------------------------------------------------------------
6、2、1 重定向
Destination NAT的一个特例被称为重定向。它相当于对进入接口进行DNAT的简单方便的一种形式。
# 发送进入的80端口的Web传输到我们的Squid(透明)代理
# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3128
注意Squid需要被配置为透明代理。
--------------------------------------------------------------------------------
6、3 深层次的映射
还有一些可能大部分人不会用到的NAT的细节。
--------------------------------------------------------------------------------
6、3、1 一个范围内多地址的选择
如果指定了IP地址的范围,那么机器会选择当前使用最少的那个IP地址。这就实现了最俭朴的负载均衡。
--------------------------------------------------------------------------------
6、3、2 建立空的NAT映射。
你可以使用 '-j ACCEPT' 目标让连接通过,不需要NAT参与。
--------------------------------------------------------------------------------
6、3、3 标准NAT行为
默认行为是根据用户给定的内在约束规则,对连接作最小的改动。也就是除非必要 不要进行端口重映射。
--------------------------------------------------------------------------------
6、3、4 内部源端口映射
如果其他的连接覆盖了一个连接,即使这个连接不需要使用NAT,源地址转换仍会发生。考虑IP伪装,这种情况就非常普遍。
1、一个从192.168.1.1 1024端口到www.netscape.com 80端口的Web连接已建立
2、它被伪装成IP伪装服务器的IP地址(1.2.3.4)
3、IP伪装服务器试图建立一个从www.netscape.com 80端口到1.2.3.4 1024端口的Web连接(它自己的外部接口IP地址)
4、NAT代码会修改第二个连接的源地址到1025,这样两个(连接)就不会冲突了。
当这种内部源地址映射发生时,端口分为三级:
512以下的端口
512至1023之间的端口
1024以上的端口
内部端口映射决不会被映射到(除此之外的)其他种类。
--------------------------------------------------------------------------------
6、3、5 如果NAT失败会怎样?
如果无法按照用户请求的那样,为连接建一个单独的映射,(包)会被删除。这也适用于那些无法被归为任何连接的包,因为它们是畸形的,或者是主机内存溢出了。
--------------------------------------------------------------------------------
6、3、6 多重映射,重叠和冲突
你的NAT规则可以把包映射到相同的范围。NAT代码聪明到可以避免它们的冲突。因此,两条规则把192.168.1.1和192.168.1.2的源地址映射都映射到1.2.3.4是没有问题的。
而且,你可以映射到真实的、已在使用的IP地址,只要那些地址也通过这个服务器。所以如果你分配到一个网络(1.2.3.0/24),但有一个内部网络使用了这些地址,另一个使用的是私有地址192.168.1.0/24,你可以简单的NAT 192.168.1.0/24的源地址 到1.2.3.0网络,不必担心冲突。
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0/24
相同的逻辑也适用于NAT服务器本身的地址。这就是得以伪装工作的原因(由伪装后的包和来自本身的“真实”的包共享一个接口地址)。
甚至,你可以映射相同的包到许多不同的目标,它们会被共享。例如,如果你不希望映射任何东西到1.2.3.5,你可以这样做:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254
--------------------------------------------------------------------------------
6、3、7 修改本地生成的连接的目标地址
NAT代码允许你插入DNAT规则到OUTPUT链,不过这在2.4中尚未完全支持(可以使用,但必须用新的配置选项,某些测试中的代码。所以除非有人在疯狂的写这部分代码,我不相信它会很快实现)。
当前的限制是你只能修改目标地址到本机(例如'-j DNAT --to 127.0.0.1'), 不能到任何其他机器,否则相应可能不能够被正确转换。
--------------------------------------------------------------------------------
7、 特定的协议
有些协议不希望被NAT。这些协议,两种延伸必须指明:一个是协议的连接跟踪,一个是真实NAT。
在发布的netfilter中,有可用的FTP模块:ip_conntrack_ftp.o和ip_nat_ftp.o。如果你加载了任一种模块到你的内核(或者编译进去),那么任何关于FTP连接的NAT都是可行的。如果没有,那么只能使用被动FTP(passive ftp),而且如果做了一些Source NAT,它(指FTP)也许不能可靠的工作。
--------------------------------------------------------------------------------
8、 关于NAT的警告
如果你对连接做NAT,所有双向传送的包(进入和送出网络的)必须通过NAT服务器,否则NAT服务器的工作可能不可靠。特别是,连接跟踪代码重组了分片,也就意味着不光是连接跟踪不能可靠工作,甚至所有包都无法通过,因为分片被丢弃。
--------------------------------------------------------------------------------
9、 Source NAT 和路由
如果你要做SNAT,你必须注意所有机器被SNAT的包的回应都将发送到NAT服务器。例如,如果你映射了一些送出的包的源地址为1.2.3.4,那么外部的路由器必须知道发送回应包的地址到NAT服务器。可以这样做:
1、如果你对本机地址做SNAT(路由等所有事情都正常),你不需要做任何事。
2、如果你在本地LAN上做SNAT到未用地址(例如,你映射为1.2.3.99,你的1.2.3.0/24网络中未用的IP),你的NAT服务器需要像那个地址(99)一样正确响应ARP请求。最简单的办法是建立一个IP别名,例如:
# ip address add 1.2.3.99 dev eth0
3、如果你对完全不同的地址做SNAT,你必须保证被SNAT的包到达的机器会返回NAT服务器。如果NAT服务器是它们的默认网关,那么就已经行了,否则你需要发布一个路由(如果运行了路由协议)或者对每个机器手工添加路由。
--------------------------------------------------------------------------------
10、 同一个网络内的Destination NAT。
如果你要对同一个网络做端口转发,你需要确认所有以后的包和回应包都通过NAT服务器(这样它们才能被修改)。NAT代码现在(自2.4.0-test6),会屏蔽掉同组的被NAT的包送出的ICMP重定向,不过收到的服务器会继续尝试直接响应客户。(不会理解这个回应)
经典的情况是,内部人员试图访问你的“公用”Web服务器,而它实际上从公用地址(1.2.3.4)被DNAT到内部机器(192.168.1.1),例如:
# iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j DNAT --to 192.168.1.1
一种办法是运行一台内部DNS服务器,它知道你的公用(外部)Web服务器的真实的(内部)IP地址,并转发所有其他请求到外部DNS服务器。也就是说你的Web服务器能够记录真实的内部IP地址。
另一种办法是让NAT服务器映射那些连接的源地址到它自己,让服务器通过它发出响应。例如,我们可以这样做(假设NAT服务器内部IP地址是192.168.1.250):
# iptables -t nat -A POSTROUTING -d 192.168.1.1 -s 192.168.1.0/24 -p tcp --dport 80 -j SNAT --to 192.168.1.250
因为PREROUTING规则会首先运行,对内部Web服务器来说,包的去向早已确定。我们可以确定好源IP地址。
--------------------------------------------------------------------------------
11. Thanks
Thanks first to WatchGuard, and David Bonn, who believed in the netfilter idea enough to support me while I worked on it. And to everyone else who put up with my ranting as I learnt about the ugliness of NAT, especially those who read my diary.
首先感谢在我工作期间相信netfilter设想并支持我的WatchGuard和David Bonn。以及所有对NAT提出指正的朋友,尤其是读过了我的日记的。
Rusty.
一起走过的日子 回复于:2004-03-15 17:37:15
1. 简介
欢迎,亲爱的读者。
你将要深入迷人的(有时是令人厌烦的)NAT世界:网络地址转换,这篇HOWTO可以成为你的Linux2.4内核及其以后的准确指南。
在Linux2.4(内核版本),引入了一个叫“netfilter”的部分,专门用于拆分(mangling) (IP)包的。他上一层提供NAT,是完全依靠以前的内核制作的。
(译者注:mangle实在找不出什么合适的翻译,抱歉)
(C) 2000 Paul `Rusty' Russell. Licensed under the GNU GPL.
--------------------------------------------------------------------------------
2、 官方站点及列表位置
这里有三个官方站点:
o Thanks to Filewatcher http://netfilter.filewatcher.org.
o Thanks to The Samba Team and SGI http://netfilter.samba.org.
o Thanks to Harald Welte http://netfilter.gnumonks.org.
你可以通过以下站点访问全部相关站点。
http://www.netfilter.org and http://www.iptables.org
以下是netfilter官方邮件列表
http://www.netfilter.org/contact.html#list.
--------------------------------------------------------------------------------
2、1 什么是网络地址转换(Network Address Translation)?
通常,,网络中的(IP)包从他们的源(地址)出发(比如你家的电脑),到他们的目的地(比如www.gnumonks.org),会经过很多不同的连接(links):例如我所在澳大利亚就有19个。这些连接不会真去修改你的包:他们只是照原样传出去。
(译者注:这里的links应当认为是所有网络节点,包括主机、路由器等。通常,路由器并不是原样传送包,它至少会修改其中一点:TTL)
如果这些连接有一个做NAT,那么它(们)就会修改通过它们的包的源或者目标(地址)。正如你猜象的那样,这并非系统设计成那样的,而是NAT做了一些事情。通常进行NAT的连接(主机、服务器、路由器)会记住它是如何拆分包的,而当另一头响应的包通过时,它会对响应的包做相反的拆分,所以世界仍在运转。
(译者注:这一段的mangle应该想象为修改更合适)
--------------------------------------------------------------------------------
2、2 我为什么要NAT?
在完美的世界里,你不需要。同时,主要的理由是:
用调制解调器连接Internet
在你拨号上网时,大部分ISP只会给你一个IP地址,你可以发送你想发送的任何源地址包,但是只有响应这个(ISP给你的)地址的包才会返回。如果这种情况下你想有多台不同的机器上网(比如一个家庭网络),你就需要NAT。
这是现在NAT用得最多的功能,Linux世界的"masquerading"(伪装)非常出名,我称之为SNAT(SNAT即Source NAT,源地址转换),因为你改变了第一个包的源地址。
(译者:关于IP数据报的第一个包等内容,请参见各TCP/IP书籍)
多(重)服务器
有时你想改变进入网络中的包的目标地址(路由)。经常的,这是因为(就像上面的例子),你只有一个IP地址,但是你希望大家可以通过到那个“真实”的IP地址进入内部。如果你重写了进入包的目标地址,这样就没问题了。这种NAT在以前的Linux版本中被称为端口转发。
一个常见的变种是负载均衡,在一组机器上做映射。如果你要进行严格的比例限制, 可能需要参考Linux Virtual Server。http://linuxvirtualserver.org
透明代理
有时你可能想要经过你的Linux的包被送往本机的一个程序。这就需要用到透明代理了:代理是位于你的网络和外部世界之间的一个程序,帮助二者进行通信。之所以称为透明,是你的网络根本不知道他在和代理交谈,当然直到代理没有正常工作。
Squid可以配置为干这项工作,在以前Linux版本中它被称作重定向或者透明代理。
--------------------------------------------------------------------------------
3、 NAT的两种类型
我把NAT分为两种不同的类型:源NAT(SNAT)和目标NAT(DNAT)。(译者注:以下不再翻译SNAT和DNAT,直接用Source NAT和Destination NAT)
Source NAT是指修改第一个包的源地址:也就是说,改变连接的来源地。Source NAT会在包送出之前的最后一刻做好post-routing(动作),伪装是SNAT的一种特殊形式。
Destination NAT 是指修改第一个包的目标地址:也就是说,改变连接的目的地。Destination NAT 总是在包进入以后(马上)进行before routing(动作)。端口转发、负载均衡和透明代理都属于DNAT。
--------------------------------------------------------------------------------
4、 从2.0和2.2内核的快速转换
如果你还在为从2.0(ipfwadm)到2.2(ipchains)的转换手忙脚乱的话,很抱歉。不过这也算是个喜忧半参的消息。
首先,你可以轻松的使用ipchains和ipfwadm,就像从前一样。不过你需要安装最新发布的netfilter中的“ipchains.o”或者“ipfwadm.o”内核模块。它们是互斥的(你会被警告),而且不能和任何其他netfilter模块结合。
一旦这其中某个模块被载入,你可以像以前一样使用ipchains和ipfwadm,不过仍有以下区别:
用ipchains -M -S,或者用ipfwadm -M -s设置伪装超时不再有效。因为超时已经转移到新的NAT构架中,所以这不能做任何事。
在详细的伪装列表中,init_seq、delta和previous_delat字段始终为零。
归零和列表计数器的 -Z -L不再有效:计数器不能被归零。
这类向后兼容的部分可能和大部分连接都不能有效配合:不要在你的公司网关中使用
开发者们还要注意:
无论是否使用伪装,现在可以绑定61000 - 65095之间的端口。以前的伪装代码占用了这部分端口,因此不能使用。
尚未成文的“getsockname”,透明代理程序可以用来发现那些已不再工作的连接的真实目的地址。
尚未成文的“bind-to-foreign-address”同样还未启用:这个用于完整透明代理的设想。
--------------------------------------------------------------------------------
4、1 我只想伪装!救命!
这是绝大部分人想要的。如果你用PPP拨号上网来动态得到IP (如果你不知道,那应该就是的)你可能只想告诉你的机器,所有来自内部网络的包,要看上去同PPP连接服务器上的包一样。
# 装载NAT模块(这取代了其他的)
modprobe iptable_nat
# 在NAT表中(-t nat),路由后 POSTROUTING 加入一条规则(-A)
# 所有由ppp0送出的包(-o ppp0) 会被伪装( -j MASQUERADE)。
iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
# 开启IP转发
echo 1 >; /proc/sys/net/ipv4/ip_forward
注意这时你没有做任何的包过滤:如果需要,参见 the Packet Filtering HOWTO。
--------------------------------------------------------------------------------
4、2 那么ipmasqadm呢?
这个完全取决于用户,所以我不担心向后兼容的问题。你可以简单的使用“iptables -t nat”做端口转发。例如,在Linux2.2你要做:
# 在2.2内核,把指向1.2.3.4 8080端口的TCP包转到192.168.1.1的80端口
ipmasqadm portfw -a -P tcp -L 1.2.3.4 8080 -R 192.168.1.1 80
现在你可以这样:
# 2.4内核,在NAT(-t nat)表中加入一条规则,在路由之前(-A PREROUTING)指向
# 1.2.3.4(-d 1.2.3.4)8080端口(--dport 8080)的TCP包(-p tcp)目标地址(-j DNAT)
# 被重定向到 192.168.1.1的80端口(--to 192.168.1.1:80)。
iptables -A PREROUTING -t nat -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to 192.168.1.1:80
--------------------------------------------------------------------------------
5、NAT可以控制什么
你需要创建NAT规则,以告诉内核哪些连接将被改变和如何改变。要做到这一点,我们要用到一个用处很多的iptables工具,并告诉它用指定的“-t nat”选项修改NAT表。
NAT规则表包含三个称为“链”的列表:每个规则都按顺序检查包,直到有一个匹配。其中两个被称为PREROUTING(用于Destination NAT,当包进入时检查),POSTROUTING(用于Source NAT,包离开时检查),第三个叫OUTPUT,这里可以忽略。
如果我有足够的艺术天分的话,下面的见图会准确的说明上述概念:
_____ _____
/ / / /
PREROUTING -->;[Routing ]----------------->;POSTROUTING----->;
/D-NAT/ [Decision] /S-NAT/
| ^
| |
| |
| |
| |
| |
| |
-------->; Local Process ------
上述每一点,当我们查看连接(中)的包时,如果是一个新的连接,我们查看 NAT表中相对应的链,看看需要做些什么。其结果就会作为对这个连接后面所有包 的反应。
(译者注:此处的连接是指一个HTTP会话之类的连接,而非物理上的线路、节点)
--------------------------------------------------------------------------------
5、1 用iptables做简单的选择
下面列出了iptables的一些标准选项。所有双横杠(--)的选项都是可以缩写的。只要iptables可以将它们与其他选项区分开来就够了。如果你的内核是以模块方式支持iptables的,你需要先用命令:insmod ip_tables来加载ip_tables.o
这是最重要的选项表格选择,“-t”。对所有NAT操作,你都需要使用'-t nat'以指定NAT表。其次重要的是'-A',添加一个新的规则到链的末尾(例如'-A POSTROUTING'到POSTROUTING链),或者'-I'从最开始插入一个规则(例如'-I PREROUTING')。
你可以指定你想要进行NAT的包的源(地址)('-s' 或者'--source')和目的(地址)('-d' 或 '--destination')。这两个选项可以跟单个IP地址(例如192.168.1.1),一个名字(例如www.gnumonks.org),或者一个网络地址(例如192.168.1.0/24或192.168.1.0/255.255.255.0[译者:这二者是等价的,只是表示方法不同])。
你可以指定进入或送出的匹配接口。不过能否指定取决于你想要写入规则的那个链:PREROUTING链你只能选择进入接口,POSTROUTING你只能选择送出接口。如果用错了,iptables会给出一个错误。
--------------------------------------------------------------------------------
5、2 关于应当挑选哪些包来拆分(mangle)的要点
我上面说了你可以指定源地址和目标地址。如果忽略源地址选项,那么所有源地址都会被匹配,同样,如果忽略目标地址,所有目标地址都将被匹配。
你还可以标出一个指定的协议('-p'或'--protocol'),诸如TCP或者UDP;那么只有这类协议的包会被匹配。这么做的主要原因是指定了协议,就可以增加额外的选项:指定'--source-port'源端口和'--destination-port'目的端口选项(可缩写为'-sport'和'-dport')。
这些选项让你可以只匹配那些特定源端口及目标端口的包。这些对于重定向Web请求(TCP 80或8080端口)而不影响其他包非常有用。
这些选项必须跟在'-p'选项后面(这可能会对加载该协议的连接库有一定影响)。你可以使用端口号,或者来自/etc/serverices文件的(端口)名。
所有这些你可以对一个包作出的不同选择都详细的列在那详细得可怕的使用手册中了(man iptables)。(译者注:参见iptables man page中文版)
--------------------------------------------------------------------------------
6、说说如何拆分包吧
现在我们知道如何选择我们想要拆分的包了。为完成我们的规则,我们需要准确的告诉内核我们想要它如何做。
--------------------------------------------------------------------------------
6、1 Source NAT
你想要进行Source NAT,改变连接的源地址。这在POSTROUIING链中完成,就在它将送出去的最后一刻。这是一个重要的细节,所有Linux本机上的其他任何东西(路由、包过滤)都会看见那个尚未改变的包。也意味着'-o'(送出接口)选项可用了。
用指定'-j SNAT'来进行Source NAT,'--to-source'选项指定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变源地址为1.2.3.4
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4
# 改变源地址为1.2.3.4、1.2.3.5或者1.2.3.6
# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to 1.2.3.4-1.2.3.6
# 改变源地址为1.2.3.4,端口1-1023
# iptables -t nat -A POSTROUTING -p tcp -o eth0 -j SNAT --to 1.2.3.4:1-1023
--------------------------------------------------------------------------------
6、1、1 伪装
Source NAT的一个特例被称作伪装。它只能被用于动态分配IP地址的情况。例如标准拨号服务(静态IP地址请用SNAT)。
你无需为IP伪装明确指定源地址。它会使用包送出的那个接口(地址)作为源地址。不过更重要的是,如果那个线路关闭了的话,连接(无论如何都会丢失了)会被忘掉,意味着启用新的IP后返回的包就会有点问题了(指那些响应掉线前发出的包的包)。
# 伪装所有由ppp0送出的东西
# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE
--------------------------------------------------------------------------------
6、2 Destination NAT
用于PREROUTING链,包刚刚进入的时候。意味着本机上的任何东西看见的都是“真正”的目的地(译者注:即已修改过的目的地址)。也意味着'-i'(进入接口)可用了。
用指定'-j DNAT'来进行Destination NAT,'--to-destination'选项指定定一个或一段IP地址,(加上)一个或一段可选的端口号(只能用于UDP和TCP协议)。
# 改变目标地址为5.6.7.8
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8
# 改变目标地址为5.6.7.8、5.6.7.9或5.6.7.10
# iptables -t nat -A PREROUTING -i eth0 -j DNAT --to 5.6.7.8-5.6.7.10
# 改变Web传送的目标地址为5.6.7.8,8080端口
# iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j DNAT --to 5.6.7.8:8080
--------------------------------------------------------------------------------
6、2、1 重定向
Destination NAT的一个特例被称为重定向。它相当于对进入接口进行DNAT的简单方便的一种形式。
# 发送进入的80端口的Web传输到我们的Squid(透明)代理
# iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 80 -j REDIRECT --to-port 3128
注意Squid需要被配置为透明代理。
--------------------------------------------------------------------------------
6、3 深层次的映射
还有一些可能大部分人不会用到的NAT的细节。
--------------------------------------------------------------------------------
6、3、1 一个范围内多地址的选择
如果指定了IP地址的范围,那么机器会选择当前使用最少的那个IP地址。这就实现了最俭朴的负载均衡。
--------------------------------------------------------------------------------
6、3、2 建立空的NAT映射。
你可以使用 '-j ACCEPT' 目标让连接通过,不需要NAT参与。
--------------------------------------------------------------------------------
6、3、3 标准NAT行为
默认行为是根据用户给定的内在约束规则,对连接作最小的改动。也就是除非必要 不要进行端口重映射。
--------------------------------------------------------------------------------
6、3、4 内部源端口映射
如果其他的连接覆盖了一个连接,即使这个连接不需要使用NAT,源地址转换仍会发生。考虑IP伪装,这种情况就非常普遍。
1、一个从192.168.1.1 1024端口到www.netscape.com 80端口的Web连接已建立
2、它被伪装成IP伪装服务器的IP地址(1.2.3.4)
3、IP伪装服务器试图建立一个从www.netscape.com 80端口到1.2.3.4 1024端口的Web连接(它自己的外部接口IP地址)
4、NAT代码会修改第二个连接的源地址到1025,这样两个(连接)就不会冲突了。
当这种内部源地址映射发生时,端口分为三级:
512以下的端口
512至1023之间的端口
1024以上的端口
内部端口映射决不会被映射到(除此之外的)其他种类。
--------------------------------------------------------------------------------
6、3、5 如果NAT失败会怎样?
如果无法按照用户请求的那样,为连接建一个单独的映射,(包)会被删除。这也适用于那些无法被归为任何连接的包,因为它们是畸形的,或者是主机内存溢出了。
--------------------------------------------------------------------------------
6、3、6 多重映射,重叠和冲突
你的NAT规则可以把包映射到相同的范围。NAT代码聪明到可以避免它们的冲突。因此,两条规则把192.168.1.1和192.168.1.2的源地址映射都映射到1.2.3.4是没有问题的。
而且,你可以映射到真实的、已在使用的IP地址,只要那些地址也通过这个服务器。所以如果你分配到一个网络(1.2.3.0/24),但有一个内部网络使用了这些地址,另一个使用的是私有地址192.168.1.0/24,你可以简单的NAT 192.168.1.0/24的源地址 到1.2.3.0网络,不必担心冲突。
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0/24
相同的逻辑也适用于NAT服务器本身的地址。这就是得以伪装工作的原因(由伪装后的包和来自本身的“真实”的包共享一个接口地址)。
甚至,你可以映射相同的包到许多不同的目标,它们会被共享。例如,如果你不希望映射任何东西到1.2.3.5,你可以这样做:
# iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.3.0-1.2.3.4 --to 1.2.3.6-1.2.3.254
--------------------------------------------------------------------------------
6、3、7 修改本地生成的连接的目标地址
NAT代码允许你插入DNAT规则到OUTPUT链,不过这在2.4中尚未完全支持(可以使用,但必须用新的配置选项,某些测试中的代码。所以除非有人在疯狂的写这部分代码,我不相信它会很快实现)。
当前的限制是你只能修改目标地址到本机(例如'-j DNAT --to 127.0.0.1'), 不能到任何其他机器,否则相应可能不能够被正确转换。
--------------------------------------------------------------------------------
7、 特定的协议
有些协议不希望被NAT。这些协议,两种延伸必须指明:一个是协议的连接跟踪,一个是真实NAT。
在发布的netfilter中,有可用的FTP模块:ip_conntrack_ftp.o和ip_nat_ftp.o。如果你加载了任一种模块到你的内核(或者编译进去),那么任何关于FTP连接的NAT都是可行的。如果没有,那么只能使用被动FTP(passive ftp),而且如果做了一些Source NAT,它(指FTP)也许不能可靠的工作。
--------------------------------------------------------------------------------
8、 关于NAT的警告
如果你对连接做NAT,所有双向传送的包(进入和送出网络的)必须通过NAT服务器,否则NAT服务器的工作可能不可靠。特别是,连接跟踪代码重组了分片,也就意味着不光是连接跟踪不能可靠工作,甚至所有包都无法通过,因为分片被丢弃。
--------------------------------------------------------------------------------
9、 Source NAT 和路由
如果你要做SNAT,你必须注意所有机器被SNAT的包的回应都将发送到NAT服务器。例如,如果你映射了一些送出的包的源地址为1.2.3.4,那么外部的路由器必须知道发送回应包的地址到NAT服务器。可以这样做:
1、如果你对本机地址做SNAT(路由等所有事情都正常),你不需要做任何事。
2、如果你在本地LAN上做SNAT到未用地址(例如,你映射为1.2.3.99,你的1.2.3.0/24网络中未用的IP),你的NAT服务器需要像那个地址(99)一样正确响应ARP请求。最简单的办法是建立一个IP别名,例如:
# ip address add 1.2.3.99 dev eth0
3、如果你对完全不同的地址做SNAT,你必须保证被SNAT的包到达的机器会返回NAT服务器。如果NAT服务器是它们的默认网关,那么就已经行了,否则你需要发布一个路由(如果运行了路由协议)或者对每个机器手工添加路由。
--------------------------------------------------------------------------------
10、 同一个网络内的Destination NAT。
如果你要对同一个网络做端口转发,你需要确认所有以后的包和回应包都通过NAT服务器(这样它们才能被修改)。NAT代码现在(自2.4.0-test6),会屏蔽掉同组的被NAT的包送出的ICMP重定向,不过收到的服务器会继续尝试直接响应客户。(不会理解这个回应)
经典的情况是,内部人员试图访问你的“公用”Web服务器,而它实际上从公用地址(1.2.3.4)被DNAT到内部机器(192.168.1.1),例如:
# iptables -t nat -A PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j DNAT --to 192.168.1.1
一种办法是运行一台内部DNS服务器,它知道你的公用(外部)Web服务器的真实的(内部)IP地址,并转发所有其他请求到外部DNS服务器。也就是说你的Web服务器能够记录真实的内部IP地址。
另一种办法是让NAT服务器映射那些连接的源地址到它自己,让服务器通过它发出响应。例如,我们可以这样做(假设NAT服务器内部IP地址是192.168.1.250):
# iptables -t nat -A POSTROUTING -d 192.168.1.1 -s 192.168.1.0/24 -p tcp --dport 80 -j SNAT --to 192.168.1.250
因为PREROUTING规则会首先运行,对内部Web服务器来说,包的去向早已确定。我们可以确定好源IP地址。
--------------------------------------------------------------------------------
11. Thanks
Thanks first to WatchGuard, and David Bonn, who believed in the netfilter idea enough to support me while I worked on it. And to everyone else who put up with my ranting as I learnt about the ugliness of NAT, especially those who read my diary.
首先感谢在我工作期间相信netfilter设想并支持我的WatchGuard和David Bonn。以及所有对NAT提出指正的朋友,尤其是读过了我的日记的。
Rusty.
一起走过的日子 回复于:2004-03-15 17:41:53
IPTABLES-SAVE(8)
总览
iptables-save [-c] [-t table]
说明
通过简单的语法格式把一个IP TABLE的内容转储到STDOUT(标准输出).可以
用由shell提供I/0重定向写到一个文件中
-c, --counters
输出中包括所有包和字节计数器的当前值
-t, --table tablename
仅输出指定表名的那个表,若没有指定,将输出所有可用的表
臭虫
在iptables-1.2.1发布版中还未发现
作者
Harald Welte <laforge@gnumonks.org>;
参见
iptables-restore(8), iptables(8)
The iptables-HOWTO 详述了更多的iptable用法
the NAT-HOWTO 详述了nat
the Netfilter-hacking-HOWTO 详述了本质
IPTABLES-RESTORE(8) IPTABLES-RESTORE(8)
总览
iptables-restore [-c] [-n]
说明
iptables-restore的作用是通过STDIN(标准输入)上指定的数据来恢复IP Table。
由你的shell提供的I/O重定向功能从一个文件中读取。
-c, --counters
恢复所有包和字节计数器的当前值
-n, --noflush
不删除表中以前的内容,如果没有指定(这一参数),iptables-restore会清空(删除)所有
以前表中的内容。
臭虫
在iptables-1.2.1发布版中还未发现
作者
Harald Welte <laforge@gnumonks.org>;
参见
iptables-restore(8), iptables(8)
The iptables-HOWTO 详述了更多的iptable用法
the NAT-HOWTO 详述了nat
the Netfilter-hacking-HOWTO 详述了本质