Linux 防火牆:Netfilter 的深度解析
想象一下,Linux 系統的網絡世界是一座繁華的城市,數據包就像是川流不息的車輛。但是,這座城市需要交通規則和守護者來維持秩序,避免混亂和危險。Netfilter 就像是這座網絡城市的超級警察和交通指揮中心,它能夠精準地識別哪些 “車輛” 可以通行,哪些需要攔截。現在,就讓我們深入瞭解一下這位網絡世界的 “守護者”——Netfilter 的工作原理和應用吧!
一、Netfilter 概述
Linux 2.4.x 引入的子系統,Netfilter 是 Linux 2.4.x 引入的一個子系統,它作爲一個通用的、抽象的框架,提供一整套的 hook 函數的管理機制,使得諸如數據包過濾、網絡地址轉換 (NAT) 和基於協議類型的連接跟蹤成爲了可能, 在 Linux 系統中發揮着至關重要的作用。它是一個強大而靈活的網絡包過濾框架,爲系統管理員提供了對網絡數據包的精細控制。
Netfilter 通過在內核中插入鉤子點,實現對網絡數據包的過濾、修改和轉發。它在 IP 報文處理流程中插入了 5 個掛載點,分別是 NF_IP_PRE_ROUTING、NF_IP_LOCAL_IN、NF_IP_FORWARD、NF_IP_LOCAL_OUT 和 NF_IP_POST_ROUTING。在這些掛載點上,可以註冊處理數據包的回調函數。當數據包進入 Linux 內核經過掛載點的時候,會執行回調函數來處理數據包。
回調函數有多種返回值,例如 NF_ACCEPT 表示繼續正常的報文處理;NF_DROP 將報文丟棄;NF_STOLEN 表示由鉤子函數處理了該報文,不要再繼續傳送;NF_QUEUE 將報文入隊,通常交由用戶程序處理;NF_REPEAT 表示再次調用該鉤子函數。
Netfilter 支持多種協議棧,目前 Linux 2.6 版內核的 Netfilter 支持 IPv4、IPv6 以及 DECnet 等協議棧。它主要通過表、鏈實現規則,其中規則是對特定報文的處理說明,包括匹配字段和 action;鏈是一組規則的集合;表是鏈中相同功能的規則集合。
Netfilter 可以實現多種功能,如在 Linux 內核中利用 Netfilter 解析數據包,自適應多層 VLan 和 PPPoe 網絡環境;對特定 DNS 域名的請求數據包進行過濾;解析 IP 層數據頭部;對特定端口的數據包進行過濾;解析 HTTP 請求和返回數據包,對特定 Host、URI、文件下載的數據包進行過濾;在以太網環境中,對數據包進行處理;在網橋環境中,對經過網橋的數據包進行解析。
二、Netfilter 工作原理
2.1 什麼是 Netfilter
Netfilter 是 Linux 內核中的一個數據包處理模塊,它可以提供數據包的過濾、轉發、地址轉換 NAT 功能。Iptables 是一個工具,可以用來在 Netfilter 中增加、修改、刪除數據包處理規則,Netfilter 是位於網卡和內核協議棧之間的一堵牆,是一種免費的軟件防火牆。
Netfilter 中有三個主要的概念:規則、表、鏈,等級依次遞增
-
規則是對特定報文的處理說明,包括匹配字段和 action。
-
鏈是一組規則的集合。
-
表是鏈中相同功能的規則集合。
這幅示意圖中,IP 包一進一出,有幾個關鍵的檢查點,它們正是 Netfilter 設置防火牆的地方。Netfilter 通過向內核協議棧中不同的位置註冊鉤子函數來對數據包進行過濾或者修改操作,這些位置稱爲掛載點,主要有 5 個:PRE_ROUTING、LOCAL_IN、FORWARD、LOCAL_OUT 和 POST_ROUTING,如下圖所示:
-
PRE_ROUTING:IP 包進入 IP 層後,還沒有對數據包進行路由判定前;
-
LOCAL_IN:進入主機,對 IP 包進行路由判定後,如果 IP 包是發送給本地的,在進入傳輸層之前對 IP 包進行過濾;
-
LOCAL_OUT:IP 包通過傳輸層進入用戶空間,交給用戶進程處理。而處理完成後,用戶進程會通過本機發出返回的 IP 包,在沒有對輸出的 IP 包進行路由判定前進行過濾;
-
FORWARD:IP 包進行路由判定後,如果 IP 包不是發送給本地的,在轉發 IP 包出去前進行過濾;
-
POST_ROUTING:對於輸出的 IP 包,在對 IP 包進行路由判定後進行過濾;
在圖中可以看出決定 IP 包走向就是路由,按照路由的判定可以分爲兩條路線:
-
第一個路由通過查找輸入數據包 IP 頭部的 IP 地址,判斷是否爲本機的 IP 地址是否一致,如果與本機的 IP 地址一致,說明數據是發送給本機的,否則說明數據包是發送給其他主機,只是經過本機中轉;
-
第二個路由判定根據輸出數據包 IP 頭部的 IP 地址 從路由表中查找對應的路由信息,然後根據路由信息獲取下一主機的 IP 地址,然後進行數據傳輸;
通過向掛載點註冊鉤子函數,就能夠對處於不同階段的數據包進行過濾或者修改操作。由於鉤子函數能夠註冊多個,因此掛載點通過鏈表鏈接,所以掛載點又被稱爲鏈,因此 LOCAL_IN 掛載點又稱爲 INPUT 鏈、LOCAL_OUT 掛載點又稱爲 OUTPUT 鏈、FORWARD 掛載點又稱爲 PORWARD 鏈、PRE_ROUTING 掛載點又稱爲 PREROUTING 鏈、POST_ROUTING 掛載點又稱爲 POSTOUTING 鏈。
2.2 什麼是 iptables
iptables 是建立在 Netfilter 之上的數據包過濾器,通過向 Netfilter 的掛載點上註冊鉤子函數來實現對數據包過濾的,從 iptables 這個名字上可以看出一定具有表的概念,iptables 通過把這些規則表掛載在 Netfilter 的不同鏈上,對進出內核協議棧的數據包進行過濾或者修改操作。
iptables 包括四種表:
-
Filter 表用於過濾數據包,是 iptables 的默認表,因此如果你配置規則時沒有指定表,那麼就默認使用 Filter 表,Filter 表可以作用於 INPUT 鏈、OUTPUT 鏈、PORWARD 鏈;
-
NAT 表用於對數據包的網絡地址轉換 (IP、端口),分別可以掛載到 PREROUTING 鏈、POSTOUTING 鏈、OUTPUT 鏈;
-
Mangle 主要用來修改 IP 數據包頭,比如修改 TTL 值,同時也用於給數據包添加一些標記,從而便於後續其它模塊對數據包進行處理,可以作用在所有鏈上;
-
Raw 表用於判定數據包是否被狀態跟蹤處理,可以作用於 PREROUTING 鏈、OUTPUT 鏈;
數據包從網絡中進入到內核協議棧的過程中,要執行的 iptables 規則,如果在執行某條 iptables 規則失敗後,會直接把數據包丟棄,不會繼續執行下面的規則。
表的實現
表的基本數據結構是 ipt_table(位於 include/linux/netfilter_ipv4/iptables.h,Line413)。
1 struct ipt_table
2 {
3 struct list_head list; // 一個雙向鏈表
4 char name[IPT_TABLE_MAXNAMELEN]; // 被用戶空間使用的表函數的名字
5 struct ipt_replace *table; // 表初始化的模板,定義了一個初始化用的表,該表的所默認的HOOK 所包含的規則等信息
7 // 用戶通過系統調用進行表的替換時也要用
8 unsigned int valid_hooks; // 表所監聽的HOOK,實質是一個位圖
9 rwlock_t lock; // 整個表的讀/寫自旋鎖
10 struct ipt_table_info *private; // 表所存儲的數據信息,也就是實際的數據區,
11 // 僅在處理ipt_table 的代碼內部使用
12 struct module *me; // 如果是模塊,那麼取THIS_MODULE,否則取NULL
13 };
其中:
unsigned int valid_hooks;:這個位圖有兩個作用:一個是檢查 Netfilter 中哪些 Hook 對應着合法的 entries;二是用來爲 ipt_match 以及 ipt_target 數據結構中的 checkentry() 函數覈算可能的 Hook。
struct module *me;:當取值爲 THIS_MODULE 時,可以阻止用戶 rmmod 一個仍然被某個規則指向的模塊的嘗試。
struct ipt_replace *table;:該數據結構是被用戶空間來替換一個表的,其定義位於 include/linux/netfilter_ipv4/ip_tables.h,Line230。
struct ipt_replace
{
char name[IPT_TABLE_MAXNAMELEN];
unsigned int valid_hooks;
unsigned int num_entries; // 規則表入口的數量
unsigned int size; // 新的規則表的總大小
/* Hook entry points. */
// 表所監聽HOOK 的規則入口, 是對於entries[ ]的偏移
unsigned int hook_entry[NF_IP_NUMHOOKS];
unsigned int underflow[NF_IP_NUMHOOKS]; // 規則表的最大下界
// 舊的計數器數目,即當前的舊entries 的數目
unsigned int num_counters;
struct ipt_counters *counters; // 舊的計數器
struct ipt_entry entries[0]; // 規則表入口
};
上文所提到的 filter、nat、mangle 表分表是 ipt_table 這個數據結構的三個實例:packet_filter(位於 net/ipv4/netfilter/iptable_filter.c,Line84)、Nat(位於 net/ipv4/netfilter/ip_nat_rule.c,Line104)以及 packet_mangler(位於 net/ipv4/netfilter/iptable_mangler.c,Line117);
ipt_table_info(位於 net/ipv4/netfilter/iptables.c,Line86),是實際描述規則表的數據結構。
struct ipt_table_info
{
unsigned int size;
unsigned int number; // 表項的數目
unsigned int initial_entries; // 初始表項數目
// 所監聽HOOK 的規則入口
unsigned int hook_entry[NF_IP_NUMHOOKS];
unsigned int underflow[NF_IP_NUMHOOKS]; // 規則表的最大下界
// 規則表入口,即真正的規則存儲結構ipt_entry 組成塊的起始地址,
//對多CPU,每個CPU 對應一個
char entries[0] ____cacheline_aligned;
};
添加 iptables 規則
使用 iptables 命令添加規則,iptables 可以分爲四部分:
iptables -t表 -A鏈 匹配規則 動作
匹配條件
匹配條件分爲基本匹配條件與擴展匹配條件,基本匹配條件包括源 IP 地址和目標 IP 地址等,擴展匹配條件包括源端口和目標端口等;
處理動作
處理動作是指當匹配條件成功後要進行的一系列操作過程,動作也可以分爲 基本動作 和 擴展動作,常用的動作如下:
-
ACCEPT:允許數據包通過;
-
DROP:直接丟棄數據包,不給任何迴應信息;
-
REJECT:拒絕數據包通過,必要時會給數據發送端一個響應的信息,客戶端剛請求就會收到拒絕的信息;
-
SNAT:源 IP 地址轉換;
-
DNAT:目標 IP 地址轉換;
-
REDIRECT:在本機做端口映射;
-t <表>:指定要操縱的表;
-A <鏈>:向規則鏈中添加條目;
-D <鏈>:從規則鏈中刪除條目;
-I <鏈>:向規則鏈中插入條目;
-R <鏈>:替換規則鏈中的條目;
-L:顯示規則鏈中已有的條目;
-F:清楚規則鏈中已有的條目;
-Z:清空規則鏈中的數據包計算器和字節計數器;
-N:創建新的用戶自定義規則鏈;
-P:定義規則鏈中的默認目標;
-h:顯示幫助信息;
-p:指定要匹配的數據包協議類型;
-s:指定要匹配的數據包源ip地址;
-j <動作>:指定要進行的動作行爲;
-i <網絡接口>:指定數據包進入本機的網絡接口;
-o <網絡接口>:指定數據包要離開本機所使用的網絡接口。
--dport <端口>:匹配目標端口號。
--sport <端口>:匹配來源端口號。
一條完整的規則由三個數據結構共同實現,分別是:
一個 ipt_entry 結構,存儲規則的整體信息;
0 或多個 ipt_entry_match 結構,存放各種 match,每個結構都可以存放任意的數據,這樣也就擁有了良好的可擴展性;
1 個 ipt_entry_target 結構,存放規則的 target,類似的,每個結構也可以存放任意的數據;
下面將依次對這三個數據結構進行分析:
存儲規則整體的結構 ipt_entry,其形式是一個鏈表(位於 include/linux/netfilter_ipv4/ip_tables.h,Line122),如下所示:
struct ipt_entry
{
struct ipt_ip ip;
unsigned int nfcache;
u_int16_t target_offset;
u_int16_t next_offset;
unsigned int comefrom;
struct ipt_counters counters;
unsigned char elems[0];
};
其成員含義如下:
struct ipt_ip ip;:這是對其將要進行匹配動作的IP 數據報報頭的描述,其定義於include/linux/netfilter_ipv4/ip_tables.h,Line122,其成員包括源/目的IP 及其掩碼,出入端口及其掩碼,協議族、標誌/取反flag 等信息。
unsigned int nfcache;:HOOK 函數返回的cache 標識,用以說明經過這個規則後數據報的狀態,其可能值有三個,定義於include/linux/netfilter.h,Line23:
#define NFC_ALTERED 0x8000 //已改變
#define NFC_UNKNOWN 0x4000 //不確定
另一個可能值是0,即沒有改變。
u_int16_t target_offset;:指出了target 的數據結構ipt_entry_target的起始位置,即從ipt_entry 的起始地址到matc存儲結束的位置 u_int16_t next_offset;:指出了整條規則的大小,也就是下一條規則的起始地址,即ipt_entry 的起始地址到match 偏移再到target 存儲結束的位置
unsigned int comefrom;:所謂的“back pointer”,據引用此變量的代碼(主要是net/ipv4/netfilter/ip_tables.c 中)來看,它應該是指向數據報所經歷的上一個規則地址,由此實現對數據報行爲的跟蹤
struct ipt_counters counters;:說明了匹配這個規則的數據報的計數以及字節計數(定義於include/linux/netfilter_ipv4/ip_tables.h,Line100)
unsigned char elems[0];:表示擴展的match 開始的具體位置(因爲它是大小不確定的),當然,如果不存在擴展的match 那麼就是target 的開始位置
擴展 match 的存儲結構 ipt_entry_match,位於 include/linux/netfilter_ipv4/ip_tables.h,Line48。
struct ipt_entry_match
{
union {
struct {
u_int16_t match_size;
char name[IPT_FUNCTION_MAXNAMELEN];
} user;
struct {
u_int16_t match_size;
struct ipt_match *match;
} kernel;
u_int16_t match_size; //總長度
} u;
unsigned char data[0];
};
其中描述match 大小的`u_int16_t match_size;`,從涉及這個變量的源碼看來,在使用的時候需要注意使用一個宏IPT_ALIGN(位於include/linux/netfilter_ipv4/ip_tables.h,Line445)來進行4 的對齊處理(0x3 & 0xfffffffc),這應該是由於match、target 擴展後大小的不確定性決定的。
在結構中,用戶空間與內核空間爲不同的實現,內核空間中的描述擁有更多的信息。在用戶空間中存放的僅僅是match 的名稱,而在內核空間中存放的則是一個指向ipt_match 結構的指針。
結構ipt_match 位於include/linux/netfilter_ipv4/ip_tables.h,Line342:
struct ipt_match
{
void *matchinfo, // 指向規則中match 數據的指針,
// 具體是什麼數據結構依情況而定
int offset, // IP 數據報的偏移
const void *hdr, // 指向協議頭的指針
u_int16_t datalen, // 實際數據長度,即數據報長度-IP 頭長度
int *hotdrop);
int (*checkentry)(const char *tablename, // 可用的表
const struct ipt_ip *ip,
void (*matchinfo,
unsigned int matchinfosize,
unsigned int hook_mask); // 對應HOOK 的位圖
void (*destroy)(void *matchinfo,
unsigned int matchinfosize);
struct module *me;
};
其中幾個重要成員:
`int (*match)(……);`:指向用該match 進行匹配時的匹配函數的指針,match 相關的核心實現。返回0 時hotdrop 置1,立即丟棄數據報;返回非0 表示匹配成功。
`int (*checkentry)(……);`:當試圖插入新的match 表項時調用這個指針所指向的函數,對新的match 表項進行有效性檢查,即檢查參數是否合法;如果返回false,規則就不會被接受(譬如,一個TCP
的match 只會TCP 包,而不會接受其它)。
`void (*destroy)(……);`:當試圖刪除一個使用這個match 的表項時,即模塊釋放時,調用這個指針所指向的函數。我們可以在checkentry()中動態地分配資源,並在destroy 中將其釋放。
target 的存儲結構 ipt_entry_target,位於 include/linux/netfilter_ipv4/ip_tables.h,Line71,這個結構與 ipt_entry_match 結構類似,同時其中描述內核 target 結構 ipt_target(位於 include/linux/netfilter_ipv4/iptables.h,Line375)也與 ipt_match 類似,只不過其中的 target() 函數返回值不是 0/1,而是 verdict。
而 target 的實際使用中,是用一個結構 ipt_standard_target 專門來描述,這纔是實際的 target 描述數據結構(位於 include/linux/netfilter_ipv4/iptables.h,Line94),它實際上就是一個 ipt_entry_target + verdict。
其中成員 verdict 這個變量時一個很巧妙的設計,也是一個非常重要的東西,其值的正負有着不同的意義。它的值包括 IPT_CONTINUE、IPT_RETURN 以及前文所述的 NF_DROP 等值,那麼它的作用是什麼呢?原因如下:
o 由於iptables 是在用戶空間中執行的,也就是說Netfilter/IPTables這個框架需要用戶態與內核態之間的數據交換以及識別。而在具體的程序中,verdict 作爲`struct ipt_standard_target`的一個成員,也是對於`struct ipt_entry_target`中的target()函數的返回值。這個返回值標識的是target()所對應的執行動作,包括系統的默認動作以及外部提交的自定義動作。
o 但是,在用戶空間中提交的數據往往是類似於“ACCPET”之類的字符串,在程序處理時則是以`#define NF_ACCEPT 1`的形式來進行的;而實際上,以上那些執行動作是以鏈表的數據結構進行存儲的,在內核空間中表現爲偏移。
o 於是,verdict 實際上描述了兩個本質相同但實現不同的值:一個是用戶空間中的執行動作,另一個則是內核空間中在鏈表中的偏移——而這就出現了衝突。
o 解決這種衝突的方法就是:用正值表示內核中的偏移,而用負值來表示數據報的那些默認動作,而外部提交的自定義動作則也是用正值來表示。這樣,在實際使用這個verdict 時,我們就可以通過判斷值的正負來進行相應的處理了。
o 位於net/ipv4/netfilter/ip_tables.h 中的函數ipt_do_table()中有一個典型的verdict 使用(Line335,其中v 是一個verdict 的實例):
if (v !=IPT_RETURN) {
verdict = (unsigned)(-v) - 1;
break;
}
其中的IPT_RETURN 定義爲:
#define IPT_RETURN (-NF_MAX_VERDICT – 1)
而宏NF_MAX_VERDICT 實際上就是:
#define NF_MAX_VERDICT NF_REPEAT
這樣,實際上IPT_RETURN 的值就是-NF_REPEAT-1,也就是對應REPEAT,這就是對執行動
match 的定位如下:
-
起始地址爲:當前規則(起始)地址 + sizeof(struct ipt_entry);
-
結束地址爲:當前規則(起始)地址 + ipt_entry->target_offset;
-
每一個 match 的大小爲:ipt_entry_match->u.match_size;
target 的定位則爲:
-
起始地址爲 match 的結束地址,即:當前規則(起始)地址 + ipt_entry->target_offset;
-
結束地址爲下一條規則的起始地址,即:當前規則(起始)地址 + ipt_entry->next_offset;
-
每一個 target 的大小爲:ipt_entry_target->u.target_size;
這些對於理解 match 以及 target 相關函數的實現是很有必要明確的。
同時,include/linux/netfilter_ipv4/ip_tables.h 中提供了三個 “helper functions”,可用於使對於 entry、target 和 match 的操作變得方便,分別爲:
-
函數 ipt_get_target(),作用是取得 target 的起始地址,也就是上面所說的當前規則(起始)地址 + ipt_entry->target_offset;
-
宏 IPT_MATCH_ITERATE(),作用是遍歷規則的所有 match,並執行同一個(參數中)給定的函數。其參數爲一個 ipt_entry_match 結構和一個函數,以及函數需要的參數。當返回值爲 0 時,表示遍歷以及函數執行順利完成;返回非 0 值時則意味着出現問題已終止;
-
宏 IPT_ENTRY_ITERATE(),作用是遍歷一個表中的所有規則,並執行同一個給定的函數。其參數是一個 ipt_entry 結構、整個規則表的大小,以及一個函數和其所需的參數。其返回值與宏 IPT_MATCH_ITERATE() 類似;
那麼,如何保證傳入的 ipt_entry 結構是整個規則表的第一個結構呢?據源碼看來,實際調用這個宏的時候傳入的第一個參數都是某個 ipt_table_info 結構的實例所指向的 entries 成員,這樣就保證了對整個規則表的完整遍歷。
規則的使用
當一個特定的 Hook 被激活後,數據報就進入 Netfilter/iptables 系統進行遍歷,首先檢查‘struct ipt_ip ip’,然後數據報將依次遍歷各個 match,也就是'struct ipt_entry_match',並執行相應的 match 函數,即 ipt_match 結構中的 * match 所指向的函數。當 match 函數匹配不成功時返回 0,或者 hotdrop 被置爲 1 時,遍歷將會停止。(這部分有點亂,先放這,等看源碼好好看看。。)
對 match 的遍歷完成後,會開始檢查'struct ipt_entry_target',其中如果是一個標準的 target,那麼會檢查‘struct ipt_standard_target'中的 verdict,如果 verdict 值是正的而偏移卻指向了不正確的位置,那麼,ipt_entry 中的 comefrom 成員就有了用武之地——數據報返回所經歷的上一個規則。對於非標準的 target 呢?就會調用 target() 函數,然後根據其返回值進行後面的處理。(對於 verdict 不太明白,先放這。。)
iptables 與 Netfilter 的關係
iptables 作爲用戶空間的工具,爲用戶提供了一個直觀的界面來編寫防火牆規則。用戶可以通過命令行操作 iptables,將特定的規則配置下發到內核空間的 Netfilter。而 Netfilter 作爲內核中的防護框架,接收來自 iptables 的規則,並在網絡數據包流經內核協議棧時,依據這些規則對數據包進行處理。例如,當用戶使用 iptables 命令設置了一條過濾規則,iptables 會將這條規則轉化爲特定的格式,並通知 Netfilter 在相應的位置進行處理。這樣,兩者緊密配合,共同實現了對網絡流量的精細控制。
三、Netfilter/iptables-IPv4 總體架構
Netfilter 主要通過表、鏈實現規則,可以這麼說,Netfilter 是表的容器,表是鏈的容器,鏈是規則的容器,最終形成對數據報處理規則的實現。
3.1Netfilter 的 Hook 機制
Netfilter 的通用框架不依賴於具體的協議,而是爲每種網絡協議定義一套 Hook 函數。這些 Hook 函數在數據報經過協議棧的幾個關鍵點時被調用,在這幾個點中,協議棧將數據報以及 Hook 函數標號作爲參數,傳遞給 Netfilter 框架。
對於它在網絡堆棧中增加的這些 Hook,內核的任何模塊可以對每種協議的一個或多個 Hook 進行註冊,實現掛接。這樣當某個數據報被傳遞給 Netfilter 框架時,內核能檢測到是否有任何模塊對該協議和 Hook 函數進行了註冊。
若註冊了,則調用該模塊的註冊時使用的 “回調” 函數,這樣這些模塊就有機會檢查、修改、丟棄該數據報及指示 Netfilter 將該數據報傳入用戶空間隊列。
這樣,Hook 提供了一種方便的機制:在數據報通過 Linux 內核的不同位置上截獲和操作處理數據報。
3.2iptables 基礎模塊
iptables 基礎模塊實現了三個表來篩選各種數據報,具體的講,Linux2.4 內核提供了這三種數據報的處理功能是相互間獨立的模塊,都基於 Netfilter 的 Hook 函數和各種表、鏈實現的。這三個表包括:filter 表、nat 表以及 mangle 表。具體功能模塊:
-
數據報過濾模塊
-
連接跟蹤模塊
-
網絡地址轉換模塊(NAT)
-
數據報修改模塊(mangle)
-
其他高級功能模塊
3.3Netfilter 的架構
Netfilter 的四表五鏈架構是其實現強大功能的關鍵。filter 表主要用於數據包過濾,當數據包經過 filter 表中的鏈時,會根據預先設置的規則判斷是否允許數據包通過。例如,可以設置規則只允許特定 IP 地址或端口的數據包通過。nat 表用於網絡地址轉換,在網絡環境中,當需要將內部網絡的 IP 地址轉換爲外部可訪問的地址時,nat 表就發揮了重要作用。比如,在一個企業網絡中,通過 nat 表可以將內部多個設備的私有 IP 地址轉換爲一個公共 IP 地址,實現對外通信。mangle 表用於修改數據包的頭部信息,如修改服務類型(TOS)、生存時間(TTL)等。這可以用於實現服務質量調整和策略路由等應用。raw 表則主要用於決定數據包是否被狀態跟蹤機制處理。優先級的設置確保了數據包在處理過程中按照特定的順序進行。當數據包進入 Netfilter 框架時,首先會經過 raw 表的處理,如果 raw 表處理完後決定不進行連接跟蹤處理,那麼數據包將跳過 nat 表和連接跟蹤處理,直接進入後續的處理階段。
⑴防火牆狀態機制配置
Netfilter 的防火牆狀態機制是其高效處理數據包的重要手段之一。根據連接狀態匹配數據包,可以加快轉發速度。連接狀態主要有 New、Established、Related 和 INVALID 四種。當一個新的連接建立時,數據包處於 New 狀態。一旦連接建立成功,後續的數據包就處於 Established 狀態。Related 狀態表示與已建立連接相關的數據包,比如 FTP 數據連接與控制連接相關。INVALID 狀態表示數據包的狀態無法確定或無效。這種狀態機制可以記錄動態網絡地址轉換(dnat),方便在需要時進行還原。例如,在進行網絡地址轉換時,Netfilter 可以記錄下轉換前的地址信息,以便在後續的數據包處理中進行還原。同時,狀態機制還可以控制規則的存放和開啓,根據不同的連接狀態應用不同的規則,提高了防火牆的靈活性和效率。
⑵Netfilter 模塊收發和轉發數據包流程
Netfilter 模塊在收發和轉發數據包時,經過多個關鍵處理階段。當數據包進入網絡層時,首先會經過 Netfilter 的 hook function。這些 hook function 就像一個個檢查點,對數據包進行特定的處理。例如,在 NF_IP_PRE_ROUTING 掛載點,數據包剛剛進入網絡層,此時可以進行目的地址轉換等操作。內置鏈在數據包處理過程中也起着重要作用。不同的鏈對應着不同的處理階段和功能。例如,在轉發數據包時,會經過 NF_IP_FORWARD 鏈的處理,在這裏可以進行 FORWARD 包過濾。Netfilter 根據優先級和規則對數據包進行處理,確保數據包按照既定的策略進行轉發、過濾或其他操作。在整個處理過程中,Netfilter 充分發揮了其靈活性和可擴展性,爲網絡安全提供了堅實的保障。
四、Netfilter 基本配置
⑴配置 22/ssh 端口訪問控制規則
使用 iptables 可以靈活地配置 22/ssh 端口的訪問控制規則。例如,可以使用以下命令禁止所有人訪問 22 端口:iptables -A INPUT -p tcp --dport 22 -j DROP。若要恢復連接,可以使用 iptables -I INPUT -p tcp --dport 22 -j ACCEPT。還可以通過插入指定行號信息,將規則插入到特定位置,如 iptables -I INPUT 2 -p tcp --dport 22 -j ACCEPT。刪除指定規則可以使用 iptables -D INPUT -p tcp --dport 22 -j ACCEPT 或根據規則行號刪除相應規則,如 iptables -D INPUT 2。如果只允許特定 IP(如 10.0.0.1)通過 ssh 連接這臺服務器,可以使用 iptables -I INPUT -s 10.0.0.1 -p tcp --dport 22 -j ACCEPT。
⑵禁止網段連入
要禁止特定網段連入服務器,可以使用以下命令。例如,禁止 172.16.1.0 網段訪問 172.16.1.188,可以使用 iptables -A INPUT -s 172.16.1.0/24 -d 172.16.1.188 -j DROP。
⑶控制特定網段訪問服務器主機的端口
如果要禁止某個 172.16.1.0 網段訪問服務器主機的 22 端口,可以使用 iptables -A INPUT -s 172.16.1.0/24 -d 172.16.1.188 -p tcp --dport 22 -j DROP。在入方向控制時,可以使用 iptables -I INPUT -i eth0 -p tcp --dport 22 -j ACCEPT;在出方向控制時,可以使用 iptables -I OUTPUT -o eth0 -p tcp --sport 22 -j DROP。
⑷設置除特定網段外其他網段禁止連接
可以通過兩種方法設置除特定網段外其他網段禁止連接。方法一是修改默認規則,將默認規則改爲拒絕,如 iptables -A INPUT -s 10.0.0.0/24 -d 172.16.1.8 -j ACCEPT;方法二是使用取反操作,如 iptables -A INPUT! -s 10.0.0.0/24 -d 172.16.1.8 -j DROP。
⑸測試匹配列舉端口範圍
可以使用 iptables 測試匹配列舉端口範圍。設置連續多端口控制策略可以使用 iptables -A INPUT -p tcp --dport 22:80 -j DROP;設置不連續多端口控制策略可以使用 iptables -A INPUT -p tcp -m multiport --dport 22,80 -j DROP。
五、企業級防火牆配置
⑴備份服務器的重要性
在企業級防火牆配置中,備份服務器起着至關重要的作用。備份服務器可以確保在防火牆配置出現問題或遭受攻擊時,能夠快速恢復到之前的穩定狀態。例如,飛塔防火牆自動備份技巧中,通過在 CentOS 7 備份服務器上安裝工具 sshpass,並進行一系列配置,可以實現對飛塔防火牆的自動備份。創建存儲備份文件的文件夾,編寫備份腳本 firewallbackup.sh,同時創建 ip.txt 文件記錄飛塔防火牆的登陸地址。通過配置 CentOS 7 的計劃任務 crontab -e,可以實現每天定時自動備份,如每天 11 點和 23 點自動備份一次。這樣可以有效防止因防火牆配置丟失或損壞而導致的業務中斷,爲企業網絡安全提供了有力的保障。
⑵開放 SSH 端口
開放 SSH 端口是企業級防火牆配置中的常見需求。使用 iptables 可以靈活地配置 SSH 端口的訪問控制規則。例如,可以使用以下命令禁止所有人訪問 22 端口:iptables -A INPUT -p tcp --dport 22 -j DROP。若要恢復連接,可以使用 iptables -I INPUT -p tcp --dport 22 -j ACCEPT。還可以通過插入指定行號信息,將規則插入到特定位置,如 iptables -I INPUT 2 -p tcp --dport 22 -j ACCEPT。刪除指定規則可以使用 iptables -D INPUT -p tcp --dport 22 -j ACCEPT 或根據規則行號刪除相應規則,如 iptables -D INPUT 2。如果只允許特定 IP(如 10.0.0.1)通過 ssh 連接這臺服務器,可以使用 iptables -I INPUT -s 10.0.0.1 -p tcp --dport 22 -j ACCEPT。
⑶防止配置出錯導致無法連接服務器
在配置企業級防火牆時,需要注意防止配置出錯導致無法連接服務器。可以在配置前進行備份,以便在出現問題時能夠快速恢復。同時,可以使用其他工具配置和管理 Netfilter 規則,如 firewalld。firewalld 是一個動態防火牆管理器,它可以動態修改單條規則,不需要像 iptables 那樣,修改了規則後必須全部刷新纔可以生效。firewalld 的配置方法主要有三種:firewall-config、firewall-cmd 和直接編輯 xml 文件。其中 firewall-config 是圖形化工具,firewall-cmd 是命令行工具。通過使用 firewalld,可以更加方便地管理防火牆規則,提高配置的準確性和可靠性。
⑷使用其他工具配置和管理 Netfilter 規則
除了 iptables 和 firewalld,還有其他工具可以配置和管理 Netfilter 規則。例如,Juniper 防火牆配置備份中,可以通過多種方式備份和恢復防火牆配置,包括設備重啓動、操作系統備份和恢復、配置文件備份和恢復等。通過這些工具,可以更加全面地管理企業級防火牆,提高網絡安全水平。
六、Netfilter 的應用案例
6.1Netfilter 在不同場景中的應用
Netfilter 在網絡安全領域有着廣泛的應用。它可以作爲強大的防火牆,通過設置規則過濾網絡數據包,阻止惡意流量進入系統。例如,可以根據數據包的源 IP 地址、目標 IP 地址、協議類型、端口號等信息進行精細過濾,確保只有合法的數據包能夠通過。
在實現負載均衡方面,Netfilter 也發揮着重要作用。正如前面提到的,通過利用 Netfilter 的功能,可以實現將網絡流量分配到不同的服務器上,提高系統的可用性和性能。例如,通過 DNAT(目標網絡地址轉換)可以將請求數據包分離到不同的目的地址,然後配置路由將這些數據包導向不同的服務器,實現負載均衡。
Netfilter 還可以與 VPN 技術集成,保護數據傳輸。例如,IPSec VPN 技術中,Netfilter 可以在數據包處理過程中進行加密、認證等操作,確保數據在傳輸過程中的安全性。
6.2 具體案例
丟棄網絡包:有開發者編寫了一個簡單的內核模塊,通過註冊 Netfilter 鉤子函數,實現對所有網絡包的丟棄,並將這一操作記錄到 / var/log/messages 中。其實現過程如下:首先定義一個 nf_hook_ops 結構體變量 nfho,然後編寫鉤子函數 hook_func,在該函數中打印 “packet dropped” 並返回 NF_DROP,表示丟棄數據包。在模塊加載時,將鉤子函數、協議類型、鉤子觸發點編號等信息設置到 nfho 結構體中,並調用 nf_register_hook 註冊鉤子函數。當模塊卸載時,調用 nf_unregister_hook 註銷鉤子函數。
針對 UDP 包過濾:另一個案例是針對 UDP 包進行過濾。同樣通過編寫內核模塊,在 Netfilter 的鉤子函數中獲取 IP 頭部和 UDP 頭部,檢查協議字段是否爲 UDP(協議號爲 17),如果是則進行相應處理。在這個案例中,首先定義了 nf_hook_ops 結構體變量 nfho 以及 udphdr 和 iphdr 結構體指針。在鉤子函數中,通過 skb_network_header 和 skb_transport_header 函數獲取網絡頭部和傳輸頭部,然後檢查協議字段。如果是 UDP 包,則打印 “got udp packet” 並返回 NF_DROP,表示丟棄該數據包。在模塊加載和卸載時,分別進行註冊和註銷鉤子函數的操作。
禁止 IP 協議:可以使用 iptables 的 u32 匹配方法來禁止具有特定 IP 選項的數據包。例如,通過檢查數據包的 IHL(互聯網標題長度)字段,如果大於 20(沒有選項的 IPv4 標頭長度),則丟棄數據包。可以使用 iptables -A INPUT -m u32! --u32 '0 & 0x0F000000 >>24 = 5' -j DROP 命令來實現,該命令表示如果數據包的前 32 位值經過處理後不等於 5(沒有選項的 IHL 值),則丟棄該數據包。
禁止特定端口及 PING:可以使用 iptables 來禁止特定端口的訪問。例如,要禁止所有人訪問 22/ssh 端口,可以使用 iptables -A INPUT -p tcp --dport 22 -j DROP 命令。如果要禁止特定網段訪問服務器主機的 22 端口,可以使用 iptables -A INPUT -s 172.16.1.0/24 -d 172.16.1.188 -p tcp --dport 22 -j DROP 命令。此外,還可以使用 iptables 禁止 ICMP 包,實現其他機器不能 ping 通本機的效果,例如使用 iptables -I INPUT -p icmp --icmp-type 8 -j DROP 命令,其中 --icmp-type 8 表示能在本機 ping 通其他機器,而其他機器不能 ping 通本機。
七、Netfilter 的特點及優勢
①強大的擴展性
Netfilter 最大的優點就在於其擴展性好,可以任意定義新的模塊擴展其功能。用戶瀏覽 netfilter.org 就會知道,它裏面融合了大量的策略,如 ebtables、arptables、nft 等都是 Netfilter 的擴展之一。Liuux 中使用的僅僅是它的一個很小的部分,大部分的內容作爲可插拔的 module 處於待命狀態,爲用戶提供了極大的靈活性來滿足不同的網絡管理需求。
②易於理解的結構
Netfilter 的結構比較容易理解,即使是新手也能很快掌握其規則配置方法。它的四表五鏈架構清晰明瞭,用戶可以通過 iptables 等工具直觀地配置規則,對網絡數據包進行過濾、修改和轉發等操作。例如,filter 表用於數據包過濾,nat 表用於網絡地址轉換,mangle 表用於修改數據包頭部信息,raw 表用於決定數據包是否被狀態跟蹤機制處理。每個表中的鏈對應着不同的處理階段和功能,用戶可以根據實際需求進行配置。
③豐富的功能和可配置性
Netfilter 允許用戶和系統管理員配置規則來過濾、修改和轉發網絡數據包,實現多種功能。例如,可以通過設置規則控制哪些流量被允許進出系統,實現數據包過濾;支持網絡地址轉換,使得私有網絡中的設備可以共享一個公共 IP 地址訪問外部網絡;可以跟蹤網絡連接的狀態,動態地管理連接狀態。同時,Netfilter 還提供了多個鉤子點,在數據包進入系統和離開系統時進行關鍵處理。常見的鉤子點包括 PREROUTING、INPUT、FORWARD、OUTPUT 和 POSTROUTING,用戶可以在這些鉤子點上註冊處理數據包的回調函數,對數據包進行特定的處理。
④高效的工作流程
Netfilter 的工作流程經過多個鉤子點處理數據包,確保數據包按照既定的策略進行轉發、過濾或其他操作。當數據包進入網絡棧時,會經過 Netfilter 的處理點。根據定義的規則,數據包可能會被接受、拒絕或修改。例如,在 NF_IP_PRE_ROUTING 掛載點,數據包剛剛進入網絡層,此時可以進行目的地址轉換等操作。內置鏈在數據包處理過程中也起着重要作用,不同的鏈對應着不同的處理階段和功能。這種工作流程充分發揮了 Netfilter 的靈活性和可擴展性,爲網絡安全提供了堅實的保障。
⑤高度的靈活性和控制能力
Netfilter 在 Linux 網絡棧中扮演着關鍵角色,提供了高度的靈活性和控制能力。用戶可以根據自己的需求配置防火牆規則、進行網絡地址轉換、實施流量控制等操作。例如,可以使用 iptables 等工具靈活地配置規則,對特定 IP 地址、端口號、協議類型等進行精細過濾。同時,Netfilter 還支持多種協議棧,目前 Linux 2.6 版內核的 Netfilter 支持 IPv4、IPv6 以及 DECnet 等協議棧,爲用戶提供了廣泛的應用場景。
八、Netfilter 的不足之處
Netfilter 雖然在網絡安全領域發揮着重要作用,但也存在一些不足之處。
①狀態表結構效率不高
Netfilter 的狀態表使用鏈表結構,雖然是 HASH 方式,但鏈接數非常大時,每個 HASH 表內的參數還是很多的,順序查找起來就比較慢。例如,專業路由器大都使用類似二叉樹結構實現快速查找,而 Linux 內核的 Netfilter 卻採用 HASH 表,這在處理大量網絡數據包時可能會導致效率下降。
②目標功能單一導致效率低
某些目標功能太單一,導致某些情況下效率不高。如要對某類數據進行流量限制,對超過限值的包記錄這樣的需求,就需要三條規則,一條是家流量限制匹配 - j ACCEPT,第二條 - j LOG --log-prefix...,第三條纔是 - j DROP,同樣的規則匹配要匹配三次。如果不要求記錄的話會簡單一些,用一個子鏈來實現流量限制,就不用重複匹配條件了。但 netfilter 把日誌作爲一個目標而不是象 2.2 的 ipchains 那樣記錄日誌是個規則選項,效率總是不高。
③缺乏某些功能
Netfilter 某些功能不太好實現,如 SYN 代理,SYN 代理在 freebsd、openbsd 等內核都自帶,但在 linux 中卻遲遲未能包括,確實在 netfilter 這個架構下這個功能不太好弄。
④對攻擊識別和單個 IP 連接數限制困難
對需要進行統計的攻擊識別比較困難,如各種 flood 攻擊,無法定義 flood 模式,只能簡單的進行流量限制,限制了非法包的同時也限制了合法包。很難對一個網段內單個 IP 的連接數進行限制,這樣一臺機器染毒瘋狂發包時不能把肇事 IP 挑出來,只能整個網段都限制,一損具損;同樣如果想對內容進行過濾,如 string 匹配,也是同樣情況。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/wzZ5TeAl2mYYCNAT2CvkGQ