2012-02-08
FORWARDチェーンによるフィルタリングとルーティング処理のタイミング
前置き
プロのためのLinuxシステム・ネットワーク管理技術の第2章(iptablesの解説)に、
・FORWARDチェーンによるフィルタリング処理の前後にパケットのルーティング処理が入る
との記述があるのですが、
とのご指摘をいただきました。
結論を言うと、私の勘違いで、ご指摘の通り、ルーティング処理はFORWARDチェーンに入る前(PREROUTINGチェーンの後)にすべて完了しており、FORWARDチェーンを抜けたパケットは、そのまま、POSTROUTINGチェーンに送り込まれます。
お詫びを兼ねて該当部分のカーネルソースを解説しておきます。m(_ _)m
#書籍の方は、2刷のタイミングで修正するようにします。
前提知識
まず、前提知識を2つほど。
・Linux KernelのL2/L3スタックが扱う個々のパケット情報は、基本的にすべて、構造体「sk_buff *skb」に押し込まれています。L2/L3スタックは、個々のパケットについて、この構造体をいじり回していくことで、パケット送受信に伴う処理を実施してきます。
・iptables(netfilter)のフィルタリング処理は、NF_HOOK()マクロから呼び出されます。
受信パケットが転送されるまで
外部から受信したパケットのsk_buffは、まずip_rcv()で処理されます。
/* * Main IP Receive routine. */ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { ・・・ return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish);
ip_rcv()は、パケットに対するSanity Checkを行います。最後に、NF_HOOK()でPREROUTINGチェーンによるフィルタリングを行なってから、ip_rcv_finish()を呼びます。
static int ip_rcv_finish(struct sk_buff *skb) { ・・・ if (skb_dst(skb) == NULL) { int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); ・・・ return dst_input(skb);
ip_rcv_finish()は、ip_route_input()を呼んで該当パケットのルーティング処理を行います。具体的には、ルーティングテーブルを参照して、次の行き先に関する情報をskbにセットします。特に、ローカル受信パケット/フォワード対象パケットに応じて、次に呼ぶ関数を決定して、skb.dst.inputにそのポインタを格納します。その後、dst_input()を呼びます。
skb.dst.inputに次の行き先を格納する部分は、少し長くなるので、コールフローだけ記載しておきます。フォワード対象パケットの場合は、
・ip_route_input() -> ip_mkroute_input() -> __mkroute_input()
と流れて、
rth->u.dst.input = ip_forward; rth->u.dst.output = ip_output;
に行きます。dst.outputに入ったip_output()はもう少し後で登場します。
ローカル受信パケットの場合は、
・ip_route_input() -> ip_route_input_slow()
と流れて、
rth->u.dst.input= ip_local_deliver;
に行きます。
続いて、dst_input()で、実際にセットした関数が呼び出されます。
/* Input packet from network to transport. */ static inline int dst_input(struct sk_buff *skb) { return skb_dst(skb)->input(skb); }
フォワード処理の場合のip_forward()を見ておきます。
int ip_forward(struct sk_buff *skb) { ・・・ return NF_HOOK(PF_INET, NF_INET_FORWARD, skb, skb->dev, rt->u.dst.dev, ip_forward_finish);
ここで、NF_HOOK()により、FORWARDチェーンのフィルタリング処理が入って、その後、ip_forward_finish()からdst_output()へと行きます。
static int ip_forward_finish(struct sk_buff *skb) { ・・・ return dst_output(skb); }
static inline int dst_output(struct sk_buff *skb) { return skb_dst(skb)->output(skb); }
ここで、先に仕込んだ、
rth->u.dst.output = ip_output;
にしたがって、ip_output()へと行きます。
int ip_output(struct sk_buff *skb) { ・・・ return NF_HOOK_COND(PF_INET, NF_INET_POST_ROUTING, skb, NULL, dev, ip_finish_output, !(IPCB(skb)->flags & IPSKB_REROUTED)); }
ここからは、ローカルからの送出パケットと処理が合流しており、NF_HOOK(_COND)で、POSTROUTINGチェーンのフィルタリングへと処理が進んでいます。
- 160 http://tkoshima.net/wp/archives/1471
- 121 http://www.google.co.jp/url?sa=t&rct=j&q=glusterfs&source=web&cd=4&ved=0CFAQFjAD&url=http://d.hatena.ne.jp/enakai00/20110915/1316069537&ei=ftsxT_SALM3ymAW_5s2sBQ&usg=AFQjCNEZ94td5GLJsRA_a9oK6Rky0IgBtw
- 34 http://www.google.co.jp/url?sa=t&rct=j&q=RHEL6&source=web&cd=2&ved=0CEUQFjAB&url=http://d.hatena.ne.jp/enakai00/20110307/1299464439&ei=etkxT8_LMo2WmQWtqcW5BQ&usg=AFQjCNGW199Kj7lCogn3rKca4ov1tYgmBg
- 24 http://d.hatena.ne.jp/notify-NotifyUser_POST_NG_CATEGORY?aHR0cDovL2QuaGF0ZW5hLm5lLmpwL2VuYWthaTAwLzIwMTEwMzA3LzEyOTk0NjQ0Mzk=
- 24 http://t.co/JMECa4Xu
- 23 http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCIQFjAA&url=http://d.hatena.ne.jp/enakai00/20110323/1300846444&ei=GcwzT9vPGqL6mAWa6t3wAQ&usg=AFQjCNE1ao__jdjrxxQM3OG0mVI8T6k_MA
- 19 http://longurl.org
- 17 http://www.google.co.jp/url?sa=t&rct=j&q=プロのための linuxシステム・ネットワーク管理技術 メ?%8
- 17 http://www.google.co.jp/url?sa=t&rct=j&q=kvm クローニング&source=web&cd=2&ved=0CCoQFjAB&url=http://d.hatena.ne.jp/enakai00/20110422/1303474416&ei=GREzT-bdPIXNmQWgs-2-BQ&usg=AFQjCNFfezPKj3V3uI1lQ9YJZX
- 17 http://www.google.co.jp/url?url=http://d.hatena.ne.jp/enakai00/20111004/1317718773&rct=j&sa=U&ei=2NgxT8npBerJmQWw_p2yBQ&ved=0CFAQFjAH&q=cron+anacron&usg=AFQjCNEZUeFHtVyzQjTASIxbGgtSHcNHZw