iptables 詳解

標籤:
1. 序言
1.1. 爲什麼要寫這個指南
我發現目前所有的HOWTO都缺乏Linux 2.4.x 內核中的Iptables和Netfilter 函數的信息,於是我試圖回答一些問題,比如狀態匹配。我會用插圖和例子 rc.firewall.txt 加以說明,此處的例子可以在你的/etc/rc.d/使用。最初這篇文章是以HOWTO文檔的形式書寫的,因爲許多人只接受HOWTO文檔。
還有一個小腳本rc.flush-iptables.txt,我寫它只是爲使你在配置它的時候能象我一樣有成功的感覺。

--------------------------------------------------------------------------------
1.2. 指南是如何寫的
我請教了Marc Boucher 及netfilter團隊的其他核心成員。對他們的工作以及對我在爲boingworld.com 書寫這個指南時的幫助表示極大的謝意,現在這個指南在我自己的站點frozentux.net上進行維護。這個文檔將一步一步教你setup過程,讓你對iptables包有更多的瞭解。這大部分的東西都基於例子rc.firewall 文件,因爲我發現這是學習iptables的一個好方法。我決定自頂向下地跟隨rc.firewall 文件來學習 iptables。雖然這樣會困難一些,但更有邏輯。當你碰到不懂的東西時再來查看這個文件。

--------------------------------------------------------------------------------
1.3. 文中出現的術語
文中包含了一些術語,你應該有所瞭解。這裏有一些解釋,並說明了本文中如何使用它們。
DNAT - Destination Network Address Translation 目的網絡地址轉換。 DNAT是一種改變數據包目的 ip地址的技術,經常和SNAT聯用,以使多臺服務器能共享一個ip地址連入Internet,並且繼續服務。通過對同一個ip地址分配不同的端口,來決定數據的流向。
Stream - 流 是指發送和接收的數據包和通信的雙方都有關係的一種連接(譯者注:本文中,作者把連接看作是單向的,流表示雙向的連接)。一般的,這個詞用於描述在兩個方向上發送兩個或三個數據包的連接。對於TCP,流意味着連接,它發送了一個SYN,然後又回覆SYN/ACK。但也可能是指這樣的連接,發送一個SYN,回覆ICMP主機不可達信息。換句話說,我使用這個詞很隨意。
SNAT - Source Network Address Translation源網絡地址轉換。這是一種改變數據包源ip地址的技術,經常用來使多臺計算機分享一個Internet地址。這隻在IPv4中使用,因爲IPv4的地址已快用完了,IPv6將解決這個問題。
State - 狀態 指明數據包處於什麼狀態。狀態在RFC 793 - Transmission Control Protocol中定義,或由用戶在Netfilter/iptables中自定義。需要注意的是Netfilter設定了一些關於連接和數據包的狀態,但沒有完全使用使用RFC 793的定義。
User space - 用戶空間,指在內核外部或發生在內核外部的任何東西。例如,調用 iptables -h 發生在內核外部,但iptables -A FORWARD -p tcp -j ACCEPT (部分地)發生在內核內部,因爲一條新的規則加入了規則集。
Kernel space - 內核空間 ,與用戶空間相對,指那些發生在內核內部。
Userland - 參見用戶空間
target - 這個詞在後文中有大量的應用,它表示對匹配的數據包所做的操作。

--------------------------------------------------------------------------------
2. 準備階段
這一章是學習iptables的開始,它將幫助你理解Netfilter和iptables在Linux中扮演的角色。它會告訴你如何配置、安裝防火牆,你的經驗也會隨之增長。當然,要想達到你的目標,是要花費時間,還要有毅力。( 譯者注:聽起來很嚇人的:) )

--------------------------------------------------------------------------------
2.1. 哪裏能取得iptables
iptables 可以從www.netfilter.org 下載,網站中的FAQs也是很好的教程。iptables 也使用一些內核空間,可以在用make configure配置內核的過程中配置,下面會介紹必要的步驟。

--------------------------------------------------------------------------------
2.2. 內核配置
爲了運行iptables,需要在內核配置期間,選擇以下一些選項,不管你用make config或其他命令。
CONFIG_PACKET - 允許程序直接訪問網絡設備(譯者注:最常用的就是網卡了),象tcpdump 和 snort就要使用這個功能。

嚴格地說,iptables並不需要CONFIG_PACKET,但是它有很多用處(譯者注:其他程序需要),所以就選上了。當然,你不想要,不選就是了。(譯者注:建議還是選的爲好)
 
CONFIG_NETFILTER - 允許計算機作爲網關或防火牆。這個是必需的,因爲整篇文章都要用到這個功能。我想你也需要這個,誰叫你學iptables呢:)
當然,你要給網絡設備安裝正確的驅動程序,比如,Ethernet 網卡, PPP 還有 SLIP 。 上面的選項,只是在內核中建立了一個框架, iptables確實已經可以運行,但不能做任何實質性的工作。我們需要更多的選項。以下給出內核2.4.9的選項和簡單的說明:
CONFIG_IP_NF_CONNTRACK - 連接跟蹤模塊,用於 NAT(網絡地址轉換) 和 Masquerading(ip地址僞裝),當然,還有其他應用。如果你想把LAN中的一臺機子作爲防火牆,這個模塊你算選對了。腳本rc.firewall.txt 要想正常工作,就必需有它的存在。
CONFIG_IP_NF_FTP - 這個選項提供針對FTP連接進行連接跟蹤的功能。一般情況下,對FTP連接進行連接跟蹤是很困難的,要做到這一點,需要一個名爲helper的動態鏈接庫。此選項就是用來編譯helper的。如果沒有這個功能,就無法穿越防火牆或網關使用FTP。
CONFIG_IP_NF_IPTABLES - 有了它,你才能使用過濾、僞裝、NAT。它爲內核加入了iptables標識框架。沒有它,iptables毫無作用。
CONFIG_IP_NF_MATCH_LIMIT - 此模塊並不是十分必要,但我在例子rc.firewall.txt中用到了。它提供匹配LIMIT的功能,以便於使用一個適當的規則來控制每分鐘要匹配的數據包的數量。比如, -m limit --limit 3/minute 的作用是每分鐘最多匹配三個數據包。這個功能也可用來消除某種DoS***。
CONFIG_IP_NF_MATCH_MAC - 選擇這個模塊,可以根據MAC地址匹配數據包。例如,我們想要阻塞使用了某些MAC地址的數據包,或阻塞某些計算機的通信,用這個很容易。因爲每個Ethernet網卡都有它自己的MAC地址,且幾乎從不會改變。但我在 rc.firewall.txt中沒有用到這個功能,其他例子也未用到。(譯者注:這又一次說明了學習是爲將來打基礎:) )
CONFIG_IP_NF_MATCH_MARK - 這個選項用來標記數據包。對數據包做 MARK(標記)操作,我們就可以在後面的表中用這個標記來匹配數據包。後文有詳細的說明。
CONFIG_IP_NF_MATCH_MULTIPORT - 選擇這個模塊我們可以使用端口範圍來匹配數據包,沒有它,是無法做到這一點的。
CONFIG_IP_NF_MATCH_TOS - 使我們可以設置數據包的TOS(Type Of Service 服務類型)。這個工作也可以用命令ip/tc完成,還可在mangle表中用某種規則設定。
CONFIG_IP_NF_MATCH_TCPMSS - 可以基於MSS匹配TCP數據包。
CONFIG_IP_NF_MATCH_STATE - 相比較ipchains 這是最大的更新,有了它,我們可以對數據包做狀態匹配。比如,在某個TCP連接的兩個方向上已有通信,則這個連接上的數據包就被看作ESTABLISHED(已建立連接)狀態。在rc.firewall.txt 裏大量使用了此模塊的功能。
CONFIG_IP_NF_MATCH_UNCLEAN - 匹配那些不符合類型標準或無效的 P、TCP、UDP、ICMP數據包(譯者注:之所以此模塊名爲UNCLEAN,可以這樣理解,凡不是正確模式的包都是髒的。這有些象操作系統內存管理中的“髒頁”,那這裏就可以稱作“髒包”了,自然也就UNCLEAN了)。我們一般丟棄這樣的包,但不知這樣做是否正確。另外要注意,這種匹配功能還在實驗階段,可能會有些問題。
CONFIG_IP_NF_MATCH_OWNER - 根據套接字的擁有者匹配數據包。比如,我們只允許root訪問Internet。在iptables中,這個模塊最初只是用一個例子來說明它的功能。同樣,這個模塊也處於實驗階段,還無法使用。
CONFIG_IP_NF_FILTER - 這個模塊爲iptables添加基本的過濾表,其中包含INPUT、FORWARD、OUTPUT鏈。通過過濾表可以做完全的IP過濾。只要想過濾數據包,不管是接收的還是發送的,也不管做何種過濾,都必需此模塊。
CONFIG_IP_NF_TARGET_REJECT - 這個操作使我們用ICMP錯誤信息來回應接收到的數據包,而不是簡單地丟棄它。有些情況必須要有迴應的,比如,相對於ICMP和UDP來說,要重置或拒絕TCP連接總是需要一個TCP RST包。
CONFIG_IP_NF_TARGET_MIRROR - 這個操作使數據包返回到發送它的計算機。例如,我們在INPUT鏈裏對目的端口爲HTTP的包設置了MIRROR操作,當有人訪問HTTP時,包就被髮送回原計算機,最後,他訪問的可能是他自己的主頁。(譯者注:應該不難理解爲什麼叫做MIRROR了)
CONFIG_IP_NF_NAT - 顧名思義,本模塊提供NAT功能。這個選項使我們有權訪問nat表。端口轉發和僞裝是必需此模塊的。當然,如果你的LAN裏的所有計算機都有唯一的有效的 IP地址,那在做防火牆或僞裝時就無須這個選項了。rc.firewall.txt 是需要的:)
CONFIG_IP_NF_TARGET_MASQUERADE - 提供MASQUERADE(僞裝)操作。如果我們不知道連接Internet的IP,首選的方法就是使用MASQUERADE,而不是DNAT或SNAT。換句話說,就是如果我們使用PPP或SLIP等連入Internet,由DHCP或其他服務分配IP,使用這個比SNAT好。因爲MASQUERADE 不需要預先知道連接Internet的IP,雖然對於計算機來說MASQUERADE要比NAT的負載稍微高一點。
CONFIG_IP_NF_TARGET_REDIRECT - 這個操作和代理程序一起使用是很有用的。它不會讓數據包直接通過,而是把包重新映射到本地主機,也就是完成透明代理。
CONFIG_IP_NF_TARGET_LOG - 爲iptables增加 LOG(日誌)操作。通過它,可以使用系統日誌服務記錄某些數據包,這樣我們就能瞭解在包上發生了什麼。這對於我們做安全審查、調試腳本的幫助是無價的。
CONFIG_IP_NF_TARGET_TCPMSS - 這個選項可以對付一些阻塞ICMP分段信息的ISP(服務提供商)或服務。沒有ICMP分段信息,一些網頁、大郵件無法通過,雖然小郵件可以,還有,在握手完成之後,ssh可以但scp不能工作。我們可以用TCPMSS解決這個問題,就是使MSS(Maximum Segment Size)被鉗制於PMTU(Path Maximum Transmit Unit)。這個方法可以處理被Netfilter開發者們在內核配置幫助中稱作“criminally brain-dead ISPs or servers”的問題。
CONFIG_IP_NF_COMPAT_IPCHAINS - ipchains 的,這只是爲內核從2.2轉換到2.4而使用的,它會在2.6中刪除。
CONFIG_IP_NF_COMPAT_IPFWADM - 同上,這只是 ipfwadm的暫時使用的兼容模式。
上面,我簡要介紹了很多選項,但這只是內核2.4.9中的。要想看看更多的選項,建議你去Netfilter 看看patch-o-matic。在那裏,有其他的一些選項。POM可能會被加到內核裏,當然現在還沒有。這有很多原因,比如,還不穩定,Linus Torvalds沒打算或沒堅持要把這些補丁放入主流的內核,因爲它們還在實驗。
把以下選項編譯進內核或編譯成模塊,rc.firewall.txt才能使用。

CONFIG_PACKET
CONFIG_NETFILTER
CONFIG_IP_NF_CONNTRACK
CONFIG_IP_NF_FTP
CONFIG_IP_NF_IRC
CONFIG_IP_NF_IPTABLES
CONFIG_IP_NF_FILTER
CONFIG_IP_NF_NAT
CONFIG_IP_NF_MATCH_STATE
CONFIG_IP_NF_TARGET_LOG
CONFIG_IP_NF_MATCH_LIMIT
CONFIG_IP_NF_TARGET_MASQUERADE
以上是爲保證 rc.firewall.txt正常工作而需要的最少的選項。其他腳本需要的選項,在相應的章節裏都有說明。目前,我們只需注意要學習的這個腳本。

--------------------------------------------------------------------------------
2.3. 編譯與安裝
下面,我們來看看如何編譯iptables。iptables很多組件的配置、編譯是與內核的配置、編譯相關聯的,瞭解這一點是很重要的。某些Linux產品預裝了iptables,比如Red Hat,但是它的缺省設置是不啓用iptables的。後文我們會介紹如何啓用它,也會介紹一下其他 Linux產品裏的iptables情況。

--------------------------------------------------------------------------------
2.3.1. 編譯
首先要解壓iptables包。這裏,我用iptables 1.2.6a做例子(譯者注:在我翻譯時,最新版本已經是 1.2.9,其中又有了不少改進,修補了一些bug,增添了幾個match和target。)。命令 bzip2 -cd iptables-1.2.6a.tar.bz2 | tar -xvf -(當然也可以用tar -xjvf iptables-1.2.6a.tar.bz2,但這個命令可能對一些老版的tar不適用 ) 將壓縮包解壓至目錄iptables-1.2.6a,其中的INSTALL文件有很多對編譯、運行有用的信息。
這一步,你將配置、安裝一些額外的模塊,也可以爲內核增加一些選項。我們這裏只是檢查、安裝一些未被納入內核的標準的補丁。當然,更多的在實驗階段的補丁,僅在進行其他某些操作時纔會用到。

