欢迎光临 www.huangdc.com

iptables 端口映射详解

Linux huangdc 1587℃ 0评论

1、iptables 简介

iptables防火墙在做信息包过滤决定时,有一套遵循和组成的规则,这些规则存储在专用的信 息包过滤表中,而这些表集成在 Linux 内核中。在信息包过滤表中,规则被分组放在我们所谓的链(chain)中。而netfilter/iptables IP 信息包过滤系统是一款功能强大的工具,可用于添加、编辑和移除规则。

虽然 netfilter/iptables IP 信息包过滤系统被称为单个实体,但它实际上由两个组件netfilter 和 iptables 组成。

注意:

a、linux 包过滤是通过内核来实现的,内核是使用netfilter架构来实现防火墙能力的。    ( netfilter 组件也称为内核空间(kernel space),是内核的一部分,由一些信息包过滤表组成,这些表包含内核用来控制信息包过滤处理的规则集 )

b、iptables 实质上是linux系统中为用户提供的 netfilter管理工具。   ( iptables 组件是一种工具,也称为用户空间(user space),它使插入、修改和除去信息包过滤表中的规则变得容易 )

        c、iptables 大致是工作在OSI七层的二、三、四层。

与Linux内核各版本集成的防火墙历史版本:

2.0.X内核:ipfwadm

2.2.X内核:ipchains

2.4.X 和 2.6.X内核:iptables

2、iptables 基础架构组成(三张表 和 五条规则链)

iptables内核netfilter主要定义了三张表(filter、nat、mangle) ,每张表又有不同的规则链Chains,主要有五条规则链Chains(INPUT 、FORWARD、OUTPUT、PREROUTING、POSTROUTING)

    三表         规则链                 备注 

filter

INPUT            进入防火墙本机数据包(经过filter表)

FORWARD        进入非防火墙本机的数据包(经过filter表)

OUTPUT        从防火墙本机外出(到局域网或外网)的数据包(经过filter表)

nat

OUTPUT         从防火墙本机外出(到局域网或外网)的数据包(经过nat表)

PREROUTING        路由前数据包位置主要是要DNAT (经过nat表)

POSTROUTING        数据包出去之前路由之后时位置主要是做SNAT (经过nat表)

mangle

包含以上五链 “mangle表则是一个自定义表,里面包括上面的filter以及nat表中的各种chains,可以让我们进行一些自定义的操作;

同时这个mangle表中的chains在netfilter对包的处理流程中处在一个比较优先的位置”

表说明:

filter :用来过滤数据包

nat:(Network Address Translation、网络地址翻译)  用以实现地址转换和端口转发功能的这个表

mangle :自定义表

3、iptables 工作流程

下面有一张图清晰的描绘了netfilter对包的处理流程(该图摘自网上,不知作者是谁,在此深表敬意!),一般情况下,我们用不到这个mangle表,在这里我们就不做介绍了。

iptables_01

A、流入和 转发数据包流程:

路由前(pre-routing):

当一个数据包进入到网络接口时,首先过的就是 mangle表的 PREROUTING链处理,然后是 nat表的 PREROUTING链处理;从这个chain的名字我们可以看出,这个chain是在路由之前(pre-routing)要过的。为什么要在路由之前过呢?大家可以看到这个图上,上面有一个菱形的部分叫ROUTING,这个ROUTING部分就是Linux的route box,也就是路由系统,它同样有很高深的功能,可以实现策略路由等等一些高级特性,此处我们不做详细解释。单说这个PREROUTING链,因为在这个链里面我们对包的操作是DNAT,也就是改变目的地址和(或端口),通常用在端口转发,或者nat到内网的DMZ区,也就是说当一个包过来的时候我们要改变它的目的地址,大家可以想想,如果一个包在改变目的地址之前就被扔进了route box,让系统选好路之后再改变目的地址,那么选路就可能是错的,或者说毫无意义了,所以,PREROUTING这个Chain一定要在进Routing 之前做。那么Linux如何做DNAT呢?我们在最后会用实例来讲解

路由判断(forward):

接着往下走,这个已经过了两个PREROUTING链了,这个时候处理了一个分支转折的地方,也就是图中下方的菱形(FORWARD)转发【我觉得这里就是封包进入,在路由前(pre-routing)的路由判断(也就是经过route box),这里用forward来表示包是否需要转发】,这里有一个对数据包目的地址的判断:

a、如果包的目的地是本机ip,那么包向上走,走入 INPUT链处理,然后进入LOCAL PROCESS

b、而如果这个数据包的目的地址不是本机ip,那么就进入 FORWARD链进行过滤

