本章介绍一下IP数据包经过路由器的过程。

1. 路由器转发IP数据包

关于路由器转发IP数据包过程中MAC地址IP地址变与不变的问题,我们先给出如下结论:MAC地址在同一个广播域传输过程中是不变的,在跨越广播域的时候会发生改变;而IP地址在传输过程中是不会改变的(除NAT的时候)。

关于MAC与IP,我们还要知道:

  • MAC地址是用于同一物理或逻辑第2层网络上的设备间进行通信的;

  • IP地址是可以在多个网络设备之间通信的;

1.1 目的MAC地址是如何得到的?

TCP/IP里面采用ARP协议来获取MAC地址。比如新建了一个内网,如果一台机器A找机器B,封装FRAME时(OSI的第二层用的数据格式),要封装对方的MAC,开始时A不知道B的MAC地址,只知道IP,因此它就发送一个ARP包,源IP是自己的,目的IP是B的,源MAC是自己的,目的MAC是广播的。然后这个请求包在内网中被广播,当其他机器接收到这个包时,用目的IP和自己的IP进行比较,不是的话就丢弃。B接到时,发现IP与自己的一样,就应答这个包的请求,把自己的MAC发送给A。如果B是其他子网的机器,那么路由器会判断出B是其他子网,然后路由器把自己的MAC返回给A,A以后再给B发包时,目的MAC封装的是路由器的。

1.2 路由转发过程

当主机A发向主机B的数据流在网络层封装成IP数据包,IP数据包的首部包含了源地址和目标地址。主机A会用本机配置的24位IP网络掩码255.255.255.0与目标地址进行与运算,得出目标网络地址与本机的网络地址是不是在同一个网段中。如果不是就将IP数据包转发到网关。

在发往网关前主机A还会通过ARP的请求获得默认网关的MAC地址。在主机A数据链路层IP数据包封装成以太网数据帧,然后才发往到网关…,也就是路由器上的一个端口。

当网关路由器接收到以太网数据帧时,发现数据帧中的目标MAC地址是自己的某一个端口的物理地址,这时路由器会把以太网数据帧的封装去掉。路由器认为这个IP数据包是要通过自己进行转发,接着它就在匹配路由表。匹配到路由项后,它就将包发往下一跳地址。

路由器转发数据包就是这样,所以它始终是不会改IP地址的,只会更改MAC。

当有数据包传到路由器时,路由器首先将其目的地址与路由表进行对比,如果是本地网络,将不会进行转发到外网络,而是直接转发给本地网关内的目的主机;但是如果目的地址经路由表对比,发现不是在本网中,有NAT就将改变源地址的IP(原源地址的IP改为路由器的IP地址),路由器将数据包转发到相应的端口,进行通信。

1.3 案例分析

MAC地址是在同一个广播域有效的,那么去了另外一个广播域(网段)MAC地址肯定要改变的。

在同一个广播域中数据帧的mac地址是不会变的,因为所有交换机应该都知道该广播域中的所有主机的MAC地址(如果不知道,会通过被动广播的方式来学习到)。既然知道所有的MAC地址,那么当交换机收到数据帧的时候就看一下目标MAC地址,然后对照一下MAC地址表,从对应的接口发送出去即可。

IP地址是在整个网络中有效的,整个Internet网络就相当于是一个大的地图,同样知道所有的IP地址如何到达,那么在传输过程中源IP和目的IP也是不会改变的。当路由器接收到数据包的时候,检查数据包的目的IP地址,然后查找路由表(路由转发表),选择合适的接口发出去。

route-theory

上图中A-R4-R2-B假设有数据帧X,传输过程如下:

A到R4: MAC地址(存在的话)源地址是A,目的地址是R4;

R4到R2: MAC地址(存在的话)源地址是R4,目的地址是R2;

R2到B: MAC地址(存在的话)源地址是R2,目的地址是B; 

在没有经过NAT的情况下,源IP地址和目的IP地址在整个传输过程是不能改变的。

2. SNAT与DNAT

在LInux操作系统中,Netfilter组件是集成在Linux内核中扩展各种网络服务的结构化底层框架,在内核级提供防火墙功能。内核中选取五个位置放了五个hook(钩子) function(INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING),而这五个hook function向用户开放,用户可以通过一个命令工具(iptables)向其写入规则。

linux-netfilter

报文流向:

  • 流入本机:PREROUTING -> INPUT -> 用户进程空间

  • 流出本机: 用户进程空间 -> OUTPUT -> POSTROUTING

  • 转发: PREROUTING -> FORWARD -> POSTROUTING

内核中数据包的传输过程:

1) 当一个数据包进入网卡时,数据包首先进入PREROUTING链,内核根据数据包的目的IP判断是否需要转送出去;

