iptables 是 Linux 系统上的一个防火墙工具,它可以通过过滤和转发数据包来实现防火墙的功能。
流量转发
1
2
3
4
5
6
7
8
$ sudo sysctl -w net.ipv4.ip_forward=1
$ sudo sysctl -p
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 4003 -j DNAT --to-destination 10.233.244.0:3307
# 添加内置的规则, 让返回的流量 ip 替换成原来的 ip, 用于在数据包离开本机时进行源地址的伪装(Masquerading),特别适用于动态 IP 地址的环境。
$ sudo iptables -t nat -A POSTROUTING -j MASQUERADE
# 添加防火墙规则
$ sudo firewall-cmd --zone=public --add-port=4003/tcp --permanent
$ sudo firewall-cmd --reload
iptables 匹配是从上至下的, 如果匹配, 则停止向下匹配, 这对于使用 -I 和 -A 来添加规则是有很大区别的
iptables -n nat -nL 和 iptables -n nat -L 有 DNS 解析上的区别, 不加 n 的指令, 在显示时会很慢
1
2
3
4
5
6
7
iptables -ADC 指定链的规则 [-A 添加 -D 删除 -C 修改]
iptables -t nat -I PREROUTING 2 [新规则内容]
iptables -D chain rule num[option] 删除规则
iptables -LFZ 链名 [选项] 清空链
iptables -[NX] 指定链 N:添加链 X:删除链
iptables -P [chain] [target][options] iptables -P FORWARD DROP
iptables -E old-chain-name new-chain-name
iptables
iptables -> tables -> chains -> rules
iptables 有五张表: filter、nat、mangle、raw、security, filter 是我们常用的表, 也是默认的操作表, 其内的 INPUT 和 OUTPUT 是常用链
每张表都有本身的作用, 比如 nat 用作地址转换用, 其中的链的生命周期也和 NAT 相关 比如 INPUT、OUTPUT、FORWARD、PREROUTING 和 POSTROUTING
1
$ iptables -t nat -nL | grep Chain
自定义的链, 必须被内置链引用才可生效, 具体要被哪条链引用, 取决于当前自定义的链要在请求的哪个阶段被使用, 比如想在出站时使用
1
2
3
$ iptables -N OUTBOUND_RULES
$ iptables -A OUTBOUND_RULES -d [目标IP] -p tcp --dport [目标端口] -j ACCEPT
$ iptables -A OUTPUT -j OUTBOUND_RULES
保存 iptables 的配置
1
$ iptables-save > /etc/iptables/rules.v4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 在 INPUT 链中添加 网卡 eth0 tcp 协议 22 端口的规则为放行
$ iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT
# 在 INPUT 中添加丢弃其他包, 应放在 INPUT 最后一条
$ iptables -A INPUT -j DROP
# 查看所有链的 rules, 并显示行号
$ iptables -L --line-numbers
# 删除 docker 第一行规则, 这时第二行会变成第一行
$ iptables -D DOCKER 1
# 精确删除规则
$ iptables -D DOCKER -s ${ip} -p tcp --dport 5432 -j ACCEPT
# 清空规则
$ iptables -F
# 保存规则
$ iptables-save > /path/to/file
# 加载规则
$ iptables-restore < /path/to/file
# 允许拒绝 链所有流量
$ iptables -P <chain_name> ACCEPT | DROP
# 添加链
$ iptables -t filter -N <chain_name>
# 端口映射
$ iptables -t nat -A PREROUTING -i [接口名称] -p [协议] --dport [目标端口] -j DNAT --to-destination [目标IP]:[目标端口]
docker 会自动维护 iptables 规则, 名字是 DOCKER 的链, 对于端口映射的规则, 会在 DOCKER 链中添加规则
iptables 的规则会在 docker 重启之后重新生成, 并且覆盖 firewall 的规则
如果需要对指定的端口添加规则, 则需要使用 -I 来添加单独的规则
1
2
3
4
5
6
7
# 执行顺序不能乱, 否则会导致5432的拒绝规则在第一位
# 其他的 ip 禁止访问 5432:5432 可以简化成 5432 他是个区间范围
$ sudo iptables -I DOCKER -p tcp --dport 5432:5432 -j DROP
# 向 docker第一行添加 5432 只允许 99 访问
$ iptables -I DOCKER -p tcp --dport 5432 -s 192.168.99.99 -j ACCEPT
脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/bash
ips="
192.168.99.99
192.168.104.3
192.168.3.123
"
function init() {
iptables -I DOCKER -p tcp --dport 5432 -j DROP
iptables -I DOCKER -p udp --dport 5432 -j DROP
for ip in ${ips}
do
iptables -I DOCKER -s ${ip} -p tcp --dport 5432 -j ACCEPT
iptables -I DOCKER -s ${ip} -p udp --dport 5432 -j ACCEPT
done
}
function del() {
iptables -D DOCKER -p tcp --dport 5432 -j DROP
iptables -D DOCKER -p udp --dport 5432 -j DROP
for ip in ${ips}
do
iptables -D DOCKER -s ${ip} -p tcp --dport 5432 -j ACCEPT
iptables -D DOCKER -s ${ip} -p udp --dport 5432 -j ACCEPT
done
}
if [ "$1" == "init" ]; then
echo '正在初始化...'
init
elif [ "$1" == "del" ]; then
echo '正在删除...'
del
else
echo "Usage: $0 [init|del]"
fi
端口映射
需要将外网访问本地IP(192.168.75.5)的80端口转换为访问192.168.75.3的8000端口,这就需要用到iptables的端口映射
实现:
需要先开启linux的数据转发功能
1
2
$ vi /etc/sysctl.conf,将net.ipv4.ip_forward=0更改为net.ipv4.ip_forward=1
$ sysctl -p //使数据转发功能生效
更改iptables,使之实现nat映射功能
1
2
3
4
#将外网访问192.168.75.5的80端口转发到192.168.75.3:8000端口。
# iptables -t nat -A PREROUTING -d 192.168.75.5 -p tcp --dport 80 -j DNAT --to-destination 192.168.75.3:8000
#将192.168.75.3 8000端口将数据返回给客户端时,将源ip改为192.168.75.5
# iptables -t nat -A POSTROUTING -d 192.168.75.3 -p tcp --dport 8000 -j SNAT --to 192.168.75.5
查看nat,可以使用命令:iptables -t nat –list检查nat列表信息
以上是针对从一台机到另一台机的端口转发,如果要针对本机进行端口转发,就需要按如下操作:
1
2
3
4
5
6
# 将外网访问80端口的数据转发到8080端口
$ iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
# 将本机访问80端口的转发到本机8080
$ iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport 80 -j DNAT --to 127.0.0.1:8080
$ iptables -t nat -A OUTPUT -p tcp -d 192.168.4.177 --dport 80 -j DNAT --to 127.0.0.1:8080
本地连接指的是在本机上,用 127.0.0.1 或者本机 IP 来访问本机的端口。本地连接的数据包不会通过网卡,而是由内核处理后直接发给本地进程。 这种数据包在 iptables 中只经过 OUTPUT 链,而不会经过 PREROUTING 链。所以需要在 OUTPUT 链中进行 DNAT。除了对 127.0.0.1 之外, 对本机 IP (即 192.168.4.177) 的访问也属于本地连接。