硬核干货——《中小企业 AI 实战指南》免费下载! 了解详情
写点什么

VPC 中 NAT 的那点事

  • 2019-11-20
  • 本文字数:3485 字

    阅读完需:约 11 分钟

VPC中NAT的那点事
### NAT就在那里


下图 是EC2实例通过IGW(Internet网关) 接入到Internet的示意图。熟悉AWS的读者会知道,这里EC2实例和Internet通信的两个方向上,实际上发生了如下的转换:
* 从EC2实例发出的前往Internet的IP包,其源地址10.0.0.10在经过IGW时,会被转换为与实例关联的公网地址 54.232.0.1;* 从Internet发给54.232.0.1的IP包,经过IGW时其目的地址会转换为ENI对应的内网地址10.0.0.10并被送到 EC2实例;
可以看到,这里Internet网关就是起到实例的内网地址和公网地址一对一的基本 NAT(网络地址转换)的功能。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/1017-01.png)
相比于没有NAT的场景,大部分的应用、软件不需要任何改变就能在基本NAT的场景下继续工作,例如基于HTTP协议的Web应用等;但是对于某些应用,例如FTP、VoIP等,网络地址转换会给应用带来一些意想不到的挑战。今天我们以历史悠久的FTP协议为例,来和大家探讨一下NAT给FTP这样的应用带来什么样的挑战,以及FTP应用和协议又是如何演进去适应它。
### 被动模式下的FTP
我们重温一下FTP的工作过程。客户端连接服务端TCP 21端口建立命令通道后,输入用户名密码完成登录;随后的每一次数据传输都需要另外建立数据通道进行; 如果数据通道由客户端发起,服务端接受,我们称之为被动模式;反之,如果数据通道由服务端发起,客户端接受,则称之为主动模式。
为简化讨论,我们以被动模式为例。
**同一个私网内**
我们在EC2实例10.0.0.10上搭建了一台FTP服务器,它监听在21端口。现在我们从同一个VPC里的另外一台EC2上运行FTP客户端;那么整个过程会很顺利。 ![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/1017-2.PNG)
**从Internet访问**
现在我们从位于Internet某处的一台PC上运行FTP客户端。 ![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/1017-3.PNG)
这里连接超时的原因显而易见,FTP服务端发送给客户端的IP地址是服务端的私有地址。位于Internet上的客户端无法建立与位于VPC内部的私有地址10.0.0.10直接通讯。
解决这个问题有多种方法,我们由简单到复杂分别叙述。
### 增强协议适配NAT
FTP协议针对NAT和其他因素,对协议进行了增强,提供了增强版的被动模式EPSV命令[1]。
下面的例子里,服务端不再显式指定IP地址,只提供数据通道的端口号。客户端默认与控制通道相同的IP地址建立数据通道。
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/1017-4.PNG)
可以看到,解决方案很优雅。实际上如果你在阅读本文的时候,绝大部分FTP服务端和客户端都已经实现了EPSV,而且优先使用它,所以FTP应用目前在EC2上是可以称之为开箱即用的。当然这需要客户端和服务端都支持增强的协议才能达成;如果我们不修改协议,能否解决这个问题呢。
### 放开那协议!我来!
有些时候,修改协议和实现需要多方协调和很长的时间才能完成。在RFC2428标准化之前,一些FTP实现就已经通过修改实现来适配基本NAT,而非修改协议。
以vsftpd为例,它允许通过配置文件vsftpd.conf中的配置项 pasv_address=54.232.0.1 告知服务端,在PASV被动模式下,应当指示客户端连接到配置项指定的IP(而不是服务端的私有IP)来适配基本NAT。
其他的一些常见应用例如VoIP类应用,也有类似的机制去适配基本NAT;例如引入STUN/TURN/ICE等方式[2]适配各种更加复杂的NAT穿越场景;但是针对部署在EC2上的基本NAT环境,也有通过实现上的简单调整,例如开源VoIP应用Asterisk就支持通过在配置文件/etc/asterisk/sip.conf里指定本机的公网地址和本地网段的方式来适配基本NAT。
nat=yes
externaddr=54.223.0.1
localnet=10.0.0.0/16
### 协议和实现我都不想动!
作为一枚任性的读者,如果您既不想动协议也不想动实现,这里笔者给读者介绍一种剑走偏锋的方式,读者若有兴趣,可以轻松愉快的在AWS上试一试,看看能否解决你的应用适配基本NAT。下面是一段shell脚本,当然是运行在Linux操作系统上的。
_\#从EC2 实例元数据服务获取本实例的公网IP(如有)、私网IP_
_public_ipv4=`curl -s http://169.254.169.254/latest/meta-data/public-ipv4`_
_local_ipv4=`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`_
_\#配置私网地址段,这里应为EC2实例所在VPC的地址范围_
_local_net=10.0.0.0/16_
_if [ “x${public_ipv4}” == “x” ]_
_then_
_echo “No public IPv4 address available for this instance, abort.”_
_exit 1_
_else_
_\#如果EC2实例的公网IP不为空,则将该公网地址添加到eth0上_
_ip address add ${public_ipv4}/32 dev eth0_
_\#本地接受的连接,如果来源不是本VPC,那么将IP包的目的地址改写为公网IP_
_iptables -t nat -A PREROUTING ! -s ${local_net} -d ${local_ipv4} -i eth0 -j DNAT –to ${public_ipv4}_
_\#本地发起的连接,如果出方向流量的源IP地址是公网地址,那么需要改写为私网IP_
_iptables -t nat -A POSTROUTING -s ${public_ipv4} -o eth0 -j SNAT –to ${local_ipv4}_
_fi_
正常情况下,脚本执行完毕后,可以通过如下方式验证效果。
### 首先检查本实例的公网IP是否已经正确配置到eth0上。
~ # ip addr show dev eth0
eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP group default qlen 1000
link/ether 02:c7:6b:9b:d2:b6 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.10/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet 54.232.0.1/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::c7:6bff:fe9b:d2b6/64 scope link
valid_lft forever preferred_lft forever
可以看到,公有IP地址(54.232.0.1/32)已经成功添加到eth0接口。
### 然后检查iptables的NAT规则是否正确配置
~ # iptables -t nat -nvL


Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 DNAT all — eth0 * ! 10.0.0.0/16 10.0.0.10 to:54.223.74.106
Chain INPUT (policy ACCEPT 1 packets, 64 bytes)
pkts bytes target prot opt in out source destination


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


