iptables簡要介紹及使用iptables實踐NAT技術

2023-07-24 12:01:51

簡介

iptables的文章多如牛毛,但是,我讀了一些,發現雖然成體系,但是不便理解,今天就結合自己的理解,好好講解下,另外,我們也會使用iptables來實驗一個nat地址轉換的demo,nat轉換,通俗地講,一般是為了解決ipv4公網地址不夠用的問題,因此在學校、公司等機構的有公網ip的伺服器上,部署nat軟體進行地址轉換,如內網機器存取網際網路時,將源地址轉換為伺服器的公網ip;在收到響應時,此時目的地址是公網ip,此時需要修改為內網機器的地址。

這個東西,教科書裡學了很多年了,沒想到還能走進現實,也是有點意思。

iptables和netfilter的關係

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

網路包的流向

大概有這麼幾種網路包:

  • 從網路卡進來,但是目的地址不是當前機器(如當前機器僅負責路由轉發、防火牆等),此時,不需要交給本機程序處理,直接按照路由錶轉發出去
  • 從網路卡進來,目的地址是當前機器,此時,會交給本機的程序處理(如tcp的話,會根據埠號找到對應程序)
  • 本機要向外傳送的資料庫包,不管是請求其他遠端服務(此時作為使用者端,會主動向外發包),或者是本機作為伺服器,對外部進來的請求包做出迴應。這兩種,都算是要出去的包

如果讓你來設計,你應該也會引入幾個時間點,在這個時間點,主動去查詢使用者定義的規則,看看規則中是要丟棄還是放行封包。

時間點的考慮,也很重要。

比如,針對網路卡收到的封包的處理,第一個時間點,應該是在檢查路由表之前(即檢查目的地址是否是本機之前),此時,給使用者提供一個介入的時機,使用者甚至可以修改這個封包,比如,本來是發給當前機器的,我可以將目的地址改為其他機器,這就是DNAT(nat分為修改源地址和目的地址,這裡說的這種,就是修改目的地址)適用的場景;

第二個時間點,應該是在路由決定做出之後,在交給程序處理之前;

第三個時間點,應該是程序處理完成後,假如需要回應,即程序將封包交給我們後,此時也可以進行處理

另外,針對那種路由轉發的資料,在轉發出去之前,應該也可以進行一些處理。

這些時間點呢,一般就是擴充套件點,就像spring裡面一樣,bean的建立過程中有很多時間點會回撥使用者的函數,使用者就可以註冊自己的回撥函數,進行一些特殊的邏輯處理。

netfilter中的擴充套件點

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是這樣搞的嗎,我們來看看。

iptables中的規則組織形式

此時,可以看下圖:

在每個hook點,如左下角的PREROUTING,按理說只需要有一個規則集合就夠了,為啥有三個黃色方塊(它們唯一指向了一堆PREROUTING階段的規則集合),也就是說,怎麼有三個規則集合呢?

其實,就是因為不同規則大相徑庭:

  • 有的規則最終是進行NAT轉換,只改改ip、埠這些;
  • 有的規則是進行大改,甚至修改報文,如ip報文中的Type of Service欄位
  • 有的規則呢,根本不去動報文,完全不改,比如我們可能就是想打個紀錄檔記錄下報文
  • 還有的規則,是檢查報文,檢查完成後,比如防火牆,發現指定埠是不開放的,那麼可以直接丟棄報文或者拒絕報文(分別造成使用者端讀超時、連線reset等異常)
  • 其實還有很多種目標動作

然後,官方就大體根據這些規則,進行了分類,把一個大集合,分成了好幾個集合,比如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):

下圖是隻針對轉發這種場景,也不錯,圖都是來源網路,侵刪:

如何使用iptables對規則集合進行增刪改查

比如,上圖中,我想操作左下角的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 iptablesman iptables-extensions(包含了各種目標操作的講解)

nat實驗

簡介

看我上面的圖,server1沒有實際監聽8080埠,server2有監聽,假設我使用者端只能直接存取server1,那麼,我想做的是,在server1上靠iptables的dnat,修改目的ip為server2,達成我存取server2的8080服務的目的。

server1開啟轉發能力

// 沒有持久化,臨時修改
echo 1 >/proc/sys/net/ipv4/ip_forward
// 檢視
[root@hx168-access ~]# sysctl -p
net.ipv4.ip_forward = 1

因為server1沒有監聽8080埠,那肯定不能自己處理,所以必須轉發給server2,所以需要開啟這個功能

增加trace規則,方便偵錯

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紀錄檔

在PREROUTING增加DNAT規則

iptables -t nat -I PREROUTING 1 -p tcp -m tcp   --dport 8080 -j DNAT --to-destination  10.80.121.115

即,在網路包剛進來時,因為目標ip是server1,此時如果不進行目標ip修改,就會交給本機處理,所以,我們不能讓這事發生,得改成server2.

在filter表的forward鏈,增加放行規則

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
正向的和反向的,各加一個,免得一會還要再加

在nat表的POSTROUTING鏈,增加SNAT規則

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