|
0 背景
. O* ?! k% I& V5 s c$ s 考虑一种网络拓扑应用情景,一个内部局域网中有多台服务器提供不同的服务,如web服务、FTP服务、ssh、telnet等,通过服务器(或网关、防火墙)连接外部网络,如果外部网络上的主机需要访问这些服务器,则需要在网关上实现转发。 再转述成另一种应用场合,多台设备连接到一台服务器,服务器有2个网卡,分别连接内外网。外网无法直接访问设备上的数据、服务。在服务器上实现转发后,则可达到目的。 网络拓扑如下: 比如,可以通过服务器的8081端口访问1号设备的web服务,8082端口访问2号设备web,这样可以在外部网络对内网设备进行参数配置、调整。类似地,通过2321访问1号设备的telnet服务,2322访问2号设备telnet,以方便登陆设备系统,进行设备状态监控,日志处理,等等。 本文将直接引用此网络拓扑图中的名称及IP地址。实际使用配置根据实际情况修改。另外说明一下,不必拘泥于本文给出的名称。像拓扑图中的“设备”,可以使用一台安装linux的服务器替换。其它的类似。 6 X# j* V8 a3 D- X
一、原理 在Linux系统使用iptables实现防火墙、数据转发等功能。iptables有不同的表(tables),每个tables有不同的链(chain),每条chain有一个或多个规则(rule)。本文利用NAT(network address translation,网络地址转换)表来实现数据包的转发。iptables命令要用-t来指定表,如果没有指明,则使用系统缺省的表“filter”。所以使用NAT的时候,就要用“-t nat”选项了。9 O0 R! B8 e3 x( o; ~
NAT表有三条缺省的链,它们分别是PREROUTING、POSTROUTING和OUTPUT。 先给出NAT结构,如下图: PREROUTING:在数据包传入时,就进到PREROUTIING链。该链执行的是修改数据包内的目的IP地址,即DNAT(变更目的IP地址)。PREROUTING只能进行DNAT。因为进行了DNAT,才能在路由表中做判断,决定送到本地或其它网口。 POSTROUTING:相对的,在POSTROUTING链后,就传出数据包,该链是整个NAT结构的最末端。执行的是修改数据包的源IP地址,即SNAT。POSTROUTING只能进行SNAT。 OUTPUT:定义对本地产生的数据包的目的NAT规则。
9 {. q9 V( r1 F: u" H5 w4 l
每个数据包都会依次经过三个不同的机制,首先是PREROUTING(DNAT),再到路由表,最后到POSTROUTING(SNAT)。下面给出数据包流方向: 文中的网络拓扑图所示的数据包,是从eth0入,eth1出。但是,无论从eth0到eth1,还是从eth1到eth0,均遵守上述的原理。就是说,SNAT和DNAT并没有规定只能在某一个网口(某一侧)。 顺便给出netfilter的完整结构图: 二、实现出于安全考虑,Linux系统默认是禁止数据包转发的。所谓转发即当主机拥有多于一块的网卡时,其中一块收到数据包,根据数据包的目的ip地址将包发往本机另一网卡,该网卡根据路由表继续发送数据包。这通常就是路由器所要实现的功能。 配置Linux系统的ip转发功能,首先保证硬件连通,然后打开系统的转发功能 cat /proc/sys/net/ipv4/ip_forward,该文件内容为0,表示禁止数据包转发,1表示允许,将其修改为1。可使用命令echo "1" > /proc/sys/net/ipv4/ip_forward 修改文件内容,重启网络服务或主机后效果不再。若要其自动执行,可将命令echo "1" > /proc/sys/net/ipv4/ip_forward 写入脚本/etc/rc.d/rc.local 或者在/etc/sysconfig/network脚本中添加 FORWARD_IPV4="YES" 但在我的系统中没有这两个文件,因此可以修改/etc/sysctl.conf文件,将net.ipv4.ip_forward=1的注释取消即可 根据拓扑图,一一实现不同IP、不同端口的映射,如下命令为一种示例形式: - $ y3 g2 [( t- X/ e! ^" v! S9 S) q
- # 第一台设备的telnet服务
4 ?6 y2 s- l" [) A5 f# N - iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 2321 -j DNAT --to 100.100.100.101:23
( G+ g& i5 j Q' A4 a - iptables -t nat -A POSTROUTING -o eth1 -d 100.100.100.101 -p tcp --dport 23 -j SNAT --to 100.100.100.44" F* _& D5 f J2 y
- # 第二台设备的telnet服务5 }4 j/ H" C' C1 `/ e' @% c" _
- iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 2322 -j DNAT --to 100.100.100.102:23- W: K4 T2 o; I7 b1 \( P
- iptables -t nat -A POSTROUTING -o eth1 -d 100.100.100.102 -p tcp --dport 23 -j SNAT --to 100.100.100.44; [" l/ A( H/ O
- $ y% K9 [% o- Z3 T& x( K7 t/ C+ a, M
- # 第一台设备的web服务$ i2 n% P; t0 m4 d% k! x* L
- iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 8081 -j DNAT --to 100.100.100.101:80
' c- u# G* E5 M. q4 |$ d) U9 ` - iptables -t nat -A POSTROUTING -o eth1 -d 100.100.100.101 -p tcp --dport 80 -j SNAT --to 100.100.100.449 \6 S N# n& g& ?4 R- ~
- # 第二台设备的web服务
9 I& w! y! \( y" I" a2 N' Z" G7 X - iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 8082 -j DNAT --to 100.100.100.102:80' l# E) d5 v5 G0 ]' B8 e2 R) x
- iptables -t nat -A POSTROUTING -o eth1 -d 100.100.100.102 -p tcp --dport 80 -j SNAT --to 100.100.100.44
复制代码
- ?9 ]$ P( n7 ~" q7 Y
以第一台设备转发命令为例,用白话解释一下。 第一条是PREROUTING链,只能进行DNAT,该命令对从eth0进入且目的IP为172.18.44.44(注:可以用-s指明数据包来源地址,但这时无法知道来源IP是多少,虽然可以用网段的做法,但用-d则指定必须一定唯一的是本机的eth0地址,相对好一点),端口号为2321的数据包进行目的地址更改,更改为100.100.100.101,端口为23,亦即此包的目的地为第一台设备的telnet服务。 第二条是POSTROUTING链,只能进行SNAT,即对先前已经DNAT过的数据包修改源IP地址。这样,这个数据包达到第一台设备时,源IP地址、目的IP地址,均为100.100.100.0/24网段了。 S& C5 e5 z! w* E9 h2 _/ u
上述命令的SNAT有些冗余,可以做简化,命令如下: - ( h/ M: b$ X Z- G1 N0 Q
- # 第一台设备的telnet、web服务5 T8 [. X% f( N. U! w
- iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 2321 -j DNAT --to 100.100.100.101:231 [' @ w3 m H v3 }
- iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 8081 -j DNAT --to 100.100.100.101:801 Z V" i: I( X0 F2 n3 K# e; ?
- # 第二台设备的telnet、web服务
8 }/ P* z* _9 z2 [6 Z. o! [* I6 L+ h' W - iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 2322 -j DNAT --to 100.100.100.102:23
: T! O% L: j z' a5 J# N - iptables -t nat -A PREROUTING -i eth0 -d 172.18.44.44 -p tcp --dport 8082 -j DNAT --to 100.100.100.102:80
' r7 \+ p8 S) }4 n - # 源IP地址SNAT
e3 H9 [0 |4 } - iptables -t nat -A POSTROUTING -o eth1 -d 100.100.100.0/24 -j SNAT --to 100.100.100.44
复制代码# B' t2 A0 C1 U
实际中使用的命令可能还有变化(简化),本文不再展示。 9 R3 d0 P9 S4 L. u7 V. R
三、测试 为了保证文中所述的正确性,本节列出操作结果,以及实验过程的信息。服务器(网关)上的路由表如下: - % K$ ~% Y0 d) w: K. ?% J# L# `' ?
- root@latelee:test# route) f) _1 R# l! b8 a: e' `
- Kernel IP routing table" y3 E; S$ @; @; a% t
- Destination Gateway Genmask Flags Metric Ref Use Iface5 a' {" A3 i4 \ F* }% y! T
- 100.100.100.0 * 255.255.255.0 U 0 0 0 eth1
4 a+ {, N% q, s) F. D$ q! D - 172.18.0.0 * 255.255.0.0 U 0 0 0 eth0
复制代码
+ `* z" \2 T& B' v7 O可以看到服务器上有2个网卡,网段都不相同。iptables的NAT表如下:
3 k& Q4 j3 \+ c' v5 w2 s- root@latelee:~# iptables -L -t nat4 N' a6 u- O' A# ?
- Chain PREROUTING (policy ACCEPT)% z% X0 E- ~" C7 V( m
- target prot opt source destination ) k6 T0 R5 Q, q/ q! Z% |
- DNAT tcp -- anywhere 172.18.44.44 tcp dpt:2324 to:100.100.100.101:23
$ T/ M) \ h% E0 h3 m4 Q' n. F - Chain INPUT (policy ACCEPT)
% g" S: T& F9 n6 v - target prot opt source destination
, M4 ~( o7 ^ f& I! c* n2 e6 ~( t - Chain OUTPUT (policy ACCEPT)6 O% D* h, p; G* s( A
- target prot opt source destination
% d: e' t- B1 I6 g! ^+ [! V- K - Chain POSTROUTING (policy ACCEPT)7 ^. @. v- o; Y; f( I# L
- target prot opt source destination " S( c; e1 u8 l6 K! W2 _7 f
- SNAT all -- anywhere 100.100.100.0/24 to:100.100.100.44
复制代码 ; [; ?3 j) k* T. Z0 z
可以看到,PREROUTING和POSTROUTING各有一条规则,这些规则由上文命令所产生。对应的,在第一号设备上查看路由信息,如下:
. Q% H- N& V$ P- root@latelee:~# route' o7 W4 O9 ^1 v* C
- Kernel IP routing table; X3 y. N& P2 b
- Destination Gateway Genmask Flags Metric Ref Use Iface
' O) o9 x3 \9 A8 }, T! g( G - 100.100.100.0 * 255.255.255.0 U 0 0 0 eth06 @4 A1 g% Q% _0 w$ O& d
- 172.18.0.0 * 255.255.0.0 U 0 0 0 eth1
) i1 M* S3 ~' U8 W3 o) M! w% ?) c - default 100.100.100.44 0.0.0.0 UG 0 0 0 eth0
复制代码
2 c- L- M. j$ d6 |& |可以看到这台设备有2个网卡,默认网关为服务器的IP地址。但是,其中一个网卡eth1竟然和PC所在网段相同!如果没有进行源IP地址修改(伪装),会匹配到eth1这个网口,无法匹配eth0。 8 R0 W- d) @# w' }7 c: S
在外网的PC上对设备进行telnet,设备抓包信息如下:
i7 S' \% [' o" X7 t9 v( ?8 E- IP 100.100.100.44.32253 > 100.100.100.101.2323: Flags [P.], seq 1:4, ack 16, win 256, length 3
1 k0 ]9 V- v& |! o3 K9 B+ e - IP 100.100.100.101.2323 > 100.100.100.44.32253: Flags [P.], seq 16:19, ack 4, win 2190, length 3$ Z( L" x# W( h. _6 m4 x b
- IP 100.100.100.44.32253 > 100.100.100.101.2323: Flags [P.], seq 4:25, ack 19, win 256, length 21
" n7 T- D. }7 R$ K; I8 o - IP 100.100.100.101.2323 > 100.100.100.44.32253: Flags [P.], seq 19:34, ack 25, win 2190, length 15
复制代码
! y* s0 B2 Z" x可见,所有包的IP段都相同。在服务器上对内网eth1进行抓包,由于进行了DNAT和SNAT,此网卡数据包IP地址还是100.100.100.0/24网段,如下:
) H; e$ @0 y( C& h% K- IP 100.100.100.44.32253 > 100.100.100.101.telnet: Flags [.], ack 1, win 256, length 0
" z* U5 S) o9 X' m4 r( F6 n; H p8 R - IP 100.100.100.101.telnet > 100.100.100.44.32253: Flags [P.], seq 1:16, ack 1, win 2190, length 15
$ R& o8 u7 r, l `$ D6 D! M4 n - IP 100.100.100.44.32253 > 100.100.100.101.telnet: Flags [P.], seq 1:4, ack 16, win 256, length 3
, t" C l9 F- k5 X6 K) A5 e - IP 100.100.100.101.telnet > 100.100.100.44.32253: Flags [P.], seq 16:19, ack 4, win 2190, length 3
复制代码
& w/ h1 \/ f$ s" W* @2 z/ A但是,在服务器eth0抓包,将会是172.18.0.0/16的网段数据包:
# i' I: t/ Q \4 e& \4 U- IP 172.18.44.142.32253 > 172.18.44.44.2324: Flags [P.], seq 18:20, ack 154, win 255, length 2) m" Q6 e5 N4 T" D( J! k$ J8 ^
- IP 172.18.44.44.2324 > 172.18.44.142.32253: Flags [P.], seq 154:156, ack 20, win 2190, length 2
J0 \( `0 ?. t - IP 172.18.44.44.2324 > 172.18.44.142.32253: Flags [F.], seq 156, ack 20, win 2190, length 0* n; F5 w u6 q5 _
- IP 172.18.44.142.32253 > 172.18.44.44.2324: Flags [.], ack 157, win 255, length 0. \% d) Z% N! z6 ?) N
- IP 172.18.44.142.32253 > 172.18.44.44.2324: Flags [F.], seq 20, ack 157, win 255, length 0
/ p9 R' n- _5 h, X) N$ [ - IP 172.18.44.44.2324 > 172.18.44.142.32253: Flags [.], ack 21, win 2190, length 0
复制代码从抓包分析,本文所用命令已经能正确进行DNAT和SNAT了。
$ S: [8 w: f w, c3 Y, z
四、其它 建议在使用iptabls指令时,使用root用户进行操作,否则容易失败 保存iptables配置方法: $ m0 n" P+ A e' l
- iptables-save > /etc/iptables.up.rules
3 Q- S2 x7 ~% L6 |
% d/ `% g7 u' s; o6 D' G/ v
配置iptables开机加载
6 Q9 e% b# u3 G) e5 d5 T+ {- iptables-save > /etc/iptables.up.rules
! i x" g" w7 q& v - echo -e '#!/bin/bash\n/sbin/iptables-restore < /etc/iptables.up.rules' > /etc/network/if-pre-up.d/iptables5 {6 I0 d/ z! ?# Q
- chmod +x /etc/network/if-pre-up.d/iptables
复制代码
. s/ t' m1 c2 Q M. \0 ^+ G
本地测试指令
! `4 v# R: d6 N: K G1 J' D+ n' @2 ?; F
4 _8 |- D- X1 X. V- iptables -t nat -A PREROUTING -i wlan0 -d 192.168.11.100 -p tcp --dport 8081 -j DNAT --to 192.168.10.101:80. O' ~- o2 S |* ~ f1 V; @
- iptables -t nat -A POSTROUTING -o eth0 -d 192.168.10.101 -p tcp --dport 80 -j SNAT --to 192.168.10.52
复制代码
" p5 h) A) e9 l8 }) d* c, f+ J |