1. 程式人生 > >VPC中NAT的那點事

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(網路地址轉換)的功能。

相比於沒有NAT的場景,大部分的應用、軟體不需要任何改變就能在基本NAT的場景下繼續工作,例如基於HTTP協議的Web應用等;但是對於某些應用,例如FTP、VoIP等,網路地址轉換會給應用帶來一些意想不到的挑戰。今天我們以歷史悠久的FTP協議為例,來和大家探討一下NAT給FTP這樣的應用帶來什麼樣的挑戰,以及FTP應用和協議又是如何演進去適應它。

被動模式下的FTP

我們重溫一下FTP的工作過程。客戶端連線服務端TCP 21埠建立命令通道後,輸入使用者名稱密碼完成登入;隨後的每一次資料傳輸都需要另外建立資料通道進行; 如果資料通道由客戶端發起,服務端接受,我們稱之為被動模式;反之,如果資料通道由服務端發起,客戶端接受,則稱之為主動模式。

為簡化討論,我們以被動模式為例。

同一個私網內

我們在EC2例項10.0.0.10上搭建了一臺FTP伺服器,它監聽在21埠。現在我們從同一個VPC裡的另外一臺EC2上執行FTP客戶端;那麼整個過程會很順利。

從Internet訪問

現在我們從位於Internet某處的一臺PC上執行FTP客戶端。

這裡連線超時的原因顯而易見,FTP服務端傳送給客戶端的IP地址是服務端的私有地址。位於Internet上的客戶端無法建立與位於VPC內部的私有地址10.0.0.10直接通訊。

解決這個問題有多種方法,我們由簡單到複雜分別敘述。

增強協議適配NAT

FTP協議針對NAT和其他因素,對協議進行了增強,提供了增強版的被動模式EPSV命令[1]。

下面的例子裡,服務端不再顯式指定IP地址,只提供資料通道的埠號。客戶端預設與控制通道相同的IP地址建立資料通道。

可以看到,解決方案很優雅。實際上如果你在閱讀本文的時候,絕大部分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被動模式的檔案傳輸全流程。

值得一提的是,本方法僅供參考,不建議在生產環境中大規模使用,推薦的解決方案請參考前文關於協議適配和實現適配。

丁成銀

AWS 解決方案架構師,獲得AWS解決方案架構師專業級認證和DevOps工程師專業級認證。負責基於AWS的雲端計算方案架構的諮詢和設計,同時致力於AWS雲 服務在國內的應用和推廣,在數字媒體、電信、網際網路和遊戲、企業混合IT等方面有著豐富的實踐和設計經驗。在加入AWS之前,歷任數字媒體娛樂系統工程 師、寬頻業務架構師、雲解決方案架構師,負責數字媒體娛樂系統、雲端計算解決方案等服務的諮詢和架構設計工作。

相關推薦

Android 關於定位(GPS,GPGGA,NMEA-0183,RTCM)

首先關於定位一些解釋 通常在Android端地圖相關用的最多的都是第三方的Sdkj進行二次開發,如百度,高德,World Wind ,arcgis等,對於手機自帶的GPS晶片和國內的北斗晶片瞭解的相對較少,GPS在android中已經由android底層驅動封

VPCNAT

NAT就在那裡 下圖 是EC2例項通過IGW(Internet閘道器) 接入到Internet的示意圖。熟悉AWS的讀者會知道,這裡EC2例項和Internet通訊的兩個方向上,實際上發生瞭如下的轉換: 從EC2例項發出的前往Interne

vue單頁應用 返回列表記住上次滾動位置、keep-alive快取之後更新列表資料

實踐場景需求 產品列表中,滾動到一定位置的時候,點選檢視產品資訊,後退之後,需要回到原先的滾動位置,這是常見的需求 所有頁面均在router-view中,暫時使用了keep-alive來快取所有頁面,所以進入不同分類的產品列表,和不同的產品詳情頁面,需要更新資料 首先注意: 本次實踐測試環境為pc

Idea之debugF7與Drop Frame的

在idea的debug中,有很多除錯的快捷鍵,比如F5進入到方法內、F6跳過方法往下執行、F8執行到下一個斷點(如果沒有下一個斷點,則執行到結束)。本文主要介紹F7和Drop Frame的使用,以及它們之間的區別。 1、F7 首先,我們寫一段測試程式碼: 1 public cla

【轉】Netty(三)Channel的Pipeline

【原文】https://github.com/code4craft/netty-learning/blob/master/posts/ch3-pipeline.md Channel是理解和使用Netty的核心。Channel的涉及內容較多,這裡我使用由淺入深的介紹方法。在這篇文章中,我們主要介紹Channe

