已复制
全屏展示
复制代码

iptables 场景还原与实战配置


· 11 min read

一. 基本原理总结

1.1 常用的几个链

  • PREROUTING(nat)
    路由之前操作,用作DNAT 、REDIRECT。 只支持 -i, 不支持 -o。在作出路由之前,对目的地址进行修改
  • INPUT(filter)
    通常对 进入本机 数据进行过滤。
  • OUTPUT(nat、filter)
    影响 本机出的 数据。常用作DNAT 、REDIRECT。 DNAT和REDIRECT规则用来处理来自NAT主机本身生成的出站数据包.
  • FORWARD(filter)
    对转发的数据进行 过滤 (通过、拒绝)。
  • POSTROUTING(nat)
    路由之后修改。只支持-o,不支持-i。在作出路由之后,对源地址进行修改。

1.2 常用的几个表

  • filter    对数据包的是否通行做出判断。
  • nat       用于对数据进行地址转换(源地址、目的地址),即修改数据包的源地址、目的地址。

1.3 常用的几个处理动作

DROP       # 丢弃(不返回信息)
REJECT     # 拒绝(返回拒绝信息)
ACCEPT     # 允许
DNAT       # 目标地址转换  --to-dest  IP  或者 IP:port
SNAT       # 源地址转换  --to-source  IP  或者 IP:port
REDIRECT   # 本机端口重定向 --to-port  port
MASQUERADE # 地址伪装

1.4 常用检查模式

-s      ip      # 检查包的源ip
-d      ip      # 检查包的目的ip
-p      tcp     # 指定协议
--dport  80     # 目的端口
--sport  80     # 源端口
-i  eth0        # 从 eth0 接收的
-o  eth1        # 从 eth1 发送的
! -s  192.168.0.1/24     # 某个网段取反

1.5 开启转发配置

  • CentOS 6 /etc/sysctl.conf  配置 net.ipv4.ip_forward = 1
  • CentOS 7 /usr/lib/sysctl.d/50-default.conf 配置 net.ipv4.ip_forward = 1

二. 本机端口到本机端口重定向

2.1 场景还原

本机开启http服务端口为 8000,为了不使 8000 端口向外界暴露,现在想对外只提供 80 端口。 访问本机的 80 端口,就相当于访问本机的 8000 端口。

2.2 细节实现

为了实现端口重定向,需要在进入本机前进行目标地址的修改,即改目标端口,目标IP不变。要用到 nat 表、 PREROUTING 链、开启转发规则。

sed -i '/net.ipv4.ip_forward/c net.ipv4.ip_forward\ =\ 1' /etc/sysctl.conf
sysctl -p

iptables -t nat -I PREROUTING -p tcp --dport 80 -i eth0 -j REDIRECT --to-port 8000
iptables -I INPUT -i eth0 -p tcp --dport 8000 -j ACCEPT

现在访问该机器的 80 端口就会自动导向到 8000 端口了。

三. 公网 IP 到 局域网的 IP 映射

3.1 场景还原

现在只有一个公网 IP, 这个公网 IP 对应的机器还有一个内网网段,这个网段内有很多的内网机器(没有公网 IP)。现在想通过这个公网 IP 访问到那些内网机器的服务。

3.2 细节实现

为了实现公网到内网的访问,需要使用目标地址转换 DNAT,将目的地址改成内网IP。 同时为了让 client 能识别服务器的IP地址,需要使用源地址转换 SNAT,将源地址改成公网 IP 地址。

下面是使用 DNAT 实现远程 ssh 的内网主机登录,即从拥有公网IP的server1 上 登录没有公网IP的 server2 。

  • server1(跳板机) 公网IP 10.16.80.213:9100,内网IP 192.168.47.10
  • server2(目标机) 内网IP 192.168.47.20:22

在server1 上做如下配置

iptables -t nat -I PREROUTING -d 10.16.80.213/32 -p tcp --dport 9100 -j DNAT --to-dest 192.168.47.20:22
iptables -t nat -I POSTROUTING -d 192.168.47.20/32 -p tcp --dport 22 -j SNAT --to-source 192.168.47.10

iptables -I FORWARD -d 192.168.47.20/32 -p tcp --dport 22 -j ACCEPT
iptables -I FORWARD -s 192.168.47.20/32  -j ACCEPT

