• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 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_EXPANDED,
       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永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>