iptables 源碼分析
發表于:2007-05-26來源:作者:點擊數:
標簽:
這里只是一個筆記,我會將進一步修改、整理,補充后的版本發在我的個人主頁上: http://www.skynet.org.cn/viewthread.php?tid=208pid=262page=1#pid262 應用軟件源碼分析發在這里不知道是否合適:D 最近看了一下iptables的實現,現在想陸續把看的心得貼出來
這里只是一個筆記,我會將進一步修改、整理,補充后的版本發在我的個人主頁上:
http://www.skynet.org.cn/viewthread.php?tid=208&pid=262&page=1#pid262
應用軟件源碼分析發在這里不知道是否合適:D
最近看了一下iptables的實現,現在想陸續把看的心得貼出來,和大家討論一下,共同學習……
一、規則的顯示
選擇先來說明規則的顯示,因為他涉及到的東東簡單,而且又全面,了解了規則的顯示,對于其它操作的了解就顯得容易了。
iptables version 1.2.7
iptables有兩條線:ipv4 和ipv6,這里只分析v4的,因為v6偶暫時還用不著,沒有去看。
iptables_standardone.c
主函數:
int main(int argc, char *argv[])
{
int ret;
char *table = "filter"; /*默認的表是filter*/
iptc_handle_t handle = NULL;
program_name = "iptables";
program_version = IPTABLES_VERSION;
#ifdef NO_SHARED_LIBS
init_extensions();
#endif
/*進入命令行處理函數*/
ret = do_command(argc, argv, &table, &handle);
if (ret)
ret = iptc_commit(&handle);
if (!ret)
fprintf(stderr, "iptables: %s\n",
iptc_strerror(errno));
exit(!ret);
}
table表示表的名稱,就是iptables -t 后面跟的那個,默認是"filter"
iptc_handle_t handle = NULL; 這個東東很重要,現在初始化NULL,后面他被用來存儲一個表的所有規則的快照。
program_name = "iptables";
program_version = IPTABLES_VERSION;
設置名稱和版本。
#ifdef NO_SHARED_LIBS
init_extensions();
#endif
iptables很多東東,是用共享庫*.so的形式(我們安裝會,可以在諸如/lib/iptables下邊看到),如果不采用共享庫,則進行一個初始化操作。我們假設是采用共享庫的,忽略它。
然后就進入核心處理模塊:
do_command(argc, argv, &table, &handle);
do_command 函數是整個系統的核心,負責處理整個用戶的輸入命令。函數首先對一些結構、變量進行初始化,初始化完畢后,進入while循環,分析用戶輸入的命令,設置相關的標志變量,然后根據相應標志,調用對應的處理函數。
struct ipt_entry fw, *e = NULL;
int invert = 0;
unsigned int nsaddrs = 0, ndaddrs = 0;
struct in_addr *saddrs = NULL, *daddrs = NULL;
int c, verbose = 0;
const char *chain = NULL;
const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL;
const char *policy = NULL, *newname = NULL;
unsigned int rulenum = 0, options = 0, command = 0;
const char *pcnt = NULL, *bcnt = NULL;
int ret = 1;
struct iptables_match *m;
struct iptables_target *target = NULL;
struct iptables_target *t;
const char *jumpto = "";
char *protocol = NULL;
const char *modprobe = NULL;
/*初始化變量*/
memset(&fw, 0, sizeof(fw));
opts = original_opts;
global_option_offset = 0;
/* re-set optind to 0 in case do_command gets called
* a second time */
optind = 0;
/*初始化兩個全局變量*/
/* clear mflags in case do_command gets called a second time
* (we clear the global list of all matches for security)*/
for (m = iptables_matches; m; m = m->next) {
m->mflags = 0;
m->used = 0;
}
for (t = iptables_targets; t; t = t->next) {
t->tflags = 0;
t->used = 0;
}
ps:開頭一大堆的變量定義和初始化,可以在程序分析的時候看它們的作用,有兩個全局結構變量很重要:iptables_matches和iptables_targets?,F在來分析他們的作用會有一點困難,因為它們涉及到了太多方面的東東,這里,可以先把它們“想像成”用戶空間用來讀取內核規則的結構(當然,這有點錯誤)。
/*開始化析命令行*/
while ((c = getopt_long(argc, argv,
"-A:C:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:",
opts, NULL)) != -1)
{
}
這個while循環處理所有的用戶輸入,對應規則輸出-L,有:
case 'L':
add_command(&command, CMD_LIST, CMD_ZERO,
invert);
if (optarg) chain = optarg;
else if (optind < argc && argv[optind][0] != '-'
&& argv[optind][0] != '!')
chain = argv[optind++];
break;
add_command函數負責將命令標志變量command與令標志 CMD_LIST求&運算, CMD_ZERO只是一個附加的判斷標志而已,invert);然后,從命令行中取得要顯示的鏈名(如果有的話)。
與此相關的還有用t參數指定了表名:
case 't':
if (invert)
exit_error(PARAMETER_PROBLEM,
"unexpected ! flag before --table");
*table = argv[optind-1];
break;
即,如果有’t’參數,則取’t’后跟的表名:*table = argv[optind-1],否則,它應該是主函數中默認的filter表。
命令處理完畢后,即進入執行模塊:
/*因為程序定義了共享庫的話,iptables_matches/iptables_target這兩個結構運行至此是NULL,并且target也是NULL,對于規則顯示而言,這一部份的處理目前沒有實際意義,回過頭再來看這一段更易理解。final_check成員函數的作用是作最終的標志檢查,如果檢測失則,則退出*/
for (m = iptables_matches; m; m = m->next) {
if (!m->used)
continue;
m->final_check(m->mflags);
}
if (target)
target->final_check(target->tflags);
接著對參數作一些必要的合法性檢查:
/* Fix me: must put inverse options checking here --MN */
if (optind < argc)
exit_error(PARAMETER_PROBLEM,
"unknown arguments found on commandline");
if (!command)
exit_error(PARAMETER_PROBLEM, "no command specified");
if (invert)
exit_error(PARAMETER_PROBLEM,
"nothing appropriate following !");
/*對于如果要進行(CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)處理來說,如果沒有設置來源/目的地址及掩碼,則給予它們一個默認值*/
if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND)) {
if (!(options & OPT_DESTINATION))
dhostnetworkmask = "0.0.0.0/0";
if (!(options & OPT_SOURCE))
shostnetworkmask = "0.0.0.0/0";
}
/*對來源/目的地址及掩碼進行拆分,它們總是以 addr/mask的形式來出現的,根據’/’前面的字符串取得地址值,根據’/’后面的掩碼位數,求得正確的掩碼值,值得注意的是,同時要處理主機地址和
網絡地址的情況*/
if (shostnetworkmask)
parse_hostnetworkmask(shostnetworkmask, &saddrs,
&(fw.ip.smsk), &nsaddrs);
if (dhostnetworkmask)
parse_hostnetworkmask(dhostnetworkmask, &daddrs,
&(fw.ip.dmsk), &ndaddrs);
/*然后檢查來源/目的網絡地址的合法性*/
if ((nsaddrs > 1 || ndaddrs > 1) &&
(fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
exit_error(PARAMETER_PROBLEM, "! not allowed with multiple"
" source or destination IP addresses");
/*對命令行格式進行合法性檢查*/
generic_opt_check(command, options);
[color=Red]如果前面只是熱身的話,那么從現在開始,就進入實質性階段了:[/color]
do_command函數最后一個參數handle,是一個指向了具體表,如filter、nat表的句柄,這里判斷,如果handle為空,則調用iptc_init,根據table的名稱,讓handle指針指向相應的表的地址空間,也就是把對應表的所有信息從內核中取出來:
/* only allocate handle if we weren't called with a handle */
if (!*handle)
*handle = iptc_init(*table);
/*如果獲取換敗,將試著插入模塊,再次獲取*/
if (!*handle) {
/* try to insmod the module if iptc_init failed */
iptables_insmod("ip_tables", modprobe);
*handle = iptc_init(*table);
/*仍然失敗,則退出*/
if (!*handle)
exit_error(VERSION_PROBLEM,
"can't initialize iptables table `%s': %s",
*table, iptc_strerror(errno));
/*繼續進行一些簡單的判斷*/
if (command == CMD_APPEND
|| command == CMD_DELETE
|| command == CMD_INSERT
|| command == CMD_REPLACE) {
/*List命令不在判斷之列,暫時不分析*/
}
/*判斷命令標志,調用相關函數進行處理*/
switch (command) {
case CMD_LIST:
ret = list_entries(chain,
options&OPT_VERBOSE,
options&OPT_NUMERIC,
options&OPT_E
XPANDED,
options&OPT_LINENUMBERS,
handle);
}
list_entries是規則顯示的主要處理函數。
Options是顯示的標志變量:
OPT_VERBOSE:對應-v
OPT_NUMERIC:對應-n
OPT_EXPANDED:對應-x
OPT_LINENUMBERS: -l
看來很簡單,說了這么大一圈子,就是調用 iptc_init獲取表的規則信息,調用list_entries函數顯示規則。
原文轉自:http://www.kjueaiud.com
老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月
|