echo 1 > /proc/sys/net/ipv4/ip_forward

其实上面的 SNAT 可以换成 MASQUERADE, 即 iptables -t nat -I POSTROUTING -d 192.168.47.20/32 -p tcp --dport 22 -j SNAT --to-source 192.168.47.10 换成 iptables -t nat -I POSTROUTING -d 192.168.47.20/32 -p tcp --dport 22 -j MASQUERADE

数据流向:外网Internet ---> server1(公网) 10.16.80.213 ---> server1(内网) 192.168.47.10 ---> server2(内网) 192.168.47.20

四. 局域网通过一个公网IP上网

4.1 场景还原

现在局域网有一批机器,在同一个网段,但是都没有公网IP。 现在运营商提供了一台有公网IP的机器。现在想通过这个公网IP为内网的机器做转发,实现内网没有公网IP的机器也可以上网。

4.2 细节实现

为了实现内网机器上网,可以在有公网IP的机器上,使用 iptables 的 SNAT 功能,为局域网的机器做转发。 SNAT 的作用是把内网发出的 IP 数据包的源地址修改为那个公网IP地址。

  • server1(有公网) 公网IP 10.16.80.213,内网IP 192.168.47.10
  • server2(无公网) 内网IP 192.168.47.20

在server1 上做如下配置


iptables -t nat -I POSTROUTING -s 192.168.47.0/24 -j SNAT --to-source 10.16.80.213

iptables -I FORWARD -s 192.168.47.0/24 -j ACCEPT
iptables -I FORWARD -d 192.168.47.0/24 -j ACCEPT

echo 1 > /proc/sys/net/ipv4/ip_forward

五. VPN 拨号方法

5.1 场景还原

现在想在 Linux 上拨 pptp协议的 VPN 服务器, 拨号成功后需要正确配置路由才能使用拨号的VPN上网。这里需要使用到 策略路由 来实现。

5.2 路由简介

Linux 上路由分为两类:缓存路由、策略路由。

  • 缓存路由
    缓存路由是自动学习获取的,用户无法干预它的配置项。
  • 策略路由
    在 Linux 系统上存在着很多路由表,每个路由表中都会记录一些路由走向,这些路由基于 源地址 进行寻址。CentOS 默认使用了三个路由表:0、254、255(local、main、default),系统默认使用的路由表示 main , 平时我们配置的路由也是在这个 main 表中配置。

5.3 细节实现

5.3a 连接VPN服务器

首先创建VPN连接、启动VPN的pppd。

yum install pptp-setup pptp ppp -y
pptpsetup --create hk --server vpnserver --user root --password 123456 --encrypt
pppd call hk
ip add

5.3b 配置自定义管理路由表

为了配置默认路由后还可以通过 ssh 远程连接到服务器,所以需要配置一个优先级更高(比 main 优先级高)的策略路由表,将其命名为 guanli。将远程登录使用的路由配置在 guanli 路由表中。

  • 公网IP 1.1.1.1
  • 私网IP 172.16.252.22
  • 网关IP 172.16.252.254
echo "250    guanli" >> /etc/iproute2/rt_tables  
ip rule add from 172.16.25.22 table guanli
ip route add default via 172.16.25.254 table guanli

然后将必要的解析走原来的网关。

ip route add 8.8.8.8 via 172.16.25.254 table guanli
ip route add 114.114.114.114 via 172.16.25.254 table guanli

5.3c 配置 main 默认策略路由

查看拨号成功后对端的IP是什么。

# ip addr 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:89:b5:db brd ff:ff:ff:ff:ff:ff
    inet 10.16.80.213/24 brd 10.16.80.255 scope global eth0
    inet6 fe80::20c:29ff:fe89:b5db/64 scope link 
       valid_lft forever preferred_lft forever
3: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1496 qdisc pfifo_fast state UNKNOWN qlen 3
    link/ppp 
    inet 192.168.0.234 peer 192.168.0.1/32 scope global ppp0

根据获得的对端IP,配置默认路由,然后查看是否成功。

ip route replace default via 192.168.0.1 
curl "http://ip.chinaz.com/getip.aspx"

注意: 上面测试在阿里云主机上测试成功。如果服务器在内网,则不需要自定义一个管理策略路由,拨号成功后,直接修改默认路由为拨号的即可。

六. 为一批客户端提供VPN拨号

6.1 场景还原

