埠轉發方法

shilei1發表於2017-03-29

0x00 故事是這樣開始的

話說某一日,突然發現自己閒來無事就喜歡F5(Command+R)的MUD遊戲網站(論壇)突然無法訪問了!下意識地ping之:

C:\Users\xxx>ping pkuxkx.net

正在 Ping pkuxkx.net [211.154.198.9] 具有 32 位元組的資料:
來自 211.154.198.9 的回覆: 位元組=32 時間=15ms TTL=128
來自 211.154.198.9 的回覆: 位元組=32 時間=8ms TTL=128
來自 211.154.198.9 的回覆: 位元組=32 時間=9ms TTL=128
來自 211.154.198.9 的回覆: 位元組=32 時間=6ms TTL=128

211.154.198.9 的 Ping 統計資訊:
    資料包: 已傳送 = 4,已接收 = 4,丟失 = 0 (0% 丟失),
往返行程的估計時間(以毫秒為單位):
    最短 = 6ms,最長 = 15ms,平均 = 9ms

發現到伺服器IP的網路是通的。那是服務down掉了?火速登陸QQ群,質問Admin故障原因,獲知原來是由於機房問題,網站的80埠暫時無法訪問。我……感謝機房,幫助我等沉迷人士戒除網癮。

可是不過半天功夫就出現了戒斷反應,開始坐立不安……怎麼辦?於是開始琢磨解決方案。

0x01 只科普一個概念:埠

這裡先給非計算機專業的同學科普一下埠的含義,之後的概念就科普不能了,pkuxkx.net的朋友直接跳過鬼畫符段落,看能看懂的操作就好:)

這裡提到的埠,是網路通訊上的一個概念。網路上兩個主機A、B之間的任何一次通訊,實際上是從A的某個埠和B的某個埠之間的通訊。假設A上的程式A1和B上的程式B1通訊,同時A上的程式A2和B上的程式B2通訊,那麼A1到B1的資料到達B後,B怎麼知道該把這些資料發給B1,而不是發給B2從而引起混亂呢?這是我們就需要給A1←->B1和A2←->B2這兩條通訊路徑分別繫結不同的埠,讓它們兩對各行其道、互不干擾。比如,A1繫結A的PA1埠,A2繫結A的PA2埠,B1繫結B的PB1埠,B2繫結B的PB2埠,這樣A1就可以明確地告訴通訊裝置,它要把資料發往B的PB1埠,這樣B收到資料後就知道這些資料應該給B1程式而不是其他程式了!從B到A的資料傳送同理。埠是用埠號來標記的(0~65535),每個埠號對應一個埠。每個埠最多隻能繫結一個程式。

埠的通訊如下:
埠轉發方法

我們平時玩MUD,連線伺服器時,都需要指定埠,比如:pkuxkx.net 5555,告訴我們的MUD客戶端——ZMUD、MUSHClient等等去訪問pkuxkx伺服器的這個埠,才能夠找到伺服器上的對應MUD服務程式。而訪問網站,比如當輸入網址訪問北俠論壇時 http://pkuxkx.net/forum 時,為什麼沒有帶埠號呢?這是因為,訪問web頁面時,瀏覽器會自動為我們訪問的目標ip加上web預設的埠:80。換言之,你在瀏覽器裡輸入 http://pkuxkx.net/forum 和 http://pkuxkx.net:80/forum 的效果是完全一樣的。注意埠號的位置,是緊跟在指向IP的域名之後,而不是整個網址的末尾。

0x02 北俠網站埠故障初步解決方案

所以這回差不多該明白了,北俠網站的埠故障其實是這樣的:

埠轉發方法

其實伺服器上的程式狀態槓槓滴,只是80埠對外的這條“線”被機房“剪斷”了,淚目……還好北俠管理員第一時間在伺服器上開放了9999埠,通過訪問9999埠,玩家可以獲得和訪問之前的80埠相同的資訊。比如之前訪問論壇的網址是 http://pkuxkx.net/forum ,現在通過 http://pkuxkx.net:9999/forum 可以訪問。另外MUD遊戲裡的fullme圖片給出的驗證碼圖片網址,也同樣可以通過在“pkuxkx.net”後面加9999埠的方法來解決。比如當你在MUD裡fullme(fullme驗證碼是北大俠客行MUD用來遏制全自動機器人,維護手動玩家樂趣的一種防掛機手段——小編注),出現以下提示——

