Chinaunix首页 | 论坛 | 博客
  • 博客访问: 825567
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2014-02-12 15:41:20

转:http://blog.csdn.net/nerdx/article/details/12587459
  1. //  ip协议数据转发  
  2. //      ip_forward以回调函数的形式,保存在skb->dst->input,skb->dst在ip_route_input路由封包时被设置  
  3. //  调用路径:ip_rcv->ip_rcv_finish->dst_input->(skb->dst->input)  
  4.   
  5. //  函数的主要任务:  
  6. //      1.递减ttl  
  7. //      2.如果路由被重定向,则向发送方发送icmp重定向报文  
  8. //      2.如果有选项,通过ip_forward_options处理在转发时需要更新的选项  
  9. //      3.通过ip_output,将报文传递到ip发送路径上  
  10. 1.1 int ip_forward(struct sk_buff *skb)  
  11. {  
  12.     struct iphdr *iph;    
  13.     struct rtable *rt;    
  14.     struct ip_options * opt = &(IPCB(skb)->opt);//ip协议控制块,由ip_options_compile初始化  
  15.   
  16.     //XFRM是 Linux 2.6 内核为安全处理引入的一个可扩展功能框架  
  17.     if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))  
  18.         goto drop;  
  19.     //  
  20.     if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))//对router alert选项的处理  
  21.         return NET_RX_SUCCESS;  
  22.   
  23.     if (skb->pkt_type != PACKET_HOST)//重复检查,l2地址非本机,直接丢弃  
  24.         goto drop;  
  25.   
  26.     skb->ip_summed = CHECKSUM_NONE;//需要软件重新计算校验和  
  27.       
  28.     iph = skb->nh.iph;  
  29.   
  30.     if (iph->ttl <= 1)//数据帧到期  
  31.                 goto too_many_hops;  
  32.     //XFRM路由  
  33.     if (!xfrm4_route_forward(skb))  
  34.         goto drop;  
  35.   
  36.     iph = skb->nh.iph;  
  37.     rt = (struct rtable*)skb->dst;  
  38.     //处理严源路由选项  
  39.     //  rt->rt_dst 目的ip地址  
  40.     //  rt->rt_gateway 当目的主机直连时,rt_gateway匹配目的地址,当需要通过网关到达目的地址时,rt_gateway设置为下一条网关  
  41.     //  skb->dst在ip_options_rcv_srr中,使用选项中指定的ip地址作为目标地址,通过路由查找,设置为第一个非本机ip的单播路由项  
  42.     if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)//由于是严源路由选项,因此下一跳地址,必须等于源路由选项中列出的地址  
  43.         goto sr_failed;  
  44.   
  45.     if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))//检查skb是否被共享,如果被共享的话,拷贝一份,并在头部预留l3+l2  
  46.         goto drop;  
  47.     iph = skb->nh.iph;  
  48.     //递减跳数  
  49.     ip_decrease_ttl(iph);  
  50.     //RTCF_DOREDIRECT在ip_route_input_slow中被设置,表示ICMP_REDIRECT必须被送回源地址  
  51.     if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)  
  52.         ip_rt_send_redirect(skb);  
  53.   
  54.     skb->priority = rt_tos2priority(iph->tos);//通过tos字段计算skb在规则队列中的优先级  
  55.   
  56.     return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,  
  57.                ip_forward_finish);  
  58.   
  59. sr_failed:  
  60.   
  61.          icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);  
  62.          goto drop;  
  63.   
  64. too_many_hops:  
  65.         icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);  
  66. drop:  
  67.     kfree_skb(skb);  
  68.     return NET_RX_DROP;  
  69. }  
  70.   
  71. //  将转发数据传递到发送路径上  
  72.   
  73. //  调用路径:ip_forward->netfilter hooks->ip_forward_finish  
  74. 1.2 static inline int ip_forward_finish(struct sk_buff *skb)  
  75. {  
  76.     struct ip_options * opt = &(IPCB(skb)->opt);  
  77.   
  78.     IP_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS);  
  79.   
  80.     if (unlikely(opt->optlen))  
  81.         ip_forward_options(skb);//处理宽松路由选项和time stamp选项  
  82.   
  83.     return dst_output(skb);//调用ip_output  
  84. }  
  85. //  数据转发时更新的选项  
  86. //      1.record route选项  
  87. //      2.源路由选项  
  88. //      3.time stamp选项  
  89. 1.3 void ip_forward_options(struct sk_buff *skb)  
  90. {  
  91.     struct   ip_options * opt   = &(IPCB(skb)->opt);  
  92.     unsigned char * optptr;  
  93.     struct rtable *rt = (struct rtable*)skb->dst;  
  94.     unsigned char *raw = skb->nh.raw;  
  95.     //record route选项  
  96.     if (opt->rr_needaddr) {//说明为出口skb,因为入口skb在ip_options_compile已经被使用首选源地址填写  
  97.         optptr = (unsigned char *)raw + opt->rr;  
  98.         ip_rt_get_source(&optptr[optptr[2]-5], rt);  
  99.         opt->is_changed = 1;  
  100.     }  
  101.     if (opt->srr_is_hit) {//表示在源路由选项列表中,有可用的下一跳ip地址  
  102.         int srrptr, srrspace;  
  103.   
  104.         optptr = raw + opt->srr;  
  105.   
  106.         for ( srrptr=optptr[2], srrspace = optptr[1];  
  107.              srrptr <= srrspace;  
  108.              srrptr += 4  
  109.              ) {  
  110.             if (srrptr + 3 > srrspace)  
  111.                 break;  
  112.             if (memcmp(&rt->rt_dst, &optptr[srrptr-1], 4) == 0)//下一跳地址在源路由地址列表中  
  113.                 break;  
  114.         }  
  115.         if (srrptr + 3 <= srrspace) {//表示下一跳在源路由地址列表中  
  116.             opt->is_changed = 1;  
  117.             ip_rt_get_source(&optptr[srrptr-1], rt);  
  118.             skb->nh.iph->daddr = rt->rt_dst;//更新目的地址为下一跳的地址  
  119.             optptr[2] = srrptr+4;//更新选项的ptr[2]指针到下一跳  
  120.         } else if (net_ratelimit())  
  121.             printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n");  
  122.         if (opt->ts_needaddr) {  
  123.             optptr = raw + opt->ts;  
  124.             ip_rt_get_source(&optptr[optptr[2]-9], rt);  
  125.             opt->is_changed = 1;  
  126.         }  
  127.     }  
  128.     if (opt->is_changed) {  
  129.         opt->is_changed = 0;  
  130.         ip_send_check(skb->nh.iph);//计算ip校验和  
  131.     }  
  132. }  
阅读(397) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~