Linux NAT软路由的简介、入门与配置

2023-11-20

在文章NAT网络地址转换技术入门到详解中,我们介绍了NAT的原理,NAT的分类,以及每种类型的NAT的功能。
netfilter/iptables是用来实现NAT的内核软件和用户配置工具软件。本文中我们会来详细描述如何使用iptables配置和实现NAT。

1、确认Linux kernel内核版本

通常的Linux发行版都已经自带了netfilter和iptables这二个软件和其它NAT需要用到的其它内核模块(比如连接跟踪,IP转发等内核功能模块),所以通常只要拿来直接使用就可以了,我们并不需要对Linux内核做出编译与修改。如果你需要自己编译Linux kernal,可以参照HowTo on compiling Linux 2.4 and 2.6 kernels 这本书(你可以在这个网页找到这本书http://www.digitalhermit.com/linux/Kernel-Build-HOWTO.html)。

2、netfilter的nat table简介

我们已经知道netfilter框架里,包含了所谓的4表5链,这里我们会需要使用4表里的nat table来实现NAT功能。nat table 包含了4个链—PREROUTING, INPUT, POSTROUTING和OUTPUT。每个链都包含多条规则rules,一个报文会被按照顺序进行匹配,直到命中某条规则。我们可以用命令sudo iptables –t nat –L查到nat表格里的这些链。

xxx@raspberrypi:~ $ sudo iptables -t nat -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

本文中不使用OUTPUT chain和INPUT chain,PREROUTING和POSTROUTING chains的名字就表明了他们的用途。在报文进入Linux后,Linux内核根据路由表做出路由决定前,去检查 PREROUTING chain里的规则,因此所以我们可以使用PREROUTING chain去改变报文的目标IP地址,然后让下一步让的路由表去根据新的目标IP地址决定如何处理报文(DNAT)。在Linux内核对某个报文根据路由表做出转发决定后,下一步会根据POSTROUTING chain中规则进行处理,这意味着在这里,我们可以改变要发送出去的报文的源IP地址(SNAT)。
在这里插入图片描述

注意:这里和报文从哪个网口进,哪个网口出没有关系,所有进入Linux的的非上送给Linux本机而是需要被转发的报文都会经过这条路径进行处理。

上图表示了 DNAT和SNAT是如何工作的。
DNAT意味着修改报文的目标IP地址,所以Linux内核必须在根据报文的目标IP地址查找路由表并决定如何转发IP报文前完成目标IP地址的修改 (所以由PREROUTING chain完成)。例如:如果我们要为一个私网服务器192.168.1.3做DNAT,那么当Linux路由器的从公网收到IP报文时,它需要收到的IP报文的目标IP地址成192.168.1.3,然后再交给Linux内核做路由查找和转发决定:

router:~# route -n
Kernel IP routing table
Destination 	Gateway	Genmask				Flags 	Metric 		Ref		Use Iface
192.168.1.0 	0.0.0.0	255.255.255.0		U		0			0		0 	eth1

Linux内核发现192.168.1.0/24网络是直接连接在Eth1网卡上的,所以它会直接将报文从Eth1发送给192.168.1.3。

SNAT 意味着修改了IP报文的源IP地址。 让我们考虑一下IP伪装Masquerade是怎么工作,这会有助于我们的理解。一个从192.168.1.3发出来的报文想要访问外网。

  • Linux内核会查找路由表,如果这个报文需要多某个接口发出去,那个就会修改报文的源IP地址成这个接口的IP地址。
  • 如果没有找到这个报文的命中的路由表项,就会路由到默认路由去,然后就会把报文的源IP地址修改成默认路由指向的那个接口。

在NAT table的末尾添加,插入,或者删除规则的命令的语法都非常类似:

  • Append在末尾添加: iptables –t nat –A
  • Insert插入到最前面: iptables –t nat –I
  • Delete删除: iptables –t nat –D
  • Delete all删除所有: iptables –t nat –F

这里 应该是PREROUTING, POSTROUTING, INPUT或者OUTPUT,替换成真正的规则。

注意:iptables –F 命令是删除了默认table, filter table里的所有chain的所有规则,如果你要删除nat table里的规则,需要用-t来指定table。

3、用iptables实现SNAT

SNAT是几种NAT技术里最常用的类型。以以下例子为例进行说明:
192.168.1.0/24是我们办公室的私网的网段。我们可以通过1.2.3.1/30这个IP访问外网,默认网关是1.2.3.2.
所有内网主机的默认网关是192.168.1.1。
在这里插入图片描述我们可以看到Linux router有二个以太网口:

  • Eth0, IP地址是192.168.1.1(掩码255.255.255.0),这个网口通过交换机连接到私网192.168.1.0/24网络上。
  • Eth1, IP地址是1.2.3.1(掩码255.255.255.252),连接到外网上
    我们可以用以下一条规则就为私网192.168.1.0/24里的所有设备都建立SNAT,并使得私网内的所有设备都可以访问外网:
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 1.2.3.1

这条命令的作用和下面这条命令的作用是一样的,但使用下面这条IP伪装的命令,我们可以支持Eth1的动态的IP地址,而不需要像上面那条命令一样指定外网的IP地址(注意IP伪装Masquerade是用指定路由出口网卡的IP地址来替换源地址,所以它能支持动态的获取出口网卡的IP地址来替代):

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE

假如我们的网络供应商说只有1024以下的端口可以被使用,那么我们除了修改源IP地址网还需要修改源端口,这个SNAT的规则也是可以用于修改端口的,如下所示将报文的源端口修改成1-1024之间未使用的端口号:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 1.2.3.1:1-1024

注意,如果么网里的笔记本电脑用户想要上IRC或者FTP的话,那么还需要针对ip_conntrack打上ip_conntrack_
irc和ip_conntrack_ftp 模块才行,原因在于NAT只工作在IP层,但IPC和FTP这种协议在用户层也带有IP地址的信息,所有需要额外的功能模块来处理用户层的IP信息替换工作。

modprobe ip_conntrack_irc
modprobe ip_conntrack_ftp
#或者
insmod ip_conntrack_irc
insmod ip_conntrack_ftp

以下我们通过几个例子来学习一下SNAT的一些进阶的设置,以解决SNAT中常见的一些问题:

3.1、 多对多(N:N)的SNAT

IRC网络的服务端是限制来自同一个IP的客户端连接数量的,意味着当私网内的多个主机都使用SNAT去访问IRC服务器时,IRC服务器会检测到来自于同一个IP(1.2.3.1)的客户端连接数量超出了上限,那到超出后IRC服务器就会拒绝连接。此时我们可以通过增加公网IP的数量,并将私网IP地址SNAT到不同的公网IP地址的方式来减少以每个公网IP地址为源IP地址的IRC连接数量。当我们拿到额外的1.2.4.0/27子网里的所有公网IP地址后,我们将SNAT规则修改如下:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 1.2.4.0-1.2.4.32

这样就解决了问题,但这样的命令的话,就使1.2.3.1这个公网IP没有被加到SNAT的IP池里,没有利用起这个公网IP地址,所以修改上述命令如下:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 1.2.4.0-1.2.4.32 --to 1.2.3.1

3.2、 将一个网段内的某个公网IP移除出SNAT可用的公有IP地址池

比如我们需要将1.2.4.15从可用的公网IP地址池中移除,那么我们可以使用以下命令

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j SNAT --to 1.2.4.0-1.2.4.14 --to 1.2.4.16-1.2.4.32 --to 1.2.3.1

3.3、 设置目标地址为特定IP地址或者网段的报文不做NAT

这个通常可以用做二个用途:

  • 防止私网用户修改网络配置后,将内网的访问报文转发到Linux router来后被Linux router误做SNAT而导致私网内的主机之间不可连接。

比如私网内的192.168.1.19主机,把自己的网络掩码从192.168.1.0/24改成了192.168.1.0/27意味着,192.168.1.19这个主机认为只有192.168.1.1-192.168.1.31这些IP地址和它是在同一个子网下的,所以当它去访问192.168.1.32这个IP地址时,它会先把报文发给它的默认网关192.168.1.1即Linux Router, 然后在没有配置SNAT时Linux Router会根据路由表将这个报文再转发给192.168.1.32这个主机,但此时设置了SNAT功能,所以Linux Router会把来自己192.168.1.19的所有报文的源地址都先修改成1.2.3.1或者其它公网IP后再把报文发给192.168.1.32,当192.168.1.32发回响应报文时就报影应报文发给了1.2.3.1,这个报文就回不到192.168.1.19了,所以导致192.168.1.19和192.168.1.32之间网络不通。我们用以下命令来解决这个问题,不对目标地址为192.168.1.0/24网段内的所有报文做SNAT功能。

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d ! 192.168.1.0/24 -j SNAT --to 1.2.4.0-1.2.4.32 --to 1.2.3.1

或者用-o eth1指定只对从Eth1发送出去的报文做SNAT:

iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.4.0-1.2.4.32 --to 1.2.3.1
  • 禁止私网内的用户访问某些公网的服务器(比如不对目标地址为1.3.3.0网段下的主机IP地址的报文做SNAT)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d ! 1.3.3.0/24 -j SNAT --to 1.2.4.0-1.2.4.32 --to 1.2.3.1
  • 局域网内二个不同网段的服务器之间的报文不做SNAT
    假设我们的私网内有二个网段192.168.1.0/24和192.168.2.0/24,二个网段都被连接到了Linux Router,那么需要添加如下的规则,避免对二个网段之间互相访问的报文被SNAT
iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -d 192.168.2.0/24 -j ACCEPT
iptables -t nat -I POSTROUTING -s 192.168.2.0/24 -d 192.168.1.0/24 -j ACCEPT

这二个命令会在NAT规则前插入这二个规则(其实-I会把当前规则插入到所有已经存在的规则的前面),当192.168.2.0/24和192.168.1.0/24之间相互通信时,报文会先分析并命中这二条规则,命中后就不会再分析后面的规则了,所以就不会发生SNAT。

3.4、通过端口号,设置允许或者禁止SNAT特定的协议

  • 黑名单制度
    假设领导不希望让特定员工访问IRC,我们知道IRC的服务器是工作在6666-6669端口的,所以我们只要把从这个员工的电脑的IP地址发出来去访问目标主机的6666-6669端口的报文全部丢弃则可,则可以插入如下规则实现:
iptables -t nat -I POSTROUTING -s 192.168.1.31 -p tcp --dport 6666:6669 -j DROP
  • 半白名单制度
    或者是只允许访问特定端口,比如某员工只允许他访问网页,其它协议服务都不可用,则我们可以只允许他访问TCP的80端口,其它数据一律丢弃:
iptables -t nat -I POSTROUTING -s 192.168.1.31 -p tcp --dport ! 80 -j DROP  

注意,这个不等同于白名单制度,这里丢弃的是非80端口的TCP协议,但UDP协议的通信依然是可以进行。

  • 白名单制度
    如果要做成白名单制度,需要在一条或者多条白名单规则后,添加一条丢弃所有报文的规则(配置实例待更新)。

4、用iptables实现DNAT

DNAT的功能与原理在NAT网络地址转换技术入门到详解中已经介绍过了,我们假设本文的读者已经明天了DNAT的功能与原理了,所以这里只简单如何配置与使用。

4.1、如果你需要从外网全权访问私网里的某个主机(比如192.168.1.50)。

将一个公网IP地址(比如1.2.4.1))绑定给192.168.1.50这个主机,这时我们就可以通过DNAT来实现这个功能:

iptables -t nat -A PREROUTING -d 1.2.4.1 -j DNAT --to 192.168.1.50

配置完后,我们对所有192.168.1.50的访问都可以通过1.2.4.1来完成。

4.2、从特定外网IP访问私网内某个服务器的某个业务

这是出于安全性考虑的最小授权原则出发,严格限制访问者(通过访问者的IP地址)和严格限制可以访问的服务。如需要从1.2.5.17访问192.168.1.100的内网web服务,那么在我们设置了以下规则后,他就可以通过1.2.4.2来访问192.168.1.100的内网web服务了。

iptables -t nat -A PREROUTING -s 1.2.5.17 -d 1.2.4.2 -p tcp --dport 80 -j DNAT --to 192.168.1.100

同样出于安全原因考虑,我们DNAT可以帮助我们做信息隐藏,增加安全性。比如,我们希望从外网的任意主机通过SSH访问内网web服务器,因为内网web服务器里往往有非常重要的信息,所以通过DNAT直接映射一个公网IP地址到内网web服务器的私网IP地址,并不是一个非常安全的方案,这会让我们的内网web服务器的SSH服务完全暴露在外,会增加受到网络攻击的风险,更安全的方式是把端口也做一个映射,而攻击者不知道我们把SSH端口映射到了哪个端口,这样会使得SSH端口对外隐藏起来,从而增加安全性(这本质上已经是PAT或者称为NAPT了)。如下用65521端口去映射22端口。