白馬客棧 -
   這是洛陽城裡最大的一家客棧,緊靠洛陽中心,以洛陽的名勝白馬寺來命名,曰「白馬客棧」,由於價格公道,因此到這裡來借宿的客人川流不息,絡繹不絕,生意極其興隆,大堂內擺了七八張桌子,店小二跑來跑去接待著從四面八方來的客人。客棧後面是客人休息的地方。櫃檯前擺著一個牌子(sign)。
   你可以看看(look):sign
   這裡明顯的出口是 east 和 west。
   店小二(Xiao er)
> 店小二用脖子上的毛巾抹了抹手,說道:這位女俠,請進請進。
fullme
你現在才來呀,不過總比不來好。
你的客戶端不支援MXP,請直接開啟連結檢視圖片。
請注意,忽略驗證碼中的紅色文字。
http://pkuxkx.net/antirobot/robot.php?filename=xxxxxx
請輸入你看到的圖片上的內容。如果感覺難以識別,可以重新整理一下再看看。
還是用這個命令,指令格式: fullme 驗證碼

這時我們直接用上面的網址已經訪問不到相關的圖片了(顯然這個網址走的也是80埠),而可以改用以下方式訪問:http://pkuxkx.net:9999/antirobot/robot.php?filename=xxxxxx ——注意埠號的新增位置。

OK,雖然看上去很麻煩,但是我們的緊急需求算是初步解決了。這種方案的實現原理是什麼呢?其實就是在伺服器後臺做了一個簡單的埠轉發,從內部將訪問pkuxkx.net:9999的資料導到pkuxkx.net:80,然後再把pkuxkx.net:80發出的資料導回pkuxkx.net:9999,最終返回到玩家那裡。一圖以蔽之:

埠轉發方法

注意上圖中綠色的線,代表資料暢通無阻的路線。其中北俠伺服器的80埠是可以從本機訪問的(就是埠z的位置),只是不能由遠端伺服器從外部(埠x的位置)訪問。埠號x、y、z是系統在連線時自動分配的埠號,這裡我們不用care它們的具體數字。

是的,由於本文的目的之一是學習和總結提高,所以要八一八更具體的方法,對此不感興趣、想看解決方案彙總的不用猶豫,用力地划動手機螢幕到頁面底部吧……

接下來,關於埠轉發的iptables、SSH、Nginx等方法,我們一個一個八過去。

以下解決方案的前提是,北大俠客行MUD伺服器端的web埠已經開在了9999。但是這樣對玩家來說仍有很多不便,例如:

  1. 需要改fullme外掛,在每個域名(也就是“pkuxkx.net”)後加9999,多有不便,甚至有些玩家還不會改fullme外掛的觸發器=.=

  2. 北俠Wiki的訪問,雖然用 http://pkuxkx.net:9999/wiki 理論上可行,但是需要載入一些樣式、圖片之類的資源,這些內容的請求地址是寫死的,仍然會去請求 pkuxkx.net,所以改埠對這類訪問無用。會導致wiki的訪問極慢(所有請求超時後瀏覽器上才會顯示相關頁面內容,所以那些說9999埠訪問不了wiki的,你們只要不嫌棄格式醜,多等等就出來啦)、格式也發生缺失,如下圖:

埠轉發方法

作為一個有強迫症的小編,對此感到非常不適(根據NASA公佈的最新13星座對應表,天蠍座的我已變身處女座T_T),所以以下解決方案都是以現存問題為解決目標各種展開。有興趣的看官我們們繼續。

0x03 iptables轉發規則