2) 如果数据包就是进入本机的,数据包就会到达INPUT链。经过INPUT链检查后,数据包被发往本地进程。本地进程经过相应处理后发送响应数据包,数据包经过OUTPUT链,然后到达POSTROUTING链输出;如果数据包是要转发出去的,且内核允许转发,数据包就会向右移动,经过FORWARD链,然后到达POSTROUTING链输出。

企业内部的主机A若配置了一个公网地址6.6.6.6,访问互联网上其他网络的公有地址不受限制,但若访问互联网上同网段的地址(即6.0.0.0/8网段的地址),由于A的路由表就有到达该网段的路由记录,就直接访问了,不会去查询路由器,但是实际上访问的不是互联网上的主机,而是本地局域网的主机,也就是说该网段的所有公有地址A都将无法访问。所以企业内部的主机一般是私有地址,但是互联网上没有私有地址的路由,也就是说私有地址无法连接互联网,可以利用防火墙的NAT表(network address translation地址转换规则表)将私有地址转换为公有地址再去访问互联网。

2.1 SNAT

企业内部的主机A想访问互联网上的主机C,首先将请求数据包(源: ipA, 目标: ipC)发送到防火墙所在主机B,B收到后将数据包源地址改为本机公网网卡的ip(源: ipB,目标: ipC),然后经互联网发送给C;C收到后将回应包(源: IpC,目标: ipB)转发给C的路由器,经互联网将回应包转发给B,B收到回应包后修改其目的地址,即回应包改为(源: ipC,目标:ipA)然后将数据包转发给A。

在这个过程中,修改了请求报文的源地址,叫做SNAT(source NAT POSTROUTING),用于局域网访问互联网。

不能在防火墙B的prerouting链上设置转换源地址的防火墙策略,因为若在B的PREROUTING链上设置转换源地址的防火墙策略,此时还未检查路由表,还不知道要到达数据包中目标主机需经过本机的哪一个网卡接口,即还不知道需要将源地址替换为哪个公网网卡的IP,因此需要在POSTROUTING设置转换源地址的防火墙策略。

2.1.1 模拟实验

路由表介绍

在介绍具体的实验之前,我们先简单介绍一下路由表的一些知识:

每个主机都有路由表,具有基础的路由功能。假设某主机上有两张网卡:eth0的IP是192.168.1.100, eth1的IP是172.18.1.110,则该主机的路由表上就会有两条记录:

destination     gateway          netmask                  iface

192.168.1.0     0.0.0.0        255.255.255.0              eth0
172.18.0.0      0.0.0.0        255.255.0.0                eth1
0.0.0.0         172.18.0.112   255.255.0.0                eth1

上面路由表表示该主机可以到达192.168.25.0/24、172.18.0.0/16两个网络,网关为0.0.0.0也就是说怎么都可以到达,所以每台主机不需经过路由器就可以与和它同网段的主机通信。若该主机想和它不同网段的主机通信,需要添加路由记录,添加时可以不指定接口,该主机会自动使用与网关IP同网段的IP所在的网卡。

对于最后一行:

0.0.0.0         172.18.0.112   255.255.0.0                eth1

其含义为:到达任何未知网络时将数据包转发到网关,也就是路由器的某个网卡。其中网关IP必须是本机可以到达的某个网段的IP,即必须是192.168.1.0/24172.18.0.0/16这两个网段的IP。

路由器的路由表实际上也是类似,也有本机IP所在网段的路由和到其他网段的路由,只是在普通股主机的基础上启用了路由转发功能,普通主机收到目标主机不是自己的数据包后会抛弃,路由器收到目标主机不是自己的数据包后会检查路由表,将数据包转发出去,也就是说普通主机的路由表只能供自己发送数据包时使用,路由器的路由表是公用的。

实验步骤

接下来我们来模拟搭建一套“局域网-Linux网关-互联网”的环境,以验证:

  • 在Linux网关上配置SNAT策略,实现局域网主机的共享上网

  • 修改现有SNAT策略,验证MASQUERAD伪装的有效性

当前的实现环境为(本实验中用172.18.0.0/16网段模拟公网ip):

局域网主机A:192.168.25.106(黄色提示符,白色字)

防火墙B:eth0 192.168.25.107 eth1 172.18.0.107(绿色提示符,白色字)

互联网主机C:172.18.0.108(紫色提示符,白色字)

linux-network

本实验中,A是局域网主机,将数据包转发至防火墙主机B,B实际上也充当了路由器的作用。实际环境中,B与C之间会有多个路由器,本实验只是为了说明SNAT的工作原理,不再考虑这些因素。

1) 主机A

为了防止实验产生的其他干扰,我们执行如下命令关闭防火墙:

# service iptables stop

执行如下命令查看主机A的路由表:

# route -n

linux-route

2) 主机B