现在有一台 Linux 服务器能上网, 同时能拨多个VPN账号。现在有一批手机与这台服务器在同一个网段,现在想通过这台 Linux 拨号,让这些手机通过这个拨号IP出网,实现手机出网更换IP的功能。

6.2 细节实现

为了可以拨号上网,需要根据源地址配置路由策略。在Linux服务器上,为每一台手机分配一个策略路由表。然后配置每个手机的路由分别走这些路由表,最后给这些路由表配置已拨号成功的对端VPN的IP地址及设备地址。

  • 内网网段
    10.16.80.0/24、
  • 内网网关
    10.16.80.1
  • Linux 服务地址
    10.16.80.250
  • 手机IP列表
    10.16.80.11
    10.16.80.12
    10.16.80.13

6.2a 拨多个VPN账号

在服务器上创建VPN连接,然后拨上。拨成功后会得到产生的虚拟设备信息比如 ppp0、ppp1、ppp2等。

# ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:89:b5:db brd ff:ff:ff:ff:ff:ff
    inet 10.16.80.213/24 brd 10.16.80.255 scope global eth0
    inet6 fe80::20c:29ff:fe89:b5db/64 scope link 
       valid_lft forever preferred_lft forever
3: ppp0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1496 qdisc pfifo_fast state UNKNOWN qlen 3
    link/ppp 
    inet 192.168.0.237 peer 192.168.3.1/32 scope global ppp0
4: ppp1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1496 qdisc pfifo_fast state UNKNOWN qlen 3
    link/ppp 
    inet 192.168.0.233 peer 192.168.0.1/32 scope global ppp1
5: ppp2: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1496 qdisc pfifo_fast state UNKNOWN qlen 3
    link/ppp 
    inet 192.168.0.234 peer 192.168.0.6/32 scope global ppp2

6.2b 设置策略路由表

下面新增了5个路由表,但是现在路由表还没有内容为空的。

#
# reserved values
#
255     local
254     main
253     default
0       unspec
#
# local
#
#1      inr.ruhep
1       rt1
2       rt2
3       rt3
# 命令行添加三个手机到不同的策略路由

ip rule add from 10.16.80.11 table rt1
ip rule add from 10.16.80.12 table rt2
ip rule add from 10.16.80.13 table rt3

6.2c 配置每个策略路由表默认路由

现在每台手机已经配置进行策略路由里面了,但是策略路由里面还没有默认路由,有了默认路由手机才可以根据默认路由走拨号VPN。

ip route add default via  192.168.3.1 dev ppp0 table rt1
ip route add default via  192.168.0.1 dev ppp1 table rt2
ip route add default via  192.168.0.6 dev ppp2 table rt3

# 同时如果需要访问内网的某一台机器,需要添加指定的路由,比如要访问 内网机器 10.16.80.20
ip route add 10.16.80.20 via 10.16.80.1 dev eth0 table rt1
ip route add 10.16.80.20 via 10.16.80.1 dev eth0 table rt2
ip route add 10.16.80.20 via 10.16.80.1 dev eth0 table rt3

6.2d 配置iptables允许转发、masquerade配置

因为Linux服务器为手机做转发,需要修改数据包源地址为拨号公网IP地址。而拨号的对端地址可能是变化的,所以要采用MASQUERADE 来动态获取对端地址。

echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -t nat -I POSTROUTING -o ppp1 -j MASQUERADE
iptables -t nat -I POSTROUTING -o ppp1 -j MASQUERADE
iptables -t nat -I POSTROUTING -o ppp2 -j MASQUERADE

上面的iptables命令可以用这一条命令来代替 iptables -t nat -I POSTROUTING -o ppp+ -j MASQUERADE

注意:因为Linux服务器和手机在同一个网段,当VPN拨号不成功时,Linux服务器会给手机通过正常的网关(10.16.80.1)上网,为了防止这种情况发生,可以增加iptables规则,使得如果该手机对于的vpn账号拨号不成功,则拒绝为其转发。添加下面命令后,如果VPN账号拨号不成功,则无法访问外网。 第一条是允许访问内网、第二条是不允许走内网网关。

iptables -I FORWARD -d 10.16.80.20 -o eth0 -j ACCEPT
iptables -I FORWARD -s 10.16.80.0/24 -o eth0 -j REJECT
🔗

文章推荐