如果我們們自己的日常PC的作業系統是Linux,那就再好不過了,可以直接修改iptables,讓所有訪問pkuxkx.net:80的流量都轉發到pkuxkx.net:9999,這樣所有web訪問(論壇、wik、fullme,我會說還有SVN嗎=.=)就不需要額外加埠了;但是考慮到大多數玩家都用的Windows系統(或者一小撮Mac使用者?OS X也是沒有iptables的,不過有類似的工具替代),所以更大眾的解決方案可能是,由部分玩家提供一個能訪問80埠的遠端Linux伺服器作為轉發伺服器,這個伺服器上的80埠接受玩家訪問(比如訪問論壇時,玩家需要在瀏覽器裡輸入類似 http://xx.xx.xx.xx/forum ,其中xx.xx.xx.xx是轉發伺服器IP),然後將訪問流量轉發到pkuxkx.net:9999上去,實現玩家與北俠伺服器之間的橋樑,如下圖所示。本節之後的內容就是以配置這樣的轉發伺服器為目標(什麼?你沒有轉發伺服器?請加入北大俠客行MUD官方QQ群詢問已經配好的IP地址,QQ群號是152814678)。

埠轉發方法

iptables工作在使用者空間中,是定義規則的工具。它通過將規則組成一個列表,實現絕對詳細的訪問控制功能。它定義的規則,可以讓核心空間中的netfilter來讀取,並實現讓防火牆工作。netfilter作用在TCP/IP協議棧經過的地方。

關於iptables和netfilter所扮演的角色,網路上copy下來一張圖(對此圖一知半解,先抄下來=.=):

埠轉發方法

netfilter在核心空間中作用的位置有5個,如下圖:

埠轉發方法

這五個位置也被稱為五個鉤子函式(hook functions)或規則鏈。

  1. PREROUTING (路由前)

  2. INPUT (資料包流入口)

  3. FORWARD (轉發管卡)

  4. OUTPUT(資料包出口)

  5. POSTROUTING(路由後)

iptables的定義規則方式:

iptables [-t table] COMMAND chain CRETIRIA -j ACTION

規則說明:

  • -t table: filter/nat(地址轉換)/mangle(修改報文原資料)

  • COMMAND:定義如何對規則進行管理

  • chain:指定你接下來的規則到底是在哪個鏈上操作的,當定義策略的時候,是可以省略的

  • CRETIRIA:指定匹配標準

  • -j ACTION:指定如何進行處理

越說越多了=.= 關於iptables的介紹暫時到此為止,各引數的說明就不展開了,詳細可以參考手冊。還是來看看轉發伺服器應該如何配置,直接上指令:

echo 1 > /proc/sys/net/ipv4/ip_forward # 指令3.0:開啟IP轉發
iptables -t nat -A PREROUTING -p tcp -d 10.1.9.131 --dport 80 -j DNAT --to 211.154.198.9:9999 # 指令3.1

  • -A:追加,在當前鏈的最後新增一個規則。

  • PREROUTING:因為是遠端(遠端指的是玩家資料來自遠端主機而非本地主機)埠轉發,那麼資料包會經過網路卡。這種資料包在iptables經過PREROUTING鏈,所以需要在PREROUTING鏈中加入規則。

  • -p:匹配協議。協議一般指TCP/UDP/ICMP。

  • -d:匹配目標地址。

  • —dport:指定目標埠。

  • -j DNAT —to IP[-IP][:埠[-埠]]:修改目標地址。

關於DNAT(Destination Network Address Translation,目標地址轉換),修改的是IP資料包的目標地址。執行上面這條命令之後,來自玩家的資料包是可以被轉發到pkuxkx.net:9999(上面的211.154.198.9就是北俠伺服器目前的真實IP)了,但是站在北俠伺服器的角度,由於IP資料包的源地址沒有被改變,所以它返回的資料還會奔著玩家IP去——然而玩家主機和北俠伺服器並沒有建立TCP連線,所以從北俠伺服器發往玩家主機的IP資料包就要丟失了,這裡我們也需要修改IP資料包的源地址,把發往211.154.198.9的IP資料包的源地址改為本伺服器的地址(一般是eth0繫結的地址,這裡是10.1.9.131),這樣資料就可以有來有往了:

iptables -t nat -A POSTROUTING -d 211.154.198.9 -j SNAT --to-source 10.1.9.131 # 指令3.2

指令1.2還可以用以下的指令1.3來代替,適用於當前(轉發)伺服器IP不固定的時候。

iptables -t nat -A POSTROUTING -j MASQUERADE # 指令3.3

另外,除錯時經常需要清空規則,方法是:

iptables -F -t nat # 指令3.4

OK,iptables埠轉發至此完成。可以把這個轉發伺服器發給朋友,讓他們用http://xx.xx.xx.xx 來訪問北俠網站了!不過每次都輸入IP地址,麻煩又難記,怎麼在輸入地址時像從前一樣只輸入 http://pkuxkx.net 呢?這個就要涉及DNS(Domain Name System,域名系統)解析了。

0x04 DNS解析配置

DNS解析的概念比較簡單。當我們輸入一個域名,比如 pkuxkx.net 時,系統如何知道這個域名指向的目標IP是211.154.198.9還是xx.xx.xx.xx呢?這就是DNS解析提供的服務內容。

正常情況下,DNS解析是自動完成的,不需要使用者操心。不過我們可以自己通過手動配置檔案來人工干預系統的DNS解析。

本節我們的任務目標是,承接上節,通過修改本機的DNS解析配置,使得當自己訪問 http://pkuxkx.net 時,系統自動訪問 http://xx.xx.xx.xx ,從而實現對北俠網站的訪問。

  • Windows 使用者,用管理員許可權開啟記事本,然後找到 C:\Windows\System32\drivers\etc\hosts,在最後新增 xx.xx.xx.xx pkuxkx.net,然後重啟瀏覽器。不同Windows版本的hosts檔案位置可能不同,詳情可以百度“修改hosts檔案”,或者加北俠QQ群,會有熱心玩家幫你解惑的:)

  • Linux/Mac使用者,sudo vim /etc/hosts,在最後新增 xx.xx.xx.xx pkuxkx.net 即可。

