iptablesの勉強(4)
ユーザ定義チェインについて
ユーザ定義チェイン
ユーザ定義チェインは先頭と末尾に固定の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
にてチェインのループチェックをおこなっている。