注意:当linux收到了一个目的ip地址不是本地的包,Linux会把这个包丢弃,因为默认情况下,Linux的三层包转发功能是关闭的,如果要让我们的linux实现转发,则需要打开这个转发功能,可以改变它的一个系统参数,使用sysctl net.ipv4.ip_forward=1 或者 echo “1” > /proc/sys/net/ipv4/ip_forward 命令打开转发功能

路由后(post-routing):

    继续前进…..

本地数据包(input):

如果包目的地址是本机ip,那么首先过的就是 mangle表的 INPUT链处理,然后是 filter表的 INPUT链处理,最终过滤进入LOCAL PROCESS

转发数据包(forward)(重点)

a、如果包目的地址不是本机ip,那么就进入 FORWARD链进行过滤(刚刚说了需要先打开系统的转发功能),首先过的 mangle表的 FORWARD链处理,然后进入filter表的 FORWARD链处理(在FORWARD链里面,我们就可以定义详细的规则,也就是是否允许他通过,或者对这个包的方向流程进行一些改变,这也是我们实现访问控制的地方),假设这个包被我们的规则放过去,也就是ACCEPT了,它将进入POSTROUTING部分 (对于转发的包来说,linux同样需要在选路由之后才能将它送出,它是在过了route box之后才进入的POSTROUITNG)

b、继续,进入POSTROUTING链,这个POSTROUTING链应该是路由之后的一个链,也就是这个包要送出这台Linux的最后一个环节了,这也是极其重要的一个环节!!这个时候linux已经完成了对这个包的路由(选路工作),已经找到了合适的接口送出这个包了,在这个链里面我们要进行重要的操作,就是被Linux称为 SNAT的一个动作,修改源ip地址!为什么修改源ip地址?很多情况需要修改源地址阿,最常见的就是我们内网多台机器需要共享一个或几个公网ip访问 internet,因为我们的内网地址是私有的,假如就让linux给路由出去,源地址也不变,这个包应该能访问到目的地,但是却回不来,因为 internet上的N多个路由节点不会转发私有地址的数据包,也就是说,不用合法ip,我们的数据包有去无回。有人会说:“既然是这样,我就不用私有 ip了,我自己分配自己合法的地址不行吗?那样包就会回来了吧?”答案是否定的,ip地址是ICANN来分配的,你的数据包或许能发到目的地,但是回来的时候人家可不会转到你那里,internet上的路由器中的路由信息会把这个返回包送到那个合法的获得ip的地方去,你同样收不到,而你这种行为有可能被定义为一种ip欺骗,很多设备会把这样的包在接入端就给滤掉了,可能都到不了你要访问的那个服务器。那么Linux如何做SNAT呢?我们在最后会用实例来讲解

B、流出数据包流程:

同样,从本地主机程序LOCAL PROCESS 往外发包时,就是图中上方的菱形(ROUTING)路由选择之后,首先过的就是 mangle表的 OUTPUT链处理,然后是 filter表的 OUTPUT链处理,最终过滤进入POSTROUTING链处理 。

好了,大致流程就是这样,接下来看看iptables基本操作命令及实例

4、iptables 基本命令

概要:

iptables [-t table] -[AD] chain rule-specification [options]

iptables [-t table] -I chain [rulenum] rule-specification [options]

iptables [-t table] -R chain rulenum rule-specification [options]

iptables [-t table] -D chain rulenum [options]

iptables [-t table] -[LFZ] [chain] [options]

iptables [-t table] -N chain

iptables [-t table] -X [chain]

iptables [-t table] -P chain target [options]

iptables [-t table] -E old-chain-name new-chain-name

在这里就介绍几种常用的参数,详细地用法可以man iptables 查看帮助文档,你会有意外的收获

参数 说明
-t 指定要操作的表,默认是filter
-A 向规则链中添加一条规则,默认被添加到末尾
-D 从规则链中删除规则,可以指定序号或者匹配的规则来删除
-R 进行规则替换
-I 插入一条规则,默认被插入到首部
-N 新建用户自定义的规则链
-F 清除iptables内置规则
-X 清除用户自定义的规则链
-L 列出iptables规则
-P 默认策略
-p 指定协议(tcp、udp、icmp等)
-s 指定源地址 -s  address[/mask]
-d 指定目的地址(同上)
-i 数据包进入接口(例如 -i eth0 )
-o 数据包流程接口
-j 对数据包操作(ACCEPT、DROP、SNAT、DNAT等)
-sport 指定源端口 (端口必须和协议一起来配合使用 –sport  port[:port] )
-dport 指定目标端口 (端口必须和协议一起来配合使用 )
–to 网络地址映射到指定地址  如: –to  address[/mask]