不過用這種方式配置DNS解析的玩家需要注意,配置過後,如果你的MUD客戶端裡的IP位址列填的是 pkuxkx.net 的話,那麼MUD連線也會指向轉發伺服器的,這沒有必要,還可能帶來一些副作用,比如和他人共用IP帶來的最大後遺症就是,連線MUD時可能顯示:

你已經超過單IP允許的最大重複登陸數了。請合理使用伺服器資源,謝謝!

產生這個現象的原因是,北俠伺服器以為共用轉發伺服器的玩家都是從xx.xx.xx.xx登陸的,所以判斷為同IP的登陸ID數過多。這時候,只需要把MUD客戶端裡的地址寫成北俠的真實源地址(211.154.198.9)就能解決登陸限制的問題了。記得埠號寫5555,因為8080埠目前也和80埠一樣處於暫時悲劇中=.=

0x05 SSH埠轉發

SSH,遠端連線(Linux)伺服器的必備利器,語言已經無法表達我對它的依賴之情了!其轉發功能也非常強大,想要實現我們的功能,使用一條指令即可:

ssh -f -N -g -L 80:211.154.198.9:9999 root@localhost

解釋下幾個引數的作用:

  • -f:後臺操作,只有當提示使用者名稱密碼的時候才轉向前臺。

  • -N:是不執行遠端命令,在只是埠轉發時這條命令很有用處。

  • -g:允許遠端主機連線本地轉發埠。

  • -L:將本地埠對映到遠端主機埠。

總結一下這種用法的通用格式(除了-g和-L是必帶引數,上面指令的其他引數都是錦上添花):

ssh -g -L [bind_addr:]port:host:hostport user@server

含義是將client機器上port埠流量通過server機器中轉,轉發到host機器的hostport埠(前面的例子中,client和server其實是一臺機器,所以server指localhost)。

另外,需要修改代理伺服器上的sshd設定,使其允許被遠端訪問,修改方法是編輯/etc/ssh/sshd_config,增加如下配置項:
GatewayPorts yes

本節內容實現的目標和之前的iptables是一樣的,都是在某臺Linux伺服器上開啟80埠,並將從80埠接收到的流量轉發給 pkuxkx.net:9999,所以配合修改DNS解析配置食用,口感更佳。而這一實現目標,我們再來看Nginx是怎麼做的。

0x06 Nginx埠轉發