有一些補丁僅僅處在實驗階段,把它們也安裝上不是一個好主意。這一步,你會遇到很多十分有趣的匹配和對數據包的操作,但它們還正在實驗。
爲了完成這一步,我們要在iptables的目錄內用到如下一些命令:
 
make pending-patches KERNEL_DIR=/usr/src/linux/
變量KERNEL_DIR指向內核原碼的真實路徑。一般情況下,都是/usr/src/linux/ ,但也會不一樣,這要看你所用的Linux產品了。

總之,只有某些補丁會被詢問是否加入內核,而Netfilter的開發者們有大量的補丁或附件想要加入內核,但還要再實驗一陣子才能做到。如果你想安裝這些東西,就用下面的命令:
 
make most-of-pom KERNEL_DIR=/usr/src/linux/
這個命令會安裝部分patch-o-matic(netfilter世界對補丁的稱呼),忽略掉的是非常極端的那一部分,它們可能會對內核造成嚴重的破壞。你要知道這個命令的作用,要了解它們對內核原碼的影響,好在在你選用之前,會有所提示。下面的命令可以安裝所有的patch-o-matic(譯者注:一定要小心哦)。
make patch-o-matic KERNEL_DIR=/usr/src/linux/
要仔細的讀讀每一個補丁的幫助文件,因爲有些patch-o-matic會損壞內核,而有些對其他補丁有破壞作用。

你要是不打算用patch-o-matic修補內核,以上的命令都用不着,它們不是必需的。不過,你可以用這些命令來看看有什麼有趣的玩意兒,這不會影響任何東西。
 
安裝好patch-o-matic,現在應該重新編譯內核了,因爲其中增加了一些補丁。但別忘了重新配置內核,現有的配置文件裏可沒有你增加的補丁的信息。當然,你也可以先編譯iptables , 再來編譯內核。
接下來就該編譯iptables了,用下面這個簡單的命令:
make KERNEL_DIR=/usr/src/linux/
iptables應該編譯好了,如果不行,好好考慮考慮問題在哪兒,要麼訂閱 Netfilter mailing list,那裏可能有人能幫助你。
一切順利的話,我們該安裝iptables了,這幾乎不會有什麼問題的。我們用下面的命令來完成這一步:
make install KERNEL_DIR=/usr/src/linux/
現在大功告成了。如果你在前面沒有重新編譯、安裝內核,現在就要做了,不然,你還是不能使用更新後的iptables。好好看看INSTALL吧,那裏面有詳細的安裝信息。

--------------------------------------------------------------------------------
2.3.2. 在Red Hat 7.1上安裝
Red Hat 7.1使用2.4.x的內核,支持Netfilter和iptables。Red Hat包含了所有基本的程序和需要的配置文件,但缺省使用的是B class=COMMAND>ipchains。“iptables爲什麼不能用”是最常見的問題,下面就讓我們就來說說如何關閉ipchains而起用iptables 。

Red Hat 7.1預裝的iptables版本有些老了,在使用之前,你可能想裝個新的,再自己編譯一下內核。
 
我們先要關閉ipchains,並且不想再讓它運行起來,做到這一點,要更改目錄/etc/rc.d/下的一些文件名。用以下命令完成:
chkconfig --level 0123456 ipchains off
這個命令把所有指向/etc/rc.d/init.d/ipchains的軟連接改名爲 K92ipchains。以S開頭表示,在啓動時會由初始化腳本運行此腳本。改爲K開頭後,就表示終止服務,或以後在啓動時不再運行。這樣,ipchains以後不會再開機就運行了。
要想終止正在運行的服務,要用service命令。終止ipchains 服務的命令是:
service ipchains stop
現在,我們可以啓動iptables服務了。首先,要確定在哪個運行層運行,一般是 2,3和5,這些層有不同的用處:
 
2. 不帶NFS的多用戶環境,和層3的區別僅在於不帶網絡支持。
3. 多用戶環境,就是我們一般事用的層。
5. X11,圖形界面。

用下面的命令以使iptables能在這些層運行:
chkconfig --level 235 iptables on
你也可以使用這個命令使iptables能在其他層運行。但沒這個必要,因爲層1是單用戶模式,一般用在維修上;層4保留不用;層6用來關閉計算機。
啓動iptables用:
service iptables start
在腳本iptables裏還沒有定義規則。在Red Hat 7.1中添加規則的方法有二:第一個方法是編輯/etc/rc.d/init.d/iptables,要注意在用RPM升級iptables時,已有的規則可能會被刪除。另一個方法是先裝載規則,然後用命令iptables-save把規則保存到文件中,再由目錄rc.d下的腳本(/etc/rc.d/init.d/iptables)自動裝載。
我們先來說明如何利用“剪切粘貼大法”設置/etc/rc.d/init.d/iptables。爲了能在計算機啓動iptables時裝載規則,可以把規則放在“start)”節或函數start()中。注意:如果把規則放在“start)”節裏,則不要在“start)”節裏運行start(),還要編輯“stop)”節,以便在關機時或進入一個不需要iptables的層時,腳本知道如何處理。還應檢查“restart”節和“condrestart”節的設置。一定要注意,我們所做的改動在升級iptables時可能會被刪除,而不管是通過Red Hat網絡自動升級還是用 RPM升級。
下面介紹第二種方法:先寫一個規則的腳本,或直接用iptables命令生成規則。規則要適合自己的需要,別忘了實驗一下是否有問題,確認正常之後,使用命令iptables-save來保存規則。一般用iptables-save > /etc/sysconfig/iptables生成保存規則的文件 /etc/sysconfig/iptables,也可以用service iptables save,它能把規則自動保存在/etc/sysconfig/iptables中。當計算機啓動時,rc.d下的腳本將用命令iptables-restore調用這個文件,從而就自動恢復了規則。
以上兩種方法最好不要混用,以免用不同方法定義的規則互相影響,甚至使防火牆的設置無效。
至此,可以刪除預裝的ipchains和iptables了,這樣可以避免新舊版本的iptables之間的衝突。其實,只有當你從原碼安裝時,才需要這樣做。但一般來說,也不會出現互相影響的問題,因爲基於rpm的包不使用原碼的缺省目錄。刪除用以下命令:
rpm -e iptables
既然不用ipchains爲什麼要保留呢?刪吧!命令如下:
rpm -e ipchains
歷經磨難,勝利終於到來了。你已經能夠從源碼安裝iptables了。那些老版的東西就刪掉吧。

--------------------------------------------------------------------------------
Chapter 3. 表和鏈
這一章我們來討論數據包是以什麼順序、如何穿越不同的鏈和表的。稍後,在你自己寫規則時,就會知道這個順序是多麼的重要。一些組件是iptables與內核共用的,比如,數據包路由的判斷。瞭解到這一點是很重要的,尤其在你用iptables改變數據包的路由時。這會幫助你弄明白數據包是如何以及爲什麼被那樣路由,一個好的例子是DNAT和SNAT,不要忘了TOS的作用。

--------------------------------------------------------------------------------
3.1. 概述
當數據包到達防火牆時,如果MAC地址符合,就會由內核裏相應的驅動程序接收,然後會經過一系列操作,從而決定是發送給本地的程序,還是轉發給其他機子,還是其他的什麼。
我們先來看一個以本地爲目的的數據包,它要經過以下步驟才能到達要接收它的程序:
下文中有個詞mangle,我實在沒想到什麼合適的詞來表達這個意思,只因爲我的英語太差!我只能把我理解的寫出來。這個詞表達的意思是,會對數據包的一些傳輸特性進行修改,在mangle表中允許的操作是 TOS、TTL、MARK。也就是說,今後只要我們見到這個詞能理解它的作用就行了。
Table 3-1. 以本地爲目標(就是我們自己的機子了)的包
Step(步驟) Table(表) Chain(鏈) Comment(註釋)
1 在線路上傳輸(比如,Internet)
2 進入接口 (比如, eth0)
3 mangle PREROUTING 這個鏈用來mangle數據包,比如改變TOS等
4 nat PREROUTING 這個鏈主要用來做DNAT。不要在這個鏈做過慮操作,因爲某些情況下包會溜過去。
5 路由判斷,比如,包是發往本地的,還是要轉發的。
6 mangle INPUT 在路由之後,被送往本地程序之前,mangle數據包。
7 filter INPUT 所有以本地爲目的的包都要經過這個鏈,不管它們從哪兒來,對這些包的過濾條件就設在這裏。
8 到達本地程序了(比如,服務程序或客戶程序)
注意,相比以前(譯者注:就是指ipchain)現在數據包是由INPUT鏈過,而不是FORWARD鏈。這樣更符合邏輯。剛看上去可能不太好理解,但仔細想想就會恍然大悟的。
現在我們來看看源地址是本地器的包要經過哪些步驟:
Table 3-2. 以本地爲源的包
Step Table Chain Comment
1 本地程序(比如,服務程序或客戶程序)
2 路由判斷,要使用源地址,外出接口,還有其他一些信息。
3 mangle OUTPUT 在這兒可以mangle包。建議不要在這兒做過濾,可能有副作用哦。
4 nat OUTPUT 這個鏈對從防火牆本身發出的包進行DNAT操作。
5 filter OUTPUT 對本地發出的包過濾。
6 mangle POSTROUTING 這條鏈主要在包DNAT之後(譯者注:作者把這一次DNAT稱作實際的路由,雖然在前面有一次路由。對於本地的包,一旦它被生成,就必須經過路由代碼的處理,但這個包具體到哪兒去,要由NAT代碼處理之後才能確定。所以把這稱作實際的路由。),離開本地之前,對包 mangle。有兩種包會經過這裏,防火牆所在機子本身產生的包,還有被轉發的包。
7 nat POSTROUTING 在這裏做SNAT。但不要在這裏做過濾,因爲有副作用,而且有些包是會溜過去的,即使你用了DROP策略。
8 離開接口(比如: eth0)
9 在線路上傳輸(比如,Internet)
在這個例子中,我們假設一個包的目的是另一個網絡中的一臺機子。讓我們來看看這個包的旅程:
Table 3-3. 被轉發的包
Step Table Chain Comment
1 在線路上傳輸(比如,Internet)
2 進入接口(比如, eth0)
3 mangle PREROUTING mangle數據包,,比如改變TOS等。
4 nat PREROUTING 這個鏈主要用來做DNAT。不要在這個鏈做過慮操作,因爲某些情況下包會溜過去。稍後會做SNAT。
5 路由判斷,比如,包是發往本地的,還是要轉發的。
6 mangle FORWARD 包繼續被髮送至mangle表的FORWARD鏈,這是非常特殊的情況纔會用到的。在這裏,包被mangle(還記得mangle的意思嗎)。這次mangle發生在最初的路由判斷之後,在最後一次更改包的目的之前(譯者注:就是下面的FORWARD鏈所做的,因其過濾功能,可能會改變一些包的目的地,如丟棄包)。
7 filter FORWARD 包繼續被髮送至這條FORWARD鏈。只有需要轉發的包纔會走到這裏,並且針對這些包的所有過濾也在這裏進行。注意,所有要轉發的包都要經過這裏,不管是外網到內網的還是內網到外網的。在你自己書寫規則時,要考慮到這一點。
8 mangle POSTROUTING 這個鏈也是針對一些特殊類型的包(譯者注:參考第6步,我們可以發現,在轉發包時,mangle表的兩個鏈都用在特殊的應用上)。這一步mangle是在所有更改包的目的地址的操作完成之後做的,但這時包還在本地上。
9 nat POSTROUTING 這個鏈就是用來做SNAT的,當然也包括Masquerade(僞裝)。但不要在這兒做過濾,因爲某些包即使不滿足條件也會通過。
10 離開接口(比如: eth0)
11 又在線路上傳輸了(比如,LAN)
就如你所見的,包要經歷很多步驟,而且它們可以被阻攔在任何一條鏈上,或者是任何有問題的地方。我們的主要興趣是iptables的概貌。注意,對不同的接口,是沒有什麼特殊的鏈和表的。所有要經防火牆/ 路由器轉發的包都要經過FORWARD鏈。

在上面的情況裏,不要在INPUT鏈上做過濾。INPUT是專門用來操作那些以我們的機子爲目的地址的包的,它們不會被路由到其它地方的。
 
現在,我們來看看在以上三種情況下,用到了哪些不同的鏈。圖示如下:
 
 
要弄清楚上面的圖,可以這樣考慮。在第一個路由判斷處,不是發往本地的包,我們會發送它穿過 FORWARD鏈。若包的目的地是本地監聽的IP地址,我們就會發送這個包穿過INPUT鏈,最後到達本地。
值得注意的是,在做NAT的過程中,發往本機的包的目的地址可能會在PREROUTING鏈裏被改變。這個操作發生在第一次路由之前,所以在地址被改變之後,才能對包進行路由。注意,所有的包都會經過上圖中的某一條路徑。如果你把一個包DNAT回它原來的網絡,這個包會繼續走完相應路徑上剩下的鏈,直到它被髮送回原來的網絡。

想要更多的信息,可以看看rc.test-iptables.txt ,這個腳本包括了一些規則,它們會向你展示包是怎樣通過各個表和鏈的。
 

--------------------------------------------------------------------------------
3.2. mangle 表
這個表主要用來mangle包,你可以使用mangle匹配來改變包的TOS等特性。

強烈建議你不要在這個表裏做任何過濾,不管是DANT,SNAT或者Masquerade。
 
以下是mangle表中僅有的幾種操作:

TOS
TTL
MARK
TOS操作用來設置或改變數據包的服務類型域。這常用來設置網絡上的數據包如何被路由等策略。注意這個操作並不完善,有時得不所願。它在Internet上還不能使用,而且很多路由器不會注意到這個域值。換句話說,不要設置發往Internet的包,除非你打算依靠TOS來路由,比如用iproute2。
TTL操作用來改變數據包的生存時間域,我們可以讓所有數據包只有一個特殊的TTL。它的存在有一個很好的理由,那就是我們可以欺騙一些ISP。爲什麼要欺騙他們呢?因爲他們不願意讓我們共享一個連接。那些ISP會查找一臺單獨的計算機是否使用不同的TTL,並且以此作爲判斷連接是否被共享的標誌。
MARK用來給包設置特殊的標記。iproute2能識別這些標記,並根據不同的標記(或沒有標記)決定不同的路由。用這些標記我們可以做帶寬限制和基於請求的分類。

--------------------------------------------------------------------------------
3.3. nat 表
此表僅用於NAT,也就是轉換包的源或目標地址。注意,就象我們前面說過的,只有流的第一個包會被這個鏈匹配,其後的包會自動被做相同的處理。實際的操作分爲以下幾類:

DNAT
SNAT
MASQUERADE
DNAT操作主要用在這樣一種情況,你有一個合法的IP地址,要把對防火牆的訪問重定向到其他的機子上(比如DMZ)。也就是說,我們改變的是目的地址,以使包能重路由到某臺主機。
SNAT改變包的源地址,這在極大程度上可以隱藏你的本地網絡或者DMZ等。一個很好的例子是我們知道防火牆的外部地址,但必須用這個地址替換本地網絡地址。有了這個操作,防火牆就能自動地對包做SNAT和De-SNAT(就是反向的SNAT),以使LAN能連接到Internet。如果使用類似 192.168.0.0/24這樣的地址,是不會從Internet得到任何迴應的。因爲IANA定義這些網絡(還有其他的)爲私有的,只能用於LAN內部。
MASQUERADE的作用和MASQUERADE完全一樣,只是計算機的負荷稍微多一點。因爲對每個匹配的包,MASQUERADE都要查找可用的IP地址,而不象SNAT用的IP地址是配置好的。當然,這也有好處,就是我們可以使用通過PPP、 PPPOE、SLIP等撥號得到的地址,這些地址可是由ISP的DHCP隨機分配的。

--------------------------------------------------------------------------------
3.4. Filter 表
filter 表用來過濾數據包,我們可以在任何時候匹配包並過濾它們。我們就是在這裏根據包的內容對包做DROP或ACCEPT的。當然,我們也可以預先在其他地方做些過濾,但是這個表纔是設計用來過濾的。幾乎所有的target都可以在這兒使用。大量具體的介紹在後面,現在你只要知道過濾工作主要是在這兒完成的就行了。

--------------------------------------------------------------------------------
Chapter 4. 狀態機制
本章將詳細介紹狀態機制。通讀本章,你會對狀態機制是如何工作的有一個全面的瞭解。我們用一些例子來進行說明狀態機制。實踐出真知嘛。

--------------------------------------------------------------------------------
4.1. 概述
狀態機制是iptables中特殊的一部分,其實它不應該叫狀態機制,因爲它只是一種連接跟蹤機制。但是,很多人都認可狀態機制這個名字。文中我也或多或或少地用這個名字來表示和連接跟蹤相同的意思。這不應該引起什麼混亂的。連接跟蹤可以讓Netfilter知道某個特定連接的狀態。運行連接跟蹤的防火牆稱作帶有狀態機制的防火牆,以下簡稱爲狀態防火牆。狀態防火牆比非狀態防火牆要安全,因爲它允許我們編寫更嚴密的規則。
在iptables裏,包是和被跟蹤連接的四種不同狀態有關的。它們是NEW,ESTABLISHED,RELATED和INVALID。後面我們會深入地討論每一個狀態。使用--state匹配操作,我們能很容易地控制 “誰或什麼能發起新的會話”。
所有在內核中由Netfilter的特定框架做的連接跟蹤稱作conntrack(譯者注:就是connection tracking 的首字母縮寫)。conntrack可以作爲模塊安裝,也可以作爲內核的一部分。大部分情況下,我們想要,也需要更詳細的連接跟蹤,這是相比於缺省的conntrack而言。也因爲此,conntrack中有許多用來處理TCP, UDP或ICMP協議的部件。這些模塊從數據包中提取詳細的、唯一的信息,因此能保持對每一個數據流的跟蹤。這些信息也告知conntrack流當前的狀態。例如,UDP流一般由他們的目的地址、源地址、目的端口和源端口唯一確定。
在以前的內核裏,我們可以打開或關閉重組功能。然而,自從iptables和Netfilter,尤其是連接跟蹤被引入內核,這個選項就被取消了。因爲沒有包的重組,連接跟蹤就不能正常工作。現在重組已經整合入 conntrack,並且在conntrack啓動時自動啓動。不要關閉重組功能,除非你要關閉連接跟蹤。
除了本地產生的包由OUTPUT鏈處理外,所有連接跟蹤都是在PREROUTING鏈裏進行處理的,意思就是, iptables會在PREROUTING鏈裏從新計算所有的狀態。如果我們發送一個流的初始化包,狀態就會在OUTPUT鏈裏被設置爲NEW,當我們收到迴應的包時,狀態就會在PREROUTING鏈裏被設置爲ESTABLISHED。如果第一個包不是本地產生的,那就會在PREROUTING鏈裏被設置爲NEW狀態。綜上,所有狀態的改變和計算都是在nat表中的PREROUTING鏈和OUTPUT鏈裏完成的。

--------------------------------------------------------------------------------
4.2. conntrack記錄
我們先來看看怎樣閱讀/proc/net/ip_conntrack裏的conntrack記錄。這些記錄表示的是當前被跟蹤的連接。如果安裝了ip_conntrack模塊,cat /proc/net/ip_conntrack 的顯示類似:
tcp 6 117 SYN_SENT src=192.168.1.6 dst=192.168.1.9 sport=32775 \
dport=22 [UNREPLIED] src=192.168.1.9 dst=192.168.1.6 sport=22 \
dport=32775 use=2

conntrack模塊維護的所有信息都包含在這個例子中了,通過它們就可以知道某個特定的連接處於什麼狀態。首先顯示的是協議,這裏是tcp,接着是十進制的6(譯者注:tcp的協議類型代碼是6)。之後的117是這條conntrack記錄的生存時間,它會有規律地被消耗,直到收到這個連接的更多的包。那時,這個值就會被設爲當時那個狀態的缺省值。接下來的是這個連接在當前時間點的狀態。上面的例子說明這個包處在狀態 SYN_SENT,這個值是iptables顯示的,以便我們好理解,而內部用的值稍有不同。SYN_SENT說明我們正在觀察的這個連接只在一個方向發送了一TCP SYN包。再下面是源地址、目的地址、源端口和目的端口。其中有個特殊的詞UNREPLIED,說明這個連接還沒有收到任何迴應。最後,是希望接收的應答包的信息,他們的地址和端口和前面是相反的。
連接跟蹤記錄的信息依據IP所包含的協議不同而不同,所有相應的值都是在頭文件linux/include/netfilter-ipv4/ip_conntrack*.h中定義的。IP、TCP、UDP、ICMP協議的缺省值是在linux/include/netfilter-ipv4/ip_conntrack.h裏定義的。具體的值可以查看相應的協議,但我們這裏用不到它們,因爲它們大都只在conntrack內部使用。隨着狀態的改變,生存時間也會改變。

最近patch-o-matic裏有一個新的補丁,可以把上面提到的超時時間也作爲系統變量,這樣我們就能夠在系統空閒時改變它們的值。以後,我們就不必爲了改變這些值而重編譯內核了。
這些可通過/proc/sys/net/ipv4/netfilter下的一些特殊的系統調用來改變。仔細看看/proc/sys/net/ipv4/netfilter/ip_ct_*裏的變量吧。
 
當一個連接在兩個方向上都有傳輸時,conntrack記錄就刪除[UNREPLIED]標誌,然後重置。在末尾有 [ASSURED]的記錄說明兩個方向已沒有流量。這樣的記錄是確定的,在連接跟蹤表滿時,是不會被刪除的,沒有[ASSURED]的記錄就要被刪除。連接跟蹤表能容納多少記錄是被一個變量控制的,它可由內核中的ip- sysctl函數設置。默認值取決於你的內存大小,128MB可以包含8192條目錄,256MB是16376條。你也可以在 /proc/sys/net/ipv4/ip_conntrack_max裏查看、設置。

--------------------------------------------------------------------------------
4.3. 數據包在用戶空間的狀態
就象前面說的,包的狀態依據IP所包含的協議不同而不同,但在內核外部,也就是用戶空間裏,只有4種狀態:NEW,ESTABLISHED,RELATED 和INVALID。它們主要是和狀態匹配一起使用。下面就簡要地介紹以下這幾種狀態:
Table 4-1. 數據包在用戶空間的狀態
State(狀態) Explanation(註釋)
NEW NEW說明這個包是我們看到的第一個包。意思就是,這是conntrack模塊看到的某個連接第一個包,它即將被匹配了。比如,我們看到一個SYN 包,是我們所留意的連接的第一個包,就要匹配它。第一個包也可能不是SYN包,但它仍會被認爲是NEW狀態。這樣做有時會導致一些問題,但對某些情況是有非常大的幫助的。例如,在我們想恢復某條從其他的防火牆丟失的連接時,或者某個連接已經超時,但實際上並未關閉時。
ESTABLISHED ESTABLISHED已經注意到兩個方向上的數據傳輸,而且會繼續匹配這個連接的包。處於ESTABLISHED狀態的連接是非常容易理解的。只要發送並接到應答,連接就是ESTABLISHED的了。一個連接要從NEW變爲ESTABLISHED,只需要接到應答包即可,不管這個包是發往防火牆的,還是要由防火牆轉發的。ICMP的錯誤和重定向等信息包也被看作是ESTABLISHED,只要它們是我們所發出的信息的應答。
RELATED RELATED是個比較麻煩的狀態。當一個連接和某個已處於ESTABLISHED狀態的連接有關係時,就被認爲是RELATED的了。換句話說,一個連接要想是RELATED的,首先要有一個ESTABLISHED的連接。這個ESTABLISHED連接再產生一個主連接之外的連接,這個新的連接就是RELATED的了,當然前提是conntrack模塊要能理解RELATED。ftp是個很好的例子,FTP-data 連接就是和FTP-control有RELATED的。還有其他的例子,比如,通過IRC的DCC連接。有了這個狀態,ICMP應答、FTP傳輸、DCC等才能穿過防火牆正常工作。注意,大部分還有一些UDP協議都依賴這個機制。這些協議是很複雜的,它們把連接信息放在數據包裏,並且要求這些信息能被正確理解。
INVALID INVALID說明數據包不能被識別屬於哪個連接或沒有任何狀態。有幾個原因可以產生這種情況,比如,內存溢出,收到不知屬於哪個連接的ICMP 錯誤信息。一般地,我們DROP這個狀態的任何東西。
這些狀態可以一起使用,以便匹配數據包。這可以使我們的防火牆非常強壯和有效。以前,我們經常打開1024以上的所有端口來放行應答的數據。現在,有了狀態機制,就不需再這樣了。因爲我們可以只開放那些有應答數據的端口,其他的都可以關閉。這樣就安全多了。

--------------------------------------------------------------------------------
4.4. TCP 連接
本節和下面的幾節,我們來詳細討論這些狀態,以及在TCP、UDP和ICMP這三種基本的協議裏怎樣操作它們。當然,也會討論其他協議的情況。我們還是從TCP入手,因爲它本身就是一個帶狀態的協議,並且具有很多關於iptables狀態機制的詳細信息。
一個TCP連接是經過三次握手協商連接信息才建立起來的。整個會話由一個SYN包開始,然後是一個 SYN/ACK包,最後是一個ACK包,此時,會話才建立成功,能夠發送數據。最大的問題在於連接跟蹤怎樣控制這個過程。其實非常簡單。
默認情況下,連接跟蹤基本上對所有的連接類型做同樣的操作。看看下面的圖片,我們就能明白在連接的不同階段,流是處於什麼狀態的。就如你看到的,連接跟蹤的代碼不是從用戶的觀點來看待TCP連接建立的流程的。連接跟蹤一看到SYN包,就認爲這個連接是NEW狀態,一看到返回的SYN/ACK包,就認爲連接是 ESTABLISHED狀態。如果你仔細想想第二步,應該能理解爲什麼。有了這個特殊處理,NEW和ESTABLISHED包就可以發送出本地網絡,且只有ESTABLISHED的連接纔能有迴應信息。如果把整個建立連接的過程中傳輸的數據包都看作NEW,那麼三次握手所用的包都是NEW狀態的,這樣我們就不能阻塞從外部到本地網絡的連接了。因爲即使連接是從外向內的,但它使用的包也是NEW狀態的,而且爲了其他連接能正常傳輸,我們不得不允許NEW狀態的包返回並進入防火牆。更復雜的是,針對TCP連接內核使用了很多內部狀態,它們的定義在 RFC 793 - Transmission Control Protocol的21-23頁。但好在我們在用戶空間用不到。後面我們會詳細地介紹這些內容。
 
 
正如你看到的,以用戶的觀點來看,這是很簡單的。但是,從內核的角度看這一塊還有點困難的。我們來看一個例子。認真考慮一下在/proc/net/ip_conntrack裏,連接的狀態是如何改變的。
tcp 6 117 SYN_SENT src=192.168.1.5 dst=192.168.1.35 sport=1031 \
dport=23 [UNREPLIED] src=192.168.1.35 dst=192.168.1.5 sport=23 \
dport=1031 use=1

從上面的記錄可以看出,SYN_SENT狀態被設置了,這說明連接已經發出一個SYN包,但應答還沒發送過來,這可從[UNREPLIED]標誌看出。
tcp 6 57 SYN_RECV src=192.168.1.5 dst=192.168.1.35 sport=1031 \
dport=23 src=192.168.1.35 dst=192.168.1.5 sport=23 dport=1031 \
use=1