我们先执行如下命令清理主机B上的所有防火墙规则:

# iptables -F                 //清理所有规则

# iptables -vnL -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
           
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
          
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)  
 pkts bytes target     prot opt in     out     source               destination 

从上面我们可以看到,nat表共有4个链:INPUT、OUTPUT、PREROUTING、POSTROUTING

我们使用如下命令添加SNAT转换规则:

# iptables -t nat -A POSTROUTING -s 192.168.25.0/24 -o eth1 -j SNAT --to-source 172.18.0.107

下面先简单介绍一下各选项的含义:

  • -t: 指定防火墙rule应用哪个表

  • -A: 指定在哪个链上添加rule

  • --to-source: 指定转换后的source

上面命令的含义就是:将来自192.168.25.0/24网段的数据包的源地址替换为172.18.0.107。

此外,我们还需要在B主机上开启ip_forard,执行如下命令:

# vi /etc/sysctl.conf
net.ipv4.ip_forward = 1
# sysctl -p

3) 主机C

在主机C上直接先关闭防火墙,然后安装http服务:

# service iptables stop
# yum install nginx

4) 测试

在主机A上执行如下命令:

# curl -X GET http://172.18.0.108:80

这时我们看到:192.168.25.106通过172.18.0.107访问172.18.0.108成功了。

我们也可以在172.18.0.108上采用tcpdump抓包来进一步验证。

5) 验证MASQUERAD

此外,我们也可以使用MASQUERAD方式来实现主机A访问主机C。在主机B上:

# iptables -t nat -nL POSTROUTING
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT all – 192.168.25.0/24 0.0.0.0/0 to:172.18.0.7

上面是我们在第2)步设置的rule。下面我们先清理到该规则,并设置MASQUERAD:

# iptables -t nat -D POSTROUTING 1
# iptables -t nat -A POSTROUTING -s 192.168.25.0/24 -o eth1 -j MASQUERAD
# iptables -t nat -nL POSTROUTING
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all – 192.168.25.0/24 0.0.0.0/0

我们再次在主机A上测试,同样可以访问主机C。

2.2 DNAT

互联网主机C想访问企业内部的Web服务器A,但A的地址是私有地址,无法直接访问。此时,C可以访问防火墙的公有地址,C的请求数据包(源:ipC, 目标: ipB)到达防火墙B后,在B的PREROUTING上将请求数据包的目标地址进行修改,并将数据包(源:ipC,目标:ipA)发送给A。A收到后进行回复发送响应包(源: ipA, 目标:ipC)到防火墙,防火墙收到后对数据包源地址进行修改,并将响应(源:ipB,目标:ipC)给C。利用这种机制可以将企业内部的服务发布到互联网。

在这个过程中,修改了请求报文的目标地址,叫做DNAT(destination NAT),用于互联网访问局域网。必须在防火墙的PREROUTING上设置修改目标地址的防火墙策略,因为若不在此处修改,请求数据包通过PREROUTING和路由表后,由于目标主机是本机,就会将数据包发往INPUT,进而被发往本地进程。

实验步骤

接下来我们来模拟搭建一套“公网-防火墙-局域网”的环境,以验证公网对局域网的访问。当前的实现环境为(本实验中用172.18.0.0/16网段模拟公网ip):

局域网Web服务器A:192.168.25.106(黄色提示符,白色字)

防火墙B:eth0 192.168.25.107 eth1 172.18.0.107(绿色提示符,白色字)

互联网主机C:172.18.0.108(紫色提示符,白色字)

linux-network

1) 主机A

在主机A上我们关闭防火墙,然后安装nginx web服务:

# service iptables stop
# yum install nginx

然后在8000端口上启动nginx的http服务。

2) 主机B

主机B上添加如下防火墙策略:

# iptables -t nat -A PREROUTING -d 172.18.0.107 -p tcp --dport 80 -j DNAT --to-destination 192.168.25.106:8000

下面先简单介绍一下各选项的含义:

  • -t: 指定防火墙rule应用哪个表

  • -A: 指定在哪个链上添加rule

  • --to-destination: 指定转换后的目标地址和端口

上面命令的含义就是:当数据包的目标地址为172.18.0.107,目标端口为80,使用协议为tcp时,将数据包的目标地址修改为192.168.25.106:8000

3) 主机C

我们在主机C上执行如下命令测试:

# curl -X GET http://172.18.0.107:80

可以看到能够正常的访问到局域网中的A服务器上的http服务。

这里因为修改的是数据包的目标地址,并未修改源地址,所以192.168.25.106认为是172.18.0.108发起的请求,与SNAT不同



参考:

  1. 网络-数据包在路由转发过程中MAC地址和IP地址,变与不变

  2. ip数据包经由路由转发的时候源ip,目的ip是否改变

  3. SNAT与DNAT