FTP(File Transfer Protocol,文件传输协议)是Internet的传统服务之一。FTP使用户能在两个联网的计算机之间传输文件,是Internet传递文件最主要的方法。除此之外,FTP还提供登录、目录查询、文件操作及其它会话控制功能。在系统中FTP服务使用23端口进行通信,在Window、Linux系统中都可以设置FTP服务。

NAT(Network Address Translation)网络地址转换,NAT服务器就是支持地址转换的代理服务器。当有几个工作站却只有一个合法的上网账户和IP地址时,可以用NAT服务器来实现地址转换。

本文主要介绍在NAT服务器上设置FTP服务。这样的FTP服务设置比起其它一些服务,如WWW, E-mial等要复杂得多。这是由于FTP自身的原因,因为FTP在连接过程中,分别需要Command和Data两个通道才能实现,而其连接的起始方向,对NAT服务器规则的设置有相当重要的影响。

设置规则

假设现在NAT服务器上有3块网卡,它们分别连接不同的网络且分配不同的IP地址。例如,第一张网卡A是用外网C类IP地址:221.7.128.1;第二张网卡接DMZ,使用A类IP:10.0.0.1;第三张网卡接内部网络,使用C类IP地址:192.168.0.1;DMZ内有一台主机,IP:10.0.0.2,并且准备提供FTP 服务(使用port 21和port 2121)。

如果DMZ和外网的路由是通的,那么NAT服务器上只进行单纯的封包过滤,没有修改packet,而且预设的policy都是DENY。如果DMZ和外网的路由是不通的,要如何设置规则,使得FTP能顺利向外部提供服务呢?可以用如下命令将第一块网卡的port 21连接请求转至10.0.0.2的port 21来提供服务。

方法一:ipchains

我们用命令:ipmasqadm portfw -a -P tcp -L 221.7.128.1 21 -R 10.0.0.2 21来进行操作。

NAT服务器上的预设policy全为DENY,要设置所有必须的规则,让FTP能顺利向外提供服务。以如下示例说明:

ipchains -A input -i eth0 -p TCP -d 10.0.0.2 21 -j ACCEPT
ipchains -A forward -p TCP -d 10.0.0.2 21 -j ACCEPT
ipchains -A output -i eth1 -p TCP -d 10.0.0.2 21 -j ACCEPT
ipchains -A input -i eth1 -p TCP -s 10.0.0.2 21 -j ACCEPT
ipchains -A forward -p TCP -s 10.0.0.2 21 -j ACCEPT
ipchains -A output -i eth0 -p TCP -s 10.0.0.2 21 -j ACCEPT
ipchains -A input -i eth0 -p TCP -d 10.0.0.2 2121 -j ACCEPT
ipchains -A forward -p TCP -d 10.0.0.2 2121 -j ACCEPT
ipchains -A output -i eth1 -p TCP -d 10.0.0.2 2121 -j ACCEPT
ipchains -A input -i eth1 -p TCP -s 10.0.0.2 2121 -j ACCEPT
ipchains -A forward -p TCP -s 10.0.0.2 2121 -j ACCEPT
ipchains -A output -i eth0 -p TCP -s 10.0.0.2 2121 -j ACCEPT


以上是在没有考虑其它安全要求、单就FTP服务进行设置的情况下,以ipchains作为命令的操作。

ipchains -A input -i eth0 -p TCP -d 221.7.128.1 21 -j ACCEPT
ipchains -A forward -p TCP -d 221.7.128.1 21 -j MASQ
ipchains -A output -i eth1 -p TCP -d 10.0.0.2 21 -j ACCEPT
ipchains -A input -i eth1 -p TCP -s 10.0.0.2 21 -j ACCEPT
ipchains -A forward -p TCP -s 10.0.0.2 21 -j MASQ
ipchains -A output -i eth0 -p TCP -s 221.7.128.1 21 -j ACCEPT
ipmasqadm portfw -a -P tcp -L 221.7.128.1 2121 -R 10.0.0.2 2121
ipchains -A input -i eth0 -p TCP -d 221.7.128.1 2121 -j ACCEPT
ipchains -A forward -p TCP -d 10.0.0.2 2121 -j MASQ
ipchains -A output -i eth1 -p TCP -d 10.0.0.2 2121 -j ACCEPT
ipchains -A input -i eth1 -p TCP -s 10.0.0.2 2121 -j ACCEPT
ipchains -A forward -p TCP -s 10.0.0.2 2121 -j MASQ
ipchains -A output -i eth0 -p TCP -s 221.7.128.1 2121 -j ACCEPT


下面对上述命令进行说明。

命令1:ipchains -A input -i eth0 -p TCP -d 221.7.128.1 21 -j ACCEPT

建立连接用,因为使用ipmasqadm命令来实现DNAT服务器(port forward),因此,destiNAT服务器就成了NAT服务器的外部界面。

命令2:ipchains -A forward -p TCP -d 221.7.128.1 21 -j MASQ *