iptables -t nat -A PREROUTING -d 1.2.4.2 -p tcp --dport 65521 -j DNAT --to 192.168.1.100:22

这样的配置下,如果我们从外网想要ssh到内网web服务器的话,我们需要ssh 1.2.4.2:65521.

我们把公司的外网web服务器部署在192.168.1.200上,通过DNS服务将域名www.mycompany.com映射到1.2.4.5,为了使外网web服务器从外网可以访问,我们需要设置如下规则:

iptables -t nat -A PREROUTING -d 1.2.4.5 -p tcp --dport 80 -j DNAT --to 192.168.1.200

5、透明代理

透明代理是一种强制使用用户使用代理服务器的方法,使用透明代理不需要用户在他们的终端或者他们的浏览器上配置代理。使用代理服务器有好多好处,比如通过代理服务器上的网页cache来节省流量,访问控制(如:禁止危险文件的下载).
使用透明代理还有一个好外,是可以防止用户自行绕过代理服务器。这个可以防止用户访问黄赌毒等有害网站。如果你的代理服务器工作在Linux Router的3128端口,那么我们可以使用下面命令来实现透明代理:

iptables -t nat -A PREROUTING -s 192.168.1.0/24 -p tcp --dport 80 -j REDIRECT --to-port 3128

将192.168.1.0/24网段过来的访问网页的IP报文都转发到3128端口。

