Nftables

簡化 nftables(網路過濾表)規則

  • April 6, 2020

我有一個有效的 nftables 規則集。但是它很長,並且有很多重複的程式碼:

  • ip4 和 ip6 完全相同(只是幾個字元不同)重複。
  • 規則鏈,分支成幾乎相同的分支。我覺得一些布爾邏輯在這裡會有所幫助。

如何減少重複程式碼,使這個規則集更簡潔?

我正在嘗試各種事情,然後意識到我可以像下面那樣做,但這讓我的程序員感到骯髒。它有太多重複的程式碼。

#!/usr/sbin/nft -f

table ip vnc_table {};
table ip6 vnc_table {};
flush table ip vnc_table;
flush table ip6 vnc_table;

table ip vnc_table {

   # 3 near identical sets
   set richardports {
       type inet_service;
       flags interval;
       elements = { 5910-5919 };
   }
   set henryports {
       type inet_service;
       flags interval;
       elements = { 5920-5929 };
   }
   set sholaports {
       type inet_service;
       flags interval;
       elements = { 5930-5939 };
   }

   chain output {
       type filter hook output priority 0; policy accept;
       ip daddr 127.0.0.1 jump localhost;
   }

   chain localhost {
       tcp dport @richardports jump richard_chain;
       tcp dport @henryports   jump henry_chain;
       tcp dport @sholaports   jump shola_chain;
   }

   # 3 near identical chains
   chain richard_chain {
       skuid "richard" accept;
       reject;
   }
   chain henry_chain {
       skuid "henry" accept;
       reject;
   }
   chain shola_chain {
       skuid "shola" accept;
       reject;
   }

}

#then we do it all again for ip6
table ip6 vnc_table {
   set richardports {
       type inet_service;
       flags interval;
       elements = { 5910-5919 };
   }
   set henryports {
       type inet_service;
       flags interval;
       elements = { 5920-5929 };
   }
   set sholaports {
       type inet_service;
       flags interval;
       elements = { 5930-5939 };
   }

   chain output {
       type filter hook output priority 0; policy accept;
       ip6 daddr ::1 jump localhost;
   }

   chain localhost {
       tcp dport @richardports jump richard_chain;
       tcp dport @henryports   jump henry_chain;
       tcp dport @sholaports   jump shola_chain;
   }

   chain richard_chain {
       skuid "richard" accept;
       reject;
   }
   chain henry_chain {
       skuid "henry" accept;
       reject;
   }
   chain shola_chain {
       skuid "shola" accept;
       reject;
   } 
}

將 IPv4 和 IPv6 連接在一起

將家庭ipip6的表加入到家庭**inet的單個表中:

  • 刪除整個ip6 vnc_table
  • ip vnc_table表更改為inet vnc_table

Family inet可以同時處理 IPv4 和 IPv6,並且在需要時仍然可以接受特定的 IPv4 或 IPv6 規則。所以替換:

table ip vnc_table {

和:

table inet vnc_table {
  • 調整之前的沖洗

在回答這個問題時,我發現這flush table不足以重新載入規則(我不得不修改我對這個主題的回答):如文件所述,它將“刷新指定表的所有鍊和規則”。但不會刪除這些對象本身,從而導致剩餘或衝突的對象。delete table應該改用:

delete table inet vnc_table

當然ip vnc_tableip6 vnc_table表應該手動刪除一次:

# nft delete table ip vnc_table
# nft delete table ip6 vnc_table
  • 添加現在缺少的 ip6 規則,以便 IPv4 和 IPv6 localhost 都匹配
nft add inet vnc_table output ip6 daddr ::1 jump localhost

需要流血邊緣才能做得更好

為了更進一步,這些集合必須以不同的方式組織,但只有在 2020年 4 月 1 日發布的 nftables 0.9.4和 libnftnl 1.1.6中才解除了一個錯誤/限制,同時還需要核心 5.6

  • 支持串聯範圍(需要 Linux 核心 >= 5.6),

如果沒有這些版本,nftables 將無法接受包含範圍(此處為埠範圍)的串聯。在處理以下規則集時,僅使用核心 5.5 而不是 5.6 會導致分段錯誤(這可以說是一個錯誤):核心也是必需的。

所以做了兩套:第一套是告訴哪些埠範圍被過濾了,需要特殊處理。第二個(仍然必須重新包含以前的埠範圍)是埠範圍和使用者 ID 的串聯。將根據數據包檢查這兩個屬性:如果存在埠 + 使用者關聯,則將被接受,否則對於那些過濾的埠,數據包將被拒絕。

結果:

table inet vnc_table
delete table inet vnc_table

table inet vnc_table {
   set filteredport {
       type inet_service
       flags interval
       elements = { 5910-5919, 5920-5929, 5930-5939 }
   }

   set portuser {
       type inet_service . uid
       flags interval
       elements = {
                5910-5919 . "richard",
                5920-5929 . "henry",
                5930-5939 . "shola"
       }
   }

   chain output {
       type filter hook output priority filter; policy accept;
       ip daddr 127.0.0.1 jump localhost
       ip6 daddr ::1 jump localhost
   }

   chain localhost {
       tcp dport @filteredport jump portuser_chain
   }

   chain portuser_chain {
       tcp dport . meta skuid @portuser accept
       reject with tcp reset
   }
}

筆記:

  • 命名集中的uid類型仍未在手冊頁中記錄,但與許多其他類型一起存在很長時間。定義它的原始碼:這里那裡
  • reject(發送ICMP)替換為reject with tcp reset(發送特定TCP RST)加速客戶端上的埠拒絕檢測(並且無需在之前指定它的TCP,隱式添加檢查,僅匹配TCP)。

引用自:https://unix.stackexchange.com/questions/578214