netfilter中iptables表的實現(xiàn)
本文檔的Copyleft歸yfydz所有,使用GPL發(fā)布,可以自由拷貝,轉(zhuǎn)載,轉(zhuǎn)載時請保持文檔的
完整性,嚴(yán)禁用于任何商業(yè)用途。
msn: yfydz_no1@hotmail.com
來源:http://yfydz.cublog.cn
1. 前言
iptables所制定的規(guī)則都是和內(nèi)核中netfilter內(nèi)的“表(table)”相聯(lián)系的,缺省情況系統(tǒng)
中已經(jīng)自帶了3個表:filter、nat和mangle,iptables命令中的“-t”參數(shù)就是用來指定該
規(guī)則是屬于哪個表。和匹配和目標(biāo)一樣,netfilter也提供了模塊化的表功能擴展,用戶可
以根據(jù)需要自己編寫新的表。
以下內(nèi)核代碼版本為2.4.26。
2. 表、規(guī)則、hook點之間的相互關(guān)系
netfilter的架構(gòu)的基本過濾原理是網(wǎng)絡(luò)棧中定義5個hook點,在每個hook點進行檢查,就是
按優(yōu)先級執(zhí)行掛接在該點上的所有struct nf_hook_ops結(jié)構(gòu)的處理函數(shù),只有這些函數(shù)都返
回NF_ACCEPT才表示該數(shù)據(jù)包允許通過該hook點。
每個表中都要定義一些起效的hook點,這些hook點就對應(yīng)了iptables規(guī)則中的鏈,如
filter表的起效hook點是NF_IP_LOCAL_IN、 NF_IP_FORWARD和NF_IP_LOCAL_OUT,對應(yīng)
iptables規(guī)則filter表中的INPUT、FORWARD和OUTPUT鏈,在每個合法hook點都定義一個
struct nf_hook_ops結(jié)構(gòu),每個struct nf_hook_ops結(jié)構(gòu)都有一個基本處理函數(shù),如
filter表NF_IP_LOCAL_IN、NF_IP_FORWARD點的是ipt_hook()函數(shù),這些函數(shù)最終都會調(diào)用
ipt_do_table()函數(shù)來進行該鏈中規(guī)則的遍歷匹配操作,但要注意的是ipt_hook()等基本處
理函數(shù)的參數(shù)中并沒有struct ipt_table結(jié)構(gòu)的參數(shù),所以目前這些表都是靜態(tài)存在而不支
持動態(tài)分配。
filter表在net/ipv4/netfilter/iptable_filter.c中定義,nat表在
net/ipv4/netfilter/ip_nat_rule.c中定義,mangle表在
net/ipv4/netfilter/iptable_mangle.c中定義.nat表和其他兩個
稍有不同,其他兩個表結(jié)構(gòu)和hook_ops都在同一個文件中定義了,而nat的hook_ops是在
net/ipv4/netfilter/ip_nat_standalone.c中定義的。
3. 數(shù)據(jù)結(jié)構(gòu)
每個表都需要一個struct ipt_table結(jié)構(gòu)來進行描述,建立一個新表就是要填寫這樣一個結(jié)
構(gòu):
/* include/linux/netfilter_ipv4/ip_tables.h */
struct ipt_table
{
struct list_head list;
/* A unique name... */
char name[IPT_TABLE_MAXNAMELEN];
/* Seed table: copied in register_table */
struct ipt_replace *table;
/* What hooks you will enter on */
unsigned int valid_hooks;
/* Lock for the curtain */
rwlock_t lock;
/* Man behind the curtain... */
struct ipt_table_info *private;
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
};
結(jié)構(gòu)中包括以下參數(shù):
struct list_head list:這是將該結(jié)構(gòu)掛接到table鏈表中
char name[]:表名稱
struct ipt_replace *table:struct ipt_replace結(jié)構(gòu)定義該表基本屬性
unsigned int valid_hooks:該表合法的掛接點位置
rwlock_t lock:表操作時的讀寫鎖
struct ipt_table_info *private:這實際上是表中規(guī)則項表的索引指針,初始化為NULL
struct module *me:指向模塊本身,統(tǒng)計模塊是否被使用
其中struct ipt_table_info結(jié)構(gòu)定義為:
/* include/linux/netfilter_ipv4/ip_tables.h */
struct ipt_table_info
{
/* Size per table */
unsigned int size;
/* Number of entries: FIXME. --RR */
unsigned int number;
/* Initial number of entries. Needed for module usage count */
unsigned int initial_entries;
/* Entry points and underflows */
unsigned int hook_entry[NF_IP_NUMHOOKS];
unsigned int underflow[NF_IP_NUMHOOKS];
/* ipt_entry tables: one per CPU */
char entries[0] ____cacheline_aligned;
};
結(jié)構(gòu)參數(shù)說明如下:
unsigned int size:表的大小
unsigned int number:規(guī)則數(shù)量
unsigned int initial_entries:初始化時的規(guī)則數(shù)
unsigned int hook_entry[NF_IP_NUMHOOKS]:各hook點起始規(guī)則的偏移
unsigned int underflow[NF_IP_NUMHOOKS]:各hook點結(jié)束規(guī)則的偏移
char entries[0]:實際的規(guī)則數(shù)組
其中struct ipt_replace結(jié)構(gòu)定義為:
/* include/linux/netfilter_ipv4/ip_tables.h */
struct ipt_replace
{
/* Which table. */
char name[IPT_TABLE_MAXNAMELEN];
/* Which hook entry points are valid: bitmask. You can't
change this. */
unsigned int valid_hooks;
/* Number of entries */
unsigned int num_entries;
/* Total size of new entries */
unsigned int size;
/* Hook entry points. */
unsigned int hook_entry[NF_IP_NUMHOOKS];
/* Underflow points. */
unsigned int underflow[NF_IP_NUMHOOKS];
/* Information about old entries: */
/* Number of counters (must be equal to current number of entries). */
unsigned int num_counters;
/* The old entries' counters. */
struct ipt_counters *counters;
/* The entries (hang off end: not really an array). */
struct ipt_entry entries[0];
};
結(jié)構(gòu)參數(shù)說明如下:
char name[IPT_TABLE_MAXNAMELEN]:表名稱
unsigned int valid_hooks:有效hook點
unsigned int num_entries:規(guī)則數(shù)
unsigned int size:規(guī)則大小
unsigned int hook_entry[NF_IP_NUMHOOKS]:各hook點起始規(guī)則的偏移
unsigned int underflow[NF_IP_NUMHOOKS]:各hook點結(jié)束規(guī)則的偏移
unsigned int num_counters:計數(shù)器的數(shù)量,各規(guī)則都有一個
struct ipt_counters *counters:計數(shù)器
struct ipt_entry entries[0]:規(guī)則入口
規(guī)則的存儲是相當(dāng)于數(shù)組方式存儲的,只是數(shù)組大小會動態(tài)修改,每個表的所有規(guī)則都形成
一個數(shù)組,而且是按hook點的順序存儲,如對于filter表,數(shù)組開始是INPUT鏈的規(guī)則,后
面是FORWARD鏈規(guī)則,然后是OUTPUT鏈的規(guī)則,最后是處理錯誤的規(guī)則,這就是iptables規(guī)
則使用“-L -v -v”時看到的實際的規(guī)則存儲方式。各個hook點的規(guī)則起始和結(jié)束規(guī)則是靠
struct ipt_table_info結(jié)構(gòu)中的hook_entry[]和underflow[]來確定的。按數(shù)組方式實現(xiàn)在
遍歷處理時會比較快,但編輯時就比較麻煩了,會伴隨大量的內(nèi)存重分配和拷貝操作。
在具體實現(xiàn)表時,在初始化ipt_table結(jié)構(gòu)的struct ipt_replace結(jié)構(gòu)參數(shù)時,除了struct
ipt_replace結(jié)構(gòu)本身的參數(shù)外,還自動添加描述各條鏈的缺省動作的規(guī)則,也就是說制定
iptables規(guī)則時用“-P”定義的鏈的缺省動作也是靠規(guī)則來實現(xiàn)的,如對于filter表的定義
如下:
/* net/ipv4/netfilter/iptable_filter.c */
struct ipt_standard
{
struct ipt_entry entry;
struct ipt_standard_target target;
};
struct ipt_error_target
{
struct ipt_entry_target target;
char errorname[IPT_FUNCTION_MAXNAMELEN];
};
struct ipt_error
{
struct ipt_entry entry;
struct ipt_error_target target;
};
static struct
{
struct ipt_replace repl;
struct ipt_standard entries[3]; // 3個hook點,各自一條缺省規(guī)則
struct ipt_error term; // 錯誤處理規(guī)則
} initial_table __initdata
4. 相關(guān)函數(shù)
表的處理函數(shù)相對比較少,使用函數(shù) int ipt_register_table(struct ipt_table *)來登
記表使之生效,而使用void ipt_unregister_table(struct ipt_table *)取消表的登記。
在登記時,會初始化數(shù)據(jù)中的struct ipt_replace結(jié)構(gòu)的數(shù)據(jù)轉(zhuǎn)化到struct
ipt_table_info結(jié)構(gòu)中。登記后用iptables規(guī)則就可以用“-t table_name”來配置新表中
的規(guī)則了。
每個表通過ipt_do_table()函數(shù)(net/ipv4/netfilter/ip_tables.c)來進行表中的規(guī)則匹配
最終確定對數(shù)據(jù)包的動作。
5. 結(jié)論
netfilter的表處理也可以模塊化實現(xiàn),新表的添加可以以當(dāng)前系統(tǒng)自帶的表為藍(lán)本來編寫
,只是要確定好各個hook點處理函數(shù)的優(yōu)先級來確定相對其他表的執(zhí)行順序。一般情況下不
需要添加新表,但在某些特殊功能,如實現(xiàn)虛擬系統(tǒng),多個表分開過濾會更方便處理一些。
后記:本文初稿在基本寫完時突然掉電,沒存,這是第二版了,內(nèi)容少了一些。
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請
點擊舉報。