這篇文章將為大家詳細(xì)講解有關(guān)網(wǎng)絡(luò)地址轉(zhuǎn)換NAT之報文跟蹤的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
永靖網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),永靖網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為永靖超過千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營銷網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的永靖做網(wǎng)站的公司定做!
網(wǎng)絡(luò)地址轉(zhuǎn)換(NAT)是一種將容器或虛擬機暴露在互聯(lián)網(wǎng)中的一種方式。傳入的連接請求將其目標(biāo)地址改寫為另一個地址,隨后被路由到容器或虛擬機。相同的技術(shù)也可用于負(fù)載均衡,即傳入的連接被分散到不同的服務(wù)器上去。
當(dāng)網(wǎng)絡(luò)地址轉(zhuǎn)換沒有按預(yù)期工作時,連接請求將失敗,會暴露錯誤的服務(wù),連接最終出現(xiàn)在錯誤的容器中,或者請求超時,等等。調(diào)試此類問題的一種方法是檢查傳入請求是否與預(yù)期或已配置的轉(zhuǎn)換相匹配。
NAT 不僅僅是修改 IP 地址或端口號。例如,在將地址 X 映射到 Y 時,無需添加新規(guī)則來執(zhí)行反向轉(zhuǎn)換。一個被稱為 “conntrack” 的 netfilter 系統(tǒng)可以識別已有連接的回復(fù)報文。每個連接都在 conntrack 系統(tǒng)中有自己的 NAT 狀態(tài)。反向轉(zhuǎn)換是自動完成的。
nftables 工具(以及在較小的程度上,iptables)允許針對某個報文檢查其處理方式以及該報文匹配規(guī)則集合中的哪條規(guī)則。為了使用這項特殊的功能,可在合適的位置插入“跟蹤規(guī)則”。這些規(guī)則會選擇被跟蹤的報文。假設(shè)一個來自 IP 地址 C 的主機正在訪問一個 IP 地址是 S 以及端口是 P 的服務(wù)。我們想知道報文匹配了哪條 NAT 轉(zhuǎn)換規(guī)則,系統(tǒng)檢查了哪些規(guī)則,以及報文是否在哪里被丟棄了。
由于我們要處理的是傳入連接,所以我們將規(guī)則添加到 prerouting 鉤子上。prerouting 意味著內(nèi)核尚未決定將報文發(fā)往何處。修改目標(biāo)地址通常會使報文被系統(tǒng)轉(zhuǎn)發(fā),而不是由主機自身處理。
# nft 'add table inet trace_debug'# nft 'add chain inet trace_debug trace_pre { type filter hook prerouting priority -200000; }'# nft "insert rule inet trace_debug trace_pre ip saddr $C ip daddr $S tcp dport $P tcp flags syn limit rate 1/second meta nftrace set 1"
第一條規(guī)則添加了一張新的規(guī)則表,這使得將來刪除和調(diào)試規(guī)則可以更輕松。一句 nft delete table inet trace_debug
命令就可以刪除調(diào)試期間臨時加入表中的所有規(guī)則和鏈。
第二條規(guī)則在系統(tǒng)進行路由選擇之前(prerouting
鉤子)創(chuàng)建了一個基本鉤子,并將其優(yōu)先級設(shè)置為負(fù)數(shù),以保證它在連接跟蹤流程和 NAT 規(guī)則匹配之前被執(zhí)行。
然而,唯一最重要的部分是第三條規(guī)則的最后一段:meta nftrace set 1
。這條規(guī)則會使系統(tǒng)記錄所有匹配這條規(guī)則的報文所關(guān)聯(lián)的事件。為了盡可能高效地查看跟蹤信息(提高信噪比),考慮對跟蹤的事件增加一個速率限制,以保證其數(shù)量處于可管理的范圍。一個好的選擇是限制每秒鐘最多一個報文或一分鐘最多一個報文。上述案例記錄了所有來自終端 $C
且去往終端 $S
的端口 $P
的所有 SYN 報文和 SYN/ACK 報文。限制速率的配置語句可以防范事件過多導(dǎo)致的洪泛風(fēng)險。事實上,大多數(shù)情況下只記錄一個報文就足夠了。
對于 iptables 用戶來講,配置流程是類似的。等價的配置規(guī)則類似于:
# iptables -t raw -I PREROUTING -s $C -d $S -p tcp --tcp-flags SYN SYN --dport $P -m limit --limit 1/s -j TRACE
原生 nft 工具的用戶可以直接運行 nft
進入 nft 跟蹤模式:
# nft monitor trace
這條命令會將收到的報文以及所有匹配該報文的規(guī)則打印出來(用 CTRL-C
來停止輸出):
trace id f0f627 ip raw prerouting packet: iif "veth0" ether saddr ..
我們將在下一章詳細(xì)分析該結(jié)果。如果你用的是 iptables,首先通過 iptables –version
命令檢查一下已安裝的版本。例如:
# iptables --versioniptables v1.8.5 (legacy)
(legacy)
意味著被跟蹤的事件會被記錄到內(nèi)核的環(huán)形緩沖區(qū)中。你可以用 dmesg
或 journalctl
命令來查看這些事件。這些調(diào)試輸出缺少一些信息,但和新工具提供的輸出從概念上來講很類似。你將需要首先查看規(guī)則被記錄下來的行號,并與活躍的 iptables 規(guī)則集合手動關(guān)聯(lián)。如果輸出顯示 (nf_tables)
,你可以使用 xtables-monitor
工具:
# xtables-monitor --trace
如果上述命令僅顯示版本號,你仍然需要查看 dmesg
/journalctl
的輸出。xtables-monitor
工具和 nft
監(jiān)控跟蹤工具使用相同的內(nèi)核接口。它們之間唯一的不同點就是,xtables-monitor
工具會用 iptables
的語法打印事件,且如果你同時使用了 iptables-nft
和 nft
,它將不能打印那些使用了 maps/sets 或其他只有 nftables 才支持的功能的規(guī)則。
我們假設(shè)需要調(diào)試一個到虛擬機/容器的端口不通的問題。ssh -p 1222 10.1.2.3
命令應(yīng)該可以遠(yuǎn)程連接那臺服務(wù)器上的某個容器,但連接請求超時了。
你擁有運行那臺容器的主機的登錄權(quán)限?,F(xiàn)在登錄該機器并增加一條跟蹤規(guī)則??赏ㄟ^前述案例查看如何增加一個臨時的調(diào)試規(guī)則表。跟蹤規(guī)則類似于這樣:
nft "insert rule inet trace_debug trace_pre ip daddr 10.1.2.3 tcp dport 1222 tcp flags syn limit rate 6/minute meta nftrace set 1"
在添加完上述規(guī)則后,運行 nft monitor trace
,在跟蹤模式下啟動 nft,然后重試剛才失敗的 ssh
命令。如果規(guī)則集較大,會出現(xiàn)大量的輸出。不用擔(dān)心這些輸出,下一節(jié)我們會做逐行分析。
trace id 9c01f8 inet trace_debug trace_pre packet: iif "enp0" ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp tcp dport 1222 tcp flags == syntrace id 9c01f8 inet trace_debug trace_pre rule ip daddr 10.2.1.2 tcp dport 1222 tcp flags syn limit rate 6/minute meta nftrace set 1 (verdict continue)trace id 9c01f8 inet trace_debug trace_pre verdict continuetrace id 9c01f8 inet trace_debug trace_pre policy accepttrace id 9c01f8 inet nat prerouting packet: iif "enp0" ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp tcp dport 1222 tcp flags == syntrace id 9c01f8 inet nat prerouting rule ip daddr 10.1.2.3 tcp dport 1222 dnat ip to 192.168.70.10:22 (verdict accept)trace id 9c01f8 inet filter forward packet: iif "enp0" oif "veth31" ether saddr .. ip daddr 192.168.70.10 .. tcp dport 22 tcp flags == syn tcp window 29200trace id 9c01f8 inet filter forward rule ct status dnat jump allowed_dnats (verdict jump allowed_dnats)trace id 9c01f8 inet filter allowed_dnats rule drop (verdict drop)trace id 20a4ef inet trace_debug trace_pre packet: iif "enp0" ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp tcp dport 1222 tcp flags == syn
輸出結(jié)果的第一行是觸發(fā)后續(xù)輸出的報文編號。這一行的語法與 nft 規(guī)則語法相同,同時還包括了接收報文的首部字段信息。你也可以在這一行找到接收報文的接口名稱(此處為 enp0
)、報文的源和目的 MAC 地址、報文的源 IP 地址(可能很重要 - 報告問題的人可能選擇了一個錯誤的或非預(yù)期的主機),以及 TCP 的源和目的端口。同時你也可以在這一行的開頭看到一個“跟蹤編號”。該編號標(biāo)識了匹配跟蹤規(guī)則的特定報文。第二行包括了該報文匹配的第一條跟蹤規(guī)則:
trace id 9c01f8 inet trace_debug trace_pre rule ip daddr 10.2.1.2 tcp dport 1222 tcp flags syn limit rate 6/minute meta nftrace set 1 (verdict continue)
這就是剛添加的跟蹤規(guī)則。這里顯示的第一條規(guī)則總是激活報文跟蹤的規(guī)則。如果在這之前還有其他規(guī)則,它們將不會在這里顯示。如果沒有任何跟蹤輸出結(jié)果,說明沒有抵達這條跟蹤規(guī)則,或者沒有匹配成功。下面的兩行表明沒有后續(xù)的匹配規(guī)則,且 trace_pre
鉤子允許報文繼續(xù)傳輸(判定為接受)。
下一條匹配規(guī)則是:
trace id 9c01f8 inet nat prerouting rule ip daddr 10.1.2.3 tcp dport 1222 dnat ip to 192.168.70.10:22 (verdict accept)
這條 DNAT 規(guī)則設(shè)置了一個到其他地址和端口的映射。規(guī)則中的參數(shù) 192.168.70.10
是需要收包的虛擬機的地址,目前為止沒有問題。如果它不是正確的虛擬機地址,說明地址輸入錯誤,或者匹配了錯誤的 NAT 規(guī)則。
通過下面的輸出我們可以看到,IP 路由引擎告訴 IP 協(xié)議棧,該報文需要被轉(zhuǎn)發(fā)到另一個主機:
trace id 9c01f8 inet filter forward packet: iif "enp0" oif "veth31" ether saddr .. ip daddr 192.168.70.10 .. tcp dport 22 tcp flags == syn tcp window 29200
這是接收到的報文的另一種呈現(xiàn)形式,但和之前相比有一些有趣的不同。現(xiàn)在的結(jié)果有了一個輸出接口集合。這在之前不存在的,因為之前的規(guī)則是在路由決策之前(prerouting
鉤子)。跟蹤編號和之前一樣,因此仍然是相同的報文,但目標(biāo)地址和端口已經(jīng)被修改。假設(shè)現(xiàn)在還有匹配 tcp dport 1222
的規(guī)則,它們將不會對現(xiàn)階段的報文產(chǎn)生任何影響了。
如果該行不包含輸出接口(oif
),說明路由決策將報文路由到了本機。對路由過程的調(diào)試屬于另外一個主題,本文不再涉及。
trace id 9c01f8 inet filter forward rule ct status dnat jump allowed_dnats (verdict jump allowed_dnats)
這條輸出表明,報文匹配到了一個跳轉(zhuǎn)到 allowed_dnats
鏈的規(guī)則。下一行則說明了連接失敗的根本原因:
trace id 9c01f8 inet filter allowed_dnats rule drop (verdict drop)
這條規(guī)則無條件地將報文丟棄,因此后續(xù)沒有關(guān)于該報文的日志輸出。下一行則是另一個報文的輸出結(jié)果了:
trace id 20a4ef inet trace_debug trace_pre packet: iif "enp0" ether saddr .. ip saddr 10.2.1.2 ip daddr 10.1.2.3 ip protocol tcp tcp dport 1222 tcp flags == syn
跟蹤編號已經(jīng)和之前不一樣,然后報文的內(nèi)容卻和之前是一樣的。這是一個重傳嘗試:第一個報文被丟棄了,因此 TCP 嘗試了重傳??梢院雎缘羰S嗟妮敵鼋Y(jié)果了,因為它并沒有提供新的信息。現(xiàn)在是時候檢查那條鏈了。
上一節(jié)我們發(fā)現(xiàn)報文在 inet 過濾表中的一個名叫 allowed_dnats
的鏈中被丟棄?,F(xiàn)在我們來查看它:
# nft list chain inet filter allowed_dnatstable inet filter { chain allowed_dnats { meta nfproto ipv4 ip daddr . tcp dport @allow_in accept drop }}
接受 @allow_in
集的數(shù)據(jù)包的規(guī)則沒有顯示在跟蹤日志中。我們通過列出元素的方式,再次檢查上述報文的目標(biāo)地址是否在 @allow_in
集中:
# nft "get element inet filter allow_in { 192.168.70.10 . 22 }"Error: Could not process rule: No such file or directory
不出所料,地址-服務(wù)對并沒有出現(xiàn)在集合中。我們將其添加到集合中。
# nft "add element inet filter allow_in { 192.168.70.10 . 22 }"
現(xiàn)在運行查詢命令,它將返回新添加的元素。
# nft "get element inet filter allow_in { 192.168.70.10 . 22 }"table inet filter { set allow_in { type ipv4_addr . inet_service elements = { 192.168.70.10 . 22 } }}
ssh
命令現(xiàn)在應(yīng)該可以工作,且跟蹤結(jié)果可以反映出該變化:
trace id 497abf58 inet filter forward rule ct status dnat jump allowed_dnats (verdict jump allowed_dnats) trace id 497abf58 inet filter allowed_dnats rule meta nfproto ipv4 ip daddr . tcp dport @allow_in accept (verdict accept) trace id 497abf58 ip postrouting packet: iif "enp0" oif "veth31" ether .. trace id 497abf58 ip postrouting policy accept
這表明報文通過了轉(zhuǎn)發(fā)路徑中的最后一個鉤子 - postrouting
。
如果現(xiàn)在仍然無法連接,問題可能處在報文流程的后續(xù)階段,有可能并不在 nftables 的規(guī)則集合范圍之內(nèi)。
關(guān)于“網(wǎng)絡(luò)地址轉(zhuǎn)換NAT之報文跟蹤的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。