如果你要让某些私网里的主机可以不需要通过代理而是直接访问外网,那么可以通过以下命令给它加一个例外:

iptables -t nat -I PREROUTING -s 192.168.1.50 -p tcp --dport 80 –j ACCEPT

在PRE-ROUTING里会命中这条规则,然后在POSTROUTING里通过SNAT功能访问外网。

6、以上场景的配置脚本

#!/bin/bash
IP=/sbin/iptables
#... some packet filtering rules
### NAT SECTION
#first of all, we want to flush the NAT table
$IP -t nat -F
############ SNAT PART
#特定电脑只能访问web和DNS.
#Don't SNAT any TCP connections from her computer except www and all
#udp connections except DNS
$IP -t nat -A POSTROUTING -s 192.168.1.31 -p tcp --dport ! 80 -j DROP
$IP -t nat -A POSTROUTING -s 192.168.1.31 -p udp --dport ! 53 -j DROP
#公司内部的二个子网间的通信不要做NAT
#Don't SNAT anything from 192.168.1.0/24 to 192.168.2.0/24
$IP -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.2.0/24 -j ACCEPT
#映射192.168.1.50成1.2.4.1使得192.168.1.50的数据访问固定从1.2.4.1发出
$IP -t nat -A POSTROUTING -s 192.168.1.50 -j SNAT --to 1.2.4.1
#从eth1出去的报文都要做SNAT
$IP -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to 1.2.4.0-1.2.4.32 --to 1.2.3.1
############ DNAT PART
#Dnat映射192.168.1.50成1.2.4.1使得192.168.1.50可以通过1.2.4.1自由访问
$IP -t nat -A PREROUTING -d 1.2.4.1 -j DNAT --to 192.168.1.50
#DNAT 特定的外部主机1.2.5.17可以访问内网web服务器
$IP -t nat -A PREROUTING -s 1.2.5.17 -d 1.2.4.2 -p tcp --dport 80 -j DNAT --to 192.168.1.100
#DNAT转换SSH登录的端口
$IP -t nat -A PREROUTING -d 1.2.4.2 -p tcp -dport 65521 -j DNAT --to 192.168.1.100:22
#DNAT 将外网web服务器部署到内部主机上
$IP -t nat -A PREROUTING -d 1.2.4.5 -p tcp --dport 80 -j DNAT --to 192.168.1.200
############ 透明代理
#允许192.168.1.50绕过代理
$IP -t nat -A PREROUTING -s 192.168.1.50 -p tcp --dport 80 -j ACCEPT
#给所有其它人设置透明代理
$IP -t nat -A PREROUTING -s 192.168.1.0/24 -p tcp --dport 80 -j REDIRECT --to-port 3128
### End of NAT section

7、验证配置脚本

我们可以查看一下nat table里的几条链来验证配置是不是被正确的配置下去。

root@router:~# iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT all -- 0.0.0.0/0 1.2.4.1 to:192.168.1.50
DNAT tcp -- 1.2.5.17 1.2.4.2 tcp dpt:80
to:192.168.1.100
DNAT tcp -- 0.0.0.0/0 1.2.4.2 tcp dpt:65521
to:192.168.1.100:22
DNAT tcp -- 0.0.0.0/0 1.2.4.5 tcp dpt:80
to:192.168.1.200
ACCEPT tcp -- 192.168.1.50 0.0.0.0/0 tcp dpt:80
REDIRECT tcp -- 192.168.1.0/24 0.0.0.0/0 tcp dpt:80 redir
ports 3128
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
DROP tcp -- 192.168.1.31 0.0.0.0/0 tcp dpt:!80
DROP udp -- 192.168.1.31 0.0.0.0/0 tcp dpt:!53
ACCEPT all -- 192.168.1.0/24 192.168.2.0/24
SNAT all -- 192.168.1.50 0.0.0.0/0 to:1.2.4.1
SNAT all -- 192.168.1.0/24 0.0.0.0/0 to:1.2.4.0-1.2.
4.32 1.2.3.1
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
root@router:~#

