Chinaunix首页 | 论坛 | 博客
  • 博客访问: 963432
  • 博文数量: 58
  • 博客积分: 10192
  • 博客等级: 上将
  • 技术积分: 1845
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-22 21:24
文章分类

全部博文(58)

文章存档

2011年(11)

2010年(12)

2009年(20)

2008年(15)

分类: LINUX

2010-12-18 12:11:16

.内核会在每层上都把流量传送至正确的协议,就是调用该协议所注册的处理程序函数。IP协议注册的处理程序函数就是ip_rcv函数(可以查看我写的《IP协议注册流程》)。

 

  1. /*

  2.  * Main IP Receive routine.

  3.  */

  4. int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)

  5. {

  6. struct iphdr *iph;


  7. /* When the interface is in promisc. mode, drop all the crap

  8.  * that it receives, do not try to analyse it.

  9.                * 如果数据帧的L2的目的地址和接收接口的地址不同时,

  10.  * skb->pkt_type就会设置为 PACKET_OTHERHOST。

  11.                * 通常情况下都会被NIC本身丢弃

  12.  */

  13. if (skb->pkt_type == PACKET_OTHERHOST)

  14. goto drop;


  15. IP_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);


  16. /*

  17.                * skb的引用计数是否大于1?

  18.                * 如果大于1,克隆一份缓冲区副本使其可以修改其封包

  19.                *

  20.                */

  21. if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {

  22. IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);

  23. goto out;

  24. }


  25. /*

  26.                * 判断skb->data所指区域的数据区块至少和IP报头一样大

  27.                * sizeof(struct iphdr) <= skb_headlen(skb)

  28.                */

  29. if (!pskb_may_pull(skb, sizeof(struct iphdr)))

  30. goto inhdr_error;


  31. /*

  32.                * skb空间可能会被pskb_may_pull改变

  33.                * iph需要重新赋值

  34.                */

  35. iph = skb->nh.iph;


  36. /*

  37.  * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.

  38.  *

  39.  * Is the datagram acceptable?

  40.  *

  41.  * 1. Length at least the size of an ip header

  42.  * 2. Version of 4

  43.  * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]

  44.  * 4. Doesn't have a bogus length

  45.  */


  46. /* 5*4 == ip header ,IP头至少为20个字节 */

  47. if (iph->ihl < 5 || iph->version != 4)

  48. goto inhdr_error;


  49. /*

  50.                * 完整的IP报头大小:ip header length + ip options length

  51.                */

  52. if (!pskb_may_pull(skb, iph->ihl*4))

  53. goto inhdr_error;


  54. iph = skb->nh.iph;


  55. if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)

  56. goto inhdr_error;


  57. {

  58. __u32 len = ntohs(iph->tot_len);

  59. if (skb->len < len || len < (iph->ihl<<2))

  60. goto inhdr_error;


  61. /* Our transport medium may have padded the buffer out. Now we know it

  62.  * is IP we can trim to the true length of the frame.

  63.  * Note this now means skb->len holds ntohs(iph->tot_len).

  64.  */

  65. if (skb->len > len) {

  66. __pskb_trim(skb, len);

  67.                                           /*

  68.                                            * __pskb_trim会修改skb,

  69.                                            * 硬件支持校验的话,就会出错

  70.                                            * 所以重置为 CHECKSUM_NONE

  71.                                            */

  72. if (skb->ip_summed == CHECKSUM_HW)

  73. skb->ip_summed = CHECKSUM_NONE;

  74. }

  75. }


  76. return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,

  77.        ip_rcv_finish);


  78. inhdr_error:

  79. IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);

  80. drop:

  81.         kfree_skb(skb);

  82. out:

  83.         return NET_RX_DROP;

  84. }

 