iOS開發ARC的

        在MRC時代,Block會隱式地對進入其作用域內的物件(或者說被Block捕獲的指標指向的物件)加retain,來確保Block使用到該物件時,能夠正確的訪問。 這件事情在下面程式碼展示的情況中要更加額外小心。 MyViewController *myController = [[MyV

關於java專案與web專案lib包的

一、在java專案中如何引入外部jar包: 1、在我們的java專案下新建一個lib資料夾; 2、將我們需要引入的jat包複製到lib資料夾下; 3、選中我們lib包下的jar,右鍵選擇Build Path --Add to Build Path;4、jar成功的新增到Re

說說geotools座標轉換

概述:本文說說geotools中座標轉換的那點事情,以WGS84和web墨卡託相互轉換為例。效果:轉換前轉換後單個Geometry轉換實現程式碼:package com.lzugis.geotools; import java.io.File; import java.io

vue關於滾動條的

vue中關於滾動條的那點事 不知道你有沒有遇到過這種情況,有時當頁面切換時,滾動條不在頁面的頂端。最近半路加入一個專案,就遇到這種情況。(若只是為了解決此問題,可直接翻到最下方)下面談談解決此問題的過程: 什麼情況下會出現滾動條的快取? 之前想要滾動條在頁面跳轉時被快取,需要自己設定keep-alive, &

設計模式--策略模式

簡化 cas enter ext font 想要 fonts 對象創建 客戶 概念: 策略模式定義了一系列的算法,分別封裝起來,讓它們之間能夠相互替換。此模式讓算法的變化,不會影響到使用算法的客戶。策略,實質上指的是算法。 樣例

談談字符串

沒有 register 用戶 今後 過程 破解 插件 運行 tro 在od破解軟件過程中,大家對於字符串應該是再熟悉不過了,但是往往事情不盡如人意,總是搜索不到想要的字符串,這時往往有的人會被迫用別的方法,消息斷點,內存斷點,硬件斷點等等,今天咱們只談字符串,把我所掌握的查

浮點數的

bsp 用兩個 處理 有一個 奇葩 加減乘 而且 出了 判斷 浮點數是計算機中儲存實數的形式。我們時常需要用浮點數去處理帶小數點的運算。可你是否知道,浮點數還有這些操作: 正負無窮大 與整數不同,浮點數沒有溢出的概念。當浮點數的運算結果超過一定範圍時,它的值就會根據運算結

新手···男生

for take edit ger har ping minutes lazy sgu 1、alarm clock go off鬧鐘響了,sleep right through it睡過去了,time to get up該起床, 2、you name it你說的 3、sle

mongodb第二篇文章~關於集群認證的

所有 目的 create 介紹 副本 這就是我 port pwd root 集群認證簡介:上一篇咱們介紹了單實力的認證方式,正好我在搞lepus監控,副本集合需要用戶認證 一 驗證方式: 1 auth 方式啟動=》單點 2 keyFile 方式啟動=》集群 請註意 開

PostgreSql(文件讀取寫入、命令執行的辦法)

ict con ext ews none urn truct 語法 tip ? 2013/07/9 作者: admin PostgreSql那點事(文件讀取寫入、命令執行的辦法) 今天無意發現了個PostgreSQL環境,線上學習了下,一般的數據註射(讀寫數據庫)差異不

搭建Maven私服

文件的 repos 版本控制工具 oracl 手工 apach security 項目 源碼 摘要:本文主要介紹在CentOS7.1下使用nexus3.6.0搭建maven私服,以及maven私服的使用(將自己的Maven項目指定到私服地址、將第三方項目jar上傳到私服供

this的

this指向 st2 開始 light pre 全局對象 很多 var 同時 對於很多初學者,this總是搞得我們暈頭轉向。 現在,我就簡單的總結一下關於this的那點事。 this在函數定義時經常是不能確定的,只有在函數執行的時候才能最終確定this的歸屬。this總是指

net 自定義泛型

toolbar user 定義和使用 程序 參考 關鍵字 double png 不同 泛型概述 泛型是程序設計語言的一種特性。允許程序員在強類型程序設計語言中編寫代碼時定義一些可變部分,那些部分在使用前必須作出指明。各種程序設計語言和其編譯器、運行環境對泛型的支持均不一樣

C#編譯器優化

代碼質量 配置 需要 但是 strong -a tool -- dbo 使用C#編寫程序,給最終用戶的程序,是需要使用release配置的,而release配置和debug配置,有一個關鍵區別,就是release的編譯器優化默認是啟用的。 優化代碼開關即optimize開關

說說學習小焦慮

碎片 com 動力 roc 生活 我們 事情 安全 shadow 說到焦慮,成了當下年輕人生活中的標配,感覺自己稍不留神就會被同齡人拋棄,被這個時代淘汰。就像現在的學習、生活,也是各種充斥著無處不在的小焦慮。營銷號熱衷制造焦慮,然後販賣焦慮,收獲流量和粉絲。也有一部分人販賣