iptables的文章多如牛毛,但是,我讀了一些,發現雖然成體系,但是不便理解,今天就結合自己的理解,好好講解下,另外,我們也會使用iptables來實驗一個nat地址轉換的demo,nat轉換,通俗地講,一般是為了解決ipv4公網地址不夠用的問題,因此在學校、公司等機構的有公網ip的伺服器上,部署nat軟體進行地址轉換,如內網機器存取網際網路時,將源地址轉換為伺服器的公網ip;在收到響應時,此時目的地址是公網ip,此時需要修改為內網機器的地址。
這個東西,教科書裡學了很多年了,沒想到還能走進現實,也是有點意思。
iptables執行在使用者態,netfilter執行在linux核心中。iptables相當於一套介面,可以將防火牆規則寫入核心中的一片記憶體區域,而netfilter會去讀取這片記憶體區域中的規則,根據規則進行對應的網路包處理,如丟棄、放行等。
正因為如此,我們需要手動安裝iptables,如yum install -y iptables-services
,但是,netfilter是linux核心本身自帶的,無需安裝。
簡單來說,netfilter才是核心,你要覺得iptables不好用,可以換其他的命令列、圖形介面工具,甚至自己寫也可以。當然,netfilter和iptables都是同一個團隊弄的,因為它不可能讓大家直接寫程式碼去操作netfilter,肯定還是得搞個好用的命令列工具給大家用吧,所以有了iptables。
而且,現在團隊覺得iptables還是不夠好,目前新搞了個nftables來取代iptables。
專案官網:https://www.netfilter.org/index.html
大概有這麼幾種網路包:
如果讓你來設計,你應該也會引入幾個時間點,在這個時間點,主動去查詢使用者定義的規則,看看規則中是要丟棄還是放行封包。
時間點的考慮,也很重要。
比如,針對網路卡收到的封包的處理,第一個時間點,應該是在檢查路由表之前(即檢查目的地址是否是本機之前),此時,給使用者提供一個介入的時機,使用者甚至可以修改這個封包,比如,本來是發給當前機器的,我可以將目的地址改為其他機器,這就是DNAT(nat分為修改源地址和目的地址,這裡說的這種,就是修改目的地址)適用的場景;
第二個時間點,應該是在路由決定做出之後,在交給程序處理之前;
第三個時間點,應該是程序處理完成後,假如需要回應,即程序將封包交給我們後,此時也可以進行處理
另外,針對那種路由轉發的資料,在轉發出去之前,應該也可以進行一些處理。
這些時間點呢,一般就是擴充套件點,就像spring裡面一樣,bean的建立過程中有很多時間點會回撥使用者的函數,使用者就可以註冊自己的回撥函數,進行一些特殊的邏輯處理。
Netfifilter一共在核心的網路協定棧中,插入了5個擴充套件點(官網叫hook)。我參考瞭如下文章:
https://www.usenix.org/system/files/login/articles/892-neira.pdf
PREROUTING:
All the packets, with no exceptions, hit this hook, which is reached before the routing decision。
Port Address Translation (NAPT) and Redirections, that is, Destination Network Translation (DNAT), are implemented in this hook.
這個時間點,就是所有的網路包在做出路由決定前,就會呼叫本hook。一般來說,埠轉換和重定向、DNAT(目標地址轉換)就是在這裡實現
LOCAL INPUT:
All the packets going to the local machine reach this hook. This is the last hook in the incoming path for the local machine traffific.
在檢查目的地址後,發現包是發給本機的,那麼這些包在交給程序之前,就會呼叫本hook。
FORWARD:
Packets not going to the local machine (e.g., packets going through the fifirewall) reach this hook.
所有不是發往本機的包,即本機充當路由轉發功能時(linux主機實現為路由器或防火牆等),會呼叫本hook
LOCAL OUTPUT
This is the fifirst hook in the outgoing packet path. Packets leaving the local machine always hit this hook.
本機對外部請求的回覆包或者對外發起的請求包,就會觸發這個hook
POSTROUTING
This hook is implemented after the routing decision. Source Network Address Translation (SNAT) is registered to this hook. All the packets that leave the local machine reach this hook.
在做出路由決定後,呼叫本hook。源地址轉換,基本就在這個hook階段完成。所有要離開本機的封包,就會觸發本hook。
具體可以看下圖:
按照這篇文章的提法,主要有下面幾種網路包流向:
Therefore we can model three kind of traffific flflows, depending on the
destination:
■ Traffific going through the fifirewall, in other words, traffific not going to
the local machine. Such traffific follows the path: PREROUTING 、
FORWARD、 POSTROUTING.
僅僅穿越本機的流量包,即,目的地址不是本機,這樣的網路包,會依次經歷:
PREROUTING 、FORWARD、POSTROUTING
■ Incoming traffific to the fifirewall, for example, traffific for the local
machine. Such traffific follows the path: PREROUTING INPUT.
發給本機的流量包,路徑為:
PREROUTING 、LOCAL INPUT
■ Outgoing traffific from the fifirewall: OUTPUT POSTROUTING.
本機生成的,要出去的流量包(別管是回覆別人的那種還是自己發起的,對機器來說都一樣,都是要出去的),經歷:
OUTPUT 、POSTROUTING
幾個時間點說清楚了,那麼,這些時間點,回撥我們的時候,是查詢我們設定的防火牆規則對吧,那麼,規則大概長啥樣呢?
iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
比如,上面這就是一個規則,其中,-p tcp --dport 8080
就是指定要篩選出哪些封包來處理,如目標埠8080的,那麼,怎麼處理呢,這個-j ACCEPT
就表示放行。
另外,我們也不可能就一個規則吧,這個規則處理8080的,那我還有其他處理8081埠的規則,所以,最終是一堆規則,一個規則列表。
此時,我們就可以往每個hook點,註冊上一個規則集合,即一個規則鏈,按鏈中順序,依次處理。
那麼,iptables是這樣搞的嗎,我們來看看。
此時,可以看下圖:
在每個hook點,如左下角的PREROUTING,按理說只需要有一個規則集合就夠了,為啥有三個黃色方塊(它們唯一指向了一堆PREROUTING階段的規則集合),也就是說,怎麼有三個規則集合呢?
其實,就是因為不同規則大相徑庭:
Type of Service
欄位然後,官方就大體根據這些規則,進行了分類,把一個大集合,分成了好幾個集合,比如nat集合負責nat相關規則、mangle集合負責改報文欄位的規則,如Type of Service
、raw集合呢,目前我接觸到的有trace、log等規則、像filter呢,就負責對報文檢查後進行篩選過濾。
另外呢,像一個報文的生命週期,可能會依次經過:
PREROUTING 、LOCAL INPUT
那麼,在這兩個階段,我們都可以執行規則,比如,filter集合裡的規則,在這兩個hook點都可以執行,所以,filter表中,包含了多個hook點的規則集合;像nat集合裡的規則呢,一般就在PREROUTING 、POSTROUTING這兩個階段發揮作用,所以呢,nat表,包含了PREROUTING 、POSTROUTING兩個hook點的規則集合,兩者互不影響,井水不犯河水。
我個人喜歡上面那張圖,下面這張也可以參考:
網上還有一張圖,我覺得也很棒(https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg):
下圖是隻針對轉發這種場景,也不錯,圖都是來源網路,侵刪:
比如,上圖中,我想操作左下角的prerouting階段的raw表:
// -t 指定表名,如raw,-I 表示插入,chain表示在哪個鏈插入,如PREROUTING,rulenum呢,是在PREROUTING鏈中插入到第幾個,後面的rule-spe就是規則定義:篩選包+對包的操作
iptables [-t table] -I chain [rulenum] rule-specification
比如,我想trace一下發往8080埠的包:
iptables -t raw -I PREROUTING -p tcp -m tcp --dport 8080 -j TRACE
其他操作:
// -R,替換,即修改
iptables [-t table] -R chain rulenum rule-specification
// -D 刪除
iptables [-t table] -D chain rulenum
// -L 查詢,一般組合使用iptables -nvL,預設檢視filter表
iptables [-t table] -L, --list [chain]
其他命令參考man iptables
、man iptables-extensions
(包含了各種目標操作的講解)
看我上面的圖,server1沒有實際監聽8080埠,server2有監聽,假設我使用者端只能直接存取server1,那麼,我想做的是,在server1上靠iptables的dnat,修改目的ip為server2,達成我存取server2的8080服務的目的。
// 沒有持久化,臨時修改
echo 1 >/proc/sys/net/ipv4/ip_forward
// 檢視
[root@hx168-access ~]# sysctl -p
net.ipv4.ip_forward = 1
因為server1沒有監聽8080埠,那肯定不能自己處理,所以必須轉發給server2,所以需要開啟這個功能
iptables -t raw -I PREROUTING -p tcp -m tcp --dport 8080 -j TRACE
iptables -t raw -I PREROUTING -p tcp -m tcp --sport 8080 -j TRACE
目標埠為8080的,表示使用者端發出來的;源埠為8080的,表示server2回覆的。都加上trace
有問題就去看/var/log/messages紀錄檔
iptables -t nat -I PREROUTING 1 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 10.80.121.115
即,在網路包剛進來時,因為目標ip是server1,此時如果不進行目標ip修改,就會交給本機處理,所以,我們不能讓這事發生,得改成server2.
iptables -t filter -I FORWARD 1 -p tcp -m tcp --dport 8080 -j ACCEPT
iptables -t filter -I FORWARD 1 -p tcp -m tcp --sport 8080 -j ACCEPT
正向的和反向的,各加一個,免得一會還要再加
iptables -t nat -I PREROUTING 1 -p tcp -m tcp --dport 8080 -j SNAT --to-source 10.80.121.114
因為此時發往server2的報文裡,源ip還是使用者端的ip,如果就這麼發過去,server2就會返回報文給使用者端,而不是server1,所以得改源ip為server1.
可以看到,完全沒問題。
在執行上述命令測試時,我在server1上抓包了:
tcpdump -i any tcp port 8080 -w 114.pcap
然後分析114.pcap時,發現就是如下這樣,一個簡單的三次握手也不簡單:
我一開始有疑問,當server2給server1返回時,目標ip為server1,我們也沒有設定什麼NAT規則,把目標ip改成使用者端的ip,那麼,伺服器為啥不是把報文交給server1的程序處理,而是原路forward轉發呢
這個其實還是因為NAT依賴了netfilter的對談跟蹤功能,簡單來說,netfilter是有狀態的,以tcp舉例,tcp連線的建立是因為使用者端ip:使用者端埠和伺服器端ip:伺服器端埠,這個四元組是有來有回的,就是我給你發了訊息,你也回我了,此時,netfilter就認為這是一個對談。
所以,在server2給server1返回時,server1拿著server2和server1之間的四元組去查,查到有對談,因此,就按照之前的路徑,原路回來。
另外,nat這個table裡的鏈,只在檢測到之前不存在對談時,才會進,後續就不會再進了;也就是隻有首次報文的時候進nat的鏈
這個可以參考:
https://serverfault.com/questions/741104/iptables-redirect-works-only-for-first-packet/741108
像上面這個案例,只要執行如下命令,關閉對談跟蹤,就執行不成功了:
iptables -t raw -I PREROUTING -p tcp -m tcp -dport 8080 -j NOTRACK
[root@hx168-access ~]# cat /proc/net/nf_conntrack
ipv4 2 tcp 6 118 TIME_WAIT src=10.0.240.103 dst=10.80.121.114 sport=8922 dport=8080 src=10.80.121.115 dst=10.80.121.114 sport=8080 dport=8922 [ASSURED] mark=0 zone=0 use=2
yum install conntrack-tools
[root@hx168-access ~]# conntrack -L
tcp 6 118 TIME_WAIT src=10.0.240.103 dst=10.80.121.114 sport=9072 dport=8080 src=10.80.121.115 dst=10.80.121.114 sport=8080 dport=9072 [ASSURED] mark=0 use=1
https://www.jianshu.com/p/0fe6aeec8d79,圖不錯
https://www.linux.org/docs/man8/iptables-extensions.html
https://gist.github.com/tomasinouk/eec152019311b09905cd 關於nat
https://www.netfilter.org/documentation/
https://www.netfilter.org/documentation/HOWTO/netfilter-hacking-HOWTO-3.html#ss3.1
https://www.usenix.org/system/files/login/articles/892-neira.pdf