iptables的背後

每次修改iptables爲子設備做轉發上網都要瞎搜索很久,iptables太踏馬的複雜了,這次搜索完我一定要寫點東西記住哪條規則讓子設備上了網。

背景:

一臺獨設備A,只連接B設備;

一臺能上網設備B,有網卡與A連接;

B設備B1網卡與A設備連接;

B設備B2網卡上外網;

完畢。

目標:

A設備上外網;

完畢。

實施:

1. iptables的PREROUTING確保通常(一般默認ACCEPT)

2. FORWARD轉發規則打開:iptables -A FORWARD -m state --state NEW,ESTABLISHED,RELATED -j ACCEP

3. POSTROUTING對A設備地址的轉發打開,指定從出外網口NAT發出:iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o B2 -j MASQUERADE

碎碎念:

iptables的5個鏈PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING的用途在一個包的傳遞過程的意義,我大概還是知道些的;但是對於這幾個鏈具體屬於四個規則表NAT、FILTER、MANGL、RAW中的哪一個,就有待回憶了,在這兒記錄一下查過之後認爲自己還認識的規則:NAT就是映射,FILTER是過濾,MANGL和RAW不懂。其中,filter表還是主要針對需要本機處理的包,會使用FORWARD、INPUT、 OUTPUT三個鏈,控制INPUT、OUTPUT當然就可以控制本機主動生成的包,再控制FORWARD就能控制本機是否會爲目標非本機包做轉發。PREROUTING鏈位於包剛已進入本設備,進行過濾還言之過早,但是對於DNAT來說,卻是剛好。下面給出各個表會使用的鏈:

filter FORWARD、INPUT、 OUTPUT

 nat PREROUTING、POSTROUTING、OUTPUT

 mangle PREROUTING、POSTROUTING、OUTPUT、INPUT、FORWARD

 raw PREROUTING、OUTPUT

然後對於上面的5個鏈,再拿出來複習複習(先上個圖片意思意思):

五個鏈

1. PREROUTING鏈作用於包的目的還未清晰的階段,所謂目的還未清晰的意思就是,這個包的目的IP可能是本機,也可能是過路包。所以PREROUTING的規則都是再說:對於收到的包的目的IP是xxx.xxx.xxx.xxx:xxxx的包,我們應該發給IP yyy.yyy.yyy.yyy:yyyy的機器。就回長成這個樣子:iptables -t nat -A PREROUTING -d xxx.xxx.xxx.xxx -p tcp --dport xxxx -j DNAT --to-destination yyy.yyy.yyy.yyy:yyyy。這也算是NAT,不過是針對包目的IP的NAT,所以叫DNAT。如果iptables的FORWARD鏈被配置爲ACCEPT(iptables -P FORWARD ACCEPT),或是設置了一條PREROUTING針對本機的指令,可能這樣就算是生效了(當然,用的應該不是DNAT,應該是REDIRECT);但是!!!如果目標IP如果不是本機,也就是需要轉發的話,這並不能使符合此規則的包順利走出去,因爲轉發會繼續落到FORWOARD規則,如果默認FORWARD規則一般都會是DROP,這樣的話,經本機的過路包是不會被轉發的。PREROUTING鏈站在是內核開始處理IP包的最前端,大多數情況下,它的默認規則都是ACCEPT的,我試過用iptables -P PREROUTING ACCEPT(沒敢試DROP),執行結果提示出錯,這是合理的,PREROUTING鏈被DROP的話,整臺計算機對於網絡就會變成一個沒有意義的事務,所以只能是ACCEPT吧。PREROUTING鏈的規則都會是非常強力的,或者說是無腦的,最常用的場景就是做轉發將發給設備A的端口a1的包轉發到設備A的a2端口(向設備A轉發包的規則可能在FORWARD鏈中已做配置):

iptables -t nat -A PREROUTING -p tcp -d 機器A的IP -dport a1 -j DNAT -to 機器A的IP:a2