現在我們已經收到了相應的SYN/ACK包,狀態也變爲SYN_RECV,這說明最初發出的SYN包已正確傳輸,並且SYN/ACK包也到達了防火牆。 這就意味着在連接的兩方都有數據傳輸,因此可以認爲兩個方向都有相應的迴應。當然,這是假設的。
tcp 6 431999 ESTABLISHED src=192.168.1.5 dst=192.168.1.35 \
sport=1031 dport=23 src=192.168.1.35 dst=192.168.1.5 \
sport=23 dport=1031 use=1

現在我們發出了三步握手的最後一個包,即ACK包,連接也就進入ESTABLISHED狀態了。再傳輸幾個數據包,連接就是[ASSURED]的了。
下面介紹TCP連接在關閉過程中的狀態。
 
 
如上圖,在發出最後一個ACK包之前,連接(指兩個方向)是不會關閉的。注意,這只是針對一般的情況。連接也可以通過發送關閉,這用在拒絕一個連接的時候。在RST包發送之後,要經過預先設定的一段時間,連接才能斷掉。
連接關閉後,進入TIME_WAIT狀態,缺省時間是2分鐘。之所以留這個時間,是爲了讓數據包能完全通過各種規則的檢查,也是爲了數據包能通過擁擠的路由器,從而到達目的地。
如果連接是被RST包重置的,就直接變爲CLOSE了。這意味着在關閉之前只有10秒的默認時間。RST包是不需要確認的,它會直接關閉連接。針對TCP連接,還有其他一些狀態我們沒有談到。下面給出一個完整的狀態列表和超時值。
Table 4-2. 內部狀態
State Timeout value
NONE 30 minutes
ESTABLISHED 5 days
SYN_SENT 2 minutes
SYN_RECV 60 seconds
FIN_WAIT 2 minutes
TIME_WAIT 2 minutes
CLOSE 10 seconds
CLOSE_WAIT 12 hours
LAST_ACK 30 seconds
LISTEN> 2 minutes
這些值不是絕對的,可以隨着內核的修訂而變化,也可以通過/proc/sys/net/ipv4/netfilter/ip_ct_tcp_*的變量更改。這些默認值都是經過實踐檢驗的。它們的單位是jiffies(百分之一秒),所以3000就代表30秒。

注意狀態機制在用戶空間裏的部分不會查看TCP包的標誌位(也就是說TCP標誌對它而言是透明的)。如果我們想讓NEW狀態的包通過防火牆,就要指定NEW狀態,我們理解的NEW狀態的意思就是指SYN包,可是iptables又不查看這些標誌位。這就是問題所在。有些沒有設置SYN或ACK的包,也會被看作NEW狀態的。這樣的包可能會被冗餘防火牆用到,但對只有一個防火牆的網絡是很不利的(可能會被***哦)。那我們怎樣才能不受這樣的包的影響呢?你可以使用未設置SYN的NEW狀態包 裏的命令。還有一個辦法,就是安裝patch-o-matic裏的tcp-window-tracking擴展功能,它可以使防火牆能根據TCP的一些標誌位來進行狀態跟蹤。
 

--------------------------------------------------------------------------------
4.5. UDP連接
UDP連接是無狀態的,因爲它沒有任何的連接建立和關閉過程,而且大部分是無序列號的。以某個順序收到的兩個數據包是無法確定它們的發出順序的。但內核仍然可以對UDP連接設置狀態。我們來看看是如何跟蹤UDP連接的,以及conntrack的相關記錄。
 
 
從上圖可以看出,以用戶的角度考慮,UDP連接的建立幾乎與TCP的一樣。雖然conntrack信息看起來有點兒不同,但本質上是一樣的。下面我們先來看看第一個UDP包發出後的conntrack記錄。
udp 17 20 src=192.168.1.2 dst=192.168.1.5 sport=137 dport=1025 \
[UNREPLIED] src=192.168.1.5 dst=192.168.1.2 sport=1025 \
dport=137 use=1

從前兩個值可知,這是一個UDP包。第一個是協議名稱,第二個是協議號,第三個是此狀態的生存時間,默認是30秒。接下來是包的源、目地址和端口,還有期待之中迴應包的源、目地址和端口。[UNREPLIED]標記說明還未收到迴應。
udp 17 170 src=192.168.1.2 dst=192.168.1.5 sport=137 \
dport=1025 src=192.168.1.5 dst=192.168.1.2 sport=1025 \
dport=137 use=1

一旦收到第一個包的迴應,[UNREPLIED]標記就會被刪除,連接就被認爲是ESTABLISHED的,但在記錄裏並不顯示ESTABLISHED標記。相應地,狀態的超時時間也變爲180秒了。在本例中,只剩170秒了,10秒後,就會減少爲160秒。有個東西是不可少的,雖然它可能會有些變化,就是前面提過的[ASSURED]。要想變爲 [ASSURED]狀態,連接上必須要再有些流量。
udp 17 175 src=192.168.1.5 dst=195.22.79.2 sport=1025 \
dport=53 src=195.22.79.2 dst=192.168.1.5 sport=53 \
dport=1025 [ASSURED] use=1

可以看出來,[ASSURED]狀態的記錄和前面的沒有多大差別,除了標記由[UNREPLIED]變成[ASSURED]。如果這個連接持續不了180秒,那就要被中斷。180秒是短了點兒,但對大部分應用足夠了。只要遇到這個連接的包穿過防火牆,超時值就會被重置爲默認值,所有的狀態都是這樣的。

--------------------------------------------------------------------------------
4.6. ICMP 連接
ICMP也是一種無狀態協議,它只是用來控制而不是建立連接。ICMP包有很多類型,但只有四種類型有應答包,它們是回顯請求和應答(Echo request and reply),時間戳請求和應答(Timestamp request and reply),信息請求和應答(Information request and reply),還有地址掩碼請求和應答(Address mask request and reply),這些包有兩種狀態,NEW和ESTABLISHED 。時間戳請求和信息請求已經廢除不用了,回顯請求還是常用的,比如ping命令就用的到,地址掩碼請求不太常用,但是可能有時很有用並且值得使用。看看下面的圖,就可以大致瞭解ICMP連接的NEW和ESTABLISHED狀態了。
 
 
如圖所示,主機向目標發送一個回顯請求,防火牆就認爲這個包處於NEW狀態。目標迴應一個回顯應答,防火牆就認爲包處於ESTABLISHED了。當回顯請求被髮送時,ip_conntrack裏就有這樣的記錄了:
icmp 1 25 src=192.168.1.6 dst=192.168.1.10 type=8 code=0 \
id=33029 [UNREPLIED] src=192.168.1.10 dst=192.168.1.6 \
type=0 code=0 id=33029 use=1

可以看到,ICMP的記錄和TCP、UDP的有點區別,協議名稱、超時時間和源、目地址都一樣,不同之處在於沒有了端口,而新增了三個新的字段:type,code和id。字段type說明ICMP的類型。code說明ICMP的代碼,這些代碼在附錄ICMP類型裏有說明。id是ICMP包的ID。每個ICMP包被髮送時都被分配一個ID,接受方把同樣的ID 分配給應答包,這樣發送方能認出是哪個請求的應答。
[UNREPLIED]的含義和前面一樣,說明數的傳輸只發生在一個方向上,也就是說未收到應答。再往後,是應答包的源、目地址,還有相應的三個新字段,要注意的是type和code是隨着應答包的不同而變化的,id和請求包的一樣。
和前面一樣,應答包被認爲是ESTABLISHED的。然而,在應答包之後,這個ICMP 連接就不再有數據傳輸了。所以,一旦應答包穿過防火牆,ICMP的連接跟蹤記錄就被銷燬了。
以上各種情況,請求被認爲NEW,應答是ESTABLISHED。換句話說,就是當防火牆看到一個請求包時,就認爲連接處於NEW狀態,當有應答時,就是ESTABLISHED狀態。

注意,應答包必須符合一定的標準,連接才能被認作established的,每個傳輸類型都是這樣。
 
ICMP的缺省超時是30秒,可以在/proc/sys/net/ipv4/netfilter/ip_ct_icmp_timeout中修改。這個值是比較合適的,適合於大多數情況。
ICMP的另一個非常重要的作用是,告訴UDP、TCP連接或正在努力建立的連接發生了什麼,這時ICMP應答被認爲是RELATED的。主機不可達和網絡不可達就是這樣的例子。當試圖連接某臺機子不成功時(可能那臺機子被關上了),數據包所到達的最後一臺路由器就會返回以上的ICMP信息,它們就是RELATED的,如下圖:
 
 
我們發送了一個SYN包到某一地址,防火牆認爲它的狀態是NEW。但是,目標網絡有問題不可達,路由器就會返回網絡不可達的信息,這是RELATED的。連接跟蹤會認出這個錯誤信息是哪個連接的,連接會中斷,同時相應的記錄刪除會被刪除。
當UDP連接遇到問題時,同樣會有相應的ICMP信息返回,當然它們的狀態也是RELATED ,如下圖:
 
 
我們發送一個UDP包,當然它是NEW的。但是,目標網絡被一些防火牆或路由器所禁止。我們的防火牆就會收到網絡被禁止的信息。防火牆知道它是和哪個已打開的UDP連接相關的,並且把這個信息(狀態是RELATED)發給它,同時,把相應的記錄刪除。客戶機收到網絡被禁止的信息,連接將被中斷。

--------------------------------------------------------------------------------
4.7. 缺省的連接操作
有時,conntrack機制並不知道如何處理某個特殊的協議,尤其是在它不瞭解這個協議或不知道協議如何工作時,比如,NETBLT,MUX還有EGP。這種情況下,conntrack使用缺省的操作。這種操作很象對UDP連接的操作,就是第一個包被認作NEW,其後的應答包等等數據都是 ESTABLISHED。
使用缺省操作的包的超時值都是一樣的,600秒,也就是10分鐘。當然,這個值可以通過/proc/sys/net/ipv4/netfilter/ip_ct_generic_timeout更改,以便適應你的通信量,尤其是在耗時較多、流量巨大的情況下,比如使用衛星等。

--------------------------------------------------------------------------------
4.8. 複雜協議和連接跟蹤
有些協議比其他協議更復雜,這裏複雜的意思是指連接跟蹤機制很難正確地跟蹤它們,比如,ICQ、IRC 和FTP,它們都在數據包的數據域裏攜帶某些信息,這些信息用於建立其他的連接。因此,需要一些特殊的 helper來完成工作。
下面以FTP作爲例子。FTP協議先建立一個單獨的連接——FTP控制會話。我們通過這個連接發佈命令,其他的端口就會打開以便傳輸和這個命令相關的數據。這些連接的建立方法有兩種:主動模式和被動模式。先看看主動模式,FTP客戶端發送端口和IP地址信息給服務器端,然後,客戶端打開這個端口,服務器端從它自己的20端口(FTP-Data端口號)建立與這個端口的連接,接着就可以使用這個連接發送數據了。
問題在於防火牆不知道這些額外的連接(相對於控制會話而言),因爲這些連接在建立時的磋商信息都在協議數據包的數據域內,而不是在可分析的協議頭裏。因此,防火牆就不知道是不是該放這些從服務器到客戶機的連接過關。
解決的辦法是爲連接跟蹤模塊增加一個特殊的helper,以便能檢測到那些信息。這樣,那些從FTP服務器到客戶機的連接就可以被跟蹤了,狀態是RELATED,過程如下圖所示:
 
 
被動FTP工作方式下,data連接的建立過程和主動FTP的相反。客戶機告訴服務器需要某些數據,服務器就把地址和端口發回給客戶機,客戶機據此建立連接接受數據。如果FTP服務器在防火牆後面,或你對用戶限制的比較嚴格,只允許他們訪問HTTP和FTP,而封閉了其他所有端口,爲了讓在Internet是的客戶機能訪問到FTP,也需要增加上面提到的helper。下面是被動模式下data連接的建立過程:
 
 
有些conntrack helper已經包含在內核中,在寫這篇文章時,FTP和IRC已有了相應的conntrack helper。如果在內核裏沒有你想要的helper,可以到iptables用戶空間的patch-o-matic目錄中看看,那裏有很多的helper,比如針對ntalk或H.323協議的等等。如果沒找到,還有幾個選擇:可以查查iptables的 CVS,或者聯繫Netfilter-devel問問有沒有你要的。還不行的話,只有你自己寫了,我可以給你介紹一篇好文章,Rusty Russell's Unreliable Netfilter Hacking HOW-TO,連接放在附錄裏其他資源和鏈接。
Conntrack helper即可以被靜態地編譯進內核,也可以作爲模塊,但要用下面的命令裝載:
modprobe ip_conntrack_*

注意連接跟蹤並不處理NAT,因此要對連接做NAT就需要增加相應的模塊。比如,你想NAT並跟蹤FTP連接,除了FTP的相應模塊,還要有NAT的模塊。所有的NAT helper名字都是以ip_nat_開頭的,這是一個命名習慣:FTP NAT helper叫做ip_nat_ftp,IRC的相應模塊就是ip_nat_irc。conntrack helper 的命名也遵循一樣的習慣:針對IRC的conntrack helper叫ip_conntrack_irc,FTP的叫作ip_conntrack_ftp。

--------------------------------------------------------------------------------
Chapter 5. 規則的保存與恢復
iptables提供了兩個很有用的工具用來處理大規則集: iptables-save和iptables-restore,它們把規則存入一個與標準腳本代碼只有細微查別的特殊格式的文件中,或從中恢復規則。