我们可以看到脚本里的配置项都已经正确的出现在nat table里。如果我们要验证功能是不是正确的话,那么就要搭建相应的服务器,发送相应的报文,然后通过TCPdump和ethereal之类的抓包工具来进行验证。
比如,我们在Linux router上抓包,然后从外网发起一个到1.2.4.1随机的目标端口上的连接,TCPdump会显示如下:

  1. 在Eth0上收到一个从2.2.2.2到1.2.4.1的包
  2. 在Eth0上从1.2.3.1发出一个报文,目标不可达
    在Eth1上没有任何报文,因为没有命中任何DNAT规则。如果命中的某个规则,则我们可以用-v选项来查看 (iptables –L –n –v)。

8、异常场景:Double NAT

Double NAT是用来解决连接见个IP地址重叠的网络的一种方法。如下图的网络,有二个局域网通过VPN连接到一起,不过这二个局域网的IP地址是重叠的,有二个解决方案:1)改变其中一个局域网的网段,重新部署,2)使用Double NAT来解决这个冲突。
在这里插入图片描述
正常情况下,二个局域网工作在不同的网段,我们通过二台Linux Router上的路由表配置,通过VPN的接口使得二个局域网可以正常通信而无需NAT。 但我们都知道,这里异常发生了,二个局域网用的是完全相同的网段,所以只靠路由功能没有办法让二个网络之间相互通信,我们要“假装”二个局域网使用的是不同的网段,才可以让二个局域网之间相互通信。所以,解决方案就是:我们告诉左边的局域网他对面的右边的局域网工作在192.168.20.0/24网段,然后告诉右边的局域网它对面的左边的局域网工作在192.168.10.0/24网段,这样二边就能正常通信了。
下面我们将以二台192.168.1.60为例来说明如何配置才能让它们俩正常通信,以这个为例,可以拓展到其它所有在192.168.1.0/24里的主机,做出相应的配置映射后也就能正常通信了。

配置完成后,我们的目标是让左边的192.168.1.60认为对面的192.168.1.60的IP地址是192.168.20.60;让右边的192.168.1.60认为对面的192.168.1.60的IP地址是192.168.10.60。

8.1、配置Linux Router 1 (左边)

  • Step 1
ifconfig eth1:0 192.168.10.1 netmask 255.255.255.0

这一步不是必须的。目标IP地址为192.168.10.0/24的IP报文会到达Linux Router 1,我们不想要通过默认路由转发这些报文,因为192.168.10.0/24是左边这个局域网假装的网段。

  • Step 2
route add –net 192.168.20.0 netmask 255.255.255.0 gw 10.10.10.2

增加这个路由,让目标IP地址为192.168.20.0/24的IP报文通过vpn1往10.10.10.2转发。

  • Step 3
iptables -t nat -A POSTROUTING -s 192.168.1.60 -d 192.168.20.60 -j SNAT --to 192.168.10.60

创建SNAT规则,把从192.168.1.60发192.168.20.60的报文的源IP地址改成192.168.10.60, 这样来假装左边的网络是192.168.10.0/24。

  • Step 4
iptables -t nat -A PREROUTING -d 192.168.10.60 -j DNAT --to 192.168.1.60

在Linux Router 1上配置DNAT规则,修改所有到达本路由器的目标地址是192.168.10.60的IP报文的目标IP地址为192.168.1.60,这样可以让报文正确的发到192.168.1.60。

8.2、配置Linux Router 2 (左边)

在Linux router 2上,基本是类似的配置,只是目标和源反一下。

  • Step 1
ifconfig eth1:0 192.168.20.1 netmask 255.255.255.0
  • Step 2
route add -net 192.168.10.0 netmask 255.255.255.0 gw 10.10.10.1

增加这个路由,让目标IP地址为192.168.10.0/24的IP报文通过vpn1往10.10.10.1转发。

  • Step 3
iptables -t nat -A POSTROUTING -s 192.168.1.60 -d 192.168.10.60 -j SNAT --to 192.168.20.60

创建SNAT规则,把从192.168.1.60发192.168.10.60的报文的源IP地址改成192.168.20.60, 这样来假装右边的网络是192.168.20.0/24。

  • Step 4
iptables -t nat -A PREROUTING -d 192.168.20.60 -j DNAT --to 192.168.1.60

在Linux Router 2上配置DNAT规则,修改所有到达本路由器的目标地址是192.168.20.60的IP报文的目标IP地址为192.168.1.60,这样可以让报文正确的发到192.168.1.60。

