目前試圖建立iptables的以允許客戶端連接到服務器通過TCP 向收聽消息流。事情是,我們希望阻止客戶端連接後發送任何消息(如果客戶端是DROP'在這種情況下編輯')。iptables的允許入站連接,但不允許入站流量
有沒有辦法允許客戶端連接並強制從服務器到客戶端的單向通信?
需要此功能純粹在iptables(無類似軟件代理的解決方案)中工作。
目前試圖建立iptables的以允許客戶端連接到服務器通過TCP 向收聽消息流。事情是,我們希望阻止客戶端連接後發送任何消息(如果客戶端是DROP'在這種情況下編輯')。iptables的允許入站連接,但不允許入站流量
有沒有辦法允許客戶端連接並強制從服務器到客戶端的單向通信?
需要此功能純粹在iptables(無類似軟件代理的解決方案)中工作。
這裏要解決的主要問題是,我們不能關閉全部建立連接後來自客戶端的流量,因爲TCP是肯定確認協議。如果服務器沒有收到來自客戶端的確認,它將重新發送,並最終超時。接下來,我將假設我們正在使用IPV4。
所以我們要做的是允許建立連接,然後只允許來自客戶端的確認,即不包含TCP有效載荷的數據包。
不幸的是,TCP有效載荷的長度在TCP header中沒有明確表示。我們可以嘗試使用IP header中的總長度,但由於IP報頭和TCP報頭包含可變長度選項字段這一事實使情況變得複雜,所以有很多可能的總長度不包含有效載荷。
由於IP選項很少使用並且經常被過濾,所以我們首先丟棄所有包含IP報頭選項的數據包(如果防火牆尚未這樣做的話),從而簡化事情。這樣做的含義詳見here。
要做到這一點,我們將所有的流量下降到我們的服務器(這裏取爲10.2.3.4:1234),其中IP報頭的長度(比特在IP報頭字節0 4-7)不是5:
iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \
-m u32 --u32 "0>>24&0xF=6:0xF" -j DROP
這使用iptables
u32
模塊抓住從分組的4個字節處開始的字節0,24位右移它,掩蓋低半字節,然後丟棄該數據包,如果這是在範圍6-15。請注意,5實際上是IP標頭的最小尺寸。
TCP選項的情況有點複雜。在建立連接時,可以使用許多不同的選項,例如。,協商窗口縮放。但是,一旦建立連接,我們唯一需要擔心的就是TCP時間戳和選擇性確認。因此,讓我們讓連接建立:
iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \
--tcp-flags SYN SYN -j ACCEPT
注意,有可能在一個SYN數據包發送有效載荷,所以在這裏我們並沒有完全滿足您的要求。儘管TCP fast open確實如此,但大多數普通的TCP實現不會這樣做。如果你想減輕這一點,你可以丟棄是分片的SYN數據包(可能會重新組合成非常大的數據包),並將非分片的SYN數據包的總長度限制在合理的範圍內,以允許通常的選項存在TCP三方握手。請注意,上述規則已添加到INPUT鏈,在 IP分段重組之後處理。
好的,我們可以建立TCP連接,IP頭限制爲5個字(20個字節)。
但是,TCP標頭可能包含選擇性ack,tcp時間戳,兩者或兩者都不包含。我們從沒有選項的TCP頭開始。沒有選項且沒有有效負載的確認將由5字IP標頭,後跟5字TCP標頭,然後是無數據組成。所以IP頭部的總長度應該是40.如果數據包是一個片段,它可能會在後續片段中隱藏一個有效載荷,但由於我們正在使用在IP碎片重組後處理的INPUT鏈,因此我們不會不得不擔心這一點。
iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \
-m u32 --u32 "32>>28=5 && 0&0xFFFF=40" -j ACCEPT
IP報頭是20個字節和數據偏移半字節是在字節12中,因此服用4個字節處開始的字節32 = 20 + 12,我們向下移動半字節,並將其與5,然後請確保IP標頭的字0的字節2和字節3的總長度爲40.
如果TCP標頭中有TCP時間戳,則TCP中會有額外的12個字節(3個字)頭。我們可以以類似的方式接受:
iptables -A INPUT -p tcp -d 10.2.3.4 --dport 1234 \
-m u32 --u32 "32>>28=8 && 0&0xFFFF=52" -j ACCEPT
我會把它作爲練習,讓讀者去計算其他組合。 (請注意,處理選擇性確認有幾種情況,因爲可以有1-4個選擇性確認塊或1-3個具有時間戳的選擇性確認塊。)
免責聲明:我沒有真正嘗試過這一點,所以我很抱歉如果有一個錯字或者我忽略了一些東西。我相信策略是健全的,如果有任何錯誤或遺漏,請讓我知道,我會糾正。