作者: 耳朵里有风
还记得刚接触Linux系统,需要在上面部署tomcat, 部署好之后却发现在浏览器上怎么也访问不了,折腾一会之后才知道端口没有放开,网上搜了开放端口的命令 iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
,试了试发现果然有效。我猜应该也有不少小伙伴和有着类似的经历吧,那你会不会好奇那串命令为什么能生效呢?本篇我想写的内容就是围绕iptables展开的,希望读完本篇,你能从中找到答案。至于为什么在Docker网络学习专题中要了解iptables, 我在后续的篇章中会有提及。好了,下面作为iptables的粉丝,开始去追逐她吧!
iptables概念
可以说iptables是用户空间的命令行工具,比如上面说的要开放一个端口,于是敲了一个iptables
命令。 那么除了开放端口,iptables还能做些什么? 下面先列出了三个常用功能(还有很多),之后会逐一来看要如何做以及为什么能这么做。
- 构建防火墙规则
- 防攻击,比如流量控制
- 转发数据包
1、构建防火墙规则
通常使用iptables来设置防火墙,比如文章最开始举的开放端口的例子,它其实就是让防火墙允许外界通过指定端口来访问服务器部署的服务,通过iptables
命令增加了一条防火墙规则,当服务器接收到请求时,内核某个模块就会根据这条规则来判断是否让这个请求通过,这个模块有个名字叫netfilter。
从图1不难发现,netfilter和iptables组成了Linux数据包果过滤的防火墙,其中iptables负责组织具体过滤的规则,而netfilter通过这些规则来处理用户请求,决定请求的进出。需要注意的是,netfilter不仅是负责数据的阻断过滤,它同时也负责网络地址转换以及数据包内容修改。
1.1、 iptables 基础
构建防火墙规则,这里有两个名词,防火墙和规则。 刚刚已经解释了防火墙实质是iptables/netfilter对规则的制定和调用,那么规则显得尤为重要;要弄懂规则是什么, 还是回顾下开放端口的命令
iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
这条命令的意思大概是在顶部添加一条新的INPUT链规则,协议是tcp, 目标端口是8080,处理的方式是接受请求,该规则会归到filter表。(简述:允许访问tcp协议下8080端口), 具体参数含义:
参数 | 含义 |
---|---|
-I |
command: 具体命令,-I 表示从顶部添加,类似的操作 -A 表示从底部追加,-D 表示删除一条规则等 |
INPUT |
chain: 指定链, 包含PREROUTING、INPUT、FORWARD、POSTROUTING、OUTPUT |
-p tcp --dport 8080 |
paramter&Xmatch: -p tcp 表示指定协议为tcp; -dport 8080表示指定目标端口(Destination Port)是8080 |
-j ACCEPT |
target: -j ACCEPT 表示允许,其他还有DROP、REJECT、DNAT、SNAT |
5链4表
重点先来看下第二个参数INPUT
, 它是用来指定规则作用在哪条链上,iptables一共有5种链,包括: PREROUTING、INPUT、FORWARD、POSTROUTING、OUTPUT,这5种链的位置如下图所示:
- PREROUTING、POSTROUTING 链是前后的处理;
- INPUT、OUTPUT 链是核心态与用户态转移时的处理;
- FORWARD链是非本机请求的转发;
链的理解:INPUT可以添加多条规则,这些规则在一起组成了INPUT链;
说到了链,不得不提另外一个重要的概念,那就是表。把具有相同功能的规则的集合叫做表,比如在INPUT链中有对请求过滤的规则,在OUTPUT、FORWARD链也同样有过滤的功能,于是把负责过滤功能的规则统统归到filter表中。下面是具体表和功能
表 | 功能 | 对应内核模块 |
---|---|---|
filter | 负责过滤功能,防火墙 | iptables_filter |
nat | network address translation,网络地址转换功能 | iptable_nat |
mangle | 拆解报文,做出修改,并重新封装 的功能 | iptable_mangle |
raw | 关闭nat表上启用的连接追踪机制 | iptable_raw |
知识点
- 表不一定会存储所有链的规则,这是因为链不需要具备所有功能,比如POSTROUTING就不需要过滤的功能,所以POSTROUTING的规则是不会存储在filter表中的。
- 链的规则根据功能不同存储在不同的表中,如果一个链中存在多个功能的规则,他们的执行顺序是raw > mangle > nat > filter
- 为了更方便的管理,我们还可以在某个表里面创建自定义链,将针对某个应用程序所设置的规则放置在这个自定义链中,但是自定义链接不能直接使用,只能被某个默认的链当做动作去调用才能起作用(讲Docker网络时还会提到)
1.2、举个栗子
有了上面的基础,假设现在有台机器,ip是10.0.1.2,先允许22访问,其他都拒绝
iptables -I INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -j REJECT
现在有应用需要用到8080到8085 这一段端口 iptables -I INPUT -p tcp -dport 8080:8085 -j ACCEPT
需要服务器能通ping的通iptables -I INPUT -p icmp -j ACCEPT
允许本机访问自己 iptables -I INPUT -i lo -j ACCEPT
( -i lo 指定网卡设备,意思是允许lo过来的数据包)
允许本机访问其他主机 iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
(往外请求时,回包的状态为ESTABLISHED或RELATED, -m state --state <状态>
: 指定请求状态)
只允许10.0.1.3 访问8090端口 iptables -I INPUT -p tcp -s 10.0.1.3 --dport 8090 -j ACCEPT
二、流量控制
流量控制也还是在INPUT进行控制
iptables -I INPUT -p tcp -dport 80 -s 10.0.1.3 -m connlimit --connlimit-above 10 -j ACCEPT
-m connlimit --connlimit-above 10
指定了并发上限为10,上面命令就是限制10.0.1.3 访问服务器80端口的并发的上限为10;
三、数据包转发
上面不管是防火墙规则还是流浪控制都是filter表功能,数据包转发用到的就是nat表功能了。转发与否的请求流程区别在于所走的链是不同的,下图绿色是转发的请求路径,转发是在内核态完成,不需要经过用户态,节省了转发时间。
除了 请求到用户态 (PREROUTING -> INPUT) 和 本机转发请求 (PREROUTING -> FORWARD -> POSTROUTING), 还有从用户态发出报文(OUTPUT --> POSTROUTING)的应用场景本篇不再具体分析
Linux数据包转发需要先指定内核参数net.ipv4.ip_forward
,这个参数指定了Linux系统当前对路由转发功能的支持情况;其值为0时表示禁止进行IP转发;如果是1,则说明IP转发功能已经打开。 打开配置 /etc/sysctl.conf 文件修改 net.ipv4.ip_forward=1
nat规则分为SNAT(源地址转换)和DNAT(目标地址转换), DNAT 在PREROUTING阶段转换目标地址, SNAT是在POSTROUTING阶段将源地址进行转换;
理解目标地址和源地址:目标地址就是我将要访问的地址,而源地址就是我自己的地址;
-
DNAT示例
假设客户端(10.0.1.2) 要访问HTTP服务器,该服务器ip是172.1.3.3,这是一个跨网段的请求,是无法直接访问的,现在实现通过10.0.1.3这台服务转发来访问HTTP服务器(就是通过 http://10.0.1.3能够请求到172.1.3.2 的服务)。 10.0.1.3 同时配置和172.1.3.3同网段的网卡,ip是172.1.3.2, 图示如下:
要实现这样的场景,只需要在转发服务器10.0.1.3 上做一个DNAT即可
iptables -t nat -A PREROUTING -d 10.0.1.3 -p tcp --dport 80 -j DNAT --to 172.1.3.3:80
-t 是指定表类型,默认是filter;上面这句话的意思就是将访问10.0.1.3:80 转到172.1.3.3:80上;
-
SNAT 示例
还是刚刚的场景,只是现在不想通过输入http://10.0.1.3来请求到172.1.3.2的服务, 而是直接输入172.1.3.2进行请求;
要实现这样的场景,只需要在转发服务器10.0.1.3 上做一个SNAT即可
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j SNAT --to 172.1.3.2
SNAT和DNAT适用于不同的场景,比如当我在公司网络环境需要访问某个外部网站(如 www.baidu.com)时,就没必要在浏览器上输一个内部ip来请求这个网站,所有此时DNAT就不太适用了,就需要配置SNAT。而当我有个服务需要开放到外网去,外部通过某个指定的域名来访问我的服务,这种场景明显就需要适用DNAT。
参考资料
- http://www.zsythink.net/archives/1199