Chain POSTROUTING (policy ACCEPT 3 packets, 222 bytes)
pkts bytes target prot opt in out source destination
0 0 SNAT all — * eth0 54.223.74.106 0.0.0.0/0 to:10.0.0.1
从上面可以看到传入、传出数据包的数量以及IP地址在传入前,传出后的地址改写情况。
### 最后分别从VPC内部和Internet连接到服务,验证结果
~ $ ss -nt
State Recv-Q Send-Q Local Address:Port Peer Address:Port
ESTAB 0 72 54.223.74.106:21 119.xx.x.xx:52425
ESTAB 0 1272 54.223.74.106:12081 119.xx.x.xx:23710
ESTAB 0 72 10.0.0.10:21 10.xx.x.xx:48361
ESTAB 0 1272 10.0.0.10:12090 10.xx.x.xx:32115
笔者在没有修改任何vsftpd的配置文件的前提下,通过上述脚本的运行和配置,同一个VPC内部的客户端和Internet客户端都能完成FTP被动模式的文件传输全流程。
值得一提的是,本方法仅供参考,不建议在生产环境中大规模使用,推荐的解决方案请参考前文关于协议适配和实现适配。
[1] FTP Extensions for IPv6 and NATs https://tools.ietf.org/html/rfc2428 [2] NAT Traversal Practices for Client-Server https://tools.ietf.org/html/rfc6314 **作者介绍:**
![](https://s3.cn-north-1.amazonaws.com.cn/images-bjs/Ding+Chandler.jpg)
丁成银
AWS 解决方案架构师,获得AWS解决方案架构师专业级认证和DevOps工程师专业级认证。负责基于AWS的云计算方案架构的咨询和设计,同时致力于AWS云 服务在国内的应用和推广,在数字媒体、电信、互联网和游戏、企业混合IT等方面有着丰富的实践和设计经验。在加入AWS之前,历任数字媒体娱乐系统工程 师、宽带业务架构师、云解决方案架构师,负责数字媒体娱乐系统、云计算解决方案等服务的咨询和架构设计工作。
复制代码


TAGS:


Amazon VPC


,


大咖专栏


,


网络和内容发布


2019-11-20 08:00874

评论

发布
暂无评论
发现更多内容

区块链一新基建 新动能 新发展大会将在南昌举办

CECBC

新基建 区块链技术

想要成功,你需要的是目标与动机,目标是你的助攻,动机是你的爱人。

叶小鍵

成功学 心理学 海蒂·格兰特·霍尔沃森

Git命令可视化展示,代码管理再也不愁了,建议收藏!

诸葛小猿

git git merge git rebase git fetch git reset

MySQL-技术专题-共享锁与排他锁

码界西柚

Github被攻击。我的GitPage博客也挂了,紧急修复之路,也教会你搭建 Jekyll 博客!

小傅哥

Java GitHub 小傅哥 博客

LeetCode题解:88. 合并两个有序数组,双指针遍历+从前往后,JavaScript,详细注释

Lee Chen

大前端 LeetCode

契约测试:解决微服务测试的问题

陈磊@Criss

手把手教你从零开始使用python编写大型冒险类游戏01之游戏介绍

Geek_8dbdc1

数据治理第一步,摆脱“手工作坊”

KAMI

大数据 数据治理 数据开发 数据平台

Flexible Box Layout 原理剖析

coolion

CSS 大前端

架构师训练营 - 第 7 周命题作业

红了哟

鲲鹏一粤,智算万里

脑极体

如何隐藏你的数据库密码

Rayjun

安全 服务器

一文了解对称加密与非对称加密

我是程序员小贱

安全

Go: Goroutine, 系统线程和CPU管理

陈思敏捷

mpg Go 语言

MySQL-技术专题-InnoDB存储引擎

码界西柚

源码分析 | Mybatis接口没有实现类为什么可以执行增删改查

小傅哥

Java 源码分析 小傅哥 mybatis

【DevOps】我们忽视了Daily Build(每日构建)吗?

Man

DevOps jenkins 每日构建

为什么修改hosts不立即生效?--浏览器DNS缓存机制分析

陈磊@Criss

Python中的单下划线和双下划线使用场景

wangkx

Python Python基础知识 Python基础

知道时间轮算法吗?在Netty和Kafka中如何应用的?为什么不用Timer、延时线程池?

yes

kafka Netty Timer ScheduledThreadPool 时间轮

Git设置分支保护实现CodeReview卡点

陈磊@Criss

国内与国外区块链关键技术现状及差异

CECBC

区块链 应用技术

Golang+Flutter实现聊天APP

Alber

IM Go 语言

并不想吹牛皮,但!为了把Github博客粉丝转移到公众号,我干了!

小傅哥

Java 小傅哥 博客 微信公众号

Dubbo2.7试用

心平气和

dubbo 灰度 hessian

用故事去理解「文件 I/O」

小林coding

操作系统 异步 文件系统 同步 非阻塞网络I/O

记一次腾讯云(西安)后台开发面试经历

z小赵

面试 分布式 高并发

MySQL 架构与历史

多选参数

MySQL 数据库 MySQL优化

架构师训练营 - 第十周作业

坂田吴奇隆

抽象类、接口、Trait

书旅

接口 面向对象 抽象 对象 Trait

VPC中NAT的那点事_其他_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章