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.1 Netfilter的Hook機制
Netfilter的通用框架不依賴于具體的協議,而是為每種網絡協議定義一套Hook函數。這些Hook函數在數據報經過協議棧的幾個關鍵點時被調用,在這幾個點中,協議棧將數據報以及Hook函數標號作為參數,傳遞給Netfilter框架。
對于它在網絡堆棧中增加的這些Hook,內核的任何模塊可以對每種協議的一個或多個Hook進行注冊,實現掛接。這樣當某個數據報被傳遞給Netfilter框架時,內核能檢測到是否有任何模塊對該協議和Hook函數進行了注冊。
若注冊了,則調用該模塊的注冊時使用的“回調”函數,這樣這些模塊就有機會檢查、修改、丟棄該數據報及指示Netfilter將該數據報傳入用戶空間隊列。
這樣,Hook提供了一種方便的機制:在數據報通過Linux內核的不同位置上截獲和操作處理數據報。
3.2 iptables基礎模塊
iptables基礎模塊實現了三個表來篩選各種數據報,具體的講,Linux2.4內核提供了這三種數據報的處理功能是相互間獨立的模塊,都基于Netfilter的Hook函數和各種表、鏈實現的。這三個表包括:filter表、nat表以及mangle表。具體功能模塊:
- 數據報過濾模塊
- 連接跟蹤模塊
- 網絡地址轉換模塊(NAT)
- 數據報修改模塊(mangle)
- 其他高級功能模塊
3.3 Netfilter 的架構
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。
防止配置出錯導致無法連接服務器
在配置企業級防火墻時,需要注意防止配置出錯導致無法連接服務器??梢栽谂渲们斑M行備份,以便在出現問題時能夠快速恢復。同時,可以使用其他工具配置和管理 Netfilter 規則,如 firewalld。firewalld 是一個動態防火墻管理器,它可以動態修改單條規則,不需要像 iptables 那樣,修改了規則后必須全部刷新才可以生效。firewalld 的配置方法主要有三種:firewall-config、firewall-cmd 和直接編輯 xml 文件。其中 firewall-config 是圖形化工具,firewall-cmd 是命令行工具。通過使用 firewalld,可以更加方便地管理防火墻規則,提高配置的準確性和可靠性。
使用其他工具配置和管理 Netfilter 規則
除了 iptables 和 firewalld,還有其他工具可以配置和管理 Netfilter 規則。例如,Juniper 防火墻配置備份中,可以通過多種方式備份和恢復防火墻配置,包括設備重啟動、操作系統備份和恢復、配置文件備份和恢復等。通過這些工具,可以更加全面地管理企業級防火墻,提高網絡安全水平。
六、Netfilter的應用案例
6.1 Netfilter 在不同場景中的應用
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 匹配,也是同樣情況。