在比如說做負載均衡這個事兒,通過把state NEW的包進行轉發,使連接建立在不同的設備上,然後提供服務的也就會變成對應的設備:

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state -state NEW -m nth -counter 0 -every 3 -packet 0 -j DNAT -to-destination 192.168.1.101:443

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state -state NEW -m nth -counter 0 -every 3 -packet 1 -j DNAT -to-destination 192.168.1.102:443

iptables -A PREROUTING -i eth0 -p tcp –dport 443 -m state -state NEW -m nth -counter 0 -every 3 -packet 2 -j DNAT -to-destination 192.168.1.103:443

就會對eth0收的,目標是443端口的NEW包(差不多算是SYN包,下面有對NEW狀態解釋),均勻的分配給192.168.1.101、192.168.1.102、192.168.1.103三個設備。

假設我要在PREROUTING鏈設置這樣一條規則,要配置來自192.168.100.100的包都發送給網關地址192.168.99.1,按照iptables的規則尿性,似乎應該是長成這樣:

iptables -t nat -A PREROUTING -s 192.168.100.0/24 -j SNAT --to-source 192.168.99.1

似乎執行下去了,但是iptables用戶態會報invalid agrument,然後dmesg就會看到:ip_tables: SNAT target: used from hooks PREROUTING, but only usable from INPUT/POSTROUTING

啥意思膩,PREROUTING鏈不能用SNAT,只能在INPUT、POSTROUTING鏈使用;SNAT是基於源地址的NAT,然後--to-destination到某個地址,在PREROUTING鏈的位置,這會意味着什麼?

2. INPUT鏈是在PREROUTING之後,認爲是給本機的包所要適配的規則,比如iptables -A INPUT -i eth0 -p tcp -dport 80 -m state --state NEW,ESTABLISHED -j ACCEPT就表示:如果是給朕80端口的包包,可以笑納。上面這一句iptables規則是增給INPUT鏈的不假,但是這裏面的-m state --state NEW,ESTABLISHED就比較有內涵了,-m state表示後面要說要匹配的包的狀態,分爲NEW、ESTABLISHED、RELATED,這幾個狀態就是iptables的connection tracking,用在INPUT鏈,就是根據經過INPUT點的包是TCP中新連接建立、連接數據傳輸中、已建立連接在新端口又建了連接等情況,構建連接的表,然後根據規則決定幹掉哪些包,通過哪些包。對於NEW,應該是新連接建立的握手包通過,因爲我試過只允許NEW,沒有ESTABLISHED的話,curl不能拿到html的頁面內容,而如果加入了ESTABLISHED的話,就可以拿到;然後僅有ESTABLISHED的話,也是拿不到html頁面內容;RELATED就沒有測試到了,不過僅開RELATED是不能得到html網頁的。ESTABLISHED、NEW非常重要,而我總是忘掉,NEW是對TCP握手包如SYN的匹配,ESTABLISHED是對建立連接開始傳輸數據數據的包的匹配,也就是說NEW決定着是否允許某地址來的或去往某地址的主動握手包通過;而ESTABLISHED決定着是否允許完成連接建立並傳輸數據。INPUT的使用比較接地氣,打開/關閉端口(掌握着打開端口的能力,也就是掌握着本機提供http、mysql等等依賴於端口提供服務的能力,實權部門兒)、是否允許指定方向的新連接建立(-m state --state NEW)、是否響應ICMP、是否允許lo迴環等等一系列與本機提供服務息息相關的關鍵規則。INPUT鏈不適配NAT規則,這也可以理解,只有發給本機的包纔會到INPUT,已經是發給本機了,還做SNAT、DNAT那不是騙鬼呢麼。

比如說iptables -A INPUT -i eth0 -p tcp -dport 80 -m state -state NEW,ESTABLISHED -j ACCEPT就是用於打開從eth0來的從80端口建立新連接、保持連接的能力,當然還要確保響應包能從eth0再發回去,這就是通過OUTPUT鏈添加權限了iptables -A OUTPUT -o eth0 -p tcp -sport 80 -m state -state ESTABLISHED -j ACCEPT,顯然作爲提供服務的server,並不需要主動與client建立連接,所以OUTPUT鏈的state中沒有new。

