totofugaのブログ

ネットワークとかc言語、perlの話。

iptablesの勉強(4)

ユーザ定義チェインについて

f:id:totofuga:20171119191701p:plain

ユーザ定義チェイン

ユーザ定義チェインは先頭と末尾に固定のipt_entryを持ったエントリとして定義される。

先頭のipt_entryはチェインの名前を示す。 チェインの名前はxt_get_revision.nameに格納される。

末尾のipt_entryはチェインから戻るための情報を持っていて xt_standard_targetとなる。 ビルドインチェインの場合末尾にはポリシーによってACCEPTやDROPが入っていたが、 ユーザ定義チェインの場合はチェインから戻るためのRETURNが入る。

ユーザ定義チェインへのジャンプ

チェインへのJUMPターゲット(-j <ユーザ定義チェイン>)を指定した場合、 ユーザ空間のiptablesコマンド内で、ユーザ定義名ではなく、xt_standard_targetのverdictとして次のエントリへのオフセットが格納される

struct xt_standard_target {        
    struct xt_entry_target target; 
    int verdict;                   
};

verdictの値はカーネル空間でチェックされ、同時に無限ループしていないかもチェックされる。

スタックについて

スタックのデータ構造

xt_table_infoにはJUMPから戻れるようにスタックを用意している。

    unsigned int stacksize;
    unsigned int __percpu *stackptr;
    void ***jumpstack;
  • stacksize => チェインはループすることがないのでスタックサイズはユーザチェインの数となる。
  • stackptr => 現在のスタック位置(CPUごとに保持する)
  • jumpstack[cpu個数][stacksize] => jumpした時のipt_entryのポインタをCPUごとに保存する

ipt_do_tableにて以下のように設定と取り出しを行なっている

jumpstack  = (struct ipt_entry **)xt_table_info->jumpstack[cpu];

// JUMP時
jumpstack[(*stackptr)++] = e;

// RETURN時
e = jumpstack[--*stackptr]; 
e = ipt_next_entry(e);

スタックサイズの決定

スタックサイズはnet/ipv4/netfilter/ip_tables.c:translate_table内で XT_ERROR_TARGETの数をカウントしている。 XT_ERROR_TARGETはtargetとして設定されることがないので XT_ERROR_TARGETの数 == チェインの数となる模様

このターゲットに処理が来ることはないが、もしも処理が来た場合には ログを出してドロップする処理になっている。

ユーザ定義チェインのループチェック

ユーザ定義チェインは同じチェインにループしないように

do_ipt_set_ctl
    do_replace
        translate_table
            mark_source_chains

にてチェインのループチェックをおこなっている。