Nginx 最近兩年好像很火的樣子,發現網上不少文章,比如《Nginx開發從入門到精通》,開篇就講Nginx架構而不提Nginx是什麼,好像已經預設大家都懂這個了,果然是小編的層次太低嗎T_T

Nginx可以說是(靜態)Web Server,和老牌勁旅Apache的定位重合比較大,可以作為負載均衡裡的前端伺服器,用來處理請求的轉發(反向代理等),將請求分配到比較空閒的後臺服務。根據百度百科,Nginx “也是一個IMAP/POP3/SMTP伺服器”,看上去好像很好玩。

先安裝Nginx,Ubuntu系統下:

sudo apt-get install nginx

編輯配置檔案:

vim /etc/nginx/conf.d/port_80_to_pkuxkx_9999.conf

server
{
    listen 80;
    server_name pkuxkx.net;
    location / {
        proxy_redirect off;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://211.154.198.9:9999;
    }
    access_log logs/pkuxkx_9999_access.log;
}

儲存後重啟下Nginx服務:service nginx restart

有一個問題:如果listen的埠號為80,生效後訪問 http://xx.xx.xx.xx ,瀏覽器會顯示一個Nginx的歡迎頁而不是預期的北俠主頁。研究 /etc/nginx/nginx.conf 後發現,配置檔案中先 include 了 /etc/nginx/conf.d/*.conf 又 include 了 /etc/nginx/sites-enabled/* ,導致80埠相關配置被後來者覆蓋。解決方案是將 include /etc/nginx/sites-enabled/* 註釋掉,或者在這一行之後加入上面的配置項。

0x07 上篇小結

埠轉發上篇就八到這裡了。下篇可能整理下 Windows 下的埠轉發、通用的指令碼實現等。本來想一篇結束,但是文章越寫越長,而且後面的內容有些目前還是很難hold得住。另外心裡一點小願望是,也許還沒等我動筆,北俠的埠問題就解決了呢(辛苦冰神~ chat* massage icer),這樣就可以省事兒了,grin……

如果北俠的朋友能從此文中真正瞭解甚至理解埠轉發解決方案那再好不過;實在看不懂也沒關係,這裡將適用於北俠玩家的操作指南再總結一下,伸手黨看這裡

  1. 最簡單直接的方案,每次訪問北俠網站(包括論壇、wiki、fullme圖片等)直接在“pkuxkx.net”後面加9999埠號(再次強調埠號位置,不是在整個網址的最後,而是緊跟在“pkuxkx.net”後面)。這種方法下的wiki訪問會比較慢而且缺少格式美化,請耐心等待。

  2. 如果想只輸入 http://pkuxkx.net 就能訪問北俠網站,那麼就需要用管理員許可權修改hosts檔案,在C:\Windows\System32\drivers\etc\hosts里加一行xx.xx.xx.xx pkuxkx.net,然後重啟瀏覽器。注意若使用這種方法,請只用轉發ip訪問網站,不要用這個IP連線MUD遊戲(因為同一IP的登入ID數是有限制的),而需要手動在MUD客戶端裡將連線IP修改為211.154.198.9,埠號是5555。xx.xx.xx.xx = ?這個問題請進QQ群(群號152814678)或在MUD裡chat詢問,實在是由於某些原因不方便過於公開,chat* sorry。

最後寫寫感想:小編我之前實現埠轉發,其實是自己寫的python指令碼,比較繁瑣……借北俠埠故障的這個機會,瞭解並梳理一下當前幾個比較成熟的輪子方案,也算不虛這麼久的國慶節碼字時光。對iptables、nginx幾乎是第一次正式接觸,SSH裡的很多模糊概念也順道明確了下,不過應該還會有不少bug和幼稚之處,歡迎指點(聯絡方式請關注訂閱號”pkuxkx“,裡面有訂閱號的聯絡郵箱)。第一次在訂閱號上寫文,對讀者的定位也不是很清晰,可能所描述內容前後的一致性很差,還請多包涵了。敲完這篇文章的時候,火車已經快要到北京了,嗯,那就順便祝大家假期之後有一個好心情投入工作!chat* bow all

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/196700/viewspace-2136229/,如需轉載,請註明出處,否則將追究法律責任。

相關文章