比如:

#设定默认规则

iptables -P INPUT DROP

iptables -P OUTPUT ACCEPT

iptables -P FORWARD DROP

##基本操作

iptables -L  #列出iptables规则

iptables -F  #清除iptables内置规则

iptables -X  #清除iptables自定义规则

iptables -L -n -v #查看定义规则的详细信息

#只允许192.168.0.3的机器进行SSH连接:

iptables -A INPUT -s 192.168.0.3 -p tcp –dport 22 -j ACCEPT

#不允许172.16.0.0/24的进行访问:

iptables -t filter -A INPUT -s 172.16.0.0/16 -p udp –dport 53 -j DROP

#当然你如果想拒绝的更彻底:

iptables -t filter -R INPUT 1 -s 172.16.0.0/16 -p udp –dport 53 -j REJECT

#允许任何地址到任何地址的确认包和关联包通过:

iptables -A FORWARD -m state –state ESTABLISHED,RELATED -j ACCEPT

#存储于恢复iptables规则

iptables-save > somefile

iptables-restore < somefile

5、 iptables端口映射(实例)

iptables_02

(1)简单的nat路由器

环境介绍:linux 2.4 +  (2个网络接口)

Lan口: 10.1.1.254/24 eth2

Wan口: 60.1.1.1/24 eth0

目的: 实现内网中的节点(10.1.1.0/24)可控的访问internet。

首先将Lan的节点pc 的网关指向 10.1.1.254

确定你的linux的ip配置无误,可以正确的ping通内外的地址。同时用route命令查看linux的本地路由表,确认指定了可用的ISP提供的默认网关。

a、sysctl net.ipv4.ip_forward=1 ##打开linux的转发功能。

b、iptables -P FORWARD DROP ##将FORWARD链的策略设置为DROP,这样做的目的是做到对内网ip的控制,你允许哪一个访问internet就可以增加一个规则,不在规则中的ip将无法访问internet.

c、iptables -A FORWARD -m state –state ESTABLISHED,RELATED -j ACCEPT ##这条规则规定允许任何地址到任何地址的确认包和关联包通过。一定要加这一条,否则你只允许lan IP访问没有用

d、iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -j SNAT –to 60.1.1.1 ##这条规则做了一个SNAT,也就是源地址转换,将来自10.1.1.0/24的地址转换为60.1.1.1

##有这几条规则,一个简单的nat路由器就实现了。这时你可以将允许访问的ip添加至FORWARD链,他们就能访问internet了

##比如我想让10.1.1.9这个地址访问internet,那么你就加如下的命令就可以了:

iptables -A FORWARD -s 10.1.1.9 -j ACCEPT

##也可以精确控制他的访问地址,比如我就允许10.1.1.99访问3.3.3.3这个ip:

iptables -A FORWARD -s 10.1.1.99 -d 3.3.3.3 -j ACCEPT

##或者只允许他们访问80端口:

iptables -A FORWARD -s 10.1.1.0/24 -p tcp –dport http -j ACCEPT

 

(2)端口转发

环境介绍:linux 2.4 + (2个网络接口)

Lan口: 10.1.1.254/24  eth1

Lan内web server:  10.1.1.1:80

Lan内ftp server: 10.1.1.2:21

Wan口: 60.1.1.1/24  eth0

目的:对内部server进行端口转发实现internet用户访问内网服务器(DMZ)

同样确认你的linux的各项配置正常,能够访问内外网。

iptables -P FORWARD DROP

iptables -A FORWARD -m state –state ESTABLISHED,RELATED -j ACCEPT   ##也需要加入确认包和关联包的允许通过

如果你要把访问60.1.1.1:80的数据包转发到Lan内web server,用下面的命令

iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp –dport 80 -j DNAT –to 10.1.1.1:80

ftp服务也同样,命令如下:

iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp –dport 21 -j DNAT –to 10.1.1.2:21

好了,命令完成了,端口转发也做完了,本例能不能转发呢?不能,为什么呢?我下面详细分析一下。对于iptables好像往外访问的配置比较容易,而对内的转发似乎就有一些问题了,在一开始的时候我就先说了一些关于netfilter的流程问题,那么我就简单说说做了这些配置之后为什么有可能还不行呢?

能引起这个配置失败的原因有很多,我们一个个的来说:

第一个原因,本例中,我们的FORWARD策略是DROP,那么也就是说,没有符合规则的包将被丢弃,不管内到外还是外到内,我们在这里依然不讨论那个确认包和关联包的问题,我们不用考虑他的问题,下面我会详细说一下这个东西,那么如何让本例可以成功呢?加入下面的规则。