.ip_rcv所做的仅是封包的基本健康检查。真正数据包操作是ip_rcv_finish完成的。

 

  1. static inline int ip_rcv_finish(struct sk_buff *skb)

  2. {

  3. struct net_device *dev = skb->dev;

  4. struct iphdr *iph = skb->nh.iph;


  5. /*

  6.  * skb->dst包含目的地的路由信息。

  7.  * 如果没有包含目的地的路由信息,就会调用ip_route_input()。

  8.  * 询问路由子系统往哪里发送,如果路由子系统没找到路由,就丢弃skb。

  9.  */

  10. if (skb->dst == NULL) {

  11. if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))

  12. goto drop;

  13. }


  14.               ...省略

  15. if (iph->ihl > 5) {

  16. struct ip_options *opt;


  17. /* It looks as overkill, because not all

  18.    IP options require packet mangling.

  19.    But it is the easiest for now, especially taking

  20.    into account that combination of IP options

  21.    and running sniffer is extremely rare condition.

  22.                                       --ANK (980813)

  23. */


  24. if (skb_cow(skb, skb_headroom(skb))) {

  25. IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);

  26. goto drop;

  27. }

  28. iph = skb->nh.iph;


  29.                             /*

  30.                              * 解析报头中携带的IP选项

  31.                              * 如果封包是由来源地路由的话,

  32.                              * 则需要分析选项是否配置“严格和松散路由选项”

  33.                              */

  34. if (ip_options_compile(NULL, skb))

  35. goto inhdr_error;


  36. opt = &(IPCB(skb)->opt);

  37. if (opt->srr) {

  38.                                           /*

  39.                                            * 以下操作主要判断数据包是发往本地还是转发

  40.                                            * 对skb->dst(路由信息)进行赋值操作

  41.                                            */

  42. struct in_device *in_dev = in_dev_get(dev);

  43. if (in_dev) {

  44. if (!IN_DEV_SOURCE_ROUTE(in_dev)) {

  45. if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit())

  46. printk(KERN_INFO "source route option %u.%u.%u.%u -> %u.%u.%u.%u\n",

  47.        NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));

  48. in_dev_put(in_dev);

  49. goto drop;

  50. }

  51. /* 转发还是本地发送 */

  52. in_dev_put(in_dev);

  53. }

  54. if (ip_options_rcv_srr(skb))

  55. goto drop;

  56. }

  57. }

  58. /*
  59.                 * dst_input(存储与skb->dst->input)会根据IP包是发送本地还是转发

  60.                 * 发往本地(dst_input等于ip_local_deliver)调用ip_local_deliver

  61.                 * 转发调用ip_forward

  62.                 */

  63. return dst_input(skb);


  64. inhdr_error:

  65. IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);

  66. drop:

  67.         kfree_skb(skb);

  68.         return NET_RX_DROP;

  69. }

 

选项处理

1.struct ip_options结构体:

 

  1. struct ip_options表示IP选项


  2. struct ip_options {


  3.     __be32 faddr;


  4.     unsigned char optlen;


  5.     unsigned char srr;


  6.     unsigned char rr;


  7.     unsigned char ts;


  8.     unsigned char is_data:1,


  9.                     is_strictroute:1,


  10.                     srr_is_hit:1,


  11.                     is_changed:1,


  12.                     rr_needaddr:1,


  13.                     ts_needtime:1,


  14.                     ts_needaddr:1;


  15.     unsigned char router_alert;


  16.     unsigned char cipso;


  17.     unsigned char __pad2;


  18.     unsigned char __data[0];


  19. };


  20.     faddr用于在IPOPT_LSRR和IPOPT_SSRR选项时,记录下一站的IP地址


  21.     optlen是IP首部中选项所占据的长度


  22.     srr记录IPOPT_LSRR或IPOPT_SSRR选项在IP首部中的偏移量(选项的第一个字节的地址减去IP首部的第一个 字节的地址)


  23.     rr用于记录 IPOPT_RR选项在IP首部中的偏移量


  24.     ts用于记录IPOPT_TIMESTAMP选项在IP首部中的偏移量


  25.     is_data表示该IP选项拥有数据,选项数据存放在__data中


  26.     is_strictroute表示该选项是IPOPT_SSRR,而不是IPOPT_LSRR


  27.     srr_is_hit跟源站路由选项相关,对IP选项作过任何的修改,需要把is_changed置1


  28.     rr_needaddr表示有IPOPT_RR选项,需要记录IP地址


  29.     ts_needtime表示IPOPT_TIMESTAMP选项需要记录时间戳


  30.     ts_needaddr表示IPOPT_TIMESTAMP选项需要记录IP地址


  31.     router_alert用于IPOPT_RA选项

 

