iptables使用教程
1. 前言
- linux社区开启了一个netfilter项目在内核中进行数据包的管理
- iptables就是这个netfilter项目的具体实现,是一个命令行的交互工具,供管理员给予内核级别数据包控制
- iptables通常用于检查,修改,转发,重定向,丢弃一个ip数据包
2 Linux内核简化处理数据包流程简介
2.1 简化的流程介绍
2.1.1 一般流程介绍
这个流程是简化过的流程,但是对于整个流程的梳理是重要的,简单介绍这个流程:
- 首先是数据包从网卡进入, 已经路由预处理链路(PREROUTING), 这个预处理可以用来修改ip包的目的地址等信息
- 路由决策就是判断ip的目的地址是不是本机的ip
- 按照一般情况, 再进入输入链路(INPUT)这个链路,这个主要是决定进入上层应用层的处理前的链路
- 上层应用处理,这个就是实际流入上层应用的数据包,例如用java或者Python构建的web服务就能接收到
- 再就是上层应用会做出响应的数据包进入输出链路(OUTPUT)
- 路由决策这里根据目的ip选择将数据包发给哪个网卡
- 进入路由后处理链路(POSTROUTING), 这个后处理可以用来修改ip地址的源ip信息等
- 输出到网卡发送出去
2.1.1.1 转发流程
- 假如当前主机是网关(例如路由器),那么从网卡上就会接收到目的ip不是本机ip的数据包
- 这个时候路由预处理(PREROUTING)之后的路由决策就会进入路由路由转发(FORWARD)线路
- 然后到最终经过路由决策到路由后处理(POSTROUTING)
- 路由后处理(POSTROUTING)这里十分重要,一般路由器就会在这里将源ip地址换成路由器自己的外网ip,这样内网机器就可以通过路由器上网了
- iptabels将这个操作称为SNAT,是可以通过命令简单配置下就能配好的
2.2 表和链介绍
- 链就是数据包传输过程中经过的各个链路,有5个,包括路由预处理,输入,输出,路由后处理,转发这五条链路
- 以上流程中还涉及到表(表是对功能的封装,例如filter专门用于防火墙),按照官方文档也有5张表
- filter 配置防火墙的规则
- nat 配置转发包的规则
- raw(不常用) 用来标记包让免于系统跟踪
- mangle(不常用) 用于对特定数据包的修改
- security(不常用) 用于访问控制。
其实linux中包处理流程要更复杂,会涉及到到这五张表,他们在其链路上都有所控制,只不过上述画的流程图被简化掉了
- 表能控制的链路关系如下 (了解就行)
表名/链名 | raw | filter | nat | mangle | security |
---|---|---|---|---|---|
PREROUTING | √ | √ | √ | ||
INPUT | √ | √ | √ | √ | |
OUTPUT | √ | √ | √ | √ | √ |
POSTROUTING | √ | √ | |||
FORWARD | √ | √ | √ |
3. 命令示例
执行命令是首先要明确
- 在哪张表上执行(因为表是功能的封装,像filter专门配置防火墙接收拒绝某种包的)
- 在哪个链路上进行增/删/改/查
- 指定要处理的哪些数据包(例如可以指定来自哪块网卡,源/目的ip,协议,源/目的端口等等信息)
- 所要执行的动作(例如防火墙常见动作接受/丢弃,或者nat表的修改源/目的ip等等)
3.1 基本示例
- 参数
- -t 指定表名 (不指定默认是filter表)
- 对链路处理的基本增删改查参数
- -A/-I 指定链路名 (在这个链路上追加/插入规则)
- 当在一个链路上保存多条规则时,会从上之下执行,匹配到了合适之后则不再往下匹配
- -A 就会追加在所有的规则之后
- -I 直接插入在规则的首位
- -D 指定链路名 (删除链路上的规则)
- 如果需要通过下标删除, 下标从1开始
- -L 指定链路名 列出在这个链路上所有规则(不指定则列出所有链路)
- -R 替换之前的规则
- 测试命令如下
- 以下命令均在Linux主机上测试通过
# 查询 filter 表上所有链路的保存的规则
sudo iptables -t filter -L
# 查询 filter 表上INPUT链路保存的规则
sudo iptables -t filter -L INPUT
# -D 既支持后面接复杂的规则来指定, 也可以根据下标来删除
# 删除 filter上 INPUT 链路上的首个规则
sudo iptables -t filter -D INPUT 1
3.2 防火墙简单示例
一般来说可以ip和tcp/udp协议等常见数据如下:
- -s 指定ip或者网段
- -p 指定协议
- –sport / --dport 指定源端口或者目的端口
- -j 指定行为, 可以指定 ACCEPT/DRP
例如我的网卡eth0的ip是192.168.1.10
# 拒绝来自 192.168.1.224/28 网段所有主机的请求
sudo iptables -t filter -A INPUT -s 192.168.1.224/28 -j DROP
# 这个时候处于这个网段下的所有主机的所有请求都无法发送进行, 例如 ping 也无法进入
# 当然了如果我们想对于在这个网段下的 192.168.1.238 主机正常访问,可以将这个规则插入首位
sudo iptables -t filter -I INPUT -s 192.168.1.238 -j ACCEPT
# 这样它先匹配到这个ip后就可以通过了, 而这个网段下的气他主机不能访问本主机
3.3 转发示例
3.3.1 内核参数修改
这里需要修改两个参数
# 修改 /etc/sysctl.conf 文件, 往这个文件中添加内容
# 这个文件用来修改内核参数
# 添加支持转发的参数, 因为Linux内核默认是不允许转发的 (必须要配置!!!!)
net.ipv4.ip_forward = 1
# 想把一些数据包转发的到本地回环接口, 就需要配置这个参数 (可选配置)
net.ipv4.conf.all.route_localnet = 1
# 修改完成之后执行如下命令重新加载内核参数
sudo sysctl -p
3.3.2 网关示例
- 假如自己是网关, 将所有数据包伪装成自己出去的发送的
- 假设自己的ip是 192.168.1.1, 管理的网段是 192.168.1.0/24网段
- 只需要将所有数据包转换成自己ip
# 以下命令就可以做到将 管理网段的主机内伪装成自己发送的数据包发到外网
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 192.168.1.1
# 有时候不知道自己的ip, 或者自己的ip地址可能会变动, SNAT有个进阶版的参数名为 MASQUERADE
# 它就是来做SANT的,并且自己根据本机的ip做转换, 不需要自己指定 (推荐使用), 效果上和前一条命令一模一样
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
3.3.3 端口转发示例
- 假设本机192.168.1.1能访问外网,有台内网机器A 192.168.1.10 不能访问到外网
- 假设有个外网ip是 123.45.67.89, 它有个22端口开启了ssh服务
- 本机可以将自己的 28122端口转发到 123.45.67.89 的22号端口
- 这样机器A可以直接通过访问 本机的28122端口直接访问到外网主机的端口
- 实现方案
- 在路由预处理(PREROUTGIN)里, 将对自己的 28122 端口的数据包的目的ip修改成123.45.67.89和22端口
- 在路由后处理(POSTROUTING)里, 再将出口对外时需要将ip转换成本机的ip
# 路由预处理
sudo iptables -t nat -A PREROUTING -p tcp --dport 28122 -j DNAT --to-destination 123.45.67.89:22
# 路由后处理
sudo iptables -t nat -A POSTROUTING -s 192.168.1.10 -j MASQUERADE
4. 杂谈
4.1 iptables与抓包软件的流程先后
以抓包软件tcpdump来做的测试
- 结论
- 简而言之, 抓包软件是直接在网卡上面获取的包,只要流入网卡的包就能捕获
- 但也同时, 没有流入到网卡的包也就捕获不到, 例如在内核或者上层应用丢弃了的没有流入到网卡的包
- 可表示像如图
- 所以会有些奇怪的现象,例如设置了防火墙阻止了某个ip数据网络,但是抓包却能够抓到
4.2 与ssh端口转发区别
- iptables是通过Linux内核来进行数据包的过滤转发处理,并且使用过程中可能会修改内核参数
- 但是ssh端口转发配置成功后,发现iptables并没有增加额外的配置项,这一点其实看起来会比较奇怪
- 实际上,ssh这种端口转发完全是用户态实现的,简单而言
- 配置了iptables了相当于命令Linux内核去做一些事
- 在用户态相当于就是上层应用处理,即这些事不交给Linux内核来做这件事,将包数据给ssh这种上层应用进行一些端口转发等的处理