值得注意的是,因为在DNAT服务器时已经将destiNAT服务器socket修改过了,也就是封包input进来后,外网的IP:221.7.128.1会改变为10.0.0.2。而且还要了解ipmasqadm这个程序的特点,是当它修改了input packet后,就不会再有ipchains的forward检测,而是直接根据路由判断后进行output。所以,这行是多余的,可以不要。

命令3:ipchains -A output -i eth1 -p TCP -d 10.0.0.2 21 -j ACCEPT

这是经过DNAT服务器修改后从NAT服务器主机输出到FTP Server的封包,必须ACCEPT,否则连接请求没办法到达Server。

命令4:ipchains -A input -i eth1 -p TCP -s 10.0.0.2 21 -j ACCEPT

这是从FTP Server回应进来的封包,也一定要ACCEPT。

命令5:ipchains -A forward -p TCP -s 10.0.0.2 21 -j MASQ

这里要非常小心,因为假设的前提是DMZ和外网不能路由,如果封包没做MASQ处理,那么将无法传送。而且,不要忽略当封包经过ipmasqadm处理进行MASQ后,出去的封包会被还原成Client所expect的socket。如果用ACCEPT的话是不行的,ipmasqadm不会对ACCEPT规则做还原动作,只有使用MASQ才能将当初被DNAT服务器处理过的连接正确的还原为原来的socket,即port 21。

命令6:ipchains -A output -i eth0 -p TCP -s 221.7.128.1 21 -j ACCEPT

这是还原socket后送回到Client的回应封包,所以要ACCEPT。

命令7:ipmasqadm portfw -a -P tcp -L 221.7.128.1 2121 -R 10.0.0.2 2121 *

照理说,ftp-data连接应该是从port 2121出去的,换句话说,基本上第一个syn的连接封包是output而不是input。这样的话,要能成功地将回应封包(不是起始封包)forward到FTP Server去,要看Client是否知道ftp-data的建立socket会在Server端的port 2121上面,也就取决于DMZ的Server经过SNAT服务器之后是否能够成功地用port 2121来起始ftp-data通道。

命令8:ipchains -A input -i eth0 -p TCP -d 221.7.128.1 2121 -j ACCEPT *

只有上一句的条件成立时,这行命令才有用。

命令9:ipchains -A forward -p TCP -d 10.0.0.2 2121 -j MASQ *

这行和命令5的道理一样,如果用命令7处理后,这行就无须使用了。

命令10:ipchains -A output -i eth1 -p TCP -d 10.0.0.2 2121 -j ACCEPT

不管命令7和上一句是否被执行,这行是必须的,因为对于DMZ的FTP Server来说,不管NAT服务器怎么处理,用来做ftp-data的port还是2121。

命令11:ipchains -A input -i eth1 -p TCP -s 10.0.0.2 2121 -j ACCEPT

这行也是必须的,理由同上。

命令12:ipchains -A forward -p TCP -s 10.0.0.2 2121 -j MASQ

这行非常重要!因为ftp-data的连接是从Server端起始的,也就是当DMZ的FTP Server要建立ftp-data连接时,因为无法路由,所以一定要用MASQ。但与命令5比较,因为命令5的连接之前已经被ipmasqadm处理过,所以能正确地还原到原来的socket(port 21)。但在这里,因为是第一个连接封包,之前不可能被ipmasaqdm处理过,是不可能被还原为port 2121的。取而代之的是,ipchains会根据MASQ的请求,重新建立一个对外的socket,而port则是随机产生的,也就是说在1024~65535之间。请记住这个特点,我们必须增加下面两行规则:

ipchains -A output -i eth0 -p TCP -s 221.7.128.1 1024:65355 -d 0/0 1024:65535 -j ACCEPT
ipchains -A input -i eth0 -p TCP -s 0/0 1024:65535 -d 221.7.128.1 1024:65535 -j ACCEPT


这样结果是,1024以上的port都能打开连接。这是非常危险的一个操作,因为开放的范围太大,至少应该将来自外网的第一个syn封包拦截下来,所以上面的input可以修改为:

ipchains -A input -i eth0 -p TCP -s 0/0 1024:65535 -d 221.7.128.1 1024:65355 ! -y -j ACCEPT


所以,命令7和其后紧接着的两行也就没什么作用,可以不要。

命令13:ipchains -A output -i eth0 -p TCP -s 221.7.128.1 2121 -j ACCEPT *

同样,这最后一行也可以不设,因为是多余的。事实上,ftp-data的socket从NAT服务器主机出去Client的时候,是不会使用到port 2121的。

这里,我们并没有使用passive模式,所有被*标识的句子,事实上都可省略掉。

方法二:iptalbes

首先进行iptables的设置如下:

# Generated by iptables-save v1.2.1a on Thu Jun 28 14:45:26 212101
# NAT服务器
:PREROUTING DROP [3:144]
:POSTROUTING ACCEPT [2:108]
:OUTPUT ACCEPT [4:948]
-A PREROUTING -p udp -m udp --dport 53 -j ACCEPT
-A PREROUTING -p udp -m udp --sport 53 -j ACCEPT
-A PREROUTING -p tcp -m tcp --dport 113 -j ACCEPT
-A PREROUTING -p tcp -m tcp --sport 113 -j ACCEPT
-A PREROUTING -p icmp -j ACCEPT
-A PREROUTING -d 10.0.0.2 -i eth0 -p tcp -m tcp --dport 21 -j ACCEPT
-A PREROUTING -s 10.0.0.2 -i eth1 -p tcp -m tcp --sport 2121 -j ACCEPT
COMMIT
# Completed on Thu Jun 28 14:45:26 212101
# Generated by iptables-save v1.2.1a on Thu Jun 28 14:45:26 212101
# filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [4:948]
-A INPUT -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 113 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 113 -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A FORWARD -p tcp -m tcp --sport 53 -j ACCEPT
-A FORWARD -p tcp -m tcp --dport 53 -j ACCEPT
-A FORWARD -s 10.0.0.2 -i eth1 -p tcp -m tcp --sport 21 -j ACCEPT
-A FORWARD -d 10.0.0.2 -i eth0 -p tcp -m tcp --dport 21 -j ACCEPT
-A FORWARD -s 10.0.0.2 -o eth0 -p tcp -m tcp --sport 2121 -j ACCEPT
-A FORWARD -d 10.0.0.2 -o eth1 -p tcp -m tcp --dport 2121 -j ACCEPT
-A FORWARD -p icmp -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --sport 53 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 113 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 113 -j ACCEPT
COMMIT
# Completed on Thu Jun 28 14:45:26 212101

# Generated by iptables-save v1.2.1a on Sat Jun 30 16:35:09 212101
# NAT服务器
:PREROUTING DROP [0:0]
:POSTROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -p udp -m udp --dport 53 -j ACCEPT
-A PREROUTING -p udp -m udp --sport 53 -j ACCEPT
-A PREROUTING -p tcp -m tcp --dport 113 -j ACCEPT
-A PREROUTING -p tcp -m tcp --sport 113 -j ACCEPT
-A PREROUTING -p icmp -j ACCEPT
-A PREROUTING -d 221.7.128.1 -i eth0 -p tcp -m tcp --dport 21 -j
# DNAT服务器到destiNAT服务器的地址10.0.0.2:21
# (注一):不用为port 2121做 DNAT服务器
-A PREROUTING -s 10.0.0.2 -i eth1 -p tcp -m tcp --sport 21 -j ACCEPT
-A PREROUTING -s 10.0.0.2 -i eth1 -p tcp -m tcp --sport 2121 -j ACCEPT
-A POSTROUTING -p tcp -m tcp -s 10.0.0.2 --sport 2121 -j MASQUERADE
# (注二):请留意上一行,在ipchains中也有相同的设计。
COMMIT
# Completed on Sat Jun 30 16:35:09 212101
# Generated by iptables-save v1.2.1a on Sat Jun 30 16:35:09 212101
# filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -p udp -m udp --sport 53 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 113 -j ACCEPT
-A INPUT -p tcp -m tcp --sport 113 -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A FORWARD -p udp -m udp --sport 53 -j ACCEPT
-A FORWARD -p udp -m udp --dport 53 -j ACCEPT
-A FORWARD -s 10.0.0.2 -i eth1 -p tcp -m tcp --sport 21 -j ACCEPT
-A FORWARD -d 10.0.0.2 -i eth0 -p tcp -m tcp --dport 21 -j ACCEPT
-A FORWARD -s 10.0.0.2 -o eth0 -p tcp -m tcp --sport 2121 -j ACCEPT
-A FORWARD -d 10.0.0.2 -o eth1 -p tcp -m tcp --dport 2121 -j ACCEPT
-A FORWARD -p icmp -j ACCEPT
-A OUTPUT -p icmp -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --sport 53 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 113 -j ACCEPT
-A OUTPUT -p tcp -m tcp --sport 113 -j ACCEPT
COMMIT
# Completed on Sat Jun 30 16:35:09 212101


iptables和ipchains的最大分别是对来自FTP Server的ftp-data封包的处理上。如果用ipchains,在MASQ后会另外建一个source socket,但不是使用port 2121;如果用iptables,在MASQ后也会另建一个source socket,却保留原来的port 2121。因为连接是从Server端由内至外建立的,所以在NAT服务器上已经有这个连接的MASQ记录存在,也就不必为port 2121做DNAT服务器了。不过,在进行passive模式测试时,尽管将ip_NAT服务器_ftp模块载入,还是不能建立ftp-data的连接。抓几个封包就可以发现:Client端从command channel中接收Server的port命令后,会尝试直接以FTP Server的IP地址作为destiNAT服务器,而不是以NAT服务器的外部界面为目标,所以连接无法建立。

结论

如果Server和Client两端都各自“躲”在NAT服务器背后,无论用ipchains或iptalbes方法都无法使用passive 模式来建立data channel。解决的方法只能是在Client端的NAT服务器上,将ip_NAT服务器_ftp的模块载入(ipchains 是用ip_masq_ftp 模块),而Server端使用标准的port 2121和port 21来提供FTP服务。
02-09 19:50