--------------------------------------------------------------------------------
5.1. 速度
使用iptables-save和iptables-restore的一個最重要的原因是,它們能在相當程度上提高裝載、保存規則的速度。使用腳本更改規則的問題是,改動每個規則都要調運命令iptables,而每一次調用iptables,它首先要把Netfilter內核空間中的整個規則集都提取出來,然後再插入或附加,或做其他的改動,最後,再把新的規則集從它的內存空間插入到內核空間中。這會花費很多時間。
爲了解決這個問題,可以使用命令iptables-save和restore 。 iptables-save用來把規則集保存到一個特殊格式的文本文件裏,而iptables-restore是用來把這個文件重新裝入內核空間的。這兩個命令最好的地方在於一次調用就可以裝載和保存規則集,而不象腳本中每個規則都要調用一次iptables。 iptables-save運行一次就可以把整個規則集從內核裏提取出來,並保存到文件裏,而iptables-restore每次裝入一個規則表。換句話說,對於一個很大的規則集,如果用腳本來設置,那這些規則就會反反覆覆地被卸載、安裝很多次,而我們現在可以把整個規則集一次就保存下來,安裝時則是一次一個表,這可是節省了大量的時間。
如果你的工作對象是一組巨大的規則,這兩個工具是明顯的選擇。當然,它們也有不足之處,下面的章節會詳細說明。

--------------------------------------------------------------------------------
5.2. restore的不足之處
iptables-restore能替代所有的腳本來設置規則嗎?不,到現在爲止不行,很可能永遠都不行。iptables-restore的主要不足是不能用來做複雜的規則集。例如,我們想在計算機啓動時獲取連接的動態分配的IP地址,然後用在腳本里。這一點,用iptables-restore來實現,或多或少是不可能的。
一個可能的解決辦法是寫一個小腳本來獲取那個IP地址,並在iptables-restore調用的配置文件中設置相應的關鍵字,然後用獲取的IP值替換關鍵字。你可以把更改後的配置文件存到一個臨時文件中,再由 iptables-restore使用它。然而這會帶來很多問題,並且你不能用iptables-save來保存帶關鍵字的配置文件。此法較笨。
另一個辦法是先裝入iptables-restore文件,再運行一個特定的腳本把動態的規則裝入。其實,這也是較笨的方法。iptables-restore並不適合於使用動態IP的場合,如果你想在配置文件裏使用選項來實現不同的要求,iptables-restore也不適用。
iptables-restore和iptables-save還有一個不足,就是功能不夠齊全。因爲使用的人不是太多,所以發現這個問題的人也不多,還有就是一些match和target被引用時考慮不細緻,這可能會出現我們預期之外的行爲。 儘管存在這些問題,我還是強烈建議你使用它們,因爲它們對於大部分規則集工作的還是很好的,只要在規則中別包含那些新的都不知如何使用的match和target。

--------------------------------------------------------------------------------
5.3. iptables-save
iptables-save用來把當前的規則存入一個文件裏以備iptables-restore使用。它的使用很簡單,只有兩個參數:

iptables-save [-c] [-t table]

參數-c的作用是保存包和字節計數器的值。這可以使我們在重啓防火牆後不丟失對包和字節的統計。帶-c參數的iptables-save命令使重啓防火牆而不中斷統計記數程序成爲可能。這個參數默認是不使用的。
參數-t指定要保存的表,默認是保存所有的表。下面給出未裝載任何規則的情況下iptables-save的輸出。

# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:17 2002
*filter
:INPUT ACCEPT [404:19766]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [530:43376]
COMMIT
# Completed on Wed Apr 24 10:19:17 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:17 2002
*mangle
:PREROUTING ACCEPT [451:22060]
:INPUT ACCEPT [451:22060]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [594:47151]
:POSTROUTING ACCEPT [594:47151]
COMMIT
# Completed on Wed Apr 24 10:19:17 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:17 2002
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [3:450]
:OUTPUT ACCEPT [3:450]
COMMIT
# Completed on Wed Apr 24 10:19:17 2002
我們來解釋一下這個輸出格式。#後面的是註釋。表都以*<table-name>開始,例如*mangle。每個表都包含鏈和規則,鏈的詳細說明是:<chain-name> <chain-policy> [<packet-counter>:<byte-counter>]。例如,鏈的名字是 PREROUTING,策略是ACCEPT,然後是包記數器和字節計數器,這兩個計數器和iptables -L -v輸出中用到的計數器一樣。每個表的描述都以關鍵字COMMIT結束,它說明在這一點,就要把規則裝入內核了。
上面的例子是最基本的,我想用一個簡短的例子說明會更好,其中包含一個非常小的規則集Iptables-save ruleset。iptables-save的輸出如下:

# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*filter
:INPUT DROP [1:229]
:FORWARD DROP [0:0]
:OUTPUT DROP [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
COMMIT
# Completed on Wed Apr 24 10:19:55 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*mangle
:PREROUTING ACCEPT [658:32445]
:INPUT ACCEPT [658:32445]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [891:68234]
:POSTROUTING ACCEPT [891:68234]
COMMIT
# Completed on Wed Apr 24 10:19:55 2002
# Generated by iptables-save v1.2.6a on Wed Apr 24 10:19:55 2002
*nat
:PREROUTING ACCEPT [1:229]
:POSTROUTING ACCEPT [3:450]
:OUTPUT ACCEPT [3:450]
-A POSTROUTING -o eth0 -j SNAT --to-source 195.233.192.1
COMMIT
# Completed on Wed Apr 24 10:19:55 2002
每個命令前都有包和字節計數器,這說明使用了-c參數。除了有計數器,其他的都和普通的腳本一樣。現在的問題是怎麼把輸出保存到文件中。非常簡單,既然使用linux,你應該早就知道了,用重定向啊:
iptables-save -c > /etc/iptables-save
這就會把規則集保存到/etc/iptables-save中,而且還有計數器。

--------------------------------------------------------------------------------
5.4. iptables-restore
iptables-restore用來裝載由iptables-save保存的規則集。不幸的是,它只能從標準輸入接受輸入,而不能從文件接受。下面是它的事方法:

iptables-restore [-c] [-n]

參數-c要求裝入包和字節計數器。如果你用iptables-save保存了計數器,現在想重新裝入,就必須用這個參數。它的另一種較長的形式是--counters。
參數-n告訴iptables-restore不要覆蓋已有的表或表內的規則。默認情況是清除所有已存的規則。這個參數的長形式是--noflush。
用iptables-restore裝載規則有好幾種方法,我們來看看最簡單、最一般的:
這樣規則集應該正確地裝入內核並正常工作了。如果有問題,你就要除措了。

--------------------------------------------------------------------------------
Chapter 6. 規則是如何練成的
本章將詳細地討論如何構件你自己的規則。規則就是指向標,在一條鏈上,對不同的連接和數據包阻塞或允許它們去向何處。插入鏈的每一行都是一條規則。我們也會討論基本的matche及其用法,還有各種各樣的target,以及如何建立我們自己的target(比如,一個新的子鏈)。

--------------------------------------------------------------------------------
6.1. 基礎
我們已經解釋了什麼是規則,在內核看來,規則就是決定如何處理一個包的語句。如果一個包符合所有的條件(就是符合matche語句),我們就運行target或jump指令。書寫規則的語法格式是:

iptables [-t table] command [match] [target/jump]

對於這個句法沒什麼可說的,但注意target指令必須在最後。爲了易讀,我們一般用這種語法。總之,你將見到的大部分規則都是按這種語法寫的。因此,如果你看到別人寫的規則,你很可能會發現用的也是這種語法,當然就很容易理解那些規則了。
如果你不想用標準的表,就要在[table]處指定表名。一般情況下沒有必要指定使用的表,因爲iptables 默認使用filter表來執行所有的命令。也沒有必要非得在這裏指定表名,實際上幾乎可在規則的任何地方。當然,把表名在開始處已經是約定俗成的標準。
儘管命令總是放在開頭,或者是直接放在表名後面,我們也要考慮考慮到底放在哪兒易讀。command告訴程序該做什麼,比如:插入一個規則,還是在鏈的末尾增加一個規則,還是刪除一個規則,下面會仔細地介紹。
match細緻地描述了包的某個特點,以使這個包區別於其它所有的包。在這裏,我們可以指定包的來源IP 地址,網絡接口,端口,協議類型,或者其他什麼。下面我們將會看到許多不同的match。
最後是數據包的目標所在。若數據包符合所有的match,內核就用target來處理它,或者說把包發往 target。比如,我們可以讓內核把包發送到當前表中的其他鏈(可能是我們自己建立的),或者只是丟棄這個包而沒有什麼處理,或者向發送者返回某個特殊的應答。下面有詳細的討論。

--------------------------------------------------------------------------------
6.2. Tables
選項-t用來指定使用哪個表,它可以是下面介紹的表中的任何一個,默認的是 filter表。注意,下面的介紹只是章節表和鏈的摘要。
Table 6-1. Tables
Table (表名) Explanation (註釋)
nat nat表的主要用處是網絡地址轉換,即Network Address Translation,縮寫爲NAT。做過NAT操作的數據包的地址就被改變了,當然這種改變是根據我們的規則進行的。屬於一個流的包只會經過這個表一次。如果第一個包被允許做NAT或Masqueraded,那麼餘下的包都會自動地被做相同的操作。也就是說,餘下的包不會再通過這個表,一個一個的被NAT,而是自動地完成。這就是我們爲什麼不應該在這個表中做任何過濾的主要原因,對這一點,後面會有更加詳細的討論。PREROUTING 鏈的作用是在包剛剛到達防火牆時改變它的目的地址,如果需要的話。OUTPUT鏈改變本地產生的包的目的地址。POSTROUTING鏈在包就要離開防火牆之前改變其源地址。
mangle 這個表主要用來mangle數據包。我們可以改變不同的包及包頭的內容,比如 TTL,TOS或MARK。注意MARK並沒有真正地改動數據包,它只是在內核空間爲包設了一個標記。防火牆內的其他的規則或程序(如tc)可以使用這種標記對包進行過濾或高級路由。這個表有五個內建的鏈: PREROUTING,POSTROUTING, OUTPUT,INPUT和 FORWARD。PREROUTING在包進入防火牆之後、路由判斷之前改變包,POSTROUTING是在所有路由判斷之後。 OUTPUT在確定包的目的之前更改數據包。INPUT在包被路由到本地之後,但在用戶空間的程序看到它之前改變包。FORWARD在最初的路由判斷之後、最後一次更改包的目的之前mangle包。注意,mangle表不能做任何NAT,它只是改變數據包的 TTL,TOS或MARK,而不是其源目地址。NAT是在nat表中操作的。
filter filter表是專門過濾包的,內建三個鏈,可以毫無問題地對包進行DROP、LOG、ACCEPT和REJECT等操作。FORWARD 鏈過濾所有不是本地產生的並且目的地不是本地(所謂本地就是防火牆了)的包,而 INPUT恰恰針對那些目的地是本地的包。OUTPUT 是用來過濾所有本地生成的包的。
上面介紹了三個不同的表的最基本的內容。你應該知道它們的使用目的完全不同,還要清楚每一條鏈的使用。如果你不瞭解,就可能會在防火牆上留下漏洞,給人以可乘之機。在章節表和鏈 中,我們已詳細地討論了這些必備的的表和鏈。如果你沒有完全理解包是怎樣通過這些表、鏈的話,我建議你回過頭去再仔細看看。

--------------------------------------------------------------------------------
6.3. Commands
在這一節裏,我們將要介紹所有的command以及它們的用途。command指定iptables 對我們提交的規則要做什麼樣的操作。這些操作可能是在某個表裏增加或刪除一些東西,或做點兒其他什麼。以下是iptables可用的command(要注意,如不做說明,默認表的是 filter表。):
Table 6-2. Commands
Command -A, --append
Example iptables -A INPUT ...
Explanation 在所選擇的鏈末添加規則。當源地址或目的地址是以名字而不是ip地址的形式出現時,若這些名字可以被解析爲多個地址,則這條規則會和所有可用的地址結合。
Command -D, --delete
Example iptables -D INPUT --dport 80 -j DROP或iptables -D INPUT 1
Explanation 從所選鏈中刪除規則。有兩種方法指定要刪除的規則:一是把規則完完整整地寫出來,再就是指定規則在所選鏈中的序號(每條鏈的規則都各自從1被編號)。
Command -R, --replace
Example iptables -R INPUT 1 -s 192.168.0.1 -j DROP
Explanation 在所選中的鏈裏指定的行上(每條鏈的規則都各自從1被編號)替換規則。它主要的用處是試驗不同的規則。當源地址或目的地址是以名字而不是ip地址的形式出現時,若這些名字可以被解析爲多個地址,則這條command會失敗。
Command -I, --insert
Example iptables -I INPUT 1 --dport 80 -j ACCEPT
Explanation 根據給出的規則序號向所選鏈中插入規則。如果序號爲1,規則會被插入鏈的頭部,其實默認序號就是1。
Command -L, --list
Example iptables -L INPUT
Explanation 顯示所選鏈的所有規則。如果沒有指定鏈,則顯示指定表中的所有鏈。如果什麼都沒有指定,就顯示默認表所有的鏈。精確輸出受其它參數影響,如-n 和-v等參數,下面會介紹。
Command -F, --flush
Example iptables -F INPUT
Explanation 清空所選的鏈。如果沒有指定鏈,則清空指定表中的所有鏈。如果什麼都沒有指定,就清空默認表所有的鏈。當然,也可以一條一條地刪,但用這個command會快些。
Command -Z, --zero
Example iptables -Z INPUT
Explanation 把指定鏈(如未指定,則認爲是所有鏈)的所有計數器歸零。
Command -N, --new-chain
Example iptables -N allowed
Explanation 根據用戶指定的名字建立新的鏈。上面的例子建立了一個名爲allowed的鏈。注意,所用的名字不能和已有的鏈、target同名。
Command -X, --delete-chain
Example iptables -X allowed
Explanation 刪除指定的用戶自定義鏈。這個鏈必須沒有被引用,如果被引用,在刪除之前你必須刪除或者替換與之有關的規則。如果沒有給出參數,這條命令將會刪除默認表所有非內建的鏈。
Command -P, --policy
Example iptables -P INPUT DROP
Explanation 爲鏈設置默認的target(可用的是DROP 和ACCEPT,如果還有其它的可用,請告訴我),這個target稱作策略。所有不符合規則的包都被強制使用這個策略。只有內建的鏈纔可以使用規則。但內建的鏈和用戶自定義鏈都不能被作爲策略使用,也就是說不能象這樣使用:iptables -P INPUT allowed(或者是內建的鏈)。
Command -E, --rename-chain
Example iptables -E allowed disallowed
Explanation 對自定義的鏈進行重命名,原來的名字在前,新名字在後。如上,就是把allowed改爲disallowed。這僅僅是改變鏈的名字,對整個表的結構、工作沒有任何影響。
在使用iptables時,如果必須的參數沒有輸入就按了回車,那麼它就會給出一些提示信息:告訴你需要哪些參數等等。iptables的選項-v用來顯示iptables的版本,-h給出語法的簡短說明。。下面將要介紹的就是部分選項,還有它們的作用。
Table 6-3. Options
Option(選項) -v, --verbose(詳細的)
可用此選項的命令 --list, --append, --insert, --delete, --replace
Explanation(說明) 這個選項使輸出詳細化,常與--list 連用。與--list連用時,輸出中包括網絡接口的地址、規則的選項、TOS掩碼、字節和包計數器,其中計數器是以K、M、G(這裏用的是10的冪而不是2的冪哦)爲單位的。如果想知道到底有多少個包、多少字節,還要用到選項-x,下面會介紹。如果-v 和--append、--insert、--delete 或--replace連用,iptables會輸出詳細的信息告訴你規則是如何被解釋的、是否正確地插入等等。
Option -x, --exact(精確的)
Commands used with --list
Explanation 使--list輸出中的計數器顯示準確的數值,而不用K、M、G等估值。注意此選項只能和--list連用。
Option -n, --numeric(數值)
Commands used with --list
Explanation 使輸出中的IP地址和端口以數值的形式顯示,而不是默認的名字,比如主機名、網絡名、程序名等。注意此選項也只能和--list連用。
Option --line-numbers
Commands used with --list
Explanation 又是一個只能和--list連用的選項,作用是顯示出每條規則在相應鏈中的序號。這樣你可以知道序號了,這對插入新規則很有用哦。
Option -c, --set-counters
Commands used with --insert, --append, --replace
Explanation 在創建或更改規則時設置計數器,語法如下:--set-counters 20 4000,意思是讓內核把包計數器設爲20,把字節計數器設爲4000。
Option --modprobe
Commands used with All
Explanation 此選項告訴iptables探測並裝載要使用的模塊。這是非常有用的一個選項,萬一modprobe命令不在搜索路徑中,就要用到了。有了這個選項,在裝載模塊時,即使有一個需要用到的模塊沒裝載上,iptables也知道要去搜索。

--------------------------------------------------------------------------------
6.4. Matches
這一節,我們會詳細討論一些matche,我把它們歸爲五類。第一類是generic matches(通用的匹配),適用於所有的規則;第二類是TCP matches,顧名思義,這隻能用於TCP包;第三類是UDP matches,當然它只能用在UDP包上了;第四類是ICMP matches ,針對ICMP包的;第五類比較特殊,針對的是狀態(state),所有者(owner)和訪問的頻率限制(limit)等,它們已經被分到更多的小類當中,儘管它們並不是完全不同的。我希望這是一種大家都容易理解的分類。

--------------------------------------------------------------------------------
6.4.1. 通用匹配
無論我們使用的是何種協議,也不管我們又裝入了匹配的何種擴展,通用匹配都使可用的。也就是說,它們可以直接使用,而不需要什麼前提條件,在後面你會看到,有很多匹配操作是需要其他的匹配作爲前提的。
Table 6-4. Generic matches
Match -p, --protocol
Example iptables -A INPUT -p tcp
Explanation 匹配指定的協議。指定協議的形式有以下幾種:
1、名字,不分大小寫,但必須是在/etc/protocols中定義的。
2、可以使用它們相應的整數值。例如,ICMP的值是1,TCP是6,UDP是17。
3、缺省設置,ALL,相應數值是0,但要注意這隻代表匹配TCP、UDP、ICMP,而不是/etc/protocols中定義的所有協議。
4、可以是協議列表,以英文逗號爲分隔符,如:udp,tcp
5、可以在協議前加英文的感嘆號表示取反,注意有空格,如: --protocol ! tcp 表示非tcp協議,也就是UDP和ICMP。可以看出這個取反的範圍只是TCP、UDP和ICMP。

Match -s, --src, --source
Example iptables -A INPUT -s 192.168.1.1
Explanation 以IP源地址匹配包。地址的形式如下:
1、單個地址,如192.168.1.1,也可寫成 192.168.1.1/255.255.255.255或192.168.1.1/32
2、網絡,如192.168.0.0/24,或 192.168.0.0/255.255.255.0
3、在地址前加英文感嘆號表示取反,注意空格,如--source ! 192.168.0.0/24 表示除此地址外的所有地址
4、缺省是所有地址

Match -d, --dst, --destination
Example iptables -A INPUT -d 192.168.1.1
Explanation 以IP目的地址匹配包。地址的形式和 -- source完全一樣。
Match -i, --in-interface
Example iptables -A INPUT -i eth0
Explanation 以包進入本地所使用的網絡接口來匹配包。要注意這個匹配操作只能用於INPUT,FORWARD和 PREROUTING這三個鏈,用在其他任何地方都會提示錯誤信息。指定接口有一下方法:
1、指定接口名稱,如:eth0、ppp0等
2、使用通配符,即英文加號,它代表字符數字串。若直接用一個加號,即iptables -A INPUT -i +表示匹配所有的包,而不考慮使用哪個接口。這也是不指定接口的默認行爲。通配符還可以放在某一類接口的後面,如:eth+表示所有Ethernet接口,也就是說,匹配所有從Ethernet接口進入的包。
3、在接口前加英文感嘆號表示取反,注意空格,如:-i ! eth0意思是匹配來自除eth0外的所有包。

Match -o, --out-interface
Example iptables -A FORWARD -o eth0
Explanation 以包離開本地所使用的網絡接口來匹配包。使用的範圍和指定接口的方法與--in-interface完全一樣。
Match -f, --fragment
Example iptables -A INPUT -f
Explanation 用來匹配一個被分片的包的第二片或及以後的部分。因爲它們不包含源或目的地址,或ICMP類型等信息,其他規則無法匹配到它,所以纔有這個匹配操作。要注意碎片***哦。這個操作也可以加英文感嘆號表示取反,但要注意位置,如:! -f 。取反時,表示只能匹配到沒有分片的包或者是被分片的包的第一個碎片,其後的片都不行。現在內核有完善的碎片重組功能,可以防止碎片***,所以不必使用取反的功能來防止碎片通過。如果你使用連接跟蹤,是不會看到任何碎片的,因爲在它們到達任何鏈之前就被處理過了。

--------------------------------------------------------------------------------
6.4.2. 隱含匹配
這種匹配操作是自動地或隱含地裝載入內核的。例如我們使用--protocol tcp 時,不需再裝入任何東西就可以匹配只有IP包纔有的一些特點。現在有三種隱含的匹配針對三種不同的協議,即TCP matches,UDP matches和 ICMP matches。它們分別包括一套只適用於相應協議的判別標準。相對於隱含匹配的是顯式匹配,它們必須使用-m或--match被明確地裝載,而不能是自動地或隱含地,下一節會介紹到。

--------------------------------------------------------------------------------
6.4.2.1. TCP matches
TCP matches只能匹配TCP包或流的細節,它們必須有--protocol tcp作爲前提條件。
Table 6-5. TCP matches
Match --sport, --source-port
Example iptables -A INPUT -p tcp --sport 22
Explanation 基於TCP包的源端口來匹配包,端口的指定形式如下:
1、不指定此項,則暗示所有端口。
2、使用服務名或端口號,但名字必須是在/etc/services 中定義的,因爲iptables從這個文件裏查找相應的端口號。從這可以看出,使用端口號會使規則裝入快一點兒,當然,可讀性就差些了。但是如果你想寫一個包含200條或更多規則的規則集,那你還是老老實實地用端口號吧,時間是主要因素(在一臺稍微慢點兒地機子上,這最多會有10秒地不同,但要是1000條、10000 條呢)。
3、可以使用連續的端口,如:--source-port 22:80這表示從22到80的所有端口,包括22和80。如果兩個號的順序反了也沒關係,如:--source-port 80:22這和 --source-port 22:80的效果一樣。
4、可以省略第一個號,默認第一個是0,如:--source-port :80表示從0到80的所有端口。
5、也可以省略第二個號,默認是65535,如:--source-port 22:表示從22到 65535的所有端口
6、在端口號前加英文感嘆號表示取反,注意空格,如:--source-port ! 22表示除22號之外的所有端口;--source-port ! 22:80表示從22到80(包括22和80)之外的所有端口。
注意:這個匹配操作不能識別不連續的端口列表,如:--source-port ! 22, 36, 80 這樣的操作是由後面將要介紹的多端口匹配擴展來完成的。

Match --dport, --destination-port
Example iptables -A INPUT -p tcp --dport 22
Explanation 基於TCP包的目的端口來匹配包,端口的指定形式和--sport完全一樣。
Match --tcp-flags
Example
Explanation 匹配指定的TCP標記。有兩個參數,它們都是列表,列表內部用英文的逗號作分隔符,這兩個列表之間用空格分開。第一個參數指定我們要檢查的標記(作用就象掩碼),第二個參數指定“在第一個列表中出現過的且必須被設爲1(即狀態是打開的)的”標記(第一個列表中其他的標記必須置0)。也就是說,第一個參數提供檢查範圍,第二個參數提供被設置的條件(就是哪些位置1)。這個匹配操作可以識別以下標記:SYN, ACK,FIN,RST ,URG,PSH。另外還有兩個詞也可使用,就是ALL和NONE。顧名思義,ALL是指選定所有的標記,NONE是指未選定任何標記。這個匹配也可在參數前加英文的感嘆號表示取反。例如:
1、iptables -p tcp --tcp-flags SYN,FIN,ACK SYN表示匹配那些SYN標記被設置而FIN和ACK標記沒有設置的包,注意各標記之間只有一個逗號而沒有空格。
2、--tcp-flags ALL NONE匹配所有標記都未置1的包。
3、iptables -p tcp --tcp-flags ! SYN,FIN,ACK SYN表示匹配那些FIN和ACK標記被設置而SYN標記沒有設置的包,注意和例1比較一下。

Match --syn
Example iptables -p tcp --syn
Explanation 這個匹配或多或少算是ipchains時代的遺留物,之所以還保留它,是爲了向後兼容,也是爲了方便規則在iptables和ipchains間的轉換。它匹配那些SYN標記被設置而 ACK和RST標記沒有設置的包,這和iptables -p tcp --tcp-flags SYN,RST,ACK SYN 的作用毫無二樣。這樣的包主要用在TCP連接初始化時發出請求。如果你阻止了這樣的包,也就阻止了所有由外向內的連接企圖,這在一定程度上防止了一些***。但外出的連接不受影響,恰恰現在有很多***就利用這一點。比如有些***黑掉服務器之後安裝會一些軟件,它們能夠利用已存的連接到達你的機子,而不要再新開一個端口。這個匹配也可用英文感嘆號取反,如:! --syn用來匹配那些 RST或ACK被置位的包,換句話說,就是狀態爲已建立的連接的包。
Match --tcp-option
Example iptables -p tcp --tcp-option 16
Explanation 根據匹配包。TCP選項是TCP頭中的特殊部分,有三個不同的部分。第一個8位組表示選項的類型,第二個8位組表示選項的長度(這個長度是整個選項的長度,但不包含填充部分所佔的字節,而且要注意不是每個TCP選項都有這一部分的),第三部分當然就是選項的內容了。爲了適應標準,我們不必執行所有的選項,但我們可以查看選項的類型,如果不是我們所支持的,那就只是看看長度然後跳過數據部分。這個操作是根據選項的十進制值來匹配的,它也可以用英文感嘆號取反。所有的選項都可在Internet Engineering Task Force裏找到。

--------------------------------------------------------------------------------
6.4.2.2. UDP matches
UDP matches是在指定--protocol UDP時自動裝入的。UDP是一種無連接協議,所以在它打開、關閉連接以及在發送數據時沒有多少標記要設置,它也不需要任何類型的確認。數據丟失了,就丟失了(不會發送ICMP錯誤信息的)。這就說明UDP matches要比TCP matches少多了。即使UDP和ICMP是無連接協議,狀態機制也可以很好的工作,就象在TCP上一樣,這在前面討論過。
Table 6-6. UDP matches
Match --sport, --source-port
Example iptables -A INPUT -p udp --sport 53
Explanation 基於UDP包的源端口來匹配包,端口的指定形式和TCP matches中的--sport完全一樣。
Match --dport, --destination-port
Example iptables -A INPUT -p udp --dport 53
Explanation 基於UDP包的目的端口來匹配包,端口的指定形式和TCP matches中的--sport完全一樣。

--------------------------------------------------------------------------------
6.4.2.3. ICMP matches
ICMP協議也是無連接協議,ICMP包更是短命鬼,比UDP的還短。ICMP協議不是IP協議的下屬協議,而是它的輔助者,其主要作用是報告錯誤和連接控制。ICMP包的頭和IP的很相似,但又有很多不同。這個協議最主要的特點是它有很多類型,以應對不同的情況。比如,我們想訪問一個無法訪問的地址,就會收到一個ICMP host unreachable信息,它的意思是主機無法到達。在附錄ICMP類型裏有完整的ICMP類型列表。雖然有這麼多類型,但只有一個 ICMP matche,這就足夠對付它們了。這個matche是在指定--protocol ICMP時自動裝入的。注意所有的通用匹配都可以使用,這樣我們就可以匹配ICMP包的源、目地址。
Table 6-7. ICMP matches
Match --icmp-type
Example iptables -A INPUT -p icmp --icmp-type 8
Explanation 根據ICMP類型匹配包,類型的指定可以使用十進制數值或相應的名字,數值在RFC792中有定義,名字可以用iptables --protocol icmp --help 查看,或者在附錄ICMP類型中查找。這個匹配也可用英文感嘆號取反,如:--icmp-type ! 8就表示匹配除類型8之外的所有ICMP包。要注意有些ICMP 類型已經廢棄不用了,還有一些可能會對無防護的主機帶來“危險”,因爲它們可能把包重定向到錯誤的地方。

--------------------------------------------------------------------------------
6.4.3. 顯式匹配
顯式匹配必須用-m或--match裝載,比如要使用狀態匹配就必須使用-m state。有些匹配還需要指定協議,有些就不需要,比如連接狀態就不要。這些狀態是NEW(還未建立好的連接的第一個包), ESTABLISHED(已建立的連接,也就是已經在內核裏註冊過的),RELATED(由已經存在的、處於已建立狀態的連接生成的新連接),等等。有些匹配還處在開發階段,或者還只是爲了說明iptables的強大能力。這說明不是所有的匹配一開始就是實用的,但以後你可能會用到它。隨着iptables 新版本的發佈,會有一些新的匹配可用。隱含匹配和顯式匹配最大的區別就是一個是跟隨協議匹配自動裝載的,一個是顯式裝載的。

--------------------------------------------------------------------------------
6.4.3.1. Limit match
這個匹配操作必須由-m limit明確指定才能使用。有了它的幫助,就可以對指定的規則的日誌數量加以限制,以免你被信息的洪流淹沒哦。比如,你可以事先設定一個限定值,當符合條件的包的數量不超過它時,就記錄;超過了,就不記錄了。我們可以控制某條規則在一段時間內的匹配次數(也就是可以匹配的包的數量),這樣就能夠減少DoS syn flood***的影響。這是它的主要作用,當然,還有很多其他作用(譯者注:比如,對於某些不常用的服務可以限制連接數量,以免影響其他服務)。limit match也可以用英文感嘆號取反,如:-m limit ! --limit 5/s表示在數量超過限定值後,所有的包都會被匹配。
(譯者注:爲了更好地理解這個匹配操作,我們通過一個比喻來解釋一下。原文也做了類似地比喻,但我覺得對於初學者不易理解,故未採用。)limit match的工作方式就像一個單位大門口的保安,當有人要進入時,需要找他辦理通行證。早上上班時,保安手裏有一定數量的通行證,來一個人,就簽發一個,當通行證用完後,再來人就進不去了,但他們不會等,而是到別的地方去(在iptables裏,這相當於一個包不符合某條規則,就會由後面的規則來處理,如果都不符合,就由缺省的策略處理)。但有個規定,每隔一段時間保安就要簽發一個新的通行證。這樣,後面來的人如果恰巧趕上,也就可以進去了。如果沒有人來,那通行證就保留下來,以備來的人用。如果一直沒人來,可用的通行證的數量就增加了,但不是無限增大的,最多也就是剛開始時保安手裏有的那個數量。也就是說,剛開始時,通行證的數量是有限的,但每隔一段時間就有新的通行證可用。limit match有兩個參數就對應這種情況,--limit-burst指定剛開始時有多少通行證可用,--limit指定要隔多長時間才能簽發一個新的通行證。要注意的是,我這裏強調的是“簽發一個新的通行證”,這是以iptables的角度考慮的。在你自己寫規則時,就要從這個角度考慮。比如,你指定了--limit 3/minute --limit-burst 5 ,意思是開始時有5個通行證,用完之後每20秒增加一個(這就是從iptables的角度看的,要是以用戶的角度看,說法就是每一分鐘增加三個或者每分鐘只能過三個)。你要是想每20分鐘過一個,只能寫成--limit 3/hour --limit-burst 5,也就是說你要把時間單位湊成整的。
Table 6-8. Limit match options
Match --limit
Example iptables -A INPUT -m limit --limit 3/hour
Explanation 爲limit match設置最大平均匹配速率,也就是單位時間內limit match可以匹配幾個包。它的形式是一個數值加一個時間單位,可以是/second /minute /hour /day 。默認值是每小時3次(用戶角度),即3/hour ,也就是每20分鐘一次(iptables角度)。
Match --limit-burst
Example iptables -A INPUT -m limit --limit-burst 5
Explanation 這裏定義的是limit match的峯值,就是在單位時間(這個時間由上面的--limit指定)內最多可匹配幾個包(由此可見,--limit-burst的值要比--limit的大)。默認值是5。爲了觀察它是如何工作的,你可以啓動“只有一條規則的腳本”Limit- match.txt,然後用不同的時間間隔、發送不同數量的ping數據包。這樣,通過返回的 echo replies就可以看出其工作方式了。

--------------------------------------------------------------------------------
6.4.3.2. MAC match
基於包的MAC源地址匹配包。到寫這篇文章時,這個match還有一點限制(就是隻能匹配MAC源地址匹),但今後定會有所發展,會更有用的。

注意,這個match是由-m mac裝入的,而不是一些人想當然的-m mac-source,後者只是前者的選項而已。
 
Table 6-9. MAC match options
Match --mac-source
Example iptables -A INPUT -m mac --mac-source 00:00:00:00:00:01
Explanation 基於包的MAC源地址匹配包,地址格式只能是XX:XX:XX:XX:XX:XX,當然它也可以用英文感嘆號取反,如--mac- source ! 00:00:00:00:00:01,意思很簡單了,就是除此之外的地址都可接受嘛。注意,因爲 MAC addresses只用於Ethernet類型的網絡,所以這個match只能用於Ethernet接口。而且,它還只能在PREROUTING,FORWARD 和INPUT鏈裏使用。

--------------------------------------------------------------------------------
6.4.3.3. Mark match
以包被設置的mark來匹配包,這個值只能由內核更改。前面曾經提到過,mark比較特殊,它不是包本身的一部分,而是在包穿越計算機的過程中由內核分配的和它相關聯的一個字段。它可能被用來改變包的傳輸路徑或過濾。時至今日,在linux裏只有一種方法能設置mark,即iptables的MARK target,以前在ipchains裏是FWMARK target。這就是爲什麼在高級路由裏我們仍要參照FWMARK的原因。mark字段的值是一個無符號的整數,在32位系統上最大可以是4294967296(就是2的32次方),這足夠用的了:)
Table 6-10. Mark match options
Match --mark
Example iptables -t mangle -A INPUT -m mark --mark 1
Explanation 以包被設置的mark值來匹配包,這個值是是由下面將要介紹的 MARK target來設置的,它是一個無符號的整數。所有通過 Netfilter的包都會被分配一個相關聯的mark field 。但要注意mark值可不是在任何情況下都能使用的,它只能在分配給它值的那臺機子裏使用,因爲它只是由內核在內存裏分配的和包相關的幾個字節,並不屬於包本身,所以我們不能在本機之外的路由器上使用。mark的格式是--mark value[/mask],如上面的例子是沒有掩碼的,帶掩碼的例子如--mark 1/1。如果指定了掩碼,就先把mark值和掩碼取邏輯與,然後再和包的mark值比較。

