僅供自學使用。html
本文介紹防火牆知識和Linux主機處理數據包的過程,同時介紹了iptables管理防火牆的方法。node
對於沒有防火牆存在的一條網絡路線中,主機A發送給主機B的任何一個數據包,主機B都會照單全收,即便是包含了病毒、木馬等的數據也同樣會收。雖然說害人之心不可有,可是在網絡上,你認爲是害你的行爲在對方眼中是利他的行爲。因此防人之心定要有,防火牆就能夠提供必定的保障。linux
有了簡單的防火牆以後,在數據傳輸的過程當中就會接受"入關"檢查,能經過的數據包才繼續傳輸,不能經過的數據包則拒絕或者直接丟棄。web
從上面的圖中能夠看出,防火牆至少須要兩個網卡,其中一塊控制流入數據包,另外一塊網卡控制流出數據包。即便是軟件防火牆,要實現完整的防火牆功能,也須要至少兩塊網卡。算法
所謂防火牆就是"防火的牆",若是過來的是"火"就得擋住,若是過來的不是"火"就放行,但什麼是"火",這由人們自行定製。shell
但不管如何,所謂的"火"都是基於OSI七層模型的,簡單的劃分爲四層:最高的應用層(如HTTP/FTP/SMTP),往下一層是傳輸層(TCP/UDP),再往下一層是網絡層,最後是鏈路層。能夠基於整個7層模型的每一層來定製防火牆,可是默認防火牆(沒有編譯內核源碼定製七層防火牆)通常認爲工做在以上的4層中。數據庫
在網上和不少書籍上都詳細解釋了OSI七層模型各層的行爲和做用,我我的推薦一本《計算機網絡原理創新教程》,裏面的OSI模型是我學習過最通俗易懂且完整詳細的教程。express
首先看看網絡數據傳輸的基本流程。後端
數據從上層進入到傳輸層,加上源端口和目標端口成爲數據段(若是是UDP則成爲數據報),再進入網絡層加上源IP和目標IP成爲數據包,再進入鏈路層加上源MAC地址和目標MAC地址成爲數據幀,這段過程是一種"加頭"封裝數據的過程。數據通過網絡傳輸到達目標主機後,逐層"剃頭"解包,最終獲得data純數據內容。安全
其實,進程間數據傳輸的方式有多種:共享內存、命名管道、套接字、消息隊列、信號量等。上面描述的OSI通訊模型只是數據傳輸的一種方式,它特指網絡數據傳輸,是基於套接字(ip+port)的,因此既能夠是主機間進程通訊,也能夠是本機服務端和客戶端進程間的通訊。
不管如何,網絡數據老是會流入、流出的,即便是本機的客戶端和服務端進程間通訊,也須要從一個套接字流出、另外一個套接字流入,只不過這些數據無需路由、無需通過物理網卡(走的是LoopBack)。當接收外界發送的數據時,在數據從網卡流入後須要對它作路由決策,根據其目標決定是流入本機數據仍是轉發給其餘主機,若是是流入本機的數據,則數據會從內核空間進入用戶空間(被應用程序接收、處理)。當用戶空間響應(應用程序生成新的數據包)時,響應數據包是本機產生的新數據,在響應包流出以前,須要作路由決策,根據目標決定從哪一個網卡流出。若是不是流入本機的,而是要轉發給其餘主機的,則必然涉及到另外一個流出網卡,此時數據包必須從流入網卡完整地轉發給流出網卡,這要求Linux主機可以完成這樣的轉發。但Linux主機默認未開啓ip_forward功能,這使得數據包沒法轉發而被丟棄。Linux主機和路由器不一樣,路由器自己就是爲了轉發數據包,因此路由器內部默認就能在不一樣網卡間轉發數據包,而Linux主機默認則不能轉發。
下圖能夠很好地解釋上面的過程:
本文是爲了介紹防火牆的,充當防火牆的主機須要至少兩塊網卡,因此有必要解釋下數據流入和流出時,Linux主機是如何處理的。
首先要說明的是,IP地址是屬於內核的(不只如此,整個tcp/ip協議棧都屬於內核,包括端口號),只要能和其中一個地址通訊,就能和另外一個地址通訊(這麼說不嚴謹,準確地說是能路由這兩個地址),而無論是否開啓了數據包轉發功能。例如某Linux主機有兩網卡eth0:172.16.10.5和eth1:192.168.100.20,某192.168.100.22主機網關指向192.168.100.20,它能ping通192.168.100.20,但也同樣能ping通172.16.10.5,由於地址屬於內核,從eth1進來的數據包被內核分析時,發現目標地址爲本機地址,直接就產生新數據包迴應192.168.100.22,根據路由決策,該響應包應從eth1出去,因而192.168.100.22能收到回覆完成整個ping過程。
在此過程當中,沒有進行數據包轉發過程,由於流出的響應包是新產生的,而非原來流入的數據包。若是流入和流出的包是同樣的(或者稍做修改),則數據流入後不能進入用戶空間,而是直接經過內核轉發給另外一個網卡。數據包從網卡1交給網卡2,這個過程就是轉發,在Linux主機上由ip_forward進行控制。例如,網卡1所在網段主機ping網卡2所在主機時,數據包流入網卡1後就須要轉交給網卡2,而後從網卡2流出。
在後文中有實驗專門測試和說明上面的過程:配置網關以及轉發。
每次TCP會話的創建都須要通過三次握手,斷開時都須要四次揮手。
如圖。
(1).客戶端和服務端都處於CLOSED狀態。(發起TCP請求的稱爲客戶端,接受請求的稱爲服務端)
(2).服務端打開服務端口,處於listen狀態。
(3).客戶端發起鏈接請求。首先發送SYN(synchronous)報文給服務端,等待服務端給出ACK報文迴應。發送的SYN=1,ACK=0,表示只發送了SYN信號。此時客戶端處於SYN-SENT狀態(SYN信號已發送)。
(4).服務端收到SYN信號後,發出ACK報文迴應,並同時發出本身的SYN信號請求鏈接。此時服務端處於SYN-RECV狀態(syn recieved,在圖中顯示的是SYN-RCVD)。發送的SYN=1 ACK=1,表示發送了SYN+ACK。
(5).客戶端收到服務端的確認信號ACK後,再次發送ACK信號給服務端以回覆服務端發送的syn。此時客戶端進入ESTABLISHED狀態,發送的SYN=0,ACK=1表示只發送了ACK。
(6).服務端收到ACK信號後,也進入ESTABLISHED狀態。
此後進行數據的傳輸都經過此鏈接進行。其中第三、四、5步是三次握手的過程。這個過程通俗地說就是雙方請求並回應的過程:①A發送syn請求B並等待B迴應;②B迴應A,並同時請求A;③A迴應B。
斷開以前,雙方都處於ESTABLISHED狀態。假設是客戶端請求斷開鏈接。
(1).客戶端發送FIN(finally)報文信號,請求斷開。此後客戶端進入FIN-WAIT-1狀態。
(2).服務端收到FIN信號,給出確認信號ACK,表示贊成斷開。此時服務端進入CLOSE-WAIT狀態。此過程結束後表示從客戶端到服務端方向的TCP鏈接已經關閉了,也就是說整個TCP鏈接處於半關閉狀態。
(3).客戶端收到服務端的ACK後進入FIN-WAIT-2狀態,以等待服務端發出斷開信號FIN。在客戶端的FIN-WAIT-2狀態的等待過程當中,服務端再發出本身的FIN信號給客戶端。此時服務端進入LAST-ACK狀態。
(4).客戶端收到服務端的FIN信號,給出迴應信號ACK,表示接受服務端的斷開請求,此時客戶端進入TIME-WAIT狀態,此時客戶端已脫離整個TCP,只需再等待一段時間(2*MSL)就自動進入CLOSED狀態。
(5).服務端收到客戶端的迴應ACK信號,知道客戶端贊成了服務端到客戶端方向的TCP斷開,直接進入CLOSED狀態。
以上的一、二、三、4步是四次揮手階段。從中能夠看出,四次揮手和三次握手的過程實際上是相似的,都是雙方發出斷開請求並回應對方,只不過四次揮手的過程是將服務端發送的ACK和FIN分開發送了,而三次握手的過程當中服務端發送的ACK和SYN是放在一個數據包內發送的。
以上所述是客戶端請求的斷開,服務端也能夠請求斷開,這時過程是徹底一致的,只不過角色互換了。還需注意的是,若是是客戶端請求斷開,那麼服務端就是被動斷開端,可能會保留大量的CLOSE-WAIT狀態的鏈接,若是是服務端主動請求斷開,則可能會保留大量的TIME_WAIT狀態的鏈接。因爲每一個鏈接都須要佔用一個文件描述符,高併發狀況下可能會耗盡這些資源。所以,須要找出對應問題,作出對應的防治,通常來講,能夠修改內核配置文件/etc/sysctl.conf來解決一部分問題。
syn洪水攻擊是一種常見的DDos攻擊手段。攻擊者能夠經過工具在極短期內僞造大量隨機不存在的ip向服務器指定端口發送tcp鏈接請求,也就是發送了大量syn=1 ack=0的數據包,當服務器收到了該數據包後會回覆並一樣發送syn請求tcp鏈接,也就是發送ack=1 syn=1的數據包,此後服務器進入SYN-RECV狀態,正常狀況下,服務器期待收到客戶端的ACK回覆。但問題是服務器回覆的目標ip是不存在的,因此回覆的數據包總被丟棄,也一直沒法收到ACK回覆,因而不斷重發ack=1 syn=1的回覆包直至超時。
在服務器被syn flood攻擊時,因爲不斷收到大量僞造的syn=1 ack=0請求包,它們將長時間佔用資源隊列,使得正常的SYN請求沒法獲得正確處理,並且服務器一直處於重傳響應包的狀態,使得cpu資源也被消耗。總之,syn flood攻擊會大量消耗網絡帶寬和cpu以及內存資源,使得服務器運行緩慢,嚴重時可能會引發網絡堵塞甚至系統癱瘓。
所以,防範syn flood攻擊很是重要。固然,首先須要判斷出是否受到了syn flood攻擊。能夠經過抓包工具或者netstat等工具獲取處於SYN_RECV狀態的半鏈接,若是有大量處於SYN_RECV且源地址都是亂七八糟的,說明受到了syn洪水攻擊。
例如使用netstat工具判斷的方法以下:
[root@xuexi ~]# netstat -tnlpa | grep tcp | awk '{print $6}' | sort | uniq -c 1 ESTABLISHED 7 LISTEN 256 SYN_RECV
從設備上分類,防火牆分爲軟件防火牆、硬件防火牆、芯片級防火牆。後文所說的多是軟件防火牆、也多是硬件防火牆,在理解上它們沒什麼區別,只是將防火牆剝離成了獨自的服務器而已。
從技術上分類,防火牆分爲數據包過濾型防火牆、應用代理型防火牆。這是由於四層模型的每一層均可以應用防火牆。
基於鏈路層的防火牆是控制MAC的。例如,能夠將公司內網員工電腦的MAC地址所有記錄到防火牆上,從而限制他們上外網。再例如,能夠將公司電腦的MAC地址所有記錄到防火牆使他們可以上網,可是非本公司的電腦就沒法從本公司上網。
可是,基本上不會有公司這樣作,這樣的行爲太死板,並且記錄MAC地址自己就是一件很麻煩的事。
網絡層的核心是IP(也包括icmp等)。因此從網絡層來判斷,能夠基於源IP、目標IP來指定防火牆的規則。例如,來自38.68.100.61的主機不能穿過防火牆;訪問目標是192.168.109.19的服務器的請求不能讓其穿過防火牆;還能夠設置icmp協議做爲判斷依據,使得外網人員的ping包被擋住。
在網絡層能夠用來制定防火牆規則的內容有不少。以下表。最經常使用的也就是後三個而已。
能夠從TCP或者UDP來判斷。以TCP爲例,例如限制目標端口是22端口的請求,這樣SSH就沒法鏈接上服務器了。
下表是TCP數據包中能夠用來制定防火牆規則的字段。
到了這一層的處理就屬於應用代理型的防火牆了。他須要解開數據包並還原數據,也就是說它能夠獲取到數據包中的全部內容,但也所以負擔很重,所需CPU和內存較大。它的適用面較窄。
除了以上4種斷定方式,還有幾種特殊的判斷方式也較爲經常使用。
◇ 根據數據包內容判斷
例如,不容許內網的客戶端連上taobao.com上的任何主機,能夠在防火牆上檢查DNS的解析包中是否包含"taobao.com"這個字符串,若是有就丟棄,這樣就可讓DNS對任何taobao.com上的主機解析失敗達到限制上該網的目的。
注意:雖然說數據部分是應用層的,可是有些防火牆在網絡層就能夠進行檢查。Linux默認自帶的iptables/netfilters就是其中一種。
◇ 根據關聯狀態判斷
假如如今不容許任何internet上的主機進入到公司內部,可是容許企業內的計算機能夠上網。這樣的設定目的是爲了防止來自外網的攻擊。可是若是"禁止源地址爲外網的全部地址穿過防火牆、容許源地址爲公司內部的地址穿過防火牆"來設置防火牆,將致使一個問題:內網連上internet後請求某個網頁,要能正常上網,內網計算機必然要接收外網網頁的返回數據。但外網數據包沒法穿過防火牆,這樣並無實現內網主機上網的目的。
如今假設內網某機器上外網時的套接字爲192.168.100.8:9000,想要訪問10.0.0.5:80,也便是說數據流向是192.168.100.8:9000→10.0.0.5:80,那麼返回的數據包流向一定是10.0.0.5:80→192.168.100.8:9000。根據這種關聯性,防火牆能夠設定容許這樣的數據包經過。
這屬於鏈接跟蹤的行爲。FTP服務器對於防火牆的設置是一個考驗,若是沒有鏈接跟蹤的功能,數據通道的端口不固定性將致使防火牆設置極其困難。
如下是協議棧(TCP/IP協議棧)底層大體機制。數據包都要經過A流入,再根據路由決策決定數據包的流向(網絡層)。若是是流入本機,則通過B進入用戶空間層,對於每一個從本機流出的數據包,也都要通過路由決策來決定從哪一個網絡接口出去,而後路經D,從E出去。若是不是流入本機則流向C,而後順着E點出去。
上圖有一處容易理解錯誤,從用戶空間層出去的數據包是本機新產生的數據包,多是對流入數據包的響應數據,也多是本機應用向外發出的請求數據包。總之,數據包走不完A-->B點-->User Space-->D-->E這條路,在數據包進入用戶空間層時已經被處理了,從用戶空間層出來的數據已經不是原流入的數據,因此在上圖中我將用戶空間的兩個箭頭斷開了。
用英文來講明ABCDE這5個點就比較淺顯易懂:
A表示:altering packets as soon as they come in,
B表示:destined to local sockets,
C表示:be routed through the box,
D表示:locally-generated packets,and altering before routing(注:這個before routing是指路由出去以前,而不是路由決策以前),
E表示:altering packets as they are about to go out。
在上圖中的ABCDE這五個點,其實就是防火牆發揮做用的點。在Linux主機上,防火牆是由內核空間的netfilter實現的,其中做用在ABCDE這五個點的分別稱爲PREROUTING鏈、INPUT鏈、FORWARD鏈、OUTPUT鏈和POSTROUTING鏈。這幾個術語在後文會作很是詳細的說明。
防火牆起做用的是Netfilter,而iptables只是管理控制netfilter的工具,可使用該工具進行相關規則的制定以及其餘的動做。iptables是用戶層的程序,netfilter是內核空間的,在netfilter剛加入到Linux中時,netfilter是一個Linux的一個內核模塊,要實現其餘的防火牆行爲還須要加載其餘對應的模塊,到了後來netfilter一部分必須的模塊已經加入到內核中了。
也就是說,iptables命令工具操做的netfilter,真正起"防火"做用的是netfilter。
Linux是一個極其模塊化的內核。netfilter也是以模塊化的形式存在於Linux中,因此每添加一個和netfilter相關的模塊,表明着netfilter就多一個功能。
可是有些模塊是使用netfilter所必須的,因此這些模塊已經默認編譯到內核中而非須要時加載。
存放netfilter模塊的目錄有三個:/lib/modules/$kernel_ver/net/{netfilter,ipv4/netfilter,ipv6/netfilter}。$kernel_ver表明內核版本號。
其中ipv4/netfilter/存放的ipv4的netfilter,ipv6/netfilter/存放的ipv6的netfilter,/lib/modules/$kernel_net/kernel/netnetfilter/存放的是同時知足ipv4和ipv6的netfilter。在最後一個目錄中放入更多的模塊,是netfilter團隊發展的目標,由於要維護ipv4和ipv6兩個版本挺累的。
要使netfilter可以工做,就須要將全部的規則讀入內存中。netfilter本身維護一個內存塊,在此內存塊中有4個表:filter表、NAT表、mangle表和raw表。在每一個表中有相應的鏈,鏈中存放的是一條條的規則,規則就是過濾防火的語句或者其餘功能的語句。也就是說表是鏈的容器,鏈是規則的容器。實際上,每一個鏈都只是一個hook函數(鉤子函數)而已。
說到這裏,須要糾正一個概念,Linux上的防火牆是由netfilter實現的,可是netfilter的功能不只僅只有"防火",通常能夠認爲"防火"的功能只是filter表的功能。
關於這4個表,它們的結構以下:
注:從內核2.6.34開始,NAT表支持操做INPUT鏈。它只爲SNAT服務。和snat on postrouting相似,只不過snat on input用來轉換"目標是本機的數據包"的源地址。
◇ filter表:netfilter中最重要的表,負責過濾數據包,也就是防火牆實現"防火"的功能。filter表中只有OUTPUT/FORWARD/INPUT鏈。
◇ NAT表:實現網絡地址轉換的表。能夠轉換源地址、源端口、目標地址、目標端口。NAT表中的鏈是PREROUTING/POSTROUTING/OUTPUT。
◇ mangle表:一種特殊的表,經過mangle表能夠實現數據包的拆分和還原。mangle表中包含全部的鏈。
◇ raw表:加速數據包穿過防火牆的表,也就是加強防火牆性能的表。只有PREROUTING/OUTPUT表。
因爲這幾個表中有重複的鏈,因此數據被不一樣鏈中規則處理時是由順序的。下圖是完整的數據包處理流程。
每一個鏈對應的都是同名稱的數據包,如INPUT鏈針對的是INPUT數據包。
INPUT鏈的做用是爲了保護本機。例如,若是進入的數據包的目標是本機的80端口,且發來數據包的地址爲192.168.100.9時則丟棄,這樣的規則應該寫入本機的INPUT鏈。可是要注意,這個本機指的是防火牆所在的機器,若是是硬件防火牆,那麼必定會配合FORWARD鏈。
OUTPUT鏈的做用是爲了管制本機。例如,限制瀏覽www.taobao.com網頁。
INPUT和OUTPUT鏈很容易理解,FORWARD鏈起的是什麼做用呢?數據包從一端流入,可是不通過本機,那麼就要從另外一端流出。對於硬件防火牆這很容易理解,以下圖,數據總要轉發到另外一個網卡接口而後進入防火牆負責爲其"防火"的網段。也就是說,FORWARD鏈的做用是保護"後端"的機器。
前文說過,Linux主機自身也有ip_forward功能用於網卡間的數據包轉發,這個ip_forward和netfilter的forward鏈有什麼區別呢?這就是防火牆的意義,當數據包須要轉發時,僅使用ip_forward時將不問是非對錯老是進行轉發,而使用forward鏈時能夠篩選這些須要轉發的數據包,以決定是否要被轉發。顯然,ip_forward的功能是轉發數據包,而forward鏈是篩選容許轉發的數據包,而後讓ip_forward轉發。這也說明forward鏈要正常工做,要求開啓ip_forward功能。
這樣的佈置不只給了服務器對外的一層防火牆,也給了服務器對內的一層防火牆,能夠防外人也能夠防內賊。
圖中的DMZ稱爲"非軍事區",通常是放在兩個防火牆中間作內網和外網的緩衝。有些必須對外提供服務的服務器應該放在這種區域,而不能直接放在內網,由於將其放入內網又對外提供服務,當它被外界攻擊時就能夠藉助它(肉機)做爲跳板攻陷其它內網主機。
通常構建DMZ區有如下幾個要求:
只考慮filter表的時候,防火牆處理數據包的過程以下圖。
當數據包流入時,首先通過路由判決該數據包是流入防火牆本機仍是轉發到其餘機器的。對於流入本機的數據包通過INPUT鏈,INPUT鏈所在位置是一個鉤子函數,數據通過時將被鉤子函數檢查一番,檢查後若是發現是被明確拒絕或須要丟棄的則直接丟棄,明確經過的則放行,不符合匹配規則的一樣丟棄。可是鉤子函數畢竟是半路劫財的角色,因此無論怎麼樣都要告訴一聲netfilter,說這個數據包是怎樣怎樣的,即便是拒絕或丟棄了數據包也仍是會給出一個通知。
當用戶空間產生的數據包要發送出去時,首先通過OUTPUT鏈並被此處的鉤子函數檢查一番,檢查經過則放行,而後通過路由決策判決從哪一個接口出去,並最終從網卡流出。
例如,當外界主機請求WEB服務的時候,請求數據包流入到本機,路經INPUT鏈被放行。進入到本機用戶空間的進程後,本機進程根據請求給出響應報文,該響應報文的源地址是本機,目標地址是外界主機。當響應報文要出去時必須先流經OUTPUT,而後通過路由決定從哪一個接口出去,最終流出並路由到外界主機。
再例如ping本機地址(如127.0.0.1)的時候,ping請求從用戶空間發送後,數據包從用戶空間流出,因而流經到OUTPUT,通過路由決策發現是某網卡的地址,而後今後網卡流出。可是因爲ping的目標爲本機地址,因此數據包仍從流出的網卡流入,並被INPUT鏈檢查,最後返回ping的結果信息。
注意:是先通過OUTPUT,再通過路由決策。這樣一來,對那些檢查不經過的數據包會直接丟棄,而無需再消耗資源去作路由決策。
iptables用法比較複雜,有不少命令、選項和參數。因此,我先絕大多數命令、選項和模塊選項列出,而後再舉例說明iptables命令的用法。
Usage: iptables [-t TABLE] COMMAND CHAIN [ expressions -j target ]
這表示要操做TABLE表中的鏈,操做動做由COMMAND決定,例如添加一條規則、刪除一條規則、列出規則列表等。若是是向鏈中增長規則,則須要寫出規則表達式用來檢查數據包,並指明數據包被規則匹配上時應該作什麼操做,例如容許該數據包ACCEPT、拒絕該數據包REJECT、丟棄該數據包DROP,這些操做稱爲target,由"-j"選項來指定。
Commands: Either long or short options are allowed. --append -A chain 鏈尾部追加一條規則 --delete -D chain 從鏈中刪除能匹配到的規則 --delete -D chain rulenum 從鏈中刪除第幾條鏈,從1開始計算 --insert -I chain [rulenum] 向鏈中插入一條規則使其成爲第rulenum條規則,從1開始計算 --replace -R chain rulenum 替換鏈中的地rulenum條規則,從1開始計算 --list -L [chain [rulenum]] 列出某條鏈或全部鏈中的規則 --list-rules -S [chain [rulenum]] 打印出鏈中或全部鏈中的規則 --flush -F [chain] 刪除指定鏈或全部鏈中的全部規則 --zero -Z [chain [rulenum]] 置零指定鏈或全部鏈的規則計數器 --new -N chain 建立一條用戶自定義的鏈 --delete-chain -X [chain] 刪除用戶自定義的鏈 --policy -P chain target 設置指定鏈的默認策略(policy)爲指定的target --rename-chain -E old new 重命名鏈名稱,從old到new Options: [!] --proto -p proto 指定要檢查哪一個協議的數據包:能夠是協議代碼也能夠是協議名稱, 如tcp,udp,icmp等。協議名和代碼對應關係存放在/etc/protocols中 省略該選項時默認檢查全部協議的數據包,等價於all和協議代碼0 [!] --source -s address[/mask][...] 指定檢查數據包的源地址,或者使用"--src" [!] --destination -d address[/mask][...] 指定檢查數據包的目標地址,或者使用"--dst" [!] --in-interface -i input name[+] 指定數據包流入接口,若接口名後加"+",表示匹配該接口開頭的全部接口 [!] --out-interface -o output name[+] 指定數據包流出接口,若接口名後加"+",表示匹配該接口開頭的全部接口 --jump -j target 爲規則指定要作的target動做,例如數據包匹配上規則時將要如何處理 --goto -g chain 直接跳轉到自定義鏈上 --match -m match 指定擴展模塊 --numeric -n 輸出數值格式的ip地址和端口號。默認會嘗試反解爲主機名和端口號對應的服務名 --table -t table 指定要操做的table,默認table爲filter --verbose -v 輸出更詳細的信息 --line-numbers 當list規則時,同時輸出行號 --exact -x 默認統計流量時是以1000爲單位的,使用此選項則使用1024爲單位
iptables支持extension匹配。支持兩種擴展匹配:使用"-p"時的隱式擴展和使用"-m"時的顯式擴展。根據指定的擴展,隨後可以使用不一樣的選項。在指定擴展項的後面可以使用"-h"來獲取該擴展項的語法幫助。
"-p"選項指定的是隱式擴展,用於指定協議類型,每種協議類型都有一些子選項。常見協議和子選項以下說明:
-p tcp 子選項 子選項: [!] --source-port,--sport port[:port] 指定源端口號或源端口範圍。指定端口範圍時格式爲"range_start:range_end",最大範圍爲0:65535。 [!] --destination-port,--dport port[:port] 指定目標端口號或目標端口號範圍。 [!] --tcp-flags mask comp 匹配已指定的tcp flags。mask指定的是須要檢查的flag列表,comp指定的是必須設置的flag。 有效的flag值爲:SYN ACK FIN RST URG PSH ALL NONE。 若是以0和1來表示,意味着mask中comp指定的flag必須爲1其他的必須爲0。 例如:iptables -A FORWARD -p tcp --tcp-flags SYN,ACK,FIN,RST SYN 表示只匹配設置了SYN=1而ACK、FIN和RST都爲0數據包,也即只匹配TCP三次握手的第一次握手。 [!] --syn 是"--tcp-flags SYN,ACK,FIN,RST SYN"的簡寫格式。 -p udp 子選項 子選項: [!] --source-port,--sport port[:port] 指定源端口號或源端口範圍。指定端口範圍時格式爲"range_start:range_end",最大範圍爲0:65535。 [!] --destination-port,--dport port[:port] 指定目標端口號或目標端口號範圍。 -p icmp 子選項 子選項: [!] --icmp-type {type[/code]|typename} 用於指定ICMP類型,能夠是ICMP類型的數值代碼或類型名稱。有效的ICMP類型 可由iptables -p icmp -h獲取。經常使用的是"echo-request"和"echo-reply",分別 表示ping和pong,數值代號分別是8和0 ping時先請求後響應:ping別人先出去8後進來0;別人ping本身,先進來8後出去0
"-m"選項指定的是顯式擴展。其實隱式擴展也是要指定擴展名的,只不過默認已經知道所使用的擴展,因而能夠省略。例如:-p tcp --dport = -p tcp -m tcp --dport。
經常使用的擴展和它們經常使用的選項以下:
(1).iprange:匹配給定的IP地址範圍。
[!] --src-range from[-to]:匹配給定的源地址範圍
[!] --dst-range from[-to]:匹配給定的目標地址範圍
(2).multiport:離散的多端口匹配模塊,如將2一、2二、80三個端口的規則合併成一條。
最多支持寫15個端口,其中"555:999"算2個端口。只有指定了-p tcp或-p udp時該選項才生效。
[!] --source-ports,--sports port[,port|,port:port]...
[!] --destination-ports,--dports port[,port|,port:port]...
[!] --ports port[,port|,port:port]... :不區分源和目標,只要是端口就行
(3).state:狀態擴展。結合ip_conntrack追蹤會話的狀態。
[!] --state state
其中state有以下4種:
INVALID:非法鏈接(如syn=1 fin=1)
ESTABLISHED:數據包處於已創建的鏈接中,它和鏈接的兩端都相關聯
NEW:新建鏈接請求的數據包,且該數據包沒有和任何已有鏈接相關聯
RELATED:表示數據包正在新建鏈接, 但它和已有鏈接是相關聯的(如被動模式的ftp的命令鏈接和數據鏈接)
例如:-m state --state NEW,ESTABLISHED -j ACCEPT
關於這4個狀態,在下文還有更詳細的描述。
(4).string:匹配報文中的字符串。
--algo {kmp|bm}:兩種算法,隨便指定一種
--string "string_pattern"
如:
iptables -A OUTPUT -m string --algo bm --sting "taobao.com" -j DROP
(5).mac:匹配MAC地址,格式必須爲XX:XX:XX:XX:XX:XX。
[!] --mac-source address
(6).limit:使用令牌桶(token bucket)來限制過濾鏈接請求數。
--limit RATE[/second/minute/hour/day]:容許的平均數量。如每分鐘容許10次ping,即6秒一次ping。默認爲3/hour。
--limit-burst:容許第一次涌進的併發數量。第一次涌進超出後就按RATE指定數來給出響應。默認值爲5。
例如:容許每分鐘6次ping,但第一次能夠ping 10次。10次以後按照RATE計算。因此,前10個ping包每秒能正常返回,從第11個ping包開始,每10秒容許一次ping:iptables -A INPUT -d ServerIP -p icmp --icmp-type 8 -m limit --limit 6/minute --limit-burst 10 -j ACCEPT
(7).connlimit:限制每一個客戶端的鏈接上限。
--connlimit-above n:鏈接數量高於上限n個時就執行TARGET
如最多隻容許某ssh客戶端創建3個ssh鏈接,超出就拒絕。兩種寫法:
iptables -A INPUT -d ServerIP -p tcp --dport 22 -m connlimit --connlimit-above 3 -j DROP iptables -A INPUT -d ServerIP -p tcp --dport 22 -m connlimit ! --connlimit-above 3 -j ACCEPT
這個模塊雖然限制能力不錯,但要根據環境計算出網頁正常訪問時須要創建的鏈接數,另外還要考慮使用NAT轉換地址時鏈接數會翻倍的問題。
最後剩下"-j"指定的target還未說明,target表示對匹配到的數據包要作什麼處理,好比丟棄DROP、拒絕REJECT、接受ACCEPT等,除這3個target外,還支持不少種target。如下是其中幾種:
DNAT:目標地址轉換
SNAT:源地址轉換
REDIRECT:端口重定向
MASQUERADE:地址假裝(其實也是源地址轉換)
RETURN:用於自定義鏈,自定義鏈中匹配完畢後返回到自定義的前一個鏈中繼續向下匹配
ip_conntrack提供追蹤功能,後來改稱爲nf_conntrack,由nf_conntrack模塊提供。
只要一加載該模塊,/proc/net/nf_conntrack文件中就會記錄下追蹤的鏈接狀態。雖然會追蹤TCP/UDP/ICMP的全部鏈接,可是在此文件中只保存tcp的鏈接狀態。
[root@mail ~]# cat /proc/net/nf_conntrack ipv4 2 tcp 6 431714 ESTABLISHED src=192.168.100.1 dst=192.168.100.8 sport=1586 dport=22 src=192.168.100.8 dst=192.168.100.1 sport=22 dport=1586 [ASSURED] mark=0 secmark=0 use=2 ipv4 2 tcp 6 427822 ESTABLISHED src=192.168.100.8 dst=192.168.100.1 sport=22 dport=1343 src=192.168.100.1 dst=192.168.100.8 sport=1343 dport=22 [ASSURED] mark=0 secmark=0 use=2 ipv4 2 tcp 6 299 ESTABLISHED src=192.168.100.1 dst=192.168.100.8 sport=1608 dport=22 src=192.168.100.8 dst=192.168.100.1 sport=22 dport=1608 [ASSURED] mark=0 secmark=0 use=2
第一條顯示的是ESTABLISHED狀態的鏈接,該鏈接是192.168.100.1:1586-->192.168.100.8:22,以及返回的鏈接192.168.100.8:22 --> 192.168.100.1:1586。
也可使用iptstate命令實時顯示鏈接狀態,它是像top工具同樣的顯示。該命令工具在iptstate包中,可能須要手動安裝,。如圖爲iptstate的一次結果。
能夠發現TTL(超時時間)值以及狀態,還有其餘的一些信息。這些TTL值的設置位置都在/proc/sys/net/netfilter/目錄下的文件中。例如上圖中web服務TIME_WAIT的超時時間爲2分鐘,能夠將其修改,對應的文件爲下圖中標示的。能夠直接修改該文件的值,如180秒,即等待TIME_WAIT的時間3分鐘後就斷開鏈接。(TIME_WAIT處於TCP鏈接4次揮手主動段開方的倒數第二個階段)
nf_conntrack好處是大大的,可是很悲劇,每個監控和追蹤的工具都是消耗性能的,而nf_conntrack也有其瓶頸所在。nf_conntrack也會消耗必定的資源,因此在設計的時候默認給出了其最大的追蹤數量,最大追蹤數量值由/proc/sys/net/netfilter/nf_conntrack_max文件決定。默認是31384個。這個值顯然是沒法知足較高併發量的服務器的,因此能夠將其增大一些,不然追蹤數達到了最大值後,後續的全部鏈接都將排隊被阻塞,可能會所以給出警告。可是不管如何要明白的是追蹤是會消耗性能的,因此該值應該酌情考慮。
[root@mail ~]# cat /proc/sys/net/netfilter/nf_conntrack_max 31384
而且要注意的一點是,nf_conntrack模塊不是必定須要顯式裝載纔會被裝載的,有些依賴它的模塊被裝載時該模塊也會被裝載。例如iptables命令中包含iptables -t nat時,就會裝載該模塊自動開啓追蹤,進而可能致使達到追蹤max值而出錯。
使用-m state表示使用簡稱爲"state"的模塊。該模塊提供4種狀態:NEW、ESTABLISHED、RELATED和INVALID。可是這些狀態和TCP三次握手四次揮手的十幾種狀態沒任何關係。並且state提供的4種狀態對於tcp/udp/icmp類型的數據包都是通用的。
注意:這四種狀態是數據包的狀態,不是客戶端或者服務器當時所處的狀態。也能夠認爲是防火牆state模塊的狀態,由於state模塊在收到對應狀態的包時會設置爲相同的狀態。
(1).NEW狀態與TCP/UDP/ICMP數據包的關係
爲了創建一條鏈接,發送的第一個數據包(如tcp三次握手的第一次SYN數據包)的狀態爲NEW。若是第一次鏈接沒創建成功,則第二個繼續請求的數據包已經不是NEW數據包了。
因此,若是不容許NEW狀態的數據包表示不容許主動和對方創建鏈接,也不容許外界和本機創建鏈接。
(2).ESTABLISHED狀態與tcp/udp/icmp數據包的關係
不管是tcp數據包、udp數據包仍是icmp數據包,只要發送的請求數據包穿過了防火牆,那麼接下來雙方傳輸的數據包狀態都是ESTABLISHED,也就是說發過去的和返回回來的都是ESTABLISHED狀態數據包。
(3).RELATED數據包的解釋
對於RELATED數據包的解釋是:與當前任何鏈接都無關,徹底是被動或臨時創建的鏈接之間傳輸的數據包。
例如,下圖中tracert發送數據包的探測過程。
圖中客戶端爲了探測服務器的地址發送了tracert命令。這個命令首先會標記一個tcp數據包的TTL值爲1,當數據包到達第一個路由器該值就減1,因此TTL變爲0表示該數據包到了壽終正寢該DROP掉的時候,而後該路由器就會發送一個icmp數據包(icmp-type=11)返回給客戶端,這樣客戶端就知道了第一個路由器的地址。而後客戶端的tracert命令繼續標記一個TTL爲2的數據包向外發送,直到第二個路由器才被丟棄,第二個路由器又發送一個icmp包給客戶端,這樣客戶端就知道了第二個路由器的地址。同理第三次也同樣。
在tracert探測的過程當中,由路由器返回的icmp包都是RELATED狀態的數據包。由於能夠確定的說,客戶端發送給路由器的tcp數據包是走的一條鏈接,數據包被路由器丟棄後路由器發送的icmp數據包與原來的鏈接已經無關了,這是另一條返回的鏈接。可是之因此有這個數據包,徹底是由於前面的鏈接結束而產生的應答數據包。
不過RELATED狀態和協議無關,只要數據包是由於本機先送出一個數據包而致使另外一條鏈接的產生,那麼這個新鏈接的全部數據包都屬於RELATED狀態的數據包。
這樣就容易理解ftp被動模式設置的related狀態了。在ftp服務器上的21號端口上開啓了命令通道(也就是命令鏈接)後,之後不管是被動模式的隨機數據端口仍是主動模式的固定20數據端口,能夠確定的是數據通道的創建是由命令通道指定要開啓的,因此這個數據通道中傳輸的數據包都是RELATED狀態的。
(4).INVALID狀態的數據包
所謂的INVALID狀態,就是惡意的數據包。只要不是ESTABLISHED、NEW、RELATED狀態的數據包,那麼就必定是INVALID狀態。對於INVALID數據包最應該放在鏈中的第一條,以防止惡意的循環攻擊。
(5).網關式防火牆的NEW狀態、ESTABLISHED狀態和RELATED
網關式的防火牆擋在客戶端和服務器端中間,用於過濾或改變數據包,可是它的狀態卻很差判斷了。
關於它的狀態變化,能夠總結爲"牆頭草":客戶端送到防火牆的數據包是什麼狀態,防火牆的state模塊就設置爲何狀態,轉發給服務器的數據包就是什麼狀態;服務端發給防火牆的數據包是什麼狀態,防火牆的state模塊就設置爲何狀態,轉發出去的數據包就是什麼狀態。也就是說,防火牆並不改變數據包狀態的性質。
雖然說數據包的狀態只有防火牆纔有資格判斷,可是這樣概括卻不妨礙理解。
例如,TCP三次握手的第一次,客戶端發送一個SYN數據包給服務器要創建鏈接,這個SYN數據包傳到防火牆上,防火牆的state模塊也會將本身的狀態設置爲SYN_SENT,並認爲這個數據包是NEW狀態的數據包,而後轉發給服務器,轉發過程的數據包的狀態也是NEW。當服務器收到SYN後應答一個SYN+ACK數據包,當SYN+ACK數據包到達防火牆時,防火牆也和服務器同樣將本身設置爲SYN_RECV狀態,並認爲這個數據包已是ESTABLISHED的數據包了,而後將這個數據包以ESTABLISHED的狀態轉發給客戶端。
RELATED狀態也是同樣的,只要雙方的鏈接是"另起爐竈"的數據包,客戶端和服務端之間的防火牆會隨着數據包的流向而作一支"牆頭草"。
其實這些狀態以及轉變都會在/proc/net/nf_conntrack文件中記錄,只是比較難以被人爲追蹤到。
iptables實驗主機地址:172.16.10.9。首先啓動iptables。
service iptables start
(1).清空自定義鏈、清空規則、清空規則計數器。
[root@xuexi ~]# iptables -X [root@xuexi ~]# iptables -F [root@xuexi ~]# iptables -Z
(2).容許172.16.10.0網段鏈接ssh(端口22)。
[root@xuexi ~]# iptables -A INPUT -s 172.16.10.0/24 -d 172.16.10.9 -p tcp --dport 22 -j ACCEPT [root@xuexi ~]# iptables -A OUTPUT -s 172.16.10.9 -p tcp --sport 22 -j ACCEPT
(3).設置filter表默認規則爲DROP。
[root@xuexi ~]# iptables -P INPUT DROP [root@xuexi ~]# iptables -P FORWARD DROP
通常防火牆對外是ACCEPT的,因此OUTPUT鏈採用默認的ACCEPT。
因爲將INPUT鏈設置爲所有DROP,所以除了前面設置的目標爲22端口的數據包容許經過,其他所有丟棄,即便是ping環回地址。
[root@xuexi ~]# ping -c 4 127.0.0.1 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. --- 127.0.0.1 ping statistics --- 4 packets transmitted, 0 received, 100% packet loss, time 13000ms
(4).查看規則列表和統計數據。
[root@xuexi ~]# iptables -L -n Chain INPUT (policy DROP) target prot opt source destination ACCEPT tcp -- 172.16.10.0/24 172.16.10.9 tcp dpt:22 Chain FORWARD (policy DROP) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination ACCEPT tcp -- 172.16.10.9 0.0.0.0/0 tcp spt:22
若是加上"-v"選項,則會顯示每條規則上的流量統計數據。
[root@xuexi ~]# iptables -L -n -v Chain INPUT (policy DROP 10 packets, 993 bytes) pkts bytes target prot opt in out source destination 655 64963 ACCEPT tcp -- * * 172.16.10.0/24 172.16.10.9 tcp dpt:22 Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination Chain OUTPUT (policy ACCEPT 9 packets, 756 bytes) pkts bytes target prot opt in out source destination 242 42857 ACCEPT tcp -- * * 172.16.10.9 0.0.0.0/0 tcp spt:22
(3).放行環回設備的進出數據包(環回地址的放行很重要)。
[root@xuexi ~]# iptables -A INPUT -i lo -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT [root@xuexi ~]# iptables -A OUTPUT -o lo -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
此時已經可ping 127.0.0.1。
[root@xuexi ~]# ping 127.0.0.1 PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.067 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.051 ms ^C --- 127.0.0.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1648ms rtt min/avg/max/mdev = 0.051/0.059/0.067/0.008 ms
可是不建議直接寫127.0.0.1,而是省略目標地址和源地址,由於ping本機ip地址最後交給環回設備可是不是交給127.0.0.1的,而是交給127.0.0網段的其餘地址。因此應該這麼寫:
[root@xuexi ~]# iptables -A INPUT -i lo -j ACCEPT [root@xuexi ~]# iptables -A OUTPUT -o lo -j ACCEPT
因此能夠將前面多餘的規則刪除掉。
[root@xuexi ~]# iptables -D INPUT 2 [root@xuexi ~]# iptables -D OUTPUT 2
(4).能本身ping本身的IP,也能ping別人的IP,可是別人不能ping本身。
ping的過程其實是ping請求對方,而後對方pong迴應,協議類型爲icmp。其中ping請求時,icmp類型爲echo-request,數值代號爲8,pong迴應時的icmp類型爲echo-reply,數值代號爲0。
因此本機向外ping時,流出的是echo-request數據包,流入的是echo-reply數據包。而外界ping本機時,則是流入echo-request數據包,流出echo-reply數據包。所以,要容許本機向外ping,只需容許icmp-type=8的流出包、icmp-type=0的流入包便可,又因爲前面的試驗中設置了INPUT和OUTPUT鏈的默認規則爲DROP,因此外界主機沒法ping本機。
[root@xuexi ~]# iptables -A OUTPUT -p icmp --icmp-type=8 -j ACCEPT [root@xuexi ~]# iptables -A INPUT -p icmp --icmp-type=0 -j ACCEPT
固然,OUTPUT鏈自己就是放行全部數據包的,因此只需寫INPUT鏈規則便可。
(5).安裝httpd,讓外界可以訪問web頁面(端口爲80)。
[root@xuexi ~]# iptables -A INPUT -d 172.16.10.9 -p tcp --dport 80 -j ACCEPT [root@xuexi ~]# iptables -A OUTPUT -s 172.16.10.9 -p tcp --sport 80 -j ACCEPT
(6).刪除(或替換)放行ssh服務和web服務的規則,並寫出基於ip_conntrack放行ssh和web的規則(進入的數據包的狀態只可能會是NEW和ESTABLISHED,出去的狀態只多是ESTABLISHED)
放行ssh:
iptables -R INPUT 1 -s 172.16.10.0/24 -d 172.16.10.9 -p tcp --dport 22 -m state --state=NEW,ESTABLISHED -j ACCEPT iptables -R OUTPUT 1 -s 172.16.10.9 -p tcp --sport 22 -m state --state=ESTABLISHED -j ACCEPT
放行web:
iptables -R INPUT 4 -d 172.16.10.9 -p tcp --dport 80 -m state --state=NEW,ESTABLISHED -j ACCEPT iptables -R OUTPUT 4 -s 172.16.10.9 -p tcp --sport 80 -m state --state=ESTABLISHED -j ACCEPT
iptables -L -n --line-number Chain INPUT (policy DROP) num target prot opt source destination 1 ACCEPT tcp -- 172.16.10.0/24 172.16.10.9 tcp dpt:22 state NEW,ESTABLISHED 2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 0 4 ACCEPT tcp -- 0.0.0.0/0 172.16.10.9 tcp dpt:80 state NEW,ESTABLISHED Chain FORWARD (policy DROP) num target prot opt source destination Chain OUTPUT (policy ACCEPT) num target prot opt source destination 1 ACCEPT tcp -- 172.16.10.9 0.0.0.0/0 tcp spt:22 state ESTABLISHED 2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 8 4 ACCEPT tcp -- 172.16.10.9 0.0.0.0/0 tcp spt:80 state ESTABLISHED
這樣的設置使得外界能夠和主機創建會話,可是由主機出去的數據包則必定只能是ESTABLISHED狀態的服務發出的,這樣本機想主動和外界創建會話是不可能的。這樣就實現了狀態監測的功能,防止黑客經過開放的22端口或80端口植入木馬並主動聯繫黑客。
(7).放行外界ping本身,可是要基於ip_conntrack來放行。
iptables -A INPUT -d 172.16.10.9 -p icmp --icmp-type=8 -m state --state=NEW,ESTABLISHED -j ACCEPT iptables -A OUTPUT -s 172.16.10.9 -p icmp --icmp-type=0 -m state --state=ESTABLISHED -j ACCEPT
iptables -L -n --line-number Chain INPUT (policy DROP) num target prot opt source destination 1 ACCEPT tcp -- 172.16.10.0/24 172.16.10.9 tcp dpt:22 state NEW,ESTABLISHED 2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 0 4 ACCEPT tcp -- 0.0.0.0/0 172.16.10.9 tcp dpt:80 state NEW,ESTABLISHED 5 ACCEPT icmp -- 0.0.0.0/0 172.16.10.9 icmp type 8 state NEW,ESTABLISHED Chain FORWARD (policy DROP) num target prot opt source destination Chain OUTPUT (policy ACCEPT) num target prot opt source destination 1 ACCEPT tcp -- 172.16.10.9 0.0.0.0/0 tcp spt:22 state ESTABLISHED 2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 8 4 ACCEPT tcp -- 172.16.10.9 0.0.0.0/0 tcp spt:80 state ESTABLISHED 5 ACCEPT icmp -- 172.16.10.9 0.0.0.0/0 icmp type 0 state ESTABLISHED
(8).安裝vsftpd,並設置其防火牆。
因爲ftp有主動模式和被動模式,被動模式的數據端口不定,且使用哪一種模式是由客戶端決定的,這使得ftp的防火牆設置比較複雜,可是藉助netfilter的state模塊,設置就簡單的多了。
首先裝載其專門的模塊nf_conntrack_ftp。
[root@xuexi ~]# modprobe nf_conntrack_ftp
也能夠寫入/etc/sysconfig/iptables-config的"IPTABLES_MODULES="nf_conntrack_ftp"。
而後編寫規則:放行21端口的進入數據包,放行related關聯數據包,放行出去的包(放行出去的包是前面已默認的,但此處爲了試驗完整性,仍是顯式指定了)。
iptables -A INPUT -d 172.16.10.9 -p tcp --dport 21 -m state --state=NEW,ESTABLISHED -j ACCEPT iptables -A INPUT -d 172.16.10.9 -m state --state=RELATED,ESTABLISHED -j ACCEPT iptables -A OUTPUT -s 172.16.10.9 -m state --state=ESTABLISHED -j ACCEPT
上面一個規則中多個狀態列表,狀態列表中的狀態是「或」的關係,知足其一便可。
[root@xuexi ~]# iptables -L -n --line-number Chain INPUT (policy DROP) num target prot opt source destination 1 ACCEPT tcp -- 172.16.10.0/24 172.16.10.9 tcp dpt:22 state NEW,ESTABLISHED 2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 0 4 ACCEPT tcp -- 0.0.0.0/0 172.16.10.9 tcp dpt:80 state NEW,ESTABLISHED 5 ACCEPT icmp -- 0.0.0.0/0 172.16.10.9 icmp type 8 state NEW,ESTABLISHED 6 ACCEPT tcp -- 0.0.0.0/0 172.16.10.9 tcp dpt:21 state NEW,ESTABLISHED 7 ACCEPT all -- 0.0.0.0/0 172.16.10.9 state RELATED,ESTABLISHED Chain FORWARD (policy DROP) num target prot opt source destination Chain OUTPUT (policy ACCEPT) num target prot opt source destination 1 ACCEPT tcp -- 172.16.10.9 0.0.0.0/0 tcp spt:22 state ESTABLISHED 2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 8 4 ACCEPT tcp -- 172.16.10.9 0.0.0.0/0 tcp spt:80 state ESTABLISHED 5 ACCEPT icmp -- 172.16.10.9 0.0.0.0/0 icmp type 0 state ESTABLISHED 6 ACCEPT all -- 172.16.10.9 0.0.0.0/0 state ESTABLISHED
如今iptables已經有不少規則,可是也足夠亂的。不只想看懂挺複雜,在數據包檢查的時候性能也更差,因此有必要將它們合併成簡單易懂的規則。
執行iptables-save命令,能夠dump出當前內核維護的netfilter指定表中的規則,默認導出filter表。
[root@xuexi ~]# iptables-save -t filter # Generated by iptables-save v1.4.7 on Sun Aug 13 05:33:29 2017 *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -s 172.16.10.0/24 -d 172.16.10.9/32 -p tcp -m tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT -A INPUT -d 172.16.10.9/32 -p tcp -m tcp --dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -d 172.16.10.9/32 -p icmp -m icmp --icmp-type 8 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -d 172.16.10.9/32 -p tcp -m tcp --dport 21 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -d 172.16.10.9/32 -m state --state RELATED,ESTABLISHED -j ACCEPT -A OUTPUT -s 172.16.10.9/32 -p tcp -m tcp --sport 22 -m state --state ESTABLISHED -j ACCEPT -A OUTPUT -o lo -j ACCEPT -A OUTPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT -A OUTPUT -s 172.16.10.9/32 -p tcp -m tcp --sport 80 -m state --state ESTABLISHED -j ACCEPT -A OUTPUT -s 172.16.10.9/32 -p icmp -m icmp --icmp-type 0 -m state --state ESTABLISHED -j ACCEPT -A OUTPUT -s 172.16.10.9/32 -m state --state ESTABLISHED -j ACCEPT COMMIT # Completed on Sun Aug 13 05:36:22 2017
從導出結果中能夠看到,input鏈中有好幾條規則都是針對state=NEW,ESTABLISHED而創建的,同理OUTPUT鏈中的state=ESTABLISHED,且他們的target都是同樣的,這樣的規則能夠考慮是否可以合併。
注意:環回接口lo必定要顯式指定全部類型的數據都經過。
例如,先將OUTPUT鏈中state=ESTABLISHED的規則進行合併。
iptables -I OUTPUT 1 -s 172.16.10.9 -m state --state=ESTABLISHED -j ACCEPT
再將OUTPUT鏈中除了lo接口的全部規則刪除掉便可。
最終OUTPUT鏈剩下如下兩條規則。
-A OUTPUT -s 172.16.10.9/32 -m state --state ESTABLISHED -j ACCEPT -A OUTPUT -o lo -j ACCEPT
雖然這樣使得OUTPUT沒有再限制端口和協議,但對於流出數據包而言,這樣已經足夠了。通常來講,OUTPUT鏈的定義方式是:默認全部數據出去,但禁止某些端口(如80)發送NEW、INVALID狀態的包。因此,在OUTPUT鏈默認規則爲ACCEPT的狀況下,能夠參照以下方式定義該鏈的規則:
-A OUTPUT -s 172.16.10.9/32 -p tcp -m multiport --sports 21,22,80 -m state --state NEW,INVALID -j DROP
如今規則以下:
[root@xuexi ~]# iptables -L -n --line-number Chain INPUT (policy DROP) num target prot opt source destination 1 ACCEPT tcp -- 172.16.10.0/24 172.16.10.9 tcp dpt:22 state NEW,ESTABLISHED 2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0 icmp type 0 4 ACCEPT tcp -- 0.0.0.0/0 172.16.10.9 tcp dpt:80 state NEW,ESTABLISHED 5 ACCEPT icmp -- 0.0.0.0/0 172.16.10.9 icmp type 8 state NEW,ESTABLISHED 6 ACCEPT tcp -- 0.0.0.0/0 172.16.10.9 tcp dpt:21 state NEW,ESTABLISHED 7 ACCEPT all -- 0.0.0.0/0 172.16.10.9 state RELATED,ESTABLISHED Chain FORWARD (policy DROP) num target prot opt source destination Chain OUTPUT (policy ACCEPT) num target prot opt source destination 1 DROP tcp -- 172.16.10.9 0.0.0.0/0 multiport sports 21,22,80 state INVALID,NEW
再來合併INPUT鏈的規則。INPUT鏈的合併應該遵循這樣一種規則:先定義好大規則,再逐漸向後添加更具體、針對性更強的小規則。
首先將INPUT鏈中第四、6兩條規則合併。
iptables -I INPUT 4 -d 172.16.10.9 -p tcp -m multiport --dport 21,80 -m state --state=NEW,ESTABLISHED -j ACCEPT
再合併INPUT鏈中對內和對外的ping規則。
iptables -I INPUT 3 -p icmp --icmp-type any -m state --state=NEW,ESTABLISHED -j ACCEPT
再刪除被合併的多餘規則。最終INPUT鏈中規則列表以下:
-A INPUT -s 172.16.10.0/24 -d 172.16.10.9/32 -p tcp -m tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p icmp -m icmp --icmp-type any -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -d 172.16.10.9/32 -p tcp -m multiport --dports 21,80 -m state --state NEW,ESTABLISHED -j ACCEPT -A INPUT -d 172.16.10.9/32 -m state --state RELATED,ESTABLISHED -j ACCEPT
以後再有其餘需求時,只需在此基礎上添加更細緻、具體的規則便可。如禁止外界ping本機,只需在第三條INPUT規則前DROP掉進來的icmp-type=8的包便可。
從上面的規則列表中,也許已經發現了順序不是很易讀。規則列表中規則的順序是相當重要的,不只影響易讀性,還影響檢查的順序從而影響性能,例如大併發量的數據包應該儘早匹配。如下是調整INPUT鏈中規則順序的幾個建議:
(1).請求量大的儘可能放前面。
(2).通用型的規則儘可能放前面。
(3).直接拒絕的考慮放前面,主要是防惡意的循環攻擊,對於個別拉黑但非攻擊意圖的其實無需放前面。
其實,iptables服務腳本配置文件/etc/sysconfig/iptables中初始的規則就是最佳的框架。
[root@xuexi ~]# cat /etc/sysconfig/iptables # Firewall configuration written by system-config-firewall # Manual customization of this file is not recommended. *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT
以後有任何特定的需求,均可以直接在這些初始規則基礎上進行追加。
使用iptables寫的規則都存放在內存中,內核會維護netfilter的每張表中的規則,因此重啓iptables"服務"會使內存中的規則列表所有被清空。
要想手動寫的規則長期有效,須要將規則保存到持久存儲文件中,例如iptables"服務"啓動時默認加載的腳本配置文件/etc/sysconfig/iptables。
有兩種方法保存規則。
方法一:直接保存到/etc/sysconfig/iptables中
service iptables save
存方法二:可自定義保存位置
iptables-save >/etc/sysconfig/iptables iptables-save >/etc/sycofnig/iptables.20170103
恢復規則的方法:
雖然將規則放入/etc/sysconfig/iptables文件中能夠每次加載netfilter都能應用相應的規則,可是極其不建議這麼作,不然未來頗有能夠能會欲哭無淚。假如防火牆規則數據庫中關於192.168.100.8的規則有100條,可是該主機改了IP地址,難道要去修改全部192.168.100.8的規則嗎。
管理規則更好的方法是寫成腳本。將這些規則所有寫入到一個shell腳本中,並對屢次重複的地址使用變量,例如服務器的地址或網段,內網的網段。以下圖所示:
使用腳本的優勢有:
1.管理的便捷。寫成腳本能夠直接修改該文件,要從新生效時只需執行一次該腳本文件便可。可是要注意腳本的第一條命令最好是iptables -F,這樣每次運行腳本都會先清空已有規則再加載腳本中的其餘規則。
2.能夠在腳本中使用變量。這樣之後某臺服務器地址改變了只需修改該服務器地址對應的變量值便可。
3.容易閱讀,由於能夠加註釋,並經過註釋來對規則進行分類,將來修改就變得相對容易的多。
4.備份規則變得更容易。備份後,即便硬盤壞了致使現有的規則丟失了也能夠簡單的拷貝一個腳本過去運行便可,而不用再一條一條命令的敲。
5.也能夠實現開機加載規則。只需在/etc/rc.d/rc.local中加上一條執行該腳本的命令便可。
6.能夠將其加入任務計劃。
自定義鏈是被主鏈引用的。引用位置由"-j"指定自定義鏈名稱,表示跳轉到自定義鏈並匹配其內規則列表。
例如,在INPUT鏈中的第三條規則爲自定義鏈的引用規則,則數據包匹配到了第三條時進入自定義鏈匹配,匹配完自定義鏈後若是定義了返回主鏈的RETURN動做,則返回主鏈繼續向下匹配,若是沒有定義RETURN動做,則匹配結束。
建立一條自定義鏈。
iptables -N mychain
向其中加入一些基於安全的攻防規則,讓每次數據包進入都匹配一次攻防鏈。
iptables -A mychain -d 255.255.255.255 -p icmp -j DROP iptables -A mychain -d 192.168.255.255 -p icmp -j DROP iptables -A mychain -p tcp ! --syn -m state --state NEW -j DROP iptables -A mychain -p tcp --tcp-flags ALL ALL -j DROP iptables -A mychain -p tcp --tcp-flags ALL NONE -j DROP
在自定義鏈中的最後一條加上一條返回主鏈的規則,表示匹配完自定義後繼續回到主鏈進行匹配。
iptables -A mychain -d 192.168.100.8 -j RETURN
在主鏈的適當位置加上一條引用主鏈的規則。表示數據包匹配到了這個位置開始進入自定義鏈匹配,若是自定義鏈都沒被匹配而是被最後的RETURN規則匹配,則回到主鏈再次匹配。
iptables -I INPUT -d 192.168.100.8 -j mychain
刪除自定義鏈:須要先清空自定義鏈,去除被引用記錄,而後使用-X刪除空的自定義鏈。
iptables -F mychain iptables -D INPUT 1 iptables -X mychain
可使用-E命令重命名自定義鏈。
首先是一個網關配置實驗。
以CentOS_1做爲兩邊內網的網關,讓內網1和內網2能夠互相通訊。試驗過程當中,先關閉CentOS_1的防火牆。
首先配置Windows Server 2003和CentOS_2的網關指向CentOS_1。
目前CentOS_1尚未打開轉發功能。測試CentOS_2和Windows Server 2003都能ping通CentOS_1的兩個地址,但CentOS_2和Windows Server 2003二者沒法互相ping通。
爲何到兩個內網到CentOS_1的兩個地址都通,可是到對方內網卻不通呢?
對於CentOS_1主機而言,網絡是內核空間中的內容,兩個IP地址都屬於主機而非屬於網卡,內核知道eth0和eth1的存在。因爲默認在路由表中有對應內網1和內網2的路由條目,這兩個路由條目用於維持和本身所在網段的地址通訊(Iface列指定了從eth1和eth0流出去)。
當CentOS_2發起ping CentOS_1:eth1的請求時,ping請求包從eth0接口進入CentOS_1,進入後被路由決策一次,內核發現這個數據包的目標地址是eth1,能夠直接應答給CentOS_2,因而產生pong響應包並被路由一次,決定從eth0出去,最終回覆給了CentOS_2。同理從eth1進來目標地址是eth0的數據包也是同樣處理的。這裏面並無涉及到數據包轉發的過程。
但內網1主機在ping內網2主機時,在CentOS_1上卻須要數據包的轉發。由於數據包到達eth0上時數據包的目標地址是win server 2003的地址172.16.10.30,路由決策時發現是和eth1同網段的主機,但卻不是本機,因而決定從eth1流出去。要完成這個過程,須要將數據包完完整整地從eth0交給eth1,這要求CentOS_1主機可以完成轉發,但沒有開啓ip_forward功能時是沒法轉發的,所以從eth0流入的數據包被丟棄,致使內網1主機ping不通內網2主機。
在CentOS_1上開啓轉發功能。
echo 1 > /proc/sys/net/ipv4/ip_forward
再使用CentOS_2來ping Windows Server 2003,結果必定是通的,若是沒有通,考慮CentOS_1是否開啓了防火牆。
打開轉發後就能夠對filter表的FORWARD鏈進行設置了:只要是被forward的數據包都會受到防火牆的"鉤子伺候",並進行一番檢查。
要注意的是,此時防火牆是負責兩個網段的,轉發後的數據包狀態並不會由於通過FORWARD而改變。例如內網1發出的NEW狀態的數據包到內網2時途經FORWARD時,若是容許經過則轉發出去的數據包仍是NEW狀態的,這樣也就保證了內網2接受到的數據包仍是NEW狀態的,若是內網2也配置一個單機防火牆就能夠判斷這是NEW狀態的數據包從而進行相關的規則過濾。
例如:
iptables -P FORWARD DROP
此時已經內網1和內網2相互ping不通了。加上下面的規則,內網1的CentOS_2就能ping通外面,且外面進來的數據包都只能是ESTABLISHED狀態的。
iptables -A FORWARD -m state --state NEW,ESTABLISHED -j ACCEPT
再加上這兩條,就能保證內網2只能向內網1主機的22和80端口發起NEW和ESTABLISHED狀態的數據包,且內網1只能向外發送ESTABLISHED狀態的數據包。
iptables -A FORWARD -d 172.16.10.15 -p tcp -m multiport --dports 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT iptables -A FORWARD -s 172.16.10.15 -m state --state ESTABLISHED -j ACCEPT
NAT依賴於ip_forward,所以須要先開啓它。NAT的基礎是nf_conntrack,用來記錄NAT表的映射關係。
注:從內核2.6.34開始,NAT表支持操做INPUT鏈。它只爲SNAT服務。和snat on postrouting相似,只不過snat on input用來轉換"目標是本機的數據包"的源地址。
NAT有三個做用:
◇ 地址轉換。讓內網(私有地址)能夠共用一個或幾個公網地址鏈接Internet。這是從內向外的,須要在網關式防火牆的POSTROUTING處修改源地址,這是SNAT功能。
◇ 保護內網服務器。內網主機鏈接Internet使用的是公網地址,對外界而言是看不到內網服務器地址的,因此外界想要訪問內部主機只能通過防火牆主機的公網地址,而後將目標地址轉換爲內網服務器地址,這起到了保護內網服務器的做用。轉換目標地址須要在網關式防火牆的PREROUTING鏈處修改,這是DNAT功能。
◇ 不只能夠修改目標地址,還可使用端口映射功能。DNAT是修改目標地址,端口映射是修改目標端口。如將web服務器的8080端口映射爲防火牆的80端口。
外網主機和內網主機通訊有兩種狀況的數據包:一種狀況是創建NEW狀態的新請求鏈接數據包,一種是迴應的數據包。不管哪一種狀況,在NEW狀態數據包通過地址轉換以後會在防火牆內存中維護一張NAT表,保存未完成鏈接的地址轉換記錄,這樣在迴應數據包到達防火牆時能夠根據這些記錄路由給正確的主機。
也就是說,SNAT主要應付的是內部主機鏈接到Internet的源地址轉換,轉換的位置是POSTROUTING鏈;DNAT主要應付的是外部主機鏈接內部服務器防止內部服務器被攻擊的目標地址轉換,轉換位置在PREROUTING;端口映射能夠在多個地方轉換。
(1).SNAT轉換源地址
SNAT過程的數據包轉換過程以下圖所示。
注意SNAT設置在postrouting鏈,流出接口eth1。因爲規則中有其餘的條件存在,使得能夠大多數時候不用指定流出接口,固然若是指定的話更完整。
iptables -t NAT -A POSTROUTING -s 172.16.10.0/24 -o eth1 -j SNAT --to-source 192.168.100.20 iptables -t NAT -A POSTROUTING -s 172.16.10.0/24 -o eth1 -j SNAT --to-source 192.168.100.20-192.168.100.25 iptables -t NAT -A POSTROUTING -s 172.16.10.0/24 -o eth1 -j MASQUERADE
第一條語句表示將內網1向外發出的數據包進行處理,將源地址轉換爲192.168.100.20。
第二條語句表示將源地址轉換成192.168.100.{20-25}之間的某個地址。
第三條語句表示動態獲取流出接口eth1的地址,並將源地址轉換爲此地址。這稱爲地址假裝(ip masquerade),地址假裝功能很實用,可是相比前兩種,性能要稍差一些,由於處理每一個數據包時都要獲取eth1的地址,也就是說多了一個查找動做。
(2).DNAT目標地址和端口轉換
DNAT過程的數據包轉換過程以下圖所示。
注意DNAT設置在prerouting鏈,流入接口eth1。
iptables -t NAT -A PREROUTING -i eth1 -d 192.168.100.20 -p tcp --dport 80 -j DNAT --to-destination 172.16.10.15:8080
上面的語句表示從外網流入的目標爲192.168.100.20:80的數據包轉換爲目標172.16.10.15:8080,因而該數據包被路由給內網1主機172.16.10.15的8080端口上。
wiki netfilter:https://en.wikipedia.org/wiki/Netfilter
很好很詳細很全面的iptables學習手冊:https://www.frozentux.net/iptables-tutorial/chunkyhtml/index.html
lvs中的netfilter實現:http://zh.linuxvirtualserver.org/node/98