iptables -A FORWARD -d 10.1.1.1 -p tcp –dport 80 -j ACCEPT

iptables -A FORWARD -d 10.1.1.2 -p tcp –dport 21 -j ACCEPT

有没有觉得有一些晕?为什么目的地址是10.xxx而不是60.xxx人家internet用户不是访问的60.xxx吗?呵呵,回到上面看看那个图吧, FORWARD链在什么位置上,它是在PREROUTING之后,也就是说当这个包到达FORWARD链的时候,目的地址已经变成10.xxx了,假如 internet用户的请求是这样202.1.1.1:1333–>60.1.1.1:80,在经过了我们的PREROUTING链之后将变成 202.1.1.1:1333–>10.1.1.1:80,这个时候如果你设置一个目的地址为60.xxx的规则有用吗?这是问题一。

这个时候应该可以完成端口转发的访问了,但是有一些时候还是不行?为什么?看问题二

第二原因,内网server的ip配置问题,这里我们以web server为例说明一下(ftp情况有一些特殊,下面我们再详细讨论,说确认包和关联包的时候讨论这个问题),上面说到,有的时候可以访问了,有的时候却不行,就是这个web server的ip设置问题了,如果web server没有指定默认的网关,那么在作了上面的配置之后,web server会收到internet的请求,但是,他不知道往哪里回啊,人家的本地路由表不知道你那个internet的ip,202.1.1.1该怎么走。如果你使用截包工具在web server上面察看,你会发现server收到了来自202.1.1.1:1333–>10.1.1.1:80的请求,由于你没有给web server配置默认网关,它不知道怎么回去,所以就出现了不通的情况。怎么办呢?两个解决方法:

第一种方法就是给这个server配置一个默认网关,当然要指向这个配置端口转发的linux,本例是10.1.1.254,配置好了,就一定能访问了。有一个疑问?难道不需要在FORWARD链上面设置一个允许 web server的ip地址访问外网的规则吗?它的包能出去?答案是肯定的,能出去。因为我们那一条允许确认包与关联包的规则,否则它是出不去的。

第二种方法,比较麻烦一些,但是对服务器来说这样似乎更安全一些。方法就是对这个包再作一次SNAT,也就是在POSTROUTING链上添加规则。命令如下:

iptables -t nat -A POSTROUTING -d 10.1.1.1 -p tcp –dport 80 -j SNAT –to 10.1.1.254

ftp的方法相同。这条命令不太好懂??其实很简单,如果使用这条命令,那么你的web server不需要再设置默认网关,就能收到这个请求,只要他和linux的lan ip地址是能互访的(也就是说web server和Linux的Lan ip在一个广播域),我们在根据上面的netfilter流程图来分析这个包到底被我们怎么样了,首先一个请求202.1.1.1:1333–> 60.1.1.1:80被linux收到了,进入PREROUTING,发现一个规则(iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp –dport 80 -j DNAT –to 10.1.1.1:80)符合,好了,改你的目的地址,于是这个包变成了202.1.1.1:1333–>10.1.1.1:80,继续往前走,进入FORWARD链,okay,也有一条规则允许通过(iptables -A FORWARD -d 10.1.1.1 -p tcp –dport 80 -j ACCEPT),进入route box选路,找到合适的路径了,继续进入POSTROUTING链,耶?又发现一个符合的规则(iptables -t nat -A POSTROUTING -d 10.1.1.1 -p tcp –dport 80 -j SNAT –to 10.1.1.254),原来是一个SNAT,改你的源地址,于是这个包变成了10.1.1.254:xxxx–>10.1.1.1:80。为什么用xxxx了,这里的端口是随机的,我也不知道会是什么。而整个的两次变化的过程都会记录在linux的ip_conntrack中(/proc/net/ip_conntrack),当web server收到这个包的时候,发现,原来是一个内网自己兄弟来的请求阿,又在一个广播域,不用找网关,把返回包直接扔给交换机了,linux在收到返回包之后,会根据他的ip_conntrack中的条目进行两次变换,返回真正的internet用户,于是完成这一次的访问。

温故而知新,最近重新过了一遍iptables 的一些基本概念及常用操作,查看了网上很多文章,综合的梳理出来做了一份笔记,当然,参考很多非常棒的文章,最重要文章URL为:http://blog.csdn.net/huguohu2006/article/details/6453522   原文作者@张天成,再次再次的 非常感谢他的文章

转载请注明:Huangdc » iptables 端口映射详解

喜欢 (8)or分享 (0)
发表我的评论
取消评论

表情
(1)个小伙伴在吐槽
  1. good
    匿名2015-10-28 21:41 回复