加入收藏 | 设为首页 | 会员中心 | 我要投稿 三明站长网 (https://www.0598zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[十四]:IP选项

发布时间:2016-09-28 22:37:56 所属栏目:Linux 来源:站长网
导读:副标题#e# 内核版本:2.6.34 在发送报文时,可以调用函数setsockopt()来设置相应的选项,本文主要分析IP选项的生成,发送以及 接收所执行的流程,选取了LSRR为例子进行说明,主要分为选项的生成、选项的转发、选项的接收三部分。 先看一个源站路 由选项的例

do_ip_setsockopt() 处理ip选项

根据optname来决定处理何种 类型的选项,决定setsockopt()中参数的optval如何解释。当是IP_OPTIONS时为IP选项,按IP选项来处理optval。

switch (optname) {     
 case IP_OPTIONS:

ip_options_get_from_use()根据用户传入值optval生成选项结构opt,xchg()这句将inet->opt 和opt进行了交换,即将opt赋值给了inet->opt,同时将inet->opt作为结果返回。

err = 

ip_options_get_from_user(sock_net(sk), &opt, optval, optlen);     
opt = xchg(&inet->opt, opt);     
kfree(opt);

ip_options_get_from_user()

分配内存给IP选项,struct ip_options记录了选项相关的一些内部数据 结构,最后的属性__data[0]才指向真正的IP选项。因此在分配空间时是struct ip_options大小加上optlen大小,当然,还要做 4字节对齐。

struct ip_options *opt = ip_options_get_alloc(optlen);     
static struct ip_options *ip_options_get_alloc(const int optlen)     
{     
 return kzalloc(sizeof(struct ip_options) + ((optlen + 3) & ~3), GFP_KERNEL);     
}

分配空间后,拷贝用户设置的IP选项到opt->__data中;最后调用ip_options_get_finish()完成选项的处理,包 括了用户传入选项的再处理、一些内部数据的填写,下面会进行详细讲解。

copy_from_user(opt->__data, data, 

optlen);     
return ip_options_get_finish(net, optp, opt, optlen);

ip_options_get_finish()

选项头部的空字节用 IPOPT_NOOP来补齐,选项尾部的空字节用IPOPT_END来补齐,IPOPT_NOOP和IPOPT_END都占用1字节,因此optlen递增,记录选项 长度到opt中。然后调用ip_options_compile()。

while (optlen & 3)     
 opt->__data[optlen++] = IPOPT_END;     
opt->optlen = optlen;

ip_options_compile()实际完成选项的处理,它在两个地方被调用:生成带IP选项的报文 时被调用,此时处理的是用户传入的选项;接收带有IP选项的报文时被调用,此时处理的是报文中的IP选项,下面详细看下该函 数,以LSRR选项为例子。

ip_options_compile(net, opt, NULL);     
kfree(*optp);     
*optp = opt;

ip_options_compile()

这里对应于该函数应用的两种情况:

1. 如果是生成带IP选项的报文,传入 的参数skb为空(此时skb还没有创建),optptr指向opt->__data,而上面已经看到用户设置的选项在函数 ip_options_get_from_user()中被拷贝到其中;

2. 如果接收到带IP选项的报文,传入skb不为空(收到报文时就创建了), optptr指向报文中IP选项的位置。iph指向IP报头的位置,当然,如果是生成选项,iph所指向的位置是没有意义的。

if (skb != NULL) {     
 rt = skb_rtable(skb);     
 optptr = (unsigned char *)&(ip_hdr(skb)[1]);     
} else 
 optptr = opt->__data;     
iph = optptr - sizeof(struct iphdr);

IP选项是按[code, len, ptr, data]这样的块排列的,每个块代表一个选项 内容,多个选项可以共存,每个块4字节对齐,不足的用IPOPT_NOOP补齐。for循环处理每个选项,其中IPOPT_END和IPOPT_ NOOP只是特殊的占位符,需要另外处理。然后按照选项块的格式,取出选项长度len到optlen,再根据选项的code分别进行处理 ,可以看到获取选项块长度的代码段在IPOPT_END和IPOPT_NOOP之后。

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

  
 switch (*optptr) {     
  case IPOPT_END: ….     
  case IPOPT_NOOP: ...     
   …...     
  optlen = optptr[1];     
  if (optlen<2 || optlen>l) {     
   pp_ptr = optptr;     
   goto error;     
  }     
  case …...      
   …...// 处理代码段     
 }     
 l -= optlen;     
 optptr += optlen;     
}

(编辑:三明站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读