上述就是所有Double NAT所需要的配置,完成配置后,二个192.168.1.60就可以通信了。

  • 左边的192.168.1.60主机给右边的192.168.1.60主机通信时
    • 它认为右边的主机的IP地址是192.168.20.60。因为192.168.20.60是另外一个网段的IP地址,所以这个报文会被转发到默认网关(即Linux Router 1) 。
    • Linux Router 1 会分析PREROUTING chain 里的规则,发现没有命中任何规则,
    • 下一步,它会去查找本地路由表,发现送往192.168.20.60的包应该通过vpn1发往10.10.10.2,
    • 然后Linux Router分析POSTROUTING chain里的规则,发现命中“所以从192.168.1.60发往192.168.20.60的包,都应该把源IP地址从192.168.1.60改成192.168.10.60”这条规则,Linux Router 1按规则修改IP报文的源IP地址,
    • 然后在ip_conntrack里保存这条连接的信息。
    • 被修改了源IP地址后的报文被通过vpn1转发到10.10.10.2。
    • 等这个报文到达Linux Router 2后,Linux Router 2收到了一个从192.168.10.60发送192.168.20.60的报文。
    • Linux Router 2 分析它自己的PREROUTING chain里的规则,发现命中“如果一个报文的目标地址是192.168.20.60就将这个报文的目标地址修改为192.168.1.60”的规则。 Linux Router 2修改报文的目标地址成192.168.1.60。
    • 然后在它的本地路由表里查找到发往192.168.1.60的IP报文应该通过Eth0直接发送,
    • 然后分析POSTROUTING chain里的规则发现没在命中任何规则Linux Router 2 将这个报文转发给192.168.1.60。
  • 右边的192.168.1.60主机给左边的192.168.1.60主机通信时
    也是一样的流程,只是方向反了一下。