3. FORWARD鏈也是PREROUTING之後,認爲不是給本機的包,決定是否需要轉發做匹配;這就是轉發控制、路由控制;比如說像這樣iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT,-m state的問題之前已經提過,添加了這條ACCEPT規則,即指定iptables的FORWARD鏈允許三種狀態的連接建立、通過;但這並不是表示對所有目標爲非本機IP進行轉發,默認規則DROP的情況下,還需要再指定哪個IP來的包(目標不是本機的包)允許轉發,就像是這樣:iptables -D FORWARD -s 192.168.100.100 -j ACCEPT;這其中的-s 192.168.100.100表示來自192.168.100.100的包會被轉發(目標不是本機的),而如果是-d 192.168.100.100則表示目標到192.168.100.100的包會被轉發。需要特別注意這樣一個事兒,如果要使能192.168.100.100來的包的轉發,不能寫成iptables -A FORWARD -s 192.168.100.100 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT,這表示僅會路由從192.168.100.100來的NEW,ESTABLISHED,RELATED的包,其他的包還是會被幹掉;那如果要爲192.168.100.100構建一個訪問網絡的通道,再添加一條iptables -A FORWARD -d 192.168.100.100 -m state --state ESTABLISHED,RELATED -j ACCEPT夠不夠呢,經測發現curl拿html並不成功,但是之前存在的下載鏈路也沒有被斷開,然後這兩句改成

iptables -A FORWARD -s 192.168.100.100 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

iptables -A FORWARD -d 192.168.100.100 -m state --state ESTABLISHED,RELATED -j ACCEPT

curl成功拿到了html數據,很明顯來自192.168.100.100需要發SYN包主動伸手到網絡IP建立TCP連接,而網絡IP卻不需要向192.168.100.100發SYN包構建連接。

4. POSTROUTING鏈負責將要離開本機的數據包的規則,匹配完POSTROUTING的規則,數據包在本設備的聲明週期也就完結了,可能發配其他設備、可能扔掉,就是說,所有本機離開的包必然是匹配POSTROUTING的,也就是說如果想要轉發某IP的來包或是去某IP的包,配置了FORWARD鏈的規則且PREROUTING鏈並沒有決定將這個包亂扔,這個包就可以到達POSTROUTING鏈,POSTROUTING鏈的規則決定是否將包真實的扔出去。POSTROUTING鏈的上游是FORWARD和OUTPUT鏈,就是說,不只是符合FORWARD鏈的包會到到POSTROUTING鏈,OUTPUT鏈的包也會送給POSTROUTING鏈,所以一般來說如果POSTROUTING鏈沒有被配置爲ACCEPT的話(黑名單禁止),OUTPUT鏈配置規則後,都需要在POSTROUTING鏈也添加規則,當然,發給本機迴環lo的不需要POSTROUTING鏈的放行,INPUT鏈和OUTPUT鏈放行即可。

比如說我最開始的目標,要讓A設備經由B設備上網,這時候B設備如果已經配置有針對A設備的轉發(3.FORWARD鏈中的兩句),還需要打開POSTROUTING鏈針對A設備來的數據包的規則,使其放行:

iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o B2 -j MASQUERADE

這條規則的-s 192.168.100.0/24與之前一樣,-s表示源地址,也就是網段192.168.100.0/24的來包都替換成自己的IP,然後-o到B2網卡進行外發,MASQUERADE表示本機的下一跳設備,下一跳IP的變化也不會使包扔錯;與MASQUERADE對應的還有--to-destination xxx.xxx.xxx.xxx:xxxx,這就表示不論下一跳怎麼變化,都要扔到xxx.xxx.xxx.xxx:xxxx。-o當然就是指定了從哪個網卡往外扔,這是無需多言的,另外還有-i表示從哪個網卡來的。着重要提出來的是-t nat這個東西,nat是我熟悉的,但並不深入,拆開理解一下:nat和filter等一樣,都是基於表的,什麼意思呢,就是說,他們是基於一個規則表來實現的,其實每一條iptables指令都是在配置這幾個表,而PREROUTING、FORWARD、POSTROUTING、INPUT、OUTPUT表示在表中插入某個鏈的規則,爲什麼有時候沒有指定nat或是filter呢,沒有指定其實是插入了默認表,也就是filter表。nat和filter這兩個表很重要,後面拆開說一下。

