李臣

摘要:網絡安全問題在現實生活中變的愈發重要,而研究利用操作系統自帶的防火墻系統來阻斷異常流量是解決網絡安全問題最常使用且高效的手段。Linux操作系統作為一個開源的操作系統廣泛應用于服務器和嵌入式領域,而這些領域往往是網絡安全問題的重災區,研究Linux下的防火墻具有重要意義。現有的防火墻系統中的配置規則一般是基于IP配置的,但是對于多個域名對應一個IP的場景這種配置便不再適用,文章在Netfilter框架的基礎上設計實現了一個基于域名進行配置的內核模塊來解決上述問題。
關鍵詞: 網絡安全; 異常流量;Linux操作系統; 防火墻規則; Netfilter框架
中圖分類號:TP311? ? ? 文獻標識碼:A
文章編號:1009-3044(2023)06-0066-03
開放科學(資源服務)標識碼(OSID)
隨著虛擬主機的廣泛應用,一個IP經常會對應多個域名[1]。這樣導致我們在使用防火墻進行單個或多個IP流量阻斷時會發生錯誤域名的阻斷。為了解決這一難題,本文基于Netfilter框架的可擴展性開發了一個Linux內核模塊使得防火墻可以針對具體的域名或者域名集進行流量的阻斷。
1? Netfilter/Iptables框架
Netfilter/Iptables 由三部分組成,分別是Netfilter框架,Iptables(內核空間)和Iptables 命令行工具(用戶空間)[2]。
1.1? Netfilter框架
Netfilter是Linux內核提供的一個框架[3],它允許以自定義處理程序的形式實現各種與網絡相關的操作。Netfilter 在 Linux內核中表現為一系列的hook, 并允許Linux 內核模塊注冊為回調函數,Linux內核模塊通過回調函數操作網絡報文。Netfilter框架一共提供了5個hook,分別位于linux 網絡棧中的各個處理節點,如圖1所示:
Netfilter Hook的意義:
NF_IP_PRE_ROUTING: 位于路由之前,報文一致性檢查之后(報文一致性檢查包括: 報文版本、報文長度和checksum)。
NF_IP_LOCAL_IN: 位于報文經過路由之后,并且目的是本機的。
NF_IP_FORWARD:位于在報文路由之后,目的地非本機的。
NF_IP_LOCAL_OUT: 由本機發出去的報文,并且在路由之前。
NF_IP_POST_ROUTING: 所有即將離開本機的報文。
Linux 內核模塊可以注冊到任何的hook,注冊的回調函數也必須指定優先級。當一個報文通過hook的時候,hook將會依據優先級調用回調函數。注冊的回調函數,可以有五種返回,每種返回代表對報文不同的操作:
NF_ACCEPT: 繼續正常處理此報文,即允許報文通過。
NF_DROP: 丟棄此報文,不再進行繼續處理,即拒絕此報文。
NF_STOLEN: 取走這個報文,不再繼續處理。
NF_QUEUE: 報文進行重新排隊,可以將報文發到用戶空間的程序,進行修改或者決定是拒絕或者允許。
NF_REPEAT: 報文重新調用hook。
1.2 Iptables內核空間
Iptables 是基于Netfilter框架實現的報文選擇系統[4],其可以用于報文的過濾、網絡地址轉換和報文修改等功能。Iptables 本質上是包含了5個規則表,而規則表則包含了一些列的報文的匹配規則以及操作目標。以下對每個規則表進行了簡單說明:
Filter Table: 是一個默認的規則表,用于報文的過濾,注冊了三個鏈: INPUT、FORWARD和OUTPUT。
NAT Table: 主要用于NAT轉換,注冊了四個鏈:PREROUTING、INPUT、OUTPUT和POSTROUTING。
Mangle Table: 主要用于報文的修改,一共注冊了五個鏈: PREROUTING、OUTPUT、INPUT、FORWARD和POSTROUTING。
Raw Table: 可以對報文不進行鏈路跟蹤,其優先級在hook中注冊很高,注冊了兩個鏈: PREROUTING和OUTPUT。
Security Table: 用于強制網絡接入控制,注冊了三個鏈:INPUT、OUTPUT 和 FORWARD。
1.3 Iptables命令行工具(用戶空間)
Iptables命令行工具是工作在用戶空間的操作工具,用于修改內核空間的規則表[5]。
2 SNI(服務器名稱指示)
SNI 是 TLS 協議(以前稱為 SSL 協議)的擴展[6],該協議在 HTTPS 中使用,它的出現是為了解決多個服務器域名對應同一個IP而產生客戶端不知道鏈接哪個服務端的問題。它包含在 TLS/SSL 握手流程中,以確保客戶端設備能夠看到他們嘗試訪問的網站的正確 SSL 證書。該擴展使得可以在 TLS 握手期間指定網站的主機名或域名 ,而不是在握手之后打開 HTTP 連接時指定。
3 SNI防火墻實現
基于Netfilter框架很好的擴展性,用戶可以開發編寫自定義的Linux內核模塊并在Netfilter上注冊為回調函數來實現自定義的防火墻功能。
3.1? 匹配模塊的實現
每一條iptables配置的規則中都包含了匹配條件(match)和動作(target),要定義一個新的匹配條件就要實現一個匹配條件模塊[7]。匹配模塊的職責是檢測每一個數據包確定是否滿足匹配條件。首先要定義一個xt_match結構體類型的變量,模塊初始化的時候調用xt_register_match函數將其注冊到netfilter框架中,xt_match結構體的定義如下:
struct xt_match {
const char name[XT_EXTENSION_MAXNAMELEN];
unsigned short family;
bool (*match) (const struct sk_buff *sbk, struct xt_action_param *);
int (*checkentry) (const struct xt_mtchk_param *);
void (*destroy) (const struct xt_mtdtor_param *);
}
3.1.1 自定義結構體
我們在iptables命令中支持的匹配條件包括域名精確匹配、域名模糊匹配和域名集匹配。域名集的匹配借鑒了ipsets[8]。為了支持這些功能自定義了一個結構體xt_tls_info和host_set
struct xt_tls_info {
char host_or_set_name[MAX_HOSTNAME_LEN + 1]; //匹配條件中的單個域名和域名集
__s32 hostset_index; //域名集存儲在域名表中的位置
}
3.1.2 域名集數據的存入與查詢
域名集中的數據集合的存入使用Linux系統中的proc文件系統,每一個域名集對應proc文件系統中的一個目錄。
host_set hs;
hs->proc_file = proc_create_data(name, 0644, proc_fs_hostset_dir, &proc_fops, hs);
在做查詢的時候我們使用紅黑樹來做高性能查詢。
3.1.3 tls_mt_init函數
原型為:static int __init tls_mt_init (void)
主要完成xt_register_matches函數將xt_match類型的變量tls_mt_regs[]注冊到netfilter框架中及host_set表的初始化:
static struct host_set *host_set_table;
host_set_table = kmalloc(sizeof (struct host_set) * max_host_sets, GFP_KERNEL);
3.1.4 tls_mt_check函數
原型為:static int tls_mt_check (const struct xt_mtchk_param *par)
首先得到iptable命令中的匹配信息,對應到代碼中的xt_tls_info類型的變量match_info,判斷規則中的匹配信息是不是域名集,如果是則把該域名集信息存入到host_set_table中。存入到表中的索引位置也要放入match_info變量的hostset_index中。
3.1.5 tls_mt函數
原型為:static bool tls_mt(const struct sk_buff *skb, struct xt_action_param *par)
首先我們會根據HTTPS協議的格式從skb->data中解析出SNI中的域名,然后從par->mathchinfo中取出我們在iptables中創建的匹配信息,從而進行規則匹配。根據標準以太網數據格式RFC6066[],SNI字段的位置和多個字段有關。具體處理流程為:
在整個TCP報文中截取TCP報文頭之后的有效TLS協議負載報文數據data
檢測data數組的第一個元素Content Type判斷是否為0x16(Handshake)
檢測data數組的第六個元素Handshake協議判斷是否為0x01(Client Hello)
依次檢測Session ID長度、ciphers長度、compression types長度是否小于報文頭長度
檢測通過后得到所有擴展數據項,依次遍歷這些擴展數據得到SNI的數據
得到域名的信息之后我們再與規則中的域名或者域名集信息進行匹配。若是域名信息則直接使用glob_match函數進行精確或者模糊匹配。若是域名集信息則根據match_info的索引信息精確定位到host_set_table表中的位置再進行匹配。
3.1.6 tls_mt_destroy函數
原型為:static void tls_mt_destroy(const struct xt_mtdtor_param *par)
在iptables命令中刪除規則時根據par中的match_info信息刪除相應的域名或者域名集信息。
3.2 用戶態功能實現
首先定義一個xtables_match類型的變量:
static struct xtables_match tls_match = {
.name = "tls",? ? // 擴展名稱與匹配模塊中的名稱一致
.size = XT_ALIGN(sizeof(struct xt_tls_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_tls_info)),
.help = tls_help,? // 輸入iptables -m tls -h調用
.save = tls_save,
.x6_parse = tls_parse, // 解析命令行參數
};
使用iptables的示例如下:
1)阻止去往facebook的流量:
sudo iptables -A OUTPUT -p tcp --dport 443 -m tls --tls-host "www.facebook.com" -j DROP
2)模糊匹配:
sudo iptables -A OUTPUT -p tcp --dport 443 -m tls --tls-host "*.googlevideo.com" -j DROP
3)域名集匹配:
sudo iptables -A OUTPUT -p tcp --dport 443 -m tls --tls-hostset blacklist -j DROP
域名集中添加域名:
sudo echo +facebook.com > /proc/net/xt_tls/hostset/blacklist
sudo echo +googlevideo.com > /proc/net/xt_tls/hostset/blacklist
域名集中刪減域名:
sudo echo -facebook.com > /proc/net/xt_tls/hostset/blacklist
4 結論
針對一個IP經常會對應多個域名在使用Linux系統自帶的防火前進行IP阻斷會發生誤阻斷的問題,基于Netfilter/Iptables框架開發了一個Linux內核模塊進行基于域名或者域名集的阻斷,具體原理是使用HTTPS協議中的SNI標示。實驗表明,在配置了基于域名的相關規則后對應的流量被正常阻斷,而且規則支持精準匹配和模糊匹配。
參考文獻:
[1] 賴雋文,張煥杰,楊壽保.大規模WWW虛擬主機設計[J].小型微型計算機系統,2001,22(3):373-375.
[2] 姚曉宇,趙晨.Linux內核防火墻Netfilter實現與應用研究[J].計算機工程,2003,29(8):112-113,163.
[3] 王一平,韋衛.網絡安全框架Netfilter在Linux中的實現[J].計算機工程與設計,2006,27(3):439-442,468.
[4] (美)Robert Love.Linux內核設計與實現[M].2版.陳莉君,康華,張波.北京:機械工業出版社,2006.
[5] Daniel P.Bovet,Marco Cesati.深入理解LINUX內核[M].陳莉君,張瓊聲,張宏偉,譯.北京:中國電力出版社,2007.
[6] 毛偉杰,李永忠.基于SNI的加密流量檢測在蜜罐中的研究與應用[J].信息技術,2021,45(8):97-101.
[7] 毛新宇.Linux內核防火墻netfilter的原理和應用[J].微型機與應用,2004,23(4):35-37.
[8] 岳新.Linux2.4內核下基于Netfilter框架可擴展性研究與實現[D].哈爾濱:哈爾濱理工大學,2005.
【通聯編輯:光文玲】