2.ip_options_compile函数主要是分析skb中的IP选项。

  1. int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)

  2. {

  3. int l;

  4. unsigned char * iph;

  5. unsigned char * optptr;

  6. int optlen;

  7. unsigned char * pp_ptr = NULL;

  8. struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL;


  9. if (!opt) {

  10.                             /* opt == NULL 处理入口的封包 */

  11. opt = &(IPCB(skb)->opt);

  12. memset(opt, 0, sizeof(struct ip_options));

  13. iph = skb->nh.raw;

  14. opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr);

  15. optptr = iph + sizeof(struct iphdr);

  16. opt->is_data = 0;

  17. } else {

  18.                             /* opt != NULL 封包正被传输 */

  19. optptr = opt->is_data ? opt->__data : (unsigned char*)&(skb->nh.iph[1]);

  20. iph = optptr - sizeof(struct iphdr);

  21. }


  22. for (l = opt->optlen; l > 0; ) {

  23. switch (*optptr) {/* 单字节选项 */

  24.       case IPOPT_END:/* 当IP选项不是4字节倍数时,以IPOPT_END选项为IP报头补白 */

  25. for (optptr++, l--; l>0; optptr++, l--) {

  26. if (*optptr != IPOPT_END) {

  27. *optptr = IPOPT_END;

  28. opt->is_changed = 1;

  29. }

  30. }

  31. goto eol;

  32.       case IPOPT_NOOP:/* 填补选项之间的空白 */

  33. l--;

  34. optptr++;

  35. continue;

  36. }

  37. optlen = optptr[1];

  38. if (optlen<2 || optlen>l) {

  39. pp_ptr = optptr;

  40. goto error;

  41. }

  42. switch (*optptr) {/* 多字节选项 */

  43.       case IPOPT_SSRR:

  44.       case IPOPT_LSRR:

  45. if (optlen < 3) {

  46. pp_ptr = optptr + 1;

  47. goto error;

  48. }

  49. if (optptr[2] < 4) { /* optptr[2]存放的偏移量 */

  50. pp_ptr = optptr + 2;

  51. goto error;

  52. }

  53. /* NB: cf RFC-1812 5.2.4.1 */

  54. if (opt->srr) {

  55. pp_ptr = optptr;

  56. goto error;

  57. }

  58. if (!skb) {/* skb == NULL解析一个由本地产生的外出封包 */

  59. if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) {

  60. pp_ptr = optptr + 1;

  61. goto error;

  62. }

  63.                                                          /* &optptr[3]表示第一个IP地址的指针 */

  64. memcpy(&opt->faddr, &optptr[3], 4);

  65. if (optlen > 7)

  66. memmove(&optptr[3], &optptr[7], optlen-7);

  67. }

  68.                                            /* optptr[0] == IPOPT_SSRR表示严格路由否则为松散路由 */

  69. opt->is_strictroute = (optptr[0] == IPOPT_SSRR);

  70. opt->srr = optptr - iph;

  71. break;

  72.       case IPOPT_RR:/* Record Route选项 */

  73. if (opt->rr) {

  74. pp_ptr = optptr;

  75. goto error;

  76. }

  77. if (optlen < 3) {

  78. pp_ptr = optptr + 1;

  79. goto error;

  80. }

  81. if (optptr[2] < 4) {

  82. pp_ptr = optptr + 2;

  83. goto error;

  84. }

  85. if (optptr[2] <= optlen) {

  86. if (optptr[2]+3 > optlen) {

  87. pp_ptr = optptr + 2;

  88. goto error;

  89. }

  90. if (skb) {/* 处理入口封包 */

  91. memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);

  92. opt->is_changed = 1;/* 重新计算校验和 */

  93. }

  94. optptr[2] += 4; /* 偏移加上4 */

  95. opt->rr_needaddr = 1; /* 还有空间,继续把IP地址写入IP报头 */

  96. }

  97. opt->rr = optptr - iph;

  98. break;

  99.       case IPOPT_TIMESTAMP:

  100. if (opt->ts) {

  101. pp_ptr = optptr;

  102. goto error;

  103. }

  104. if (optlen < 4) {

  105. pp_ptr = optptr + 1;

  106. goto error;

  107. }

  108. if (optptr[2] < 5) {

  109. pp_ptr = optptr + 2;

  110. goto error;

  111. }

  112. if (optptr[2] <= optlen) {

  113. __u32 * timeptr = NULL;

  114. if (optptr[2]+3 > optptr[1]) {

  115. pp_ptr = optptr + 2;

  116. goto error;

  117. }

  118. switch (optptr[3]&0xF) {/* 低四位表示子命令 */

  119.       case IPOPT_TS_TSONLY:

  120. opt->ts = optptr - iph;

  121. if (skb)

  122. timeptr = (__u32*)&optptr[optptr[2]-1];

  123. opt->ts_needtime = 1;

  124. optptr[2] += 4;

  125. break;

  126.       case IPOPT_TS_TSANDADDR:

  127. if (optptr[2]+7 > optptr[1]) {

  128. pp_ptr = optptr + 2;

  129. goto error;

  130. }

  131. opt->ts = optptr - iph;

  132. if (skb) {

  133. memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);

  134. timeptr = (__u32*)&optptr[optptr[2]+3];

  135. }

  136. opt->ts_needaddr = 1;

  137. opt->ts_needtime = 1;

  138. optptr[2] += 8;

  139. break;

  140.       case IPOPT_TS_PRESPEC:

  141. if (optptr[2]+7 > optptr[1]) {

  142. pp_ptr = optptr + 2;

  143. goto error;

  144. }

  145. opt->ts = optptr - iph;

  146. {

  147. u32 addr;

  148. memcpy(&addr, &optptr[optptr[2]-1], 4);

  149. if (inet_addr_type(addr) == RTN_UNICAST)

  150. break;

  151. if (skb)

  152. timeptr = (__u32*)&optptr[optptr[2]+3];

  153. }

  154. opt->ts_needtime = 1;

  155. optptr[2] += 8;

  156. break;

  157.       default:

  158. if (!skb && !capable(CAP_NET_RAW)) {

  159. pp_ptr = optptr + 3;

  160. goto error;

  161. }

  162. break;

  163. }

  164. if (timeptr) {/* 写入时间戳并更新校验和 */

  165. struct timeval tv;

  166. __u32 midtime;

  167. do_gettimeofday(&tv);

  168. midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);

  169. memcpy(timeptr, &midtime, sizeof(__u32));

  170. opt->is_changed = 1;

  171. }

  172. } else {/* 是否溢出 */

  173. unsigned overflow = optptr[3]>>4;

  174. if (overflow == 15) {

  175. pp_ptr = optptr + 3;

  176. goto error;

  177. }

  178. opt->ts = optptr - iph;

  179. if (skb) {

  180. optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4);

  181. opt->is_changed = 1;

  182. }

  183. }

  184. break;

  185.       case IPOPT_RA:

  186. if (optlen < 4) {

  187. pp_ptr = optptr + 1;

  188. goto error;

  189. }

  190. if (optptr[2] == 0 && optptr[3] == 0)

  191. opt->router_alert = optptr - iph;

  192. break;

  193.       case IPOPT_SEC:

  194.       case IPOPT_SID:

  195.       default:

  196. if (!skb && !capable(CAP_NET_RAW)) {

  197. pp_ptr = optptr;

  198. goto error;

  199. }

  200. break;

  201. }

  202. l -= optlen;

  203. optptr += optlen;

  204. }


  205. eol:

  206. if (!pp_ptr)

  207. return 0;


  208. error:

  209. if (skb) {

  210. icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24));

  211. }

  212. return -EINVAL;

  213. }
阅读(3986) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~