5. OUTPUT鏈是控制本機IP對外發送數據包時適配的規則,同INPUT鏈一樣是實權部門,不過與INPUT不同的點在於,OUTPUT同時適配NAT規則表的DNAT,也就是說,本機的輸出包,是可能根據規則替換目的地址的,大概也是代理方面的事情。

規則表

對於NAT,分爲SNAT、DNAT,直白一點說,實現包的源、目的地址替換,放在nat表中。在5個鏈中的PREROUTING、POSTROUTING、OUTPUT鏈指定規則,爲什麼是在這3個鏈呢。

NAT的源、目的地址的替換本質上是一種欺騙這種欺騙首先就產生於內外網(沒有內外網NAT也沒有什麼意義,注意內網並不就是子網,192.168.1.0/24是192.168.192.0/23一個子網)。

第1條應用便是將內網某端口的包包去掉子網的痕跡(替換掉源IP和端口),作爲自己的包從動態端口發出去,就是SNAT,然後網關記住自己的這個端口收到的回包要再返回給子網的這個端口(記住的這條信息,就算是一條連接的建立,網關的一個端口也就分配使用),網關的下一跳只知道網關在往外發數據,而不能察覺其後的子網,但是這裏面有一個問題就是:子網中的每一個設備都有65535個端口,而網關也有65535個端口;假設這樣一個事兒,內網有100臺設備,每臺設備都向通過65535個端口與外面建立,似乎情況不妙呀;這其實就是傳說中的SNAT網關端口耗盡,當然,如果不是機房,內網也很難湊夠100臺設備,也不太可能每臺設備同時與外部建立,但是SNAT端口耗盡這個事兒是真實存在的,所以網關會通過連接老化,也就是對建立起的連接,如果時間長了沒有新消息傳輸,這條連接就會被幹掉,幹掉之後端口也就得到了釋放。嗯,這也是爲什麼內網裏沒有心跳的TCP長連接爲啥總是連接不長。SNAT需要根據源地址、源端口記錄一條連接,並將數據包轉給下一跳,這很明顯應該發生在POSTROUTING鏈,即包離開網關的時候替掉其源IP、源端口,假設這個事兒發生在PREROUTING節點,替掉源地址之後,PREROUTING後續的鏈都不會知道這是從哪兒來的包,自己騙自己很明顯是沒有什麼意思的事情,所以PREROUTING不能設置SNAT。

NAT的第2條應用便將網關作爲代理,進行外來數據包的轉發分配,也就是DNAT,將來自外網來的數據包,偷樑換柱(替換掉目的IP和端口)發送給內網真實與外網溝通的設備,當然,還要記錄這條連接爲內網返回的包原路發還,DNAT可以掩蔽內網提供服務的設備,能對內網設備提供保護(內網設備僅有顯式映射的端口才能接受外網的訪問),同時也具有天然的負載均衡屬性,假設內網中的兩臺設備均可提供相同的網頁,在網關配置兩條代理,對於新建立連接,也就是-m state --state NEW,通過將新連接請求分別均勻的分發給兩臺設備,於是每臺設備就都可以提供網頁,也就做到負載均衡。

FILTER表明面上是包過濾,其實就是爲了控制路的通斷。從這5個鏈的組合後包的流通路徑來講,包的通路有大概3條:

包->PREROUTING->INPUT->本機接收

包->PREROUTING->FORWARD->POSTROUTING->另一臺設備

本機發出->OUTPUT->POSTROUTING->另一臺設備

每一條通路必經filter表,filter能通、斷每一條包的通路,這也是filter的地位。

其他的表我不會,所以就不說了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章