--------------------------------------------------------------------------------
6.4.3.4. Multiport match
多端口匹配擴展使我們能夠在一條規則裏指定不連續的多個端口,如果沒有這個擴展,我們只能按端口來寫規則了。其實這只是標準端口匹配的增強版罷了,使我們書寫規則更方便而已。

注意:不能在一條規則裏同時使用標準端口匹配和多端口匹配,如--sport 1024:63353 -m multiport --dport 21,23,80。這條規則並不能想你想象的那樣工作,但也不是不能工作,iptables會使用第一個合法的條件,那麼這裏多端口匹配就白寫了:)
 
Table 6-11. Multiport match options
Match --source-port
Example iptables -A INPUT -p tcp -m multiport --source-port 22,53,80,110
Explanation 源端口多端口匹配,最多可以指定15個端口,以英文逗號分隔,注意沒有空格。使用時必須有-p tcp或-p udp爲前提條件。
Match --destination-port
Example iptables -A INPUT -p tcp -m multiport --destination-port 22,53,80,110
Explanation 目的端口多端口匹配,使用方法和源端口多端口匹配一樣,唯一的區別是它匹配的是目的端口。
Match --port
Example iptables -A INPUT -p tcp -m multiport --port 22,53,80,110
Explanation 同端口多端口匹配,意思就是它匹配的是那種源端口和目的端口是同一個端口的包,比如:端口80到端口80的包,110到110的包等。使用方法和源端口多端口匹配一樣。

--------------------------------------------------------------------------------
6.4.3.5. Owner match
基於包的生成者(也就是所有者,或稱作擁有者,owner)的ID來匹配包,owner可以是啓動進程的用戶的ID,或用戶所在的組的ID,或進程的ID,或會話的ID。這個擴展原本只是爲了說明iptables可以做什麼,現在發展到實用階段了。但要注意,此擴展只能用在OUTPUT中,原因顯而易見:我們幾乎不可能得到發送端例程的ID的任何信息,或者在去往真正目的地的路上哪兒有路由。甚至在 OUTPUT鏈裏,這也不是十分可靠,因爲有些包根本沒有owner,比如 ICMP responses,所以它們從不會被這個match抓到:)
Table 6-12. Owner match options
Match --uid-owner
Example iptables -A OUTPUT -m owner --uid-owner 500
Explanation 按生成包的用戶的ID(UID)來匹配外出的包。使用這個匹配可以做這樣一些事,比如,阻止除root外的用戶向防火牆外建立新連接,或阻止除用戶http外的任何人使用HTTP端口發送數據。
Match --gid-owner
Example iptables -A OUTPUT -m owner --gid-owner 0
Explanation 按生成包的用戶所在組的ID(GID)來匹配外出的包。比如,我們可以只讓屬於network組的用戶上Internet,而其他用戶都不行;或者只允許http組的成員能從HTTP端口發送數據。
Match --pid-owner
Example iptables -A OUTPUT -m owner --pid-owner 78
Explanation 按生成包的進程的ID(GID)來匹配外出的包。比如,我們可以只允許PID爲94的進程(http進程當然不能是多線程的)使用http端口。這個匹配使用起來有一點難度,因爲你要知道進程的ID號。當然,你也可以寫一個小小的腳本,先從ps的輸出中得到PID,再添加相應的規則,這兒有個例子Pid-owner.txt。
Match --sid-owner
Example iptables -A OUTPUT -m owner --sid-owner 100
Explanation 按生成包的會話的ID(SID)來匹配外出的包。一個進程以及它的子進程或它的多個線程都有同一個SID。比如,所有的HTTPD進程的SID和它的父進程一樣(最初的 HTTPD進程),即使HTTPD是多線程的(現在大部分都是,比如Apache和Roxen)也一樣。這裏有個腳本Sid-owner.txt可以反映出這一點。

--------------------------------------------------------------------------------
6.4.3.6. State match
狀態匹配擴展要有內核裏的連接跟蹤代碼的協助,因爲它是從連接跟蹤機制中得到包的狀態的。這樣我們就可以瞭解連接所處的狀態。它幾乎適用於所有的協議,包括那些無狀態的協議,如ICMP和UDP。針對每個連接都有一個缺省的超時值,如果連接的時間超過了這個值,那麼這個連接的記錄就被會從連接跟蹤的記錄數據庫中刪除,也就是說連接就不再存在了。這個match必須有-m state作爲前提才能使用。狀態機制的詳細內容在章節狀態機制 中。
Table 6-13. State matches
Match --state
Example iptables -A INPUT -m state --state RELATED,ESTABLISHED
Explanation 指定要匹配包的的狀態,當前有4種狀態可用:INVALID,ESTABLISHED,NEW和RELATED。 INVALID意味着這個包沒有已知的流或連接與之關聯,也可能是它包含的數據或包頭有問題。ESTABLISHED意思是包是完全有效的,而且屬於一個已建立的連接,這個連接的兩端都已經有數據發送。NEW表示包將要或已經開始建立一個新的連接,或者是這個包和一個還沒有在兩端都有數據發送的連接有關。RELATED說明包正在建立一個新的連接,這個連接是和一個已建立的連接相關的。比如,FTP data transfer,ICMP error 和一個TCP或UDP連接相關。注意NEW狀態並不在試圖建立新連接的TCP包裏尋找SYN標記,因此它不應該不加修改地用在只有一個防火牆或在不同的防火牆之間沒有啓用負載平衡的地方。具體如何使用,你就再看看章節狀態機制吧:)

--------------------------------------------------------------------------------
6.4.3.7. TOS match
根據TOS字段匹配包,必須使用-m tos才能裝入。TOS是IP頭的一部分,其含義是Type Of Service,由8個二進制位組成,包括一個3 bit的優先權子字段(現在已被忽略),4 bit的TOS子字段和1 bit未用位(必須置0)。它一般用來把當前流的優先權和需要的服務(比如,最小延時、最大吞吐量等)通知路由器。但路由器和管理員對這個值的處理相差很大,有的根本就不理會,而有的就會盡量滿足要求。
Table 6-14. TOS matches
Match --tos
Example iptables -A INPUT -p tcp -m tos --tos 0x16
Explanation 根據TOS字段匹配包。這個match常被用來mark包,以便後用,除此之外,它還常和iproute2或高級路由功能一起使用。它的參數可以是16進制數,也可以是十進制數,還可以是相應的名字(用 iptables -m tos -h能查到)。到寫這篇文章時,有以下參數可用:
Minimize-Delay 16 (0x10),要求找一條路徑使延時最小,一些標準服務如telnet、SSH、FTP-control 就需要這個選項。
Maximize-Throughput 8 (0x08),要求找一條路徑能使吞吐量最大,標準服務FTP-data能用到這個。
Maximize-Reliability 4 (0x04),要求找一條路徑能使可靠性最高,使用它的有BOOTP和TFTP。
Minimize-Cost 2 (0x02),要求找一條路徑能使費用最低,一般情況下使用這個選項的是一些視頻音頻流協議,如RTSP(Real Time Stream Control Protocol)。
Normal-Service 0 (0x00),一般服務,沒有什麼特殊要求。
 

