åç½®ã
プロのためのLinuxシステム・ネットワーク管理技術ã®ç¬¬2ç« ï¼iptablesã®è§£èª¬ï¼ã«ã
ã»FORWARDãã§ã¼ã³ã«ãããã£ã«ã¿ãªã³ã°å¦çã®åå¾ã«ãã±ããã®ã«ã¼ãã£ã³ã°å¦çãå ¥ã
ã¨ã®è¨è¿°ãããã®ã§ããã
ã»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ã«æ¬¡ã®è¡ãå ãæ ¼ç´ããé¨åã¯ãå°ãé·ããªãã®ã§ãã³ã¼ã«ããã¼ã ãè¨è¼ãã¦ããã¾ãããã©ã¯ã¼ã対象ãã±ããã®å ´åã¯ã
net/ipv4/route.c
ã»ip_route_input() -> ip_mkroute_input() -> __mkroute_input()
ã¨æµãã¦ã
rth->u.dst.input = ip_forward; rth->u.dst.output = ip_output;
ã«è¡ãã¾ããdst.outputã«å ¥ã£ãip_output()ã¯ããå°ãå¾ã§ç»å ´ãã¾ãã
ãã¼ã«ã«åä¿¡ãã±ããã®å ´åã¯ã
net/ipv4/route.c
ã»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ãã§ã¼ã³ã®ãã£ã«ã¿ãªã³ã°ã¸ã¨å¦çãé²ãã§ãã¾ãã