到此,我们就完成了重叠IP的二个主机通过Double NAT后成功通信了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux NAT软路由的简介、入门与配置 的相关文章

  • 如何在perl中使用O_ASYNC和fcntl?

    我想使用 O ASYNC 选项 当管道可以读取时 SIGIO 的处理程序将运行 但以下代码不起作用 任何人都可以帮助我吗 bin env perl use Fcntl SIG IO sub print catch SIGIO n my fl
  • 在非实时操作系统/内核上执行接近实时任务的最佳方法是什么?

    在一台 GNU Linux 机器上 如果想要执行 实时 亚毫秒级时间关键 任务 您几乎总是必须经历漫长 复杂且容易出现问题的内核补丁过程 以提供足够的支持 1 http en wikipedia org wiki RTLinux Backg
  • 如何将 elf 解释器(ld-linux.so.2/ld-2.17.so)构建为静态库?

    如果我的问题不准确 我深表歉意 因为我没有太多 Linux 相关经验 我目前正在构建一个 Linux 从头开始 主要遵循 linuxfromscratch org 版本的指南 7 3 我遇到了以下问题 当我构建可执行文件时 获取一个称为 E
  • 了解 Linux oom-killer 日志

    我的应用程序被 oom killer 杀死了 它是在实时 USB 上运行的 Ubuntu 11 10 无需交换 PC 具有 1 Gig 的 RAM 唯一运行的应用程序 除了所有内置的 Ubuntu 东西 是我的程序 flasherav 请注
  • Grep 递归和计数

    需要在具有大量子目录的目录中搜索文件内的字符串 我在用着 grep c r string here 我怎样才能找到总数量 如何仅输出至少具有一个实例的文件 使用 Bash 的进程替换 这给出了我认为是您想要的输出 如果不是 请澄清问题 gr
  • 如何使用 go1.6.2 构建 linux 32 位

    有没有任何组合GOARCH and GOOS我可以设置哪些值来构建 ELF 32 位二进制文 件 GOOS linux and GOARCH 386 更多示例 架构 32 bit gt GOARCH 386 64 bit gt GOARCH
  • 为什么 call_usermodehelper 大多数时候都会失败?

    从内核模块中 我尝试使用 call usermodehelper 函数来执行可执行文件 sha1 该可执行文件将文件作为参数并将文件的 SHA1 哈希和写入另一个文件 名为输出 可执行文件完美运行 int result 1 name hom
  • aarch64 Linux 硬浮点或软浮点

    linux系统有arm64 有arm架构armv8 a 如何知道 Debian 运行的是硬浮动还是软浮动 符合 AAPCS64 GNU GCC for armv8仅提供硬浮动aarch64工具链 这与 armv7 a 的 GCC 不同 后者
  • Apache LOG:子进程 pid xxxx 退出信号分段错误 (11)

    Apache PHP Mysql Linux 注意 子进程 pid 23145 退出信号分段错误 11 tmp 中可能存在 coredump 但 tmp下没有找到任何东西 我怎样才能找到错误 PHP 代码中函数的无限循环导致了此错误
  • 如何使用 VSCode 调试 Linux 核心转储?

    我故意从我使用 VSCode 编写的 C 应用程序生成核心转储 我不知道如何调试核心转储 有没有人愿意分享这方面的经验 更新 我相信我现在已经可以使用了 我为核心文件创建了第二个调试配置 我需要添加指向生成的转储文件的 coreDumpPa
  • Unix 中的访问时间是多少

    我想知道访问时间是多少 我在网上搜索但得到了相同的定义 读 被改变 我知道与touch我们可以改变它 谁能用一个例子来解释一下它是如何改变的 有没有办法在unix中获取创建日期 时间 stat结构 The stat 2 结构跟踪所有文件日期
  • Java时区混乱

    我正在运行 Tomcat 应用程序 并且需要显示一些时间值 不幸的是 时间快到了 还有一个小时的休息时间 我调查了一下 发现我的默认时区被设置为 sun util calendar ZoneInfo id GMT 08 00 offset
  • 如何在 Linux 中向热敏打印机发送 ESC/POS 命令

    我正在尝试在热敏打印机上发送 ESC POS 命令 但每当我发送它们时 热敏打印机都会将它们打印为文本 而不是作为命令执行它们 我在 prn 文件中编写这些命令 每当我执行 lp 命令来打印文件时 这些 prn 文件也会被打印 但作为文本
  • 有没有办法提高linux管道的性能?

    我正在尝试使用 64 位将超高速数据从一个应用程序传输到另一个应用程序CentOS http en wikipedia org wiki CentOS6 我使用以下方法进行了基准测试dd发现阻碍我的是管道而不是程序中的算法 我的目标是达到
  • Linux 中有没有一种轻量级的方法来获取当前进程数?

    我希望我的 基于 C C 的 程序显示一个数字指示器 指示本地系统上当前有多少个进程 将经常查询正在运行的进程数值 例如每秒一次 以更新我的显示 有没有一种轻量级的方法来获取该数字 显然我可以调用 ps ax wc l 但我不想强迫计算机生
  • grep 彩色线条

    我编写了一个简单的 PHP shell 脚本 它解析文件并输出某些元素 它产生大量的输出 采用不同的 bash 颜色 绿色表示正常 黄色表示警告 红色表示错误等 在开发过程中我想过滤掉一些行 例如 所有包含红色文本的行 我可以使用grep
  • 在 MacOS 上构建需要 net461 的 dotnet SDK 项目的最简单方法

    我有一个 dotnet SDK sln and a build proj with
  • Linux 上的“软/硬 nofile”是什么意思

    当我尝试在RedHat EL5上安装软件时 我得到了错误 软 硬nofile的期望值是4096 而默认值是1024 我设法增加了这个数字 但我不知道参数是什么 他们指的是软链接和硬链接吗 我改变的方法是 a 修改 etc security
  • 使用 .htaccess 启用 PHP 短标签

    我在自己的 Centos 服务器上设置了 Apache 并具有多个虚拟 Web 服务器 并且我希望仅为位于以下位置的其中一个 Web 服务器启用 PHP 短标记 var www ostickets html 我可以通过添加成功启用短标签sh
  • php56 - CentOS - Remi 仓库

    我刚刚在测试盒上安装了 php 5 6 正常的 cli php 解释器似乎不存在 gt php v bash php command not found gt php56 v PHP 5 6 13 cli built Sep 3 2015