--------------------------------------------------------------------------------
6.4.3.8. TTL match
根據IP頭裏的TTL (Time To Live,即生存期)字段來匹配包,此必須由-m ttl裝入。TTL field是一個字節(8個二進制位),一旦經過一個處理它的路由器,它的值就減去1它的值。當該字段的值減爲0時,報文就被認爲是不可轉發的,數據報就被丟棄,併發送ICMP報文通知源主機,不可轉發的報文被丟棄。這也有兩種情況,一是傳輸期間生存時間爲0,使用類型爲11代碼是0的ICMP報文;二是在數據報重組期間生存時間爲0,使用類型爲11代碼是1的ICMP報文。這個match只是根據TTL匹配包,而對其不做任何更改,所以在它之後可使用任何類型的match。
Table 6-15. TTL matches
Match --ttl
Example iptables -A OUTPUT -m ttl --ttl 60
Explanation 根據TTL的值來匹配包,參數的形式只有一種,就是十進制數值。它可以被用來調試你的局域網,比如解決LAN內的主機到Internet上的主機的連接問題,或找出 Trojan(Trojan)可能的入口。這個match的用處相對有限,但它其實是很有用的,這就看你的想象力如何了。比如可以用它來發現那些TTL具有錯誤缺省值的機子(這可能是實現TCP/IP棧功能的那個程序本身的錯誤,或者是配置有問題)。

--------------------------------------------------------------------------------
6.4.4. 針對非正常包的匹配
這個匹配沒有任何參數,也不需要顯式地裝載。注意這應該被看作是一個實驗性的匹配,它不總是能正常工作的,對有些不正常的包(unclean package,就是所謂的髒包)或問題,它是視而不見的。這個match 試圖匹配那些好象畸形或不正常的包,比如包頭錯或校驗和錯,等等。它可能常用來DROP錯誤的連接、檢查有錯的流,但要知道這樣做也可能會中斷合法的連接。

--------------------------------------------------------------------------------
6.5. Targets/Jumps
target/jump決定符合條件的包到何處去,語法是--jump target或-j target。(譯者注:本文中,原作者把target細分爲兩類,即Target和Jump。它們唯一的區別是jump的目標是一個在同一個表內的鏈,而target的目標是具體的操作。)我們會先接觸到兩個基本的target,就是ACCEPT和DROP。
前面提到過用戶自定義鏈要用到-N命令。下面我們在filter表中建一個名爲tcp_packets的鏈:
iptables -N tcp_packets
然後再把它作爲jump的目標:
iptables -A INPUT -p tcp -j tcp_packets
這樣我們就會從INPUT鏈跳入tcp_packets鏈,開始在tcp_packets中的旅行。如果到達了tcp_packets鏈的結尾(也就是未被鏈中的任何規則匹配),則會退到INPUT鏈的下一條規則繼續它的旅行。如果在子鏈中被ACCEPT了,也就相當於在父鏈中被ACCEPT了,那麼它不會再經過父鏈中的其他規則。但要注意這個包能被其他表的鏈匹配,過程可查看章節 表和鏈。
target指定我們要對包做的操作,比如DROP和ACCEPT,還有很多,我們後面會介紹。不同的target有不同的結果。一些target會使包停止前景,也就是不再繼續比較當前鏈中的其他規則或父鏈中的其他規則,最好的例子就是DROP和ACCEPT。而另外一些target在對包做完操作之後,包還會繼續和其他的規則比較,如LOG,ULOG和TOS。它們會對包進行記錄、mangle,然後讓包通過,以便匹配這條鏈中的其他規則。有了這樣的target,我們就可以對同一個包既改變它的TTL又改變它的TOS。有些target必須要有準確的參數(如TOS需要確定的數值),有些就不是必須的,但如果我們想指定也可以(如日誌的前綴,僞裝使用的端口,等等)。本節我們會儘可能全面地介紹每一個target。現在我們就來看看有哪幾種target。

--------------------------------------------------------------------------------
6.5.1. ACCEPT target
這個target沒有任何選項和參數,使用也很簡單,指定-j ACCEPT即可。一旦包滿足了指定的匹配條件,就會被ACCEPT,並且不會再去匹配當前鏈中的其他規則或同一個表內的其他規則,但它還要通過其他表中的鏈,而且在那兒可能會百DROP也說不準哦。

--------------------------------------------------------------------------------
6.5.2. DNAT target
這個target是用來做目的網絡地址轉換的,就是重寫包的目的IP地址。如果一個包被匹配了,那麼和它屬於同一個流的所有的包都會被自動轉換,然後就可以被路由到正確的主機或網絡。DNAT target是非常有用的。比如,你的Web服務器在LAN內部,而且沒有可在Internet上使用的真實IP地址,那就可以使用這個 target讓防火牆把所有到它自己HTTP端口的包轉發給LAN內部真正的Web服務器。目的地址也可以是一個範圍,這樣的話,DNAT會爲每一個流隨機分配一個地址。因此,我們可以用這個target做某種類型地負載平衡。
注意,DANT target只能用在nat表的PREROUTING和OUTPUT鏈中,或者是被這兩條鏈調用的鏈裏。但還要注意的是,包含DANT target的鏈不能被除此之外的其他鏈調用,如POSTROUTING。
Table 6-16. DNAT target
Option --to-destination
Example iptables -t nat -A PREROUTING -p tcp -d 15.45.23.67 --dport 80 -j DNAT --to-destination 192.168.1.1-192.168.1.10
Explanation 指定要寫入IP頭的地址,這也是包要被轉發到的地方。上面的例子就是把所有發往地址15.45.23.67的包都轉發到一段LAN使用的私有地址中,即192.168.1.1到 192.168.1.10。如前所述,在這種情況下,每個流都會被隨機分配一個要轉發到的地址,但同一個流總是使用同一個地址。我們也可以只指定一個IP地址作爲參數,這樣所有的包都被轉發到同一臺機子。我們還可以在地址後指定一個或一個範圍的端口。比如:--to-destination 192.168.1.1:80或 --to-destination 192.168.1.1:80-100。SNAT的語法和這個target的一樣,只是目的不同罷了。要注意,只有先用--protocol指定了TCP或 UDP協議,才能使用端口。
因爲DNAT要做很多工作,所以我要再羅嗦一點。我們通過一個例子來大致理解一下它是如何工作的。比如,我想通過Internet連接發佈我們的網站,但是HTTP server在我們的內網裏,而且我們對外只有一個合法的IP,就是防火牆那個對外的IP——$INET_IP。防火牆還有一個內網的IP——$LAN_IP,HTTP server的IP是$HTTP_IP (這當然是內網的了)。爲了完成我們的設想,要做的第一件事就是把下面的這個簡單的規則加入到nat表的PREROUTING鏈中:
iptables -t nat -A PREROUTING --dst $INET_IP -p tcp --dport 80 -j DNAT \ --to-destination $HTTP_IP
現在,所有從Internet來的、到防火牆的80端口去的包都會被轉發(或稱做被DNAT )到在內網的HTTP服務器上。如果你在Internet上試驗一下,一切正常吧。再從內網裏試驗一下,完全不能用吧。這其實是路由的問題。下面我們來好好分析這個問題。爲了容易閱讀,我們把在外網上訪問我們服務器的那臺機子的IP地址記爲$EXT_BOX。

包從地址爲$EXT_BOX的機子出發,去往地址爲$INET_IP 的機子。
包到達防火牆。
防火牆DNAT(也就是轉發)這個包,而且包會經過很多其他的鏈檢驗及處理。
包離開防火牆向$HTTP_IP前進。
包到達HTTP服務器,服務器就會通過防火牆給以迴應,當然,這要求把防火牆作爲HTTP到達$EXT_BOX的網關。一般情況下,防火牆就是HTTP服務器的缺省網關。
防火牆再對返回包做Un-DNAT(就是照着DNAT的步驟反過來做一遍),這樣就好像是防火牆自己回覆了那個來自外網的請求包。
返回包好象沒經過這麼複雜的處理、沒事一樣回到$EXT_BOX。
現在,我們來考慮和HTTP服務器在同一個內網(這裏是指所有機子不需要經過路由器而可以直接互相訪問的網絡,不是那種把服務器和客戶機又分在不同子網的情況)的客戶訪問它時會發生什麼。我們假設客戶機的IP爲$LAN_BOX,其他設置同上。

包離開$LAN_BOX,去往$INET_IP。
包到達防火牆。
包被DNAT,而且還會經過其他的處理。但是包沒有經過SNAT 的處理,所以包還是使用它自己的源地址,就是$LAN_BOX(譯者注:這就是IP 傳輸包的特點,只根據目的地的不同改變目的地址,但不因傳輸過程中要經過很多路由器而隨着路由器改變其源地址,除非你單獨進行源地址的改變。其實這一步的處理和對外來包的處理是一樣的,只不過內網包的問題就在於此,所以這裏交待一下原因)。
包離開防火牆,到達HTTP服務器。
HTTP服務器試圖回覆這個包。它在路由數據庫中看到包是來自同一個網絡的一臺機子,因此它會把回覆包直接發送到請求包的源地址(現在是回覆包的目的地址),也就是$LAN_BOX。
回覆包到達客戶機,但它會很困惑,因爲這個包不是來自它訪問的那臺機子。這樣,它就會把這個包扔掉而去等待“真正”的回覆包。
針對這個問題有個簡單的解決辦法,因爲這些包都要進入防火牆,而且它們都去往需要做DNAT才能到達的那個地址,所以我們只要對這些包做SNAT操作即可。比如,我們來考慮上面的例子,如果對那些進入防火牆而且是去往地址爲$HTTP_IP、端口爲80的包做SNAT操作,那麼這些包就好象是從$LAN_IP來的了,也就是說,這些包的源地址被改爲$LAN_IP了。這樣,HTTP服務器就會把回覆包發給防火牆,而防火牆會再對包做 Un-DNAT操作,並把包發送到客戶機。解決問題的規則如下:
iptables -t nat -A POSTROUTING -p tcp --dst $HTTP_IP --dport 80 -j SNAT \ --to-source $LAN_IP
要記住,按運行的順序POSTROUTING鏈是所有鏈中最後一個,因此包到達這條鏈時,已經被做過DNAT操作了,所以我們在規則裏要基於內網的地址$HTTP_IP(包的目的地)來匹配包。

警告:我們剛纔寫的這條規則會對日誌產生很大影響,這種影響應該說是很不好的。因爲來自 Internet包在防火牆內先後經過了DNAT和SNAT處理,才能到達HTTP服務器(上面的例子),所以HTTP服務器就認爲包是防火牆發來的,而不知道真正的源頭是其他的IP。這樣,當它記錄服務情況時,所有訪問記錄的源地址都是防火牆的IP而不是真正的訪問源。我們如果想根據這些記錄來了解訪問情況就不可能了。因此上面提供的“簡單辦法”並不是一個明智的選擇,但它確實可以解決“能夠訪問”的問題,只是沒有考慮到日誌而已。
其他的服務也有類似的問題。比如,你在LAN內建立了SMTP服務器,那你就要設置防火牆以便能轉發SMTP的數據流。這樣你就創建了一個開放的SMTP中繼服務器,隨之而來的就是日誌的問題了。
一定要注意,這裏所說的問題只是針對沒有建立DMZ或類似結構的網絡,並且內網的用戶訪問的是服務器的外網地址而言的。(譯者注:因爲如果建立了DMZ,或者服務器和客戶機又被分在不同的子網裏,那就不需要這麼麻煩了。因爲所有訪問的源頭都不在服務器所在的網裏,所以就沒必要做SNAT去改變包的源地址了,從而記錄也就不是問題了。如果內網客戶是直接訪問服務器的內網地址那就更沒事了)
較好的解決辦法是爲你的LAN在內網建立一臺單獨的DNS服務器(譯者注:這樣,內網的客戶使用網站名訪問HTTP服務器時,DNS就可以把它解析成內網地址。客戶機就可以直接去訪問HTTP服務器的內網地址了,從而避免了通過防火牆的操作,而且包的源地址也可以被HTTP服務器的日誌使用,也就沒有上面說的日誌問題了。),或者乾脆建立DMZ得了(這是最好的辦法,但你要有錢哦,因爲用的設備多啊)。
 
對上面的例子應該考慮再全面些,現在還有一個問題沒解決,就是防火牆自己要訪問HTTP服務器時會發生什麼,能正常訪問嗎?你覺得呢:)很可惜,現在的配置還是不行,仔細想想就明白了。我們這裏討論的基礎都是假設機子訪問的是HTTP服務器的外網地址,但這個外網地址其實就是防火牆對外的地址,所以當防火牆訪問這個外網地址時,就是訪問它自己。防火牆上如果有HTTP服務,那客戶機就會看到頁面內容,不過這不是它想看到的(它想要的在DNAT上了),如果沒有HTTP服務,客戶就只能收到錯誤信息了。前面給出的規則之所以不起作用是因爲從防火牆發出的請求包不會經過那兩條鏈。還記得防火牆自己發出的包經過哪些鏈吧:)我們要在nat表的OUTPUT鏈中添加下面的規則:
iptables -t nat -A OUTPUT --dst $INET_IP -p tcp --dport 80 -j DNAT \ --to-destination $HTTP_IP
有了最後這條規則,一切都正常了。和HTTP服務器不在同一個網的機子能正常訪問服務了,和它在一個網內的機子也可以正常訪問服務了,防火牆本身也能正常訪問服務了,沒有什麼問題了。這種心情,套用《大話西遊》裏的一句話,就是“世界又清淨了”。(不要說你不知道什麼是《大話西遊》)

我想大家應該能明白這些規則只說明了數據包是如何恰當地被DNAT和SNAT的。除此之外,在 filter表中還需要其他的規則(在FORWARD鏈裏),以允許特定的包也能經過前面寫的(在POSTROUTING鏈和 OUTPUT鏈裏的)規則。千萬不要忘了,那些包在到達FORWARD鏈之前已經在PREROUTING鏈裏被DNAT過了,也就是說它們的目的地址已被改寫,在寫規則時要注意這一點。
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章