歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux技術

iptables nat及端口映射(轉載)

本文摘自鏈接(http://www.91linux.com/html/article/network/20090120/15460.html )
iptables 應用初探(nat+三層訪問控制)
[code]iptables是 一個Linux下優秀的nat+防火牆工具,我使用該工具以較低配置的傳統pc配置了一個靈活強勁的防火牆+nat系統,小有心得,看了網上也有很多這方 面的文章,但是似乎要麼說的比較少,要麼就是比較偏,內容不全,容易誤導,我研究了一段時間的iptables同時也用了很久,有點滴經驗,寫來供大家參 考,同時也備日後自己翻閱。

首先要說明的是,iptables操作的是2.4以上內核的netfilter.所以需要linux的內核在2.4以上。其功能與安全性遠遠比其前 輩 ipfwadm,ipchains強大,iptables大致是工作在OSI七層的二、三、四層,其前輩ipchains不能單獨實現對 tcp/udp port以及對mac地址的的定義與操作,所以我想ipchains應該是僅僅工作在三層上的。

   我們先簡單介紹一下netfilter的大致工作流程,也就是一個數據包(或者叫分組、packet,我個人習慣叫包)在到達linux的網絡接口的時候 (網卡)如何處理這個包,然後再介紹一下如何用iptables改變或者說控制對這個數據包進行操作。netfilter內部分為三個表,分別 是 filter,nat,mangle,每個表又有不同的操作鏈(Chains)。在filter(過濾)表中,也就是他的防火牆功能的這個表,定義了 三個 Chain。分別是INPUT,FORWARD,OUTPUT。也就是對包的入、轉發、出進行定義的三個過濾鏈。對於這個filter表的操作和控 制也是我們實現防火牆功能的一個重要手段;在nat(Network Address Translation、網絡地址翻譯)表中,也就是我們用以實現 地址轉換和端口轉發功能的這個表,定義了PREROUTING, POSTROUTING,OUTPUT三個鏈,下面我們會對這三個鏈作詳細的說明;而 netfilter的mangle表則是一個自定義表,裡面包括上面的filter以及nat表中的各種chains,它可以讓我們進行一些自定義的操 作,同時這個mangle表中的chains在netfilter對包的處理流程中處在一個比較優先的位置,下面有一張圖清晰的描繪了netfilter 對包的處理流程,一般情況下,我們用不到這個mangle表,在這裡我們就不做介紹了。

 大家可以看到,PREROUTING這個chain在最前面,當一個包來到linux的網絡接口的時候先過mangle的PREROUTING,然後 是 nat的PREROUTING,從這個chain的名字我們可以看出,這個chain是在路由之前(pre-routing)要過的。為什麼要在路由 之前過呢?大家可以看到這個圖上,上面有一個菱形的部分叫ROUTING,這個ROUTING部分就是Linux的route box,也就是路由系統, 它同樣有很高深的功能,可以實現策略路由等等一些高級特性,此處我們不做詳細解釋。單說這個PREROUTING鏈,因為在這個鏈裡面我們對包的操作是 DNAT,也就是改變目的地址和(或端口),通常用在端口轉發,或者nat到內網的DMZ區,也就是說當一個包過來的時候我們要改變它的目的地址,大家可 以想想,如果一個包在改變目的地址之前就被扔進了route box,讓系統選好路之後再改變目的地址,那麼選路就可能是錯的,或者說毫無意義了,所 以,PREROUTING這個Chain一定要在進Routing 之前做。比如說,我們的公網ip是60.1.1.1/24,位於linux中的 eth0,內網ip是10.1.1.1/24位於linux中的eth1, 我們的內網有一台web服務器,地址是10.1.1.2/24,我們怎麼樣能 讓internet用戶通過這個公網ip訪問我們內部的這個web服務器呢?我們就可以在這個PREROUTING鏈上面定義一個規則,把訪問 60.1.1.1:80的用戶的目的地址改變一下,改變為10.1.1.2:80,這樣就實現了internet用戶對內網服務器的訪問了,當然了,這個 端口是比較靈活的,我們可以定義任何一個端口的轉發,不一定是80-->80,具體的命令我們在下面的例子中介紹,這裡我們只談流程與概念上的實現方法。

好了,我們接著往下走,這個包已經過了兩個PREROUTING鏈了,這個時候,出現了一個分支轉折的地方,也就是圖中下方的那個菱形 (FORWARD),轉發!這裡有一個對目的地址的判斷(這裡同樣說明了PREROUTING一定要在最先,不僅要在route box之前,甚至是這個 對目的地址的判斷之前,因為我們可能做一個去某某某ip的地方轉到自己的ip的規則,所以PREROUTING是最先處理這個包的 Chain)!如果包 的目的地是本機ip,那麼包向上走,走入INPUT鏈處理,然後進入LOCAL PROCESS,如果非本地,那麼就進入FORWARD鏈進行過濾,我們 在這裡就不介紹INPUT,OUTPUT的處理了,因為那主要是對於本機安全的一種處理,我們這裡主要說對轉發的過濾和nat的實現。

這裡的FORWARD我簡單說一下,當linux收到了一個目的ip地址不是本地的包,Linux會把這個包丟棄,因為默認情況下,Linux的三層包轉 發功能是關閉的,如果要讓我們的linux實現轉發,則需要打開這個轉發功能,可以改變它的一個系統參數,使用 sysctl net.ipv4.ip_forward=1或者echo "1" > /proc/sys/net/ipv4 /ip_forward命令打開轉發功能。好了,在這裡我們讓linux允許轉發,這個包的目的地址也不是本機,那麼它將接著走入FORWARD鏈,在 FORWARD鏈裡面,我們就可以定義詳細的規則,也就是是否允許他通過,或者對這個包的方向流程進行一些改變,這也是我們實現訪問控制的地方,這裡同樣 也是Mangle_FORWARD然後filter_FORWARD,我們操作任何一個鏈都會影響到這個包的命運,在下面的介紹中,我們就忽略掉 mangle表,我們基本用不到操作它,所以我們假設它是透明的。假設這個包被我們的規則放過去了,也就是ACCEPT了,它將進入 POSTROUTING部分,注意!這裡我注意到一個細節問題,也就是上面的圖中數據包過了FORWARD鏈之後直接進入了POSTROUITNG 鏈, 我覺得這中間缺少一個環節,也就是route box,對於轉發的包來說,linux同樣需要在選路(路由)之後才能將它送出,這個圖卻沒有標明這一點, 我認為它是在過了route box之後才進入的POSTROUITNG,當然了,這對於我們討論iptables的過濾轉發來說不是很重要,只是我覺得 流程上有這個問題,還是要說明一下。

同樣的,我們在這裡從名字就可以看出,這個POSTROUTING鏈應該是路由之後的一個鏈,也就是這個包要送出這台Linux的最後一個環節了,這也是極 其重要的一個環節!!這個時候linux已經完成(has done..^_^)了對這個包的路由(選路工作),已經找到了合適的接口送出這個包了,在這 個鏈裡面我們要進行重要的操作,就是被Linux稱為 SNAT的一個動作,修改源ip地址!為什麼修改源ip地址?很多情況需要修改源地址阿,最常見的 就是我們內網多台機器需要共享一個或幾個公網ip訪問 internet,因為我們的內網地址是私有的,假如就讓linux給路由出去,源地址也不變,這 個包應該能訪問到目的地,但是卻回不來,因為 internet上的N多個路由節點不會轉發私有地址的數據包,也就是說,不用合法ip,我們的數據包有去 無回。有人會說:“既然是這樣,我就不用私有 ip了,我自己分配自己合法的地址不行嗎?那樣包就會回來了吧?”答案是否定的,ip地址是ICANN來分 配的,你的數據包或許能發到目的地,但是回來的時候人家可不會轉到你那裡,internet上的路由器中的路由信息會把這個返回包送到那個合法的獲得ip 的地方去,你同樣收不到,而你這種行為有可能被定義為一種ip欺騙,很多設備會把這樣的包在接入端就給濾掉了,可能都到不了你要訪問的那個服務器,呵呵。

那麼Linux如何做SNAT呢?比如一個內網的10.1.1.11的pc訪問202.2.2.2的一個web服務器,linux的內網接口 10.1.1.1在收到這個包之後把原來的PC的 ip10.1.1.11改變為60.1.1.1的合法地址然後送出,同時在自己的 ip_conntrack表裡面做一個記錄,記住是內網的哪一個ip的哪個端口訪問的這個web服務器,自己把它的源地址改成多少了,端口改成多少了,以 便這個web服務器返回數據包的時候linux將它准確的送回給發送請求的這個pc.  

大體的數據轉發流程我們說完了,我們看看iptables使用什麼樣的參數來完成這些操作。

在 描述這些具體的操作之前,我還要說幾個我對iptables的概念的理解(未必完全正確),這將有助於大家理解這些規則,以實現更精確的控制。上文中我們 提到過,對包的控制是由我們在不同的Chain(鏈)上面添加不同的規則來實現的,比如我們對過濾表(filter table)添加規則來執行對包的操 控。那麼既然叫鏈,一定就是一條或者多條規則組成的了,這時就有一個問題了,如果多個規則對同一種包進行了定義,會發生什麼事情呢?在Chain中,所有 的規則都是從上向下來執行的,也就是說,如果匹配了第一行,那麼就按照第一行的規則執行,一行一行的往下找,直到找到符合這個類型的包的規則為止。如果找 了一遍沒有找到符合這個包的規則怎麼辦呢?itpables裡面有一個概念,就是Policy,也就是策略。一說這個東西大家可能就會覺得比較麻煩,什麼 策略阿,我對於它的理解就是所謂這個策略就是chain中的最後一條規則,也就是說如果找了一遍找不到符合處理這個包的規則,就按照policy來辦。這 樣理解起來就容易多了。iptables 使用-P來設置Chain的策略。
[code]好了,我們言歸正傳,來說說iptables到底怎樣實現對包的控制

先介紹一下iptables如何操作鏈
對鏈的操作就那麼幾種,-I(插入) -A(追加) -R(替換) -D(刪除) -L(列表顯示)
這裡要說明的就是-I將會把規則放在第一行,-A將會放在最後一行。
比如我們要添加一個規則到filter表的FORWARD鏈
iptables -t filter -A FORWARD -s 10.1.1.11 -d 202.1.1.1 -j ACCEPT
上 面的命令意思為:追加一個規則至filter表中的FORWARD鏈尾,允許(-j ACCEPT)源地址為10.1.1.11目的地址為 202.1.1.1的數據包通過。其中-t後面跟的是表名,在-A後面跟Chain名,後面的小寫的 -s為源地址,-d為目的地址,-j為處理方向。
[code]在iptables中,默認的表名就是filter,所以這裡可以省略-t filter直接寫成:iptables -A FORWARD -s 10.1.1.11 -d 202.1.1.1 -j ACCEPT

iptables中的匹配參數:
我們在這裡就介紹幾種常用的參數,詳細地用法可以man iptables看它的聯機文檔,你會有意外的收獲。
-s匹配源地址
-d匹配目的地址
-p協議匹配
-i入接口匹配
-o出接口匹配
–sport,–dport源和目的端口匹配
-j跳轉,也就是包的方向
[code]其中還有一個!參數,使用!就是取反的意思。下面我們簡單舉幾個例子介紹一下。

-s這 個參數呢就是指定源地址的,如果使用這個參數也就是告訴netfilter,對於符合這樣一個源地址的包怎麼去處理,可以指定某一個單播ip地址,也可以 指定一個網絡,如果單個的ip地址其實隱含了一個32位的子網掩碼,比如-s 10.1.1.11 其實就是-s 10.1.1.11/32 同樣我們可 以指定不同的掩碼用以實現源網絡地址的規則,比如一個C類地址我們可以用-s 10.1.1.0/24來指定。
-d參數與-s格式一樣。
-i參數是指定入接口的網絡接口,比如我僅僅允許從eth3接口過來的包通過FORWARD鏈,就可以這樣指定iptables -A FORWARD -i eth3 -j ACCEPT
-o是出接口,與上同.
我們下面用一些簡單的實例來step by step看看iptables的具體配置方法。
實例一:簡單的nat路由器
環境介紹:
2個網絡接口
Lan口:10.1.1.254/24 eth0
Wan口:60.1.1.1/24 eth1
目的:實現內網中的節點(10.1.1.0/24)可控的訪問internet。
[code]首先將Lan的節點pc的網關指向10.1.1.254

確定你的linux的ip配置無誤,可以正確的ping通內外的地址。同時用route命令查看linux的本地路由表,確認指定了可用的ISP提供的默認網關。
使用sysctl net.ipv4.ip_forward=1打開linux的轉發功能。
iptables -P FORWARD DROP
將FORWARD鏈的策略設置為DROP,這樣做的目的是做到對內網ip的控制,你允許哪一個訪問internet就可以增加一個規則,不在規則中的ip將無法訪問internet.
iptables -A FORWARD -m state –state ESTABLISHED,RELATED -j ACCEPT
這條規則規定允許任何地址到任何地址的確認包和關聯包通過。一定要加這一條,否則你只允許lan IP訪問沒有用,至於為什麼,下面我們再詳細說。
iptables -t nat -A POSTROUTING -s 10.1.1.0/24 -j SNAT –to 60.1.1.1
這條規則做了一個SNAT,也就是源地址轉換,將來自10.1.1.0/24的地址轉換為60.1.1.1
有這幾條規則,一個簡單的nat路由器就實現了。這時你可以將允許訪問的ip添加至FORWARD鏈,他們就能訪問internet了。
比如我想讓10.1.1.9這個地址訪問internet,那麼你就加如下的命令就可以了。
iptables -A FORWARD -s 10.1.1.9 -j ACCEPT
也可以精確控制他的訪問地址,比如我就允許10.1.1.99訪問3.3.3.3這個ip
iptables -A FORWARD -s 10.1.1.99 -d 3.3.3.3 -j ACCEPT
或者只允許他們訪問80端口。
iptables -A FORWARD -s 10.1.1.0/24 -p tcp –dport http -j ACCEPT
更多的控制可以自己靈活去做,或者查閱iptables的聯機文檔。
實例二:端口轉發
環境介紹:
2個網絡接口
Lan口:10.1.1.254/24 eth0
Lan內web server: 10.1.1.1:80
Lan內ftp server: 10.1.1.2:21
Wan口:60.1.1.1/24 eth1
目的:對內部server進行端口轉發實現internet用戶訪問內網服務器
[code]同樣確認你的linux的各項配置正常,能夠訪問內外網。

iptables -P FORWARD DROP
iptables -A FORWARD -m state –state ESTABLISHED,RELATED -j ACCEPT
也需要加入確認包和關聯包的允許通過
如果你要把訪問60.1.1.1:80的數據包轉發到Lan內web server,用下面的命令
iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp –dport 80 -j DNAT –to 10.1.1.1:80
ftp服務也同樣,命令如下:
iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp –dport 21 -j DNAT –to 10.1.1.2:21
[code]好了,命令完成了,端口轉發也做完了,本例能不能轉發呢?不能,為什麼呢?我下面詳細分析一下。對於iptables好像往外訪問的配置比較容易,而對內 的轉發似乎就有一些問題了,在一開始的時候我就先說了一些關於netfilter的流程問題,那麼我就簡單說說做了這些配置之後為什麼有可能還不行呢?

能引起這個配置失敗的原因有很多,我們一個個的來說:

第一,本例中,我們的FORWARD策略是DROP,那麼也就是說,沒有符合規則的包將被丟棄,不管內到外還是外到內,我們在這裡依然不討論那個確認包和關聯包的問題,我們不用考慮他的問題,下面我會詳細說一下這個東西,那麼如何讓本例可以成功呢?加入下面的規則。
iptables -A FORWARD -d 10.1.1.1 -p tcp –dport 80 -j ACCEPT
iptables -A FORWARD -d 10.1.1.2 -p tcp –dport 21 -j ACCEPT
[code]有沒有覺得有一些暈?為什麼目的地址是10.xxx而不是60.xxx人家internet用戶不是訪問的60.xxx嗎?呵呵,回到上面看看那個圖 吧, FORWARD鏈在什麼位置上,它是在PREROUTING之後,也就是說當這個包到達FORWARD鏈的時候,目的地址已經變成10.xxx了, 假如 internet用戶的請求是這樣202.1.1.1:1333-->60.1.1.1:80,在經過了我們的PREROUTING鏈之後將 變成 202.1.1.1:1333-->10.1.1.1:80,這個時候如果你設置一個目的地址為60.xxx的規則有用嗎?呵呵,這是問題 一。這個時候應該可以完成端口轉發的訪問了,但是有一些時候還是不行?為什麼?看問題二。

第 二,內網server的ip配置問題,這裡我們以web server為例說明一下(ftp情況有一些特殊,下面我們再詳細討論,說確認包和關聯包的時候 討論這個問題),上面說到,有的時候可以訪問了,有的時候卻不行,就是這個web server的ip設置問題了,如果web server沒有指定默認 的網關,那麼在作了上面的配置之後,web server會收到internet的請求,但是,他不知道往哪裡回啊,人家的本地路由表不知道你那個 internet的ip,202.1.1.1該怎麼走。如果你使用截包工具在web server上面察看,你會發現server收到了來自 202.1.1.1:1333–>10.1.1.1:80的請求,由於你沒有給web server配置默認網關,它不知道怎麼回去,所以就出現 了不通的情況。怎麼辦呢?兩個解決方法:一就是給這個server配置一個默認網關,當然要指向這個配置端口轉發的linux,本例是 10.1.1.254,配置好了,就一定能訪問了。有一個疑問?難道不需要在FORWARD鏈上面設置一個允許 web server的ip地址訪問外網 的規則嗎?它的包能出去?答案是肯定的,能出去。因為我們那一條允許確認包與關聯包的規則,否則它是出不去的。第二種方法,比較麻煩一些,但是對服務器來 說這樣似乎更安全一些。方法就是對這個包再作一次SNAT,也就是在POSTROUTING鏈上添加規則。命令如下:
iptables -t nat -A POSTROUTING -d 10.1.1.1 -p tcp –dport 80 -j SNAT –to 10.1.1.254
[code]ftp的 方法相同。這條命令不太好懂??其實很簡單,如果使用這條命令,那麼你的web server不需要再設置默認網關,就能收到這個請求,只要他和 linux的lan ip地址是能互訪的(也就是說web server和Linux的Lan ip在一個廣播域),我們在根據上面的netfilter 流程圖來分析這個包到底被我們怎麼樣了,首先一個請求202.1.1.1:1333--> 60.1.1.1:80被linux收到了,進入 PREROUTING,發現一個規則 (iptables -t nat -A PREROUTING -d 60.1.1.1 -p tcp --dport 80 -j DNAT --to 10.1.1.1:80) 符合,好了,改你的目的地址,於是這個包變成了202.1.1.1:1333-->10.1.1.1:80,繼續往前走,進入FORWARD 鏈,okay,也有一條規則允許通過 (iptables -A FORWARD -d 10.1.1.1 -p tcp --dport 80 -j ACCEPT),進入 route box選路,找到合適的路徑了,繼續進入POSTROUTING鏈,耶?又發現一個符合的規則 (iptables -t nat -A POSTROUTING -d 10.1.1.1 -p tcp --dport 80 -j SNAT --to 10.1.1.254), 原來是一個SNAT,改你的源地址,於是這個包變成了10.1.1.254:xxxx-->10.1.1.1:80。為什麼用xxxx了,這裡的端 口是隨機的,我也不知道會是什麼。而整個的兩次變化的過程都會記錄在linux的ip_conntrack中,當web server收到這個包的時候, 發現,原來是一個內網自己兄弟來的請求阿,又在一個廣播域,不用找網關,把返回包直接扔給交換機了,linux在收到返回包之後,會根據他的 ip_conntrack中的條目進行兩次變換,返回真正的internet用戶,於是完成這一次的訪問。

看了上面的兩個例子,不知道大家是否清楚了iptables的轉發流程,希望對大家有所幫助,下面我們就說說我一直在上面提到的關於那 個 ESTABLISHED,RELATED的規則是怎麼回事,到底有什麼用處。說這個東西就要簡單說一下網絡的數據通訊的方式,我們知道,網絡的訪問是 雙向的,也就是說一個Client與Server之間完成數據交換需要雙方的發包與收包。在netfilter中,有幾種狀態,也就是 new, established,related,invalid。當一個客戶端,在本文例一中,內網的一台機器訪問外網,我們設置了規則允許他出去, 但是沒有設置允許回來的規則阿,怎麼完成訪問呢?這就是netfilter的狀態機制,當一個lan用戶通過這個linux訪問外網的時候,它發送了一個 請求包,這個包的狀態是new,當外網回包的時候他的狀態就是established,所以,linux知道,哦,這個包是我的內網的一台機器發出去的應 答包,他就放行了。而外網試圖對內發起一個新的連接的時候,他的狀態是new,所以linux壓根不去理會它。這就是我們為什麼要加這一句的原因。還有那 個 related,他是一個關聯狀態,什麼會用到呢?tftp,ftp都會用到,因為他們的傳輸機制決定了,它不像http訪問那 樣,Client_IP: port-->server:80  然後server:80-->Client_IP:port,ftp使用 tcp21建立連接,使用20端口發送數據,其中又有兩種方式,一種主動 active mode,一種被動passive mode,主動模式 下,client使用port命令告訴server我用哪一個端口接受數據,然後server主動發起對這個端口的請求。被動模式下, server使用 port命令告訴客戶端,它用那個端口監聽,然後客戶端發起對他的數據傳輸,所以這對於一個防火牆來說就是比較麻煩的事情,因為有可能會有new狀態的數 據包,但是它又是合理的請求,這個時候就用到這個related狀態了,他就是一種關聯,在linux中,有個叫 ftp_conntrack的模塊,它 能識別port命令,然後對相應的端口進行放行。

還有幾個在實際中比較實用(也比較受用:-))的命令參數,寫出來供大家參考
iptables -L -n
這 樣的列表會跳過linux的domain lookup,有的時候使用iptables -L會比較慢,因為linux會嘗試解析ip的域名,真是羅嗦, 如果你的dns server比較不爽的話,iptables -L就會讓你很不爽,加一個-n參數就好了。列表刷的就出來。當然了,如果你的linux 就是做防火牆,建議把nameserver去掉,在 /etc/resolve.conf裡面,因為有時候使用route命令也會比較慢列出來,很是不 爽。
iptables -L -v
這個命令會顯示鏈中規則的包和流量計數,嘿嘿,看看哪些小子用的流量那麼多,用tc限了他。
cat /proc/net/ip_conntrack
查看目前的conntrack,可能會比較多哦,最好加一個|grep “關鍵字”,看看你感興趣的鏈接跟蹤
wc -l /proc/net/ip_conntrack
看看總鏈接有多少條。
iptables-save >/etc/iptables
把當前的所有鏈備份一下,之所以放到/etc下面叫iptables,因為這樣重起機器的時候會自動加載所有的鏈,經常地備份一下吧,否則如果鏈多,萬一掉電重啟,你還是會比較痛苦。
Copyright © Linux教程網 All Rights Reserved