随机推荐

  • SAS安装错误

    SAS安装 SAS安装分为两个阶段 系统要求 安装 第1阶段 Stage1 系统要求 System Requirement 需确保安装Microsoft Office Access Database Engine Microsoft Run
  • 定位shadow

    1 先定位到 shadow root 的宿主节点 此处为 id box 的 div 2 切换到 shadow root 中 3 然后再选择 shadow root 下的 span 标签 import time from selenium i
  • 2022亚太数学杯数学建模竞赛C题(思路、程序......)

    目录 一 英文题目及数据 二 中文翻译题目参考 2 1 题目 2 2 题目 三 思路 程序参考 四 参考文献 一 英文题目及数据 Canada s 49 6 C has set a new temperature record for re
  • 前端高频面试题 js中堆和栈的区别和浏览器的垃圾回收机制

    一 栈 stack 和 堆 heap 栈 stack 是栈内存的简称 栈是自动分配相对固定大小的内存空间 并由系统自动释放 栈数据结构遵循FILO first in last out 先进后出的原则 较为经典的就是乒乓球盒结构 先放进去的乒
  • 将数据导入Hive数据库中,使用python链接Hive读取数据库,转化成pandas的dataframe

    做互联网应用开发过程中 时常需要面对海量的数据存储及计算 传统的服务器已经很难再满足一些运算需求 基于hadoop spark的大数据处理平台得到广泛的应用 本文提供一个导入数据到hive 用python读取hive数据库的例子 这实际是个
  • blender学习记录3--物体的操作

    添加删除物体 删除选中物体按delete或者x 进行选择删除 操作面板 在上一个步骤 比如添加物体 后 在屏幕两侧下方都会出现添加xx 点开这个操作面板就能够将刚添加的物体属性进行选择 若是做了其他步骤还想在修改只能在侧栏的条目或者编辑器类
  • 使用大块内存的设置

    C 如下分配内存的代码 booleantempTag true do try double K NULL int nnz cout lt lt 请输入分配内存大小 MB lt
  • logstash过滤器插件filter详解及实例

    原创作者 峰哥ge 原创地址 https www cnblogs com FengGeBlog p 10305318 html logstash过滤器插件filter grok正则捕获 grok是一个十分强大的logstash filter
  • Docker:数据卷&数据卷容器

    一 概念解析 1 数据卷 数据卷就是在宿主中可以在容器之间进行共享和重用的一系列和文件和文件夹 通过docker run v命令可以将数据卷挂载到对应的容器目录空间 进行文件读取 容器卷特性如下 数据卷可以在容器之间共享和重用 容器间传递数
  • MOOC《Python语言程序设计》第6周练习题

    这周讲解了组合数据类型 重点介绍表达和处理一组数据的方法 涉及到多种数据类型 包括 集合类型 序列类型 含元组类型和列表类型 和字典类型 讲解2个颇有用处的实例 基本统计值计算和文本词频统计 其中 即有英文Hamlet的词频统计 也有中文
  • mysql设置utf-8和查询修改数据库、表常用命令

    mysql设置utf 8和查询修改数据库 表常用命令 1 设置utf8字符集 2 查询修改数据库 表的字符集 1 设置utf8字符集 二级目录 默认情况下 通过 show variables like char 命令查询mysql字符编码如
  • 'findstr' 不是内部或外部命令,也不是可运行的程序或批处理文件

    今天通过windows cmd客户端输入 solr cmd start 启动solr时 提示 findstr 不是内部或外部命令 也不是可运行的程序或批处理文件 这是PATH环境变量的问题 将windows命令的目录添加到PATH中就好了
  • JDBC连接步骤

    第一步 在项目中新建一个名称叫lib的文件夹 然后将下载的MySQL连接jar包存入到这个lib文件夹中并配置环境 第二步 编写代码 连接数据库并操作数据库中某个表里的数据 基本操作 1 注册驱动 Class forName com mys
  • matlab 非极大值抑制,非极大值抑制算法(matlab实现)

    参考 http www cnblogs com liekkas0626 p 5219244 html function pickLocate nms boxes overlap Non maximum suppression In obje
  • leetcode 字符串压缩

    思路 用双指针的方法 定一个 i 和 j AC代码 class Solution public string compressString string S 两层循环 if S size 0 return S int i 0 j 0 str
  • 【杂谈】概率与随机以及手游抽卡机制的科普

    原文 NGA的一篇随机科普 其中包含了对手游抽卡机制的探讨 本文摘选了我自己感兴趣的部分 真随机 先说点题外话 请先看这个问题 一杯热水和一杯冷牛奶哪个热量更高 很显然这个问题从物理学和营养学的层面会得出相反的答案 先不考虑物理学层面说 一
  • java 静态初始化块中,方法中不可以定义静态变量(重要)

    来源 https zhidao baidu com question 493515697 html 静态变量只能定义在类的内部 不可以定义在静态块或方法中 可以在类内部定义静态变量 在静态块中进行初始化操作 因为类的内部是不允许有操作语句存
  • uniapp开发常见问题整理

    1 自适应尺寸 移动端开发时使用rpx单位 以便适应各种手机像素 避免使用px 2 微信超包限制 小程序规定每个包源码不能超过2M uniapp打包时会将一些公共资源打包到主包中 从而造成小程序无法打包上传 提倡做法 1 底部导航栏对应的界
  • gitlab remote: HTTP Basic: Access denied

    使用 http流程 问题 git push报错 HTTP Basic Access denied 原因 本地git配置的用户名 密码与gitlabs上注册的用户名 密码不一致 解决方案 进入控制面板 用户账号 凭据管理器 windows凭据
  • Linux NAT软路由的简介、入门与配置

    本文目录 1 确认Linux kernel内核版本 2 netfilter的nat table简介 3 用iptables实现SNAT 3 1 多对多 N N 的SNAT 3 2 将一个网段内的某个公网IP移除出SNAT可用的公有IP地址池