linux内核学习笔记------iP选项处理(一)

来源:互联网 发布:淘宝无线端主图大小 编辑:程序博客网 时间:2024/05/16 09:48

ip首部分为固定部分和选项部分;固定部分为20个字节,而选项部分则是变长的,最长不超过40个字节。选项的格式分为单字节和多字节两种。单字节只包括一个字节的选项类型,而多字节则除一个字节的类型之外,还包括选项长度以及选项数据。包括以下几种ip选项:

1、选项列表的结束符

此选项标识了选项列表的结束,所有选项的结束,而不是一个选项的结束。如下图

00000000type=0


2、空操作

此选项一般在选项中间或者选项尾使用,用于32位边界对齐的填充。如下图

00000001type=1


3、安全选项

此选项为主机提供了发送安全级别,Compartments,处理限制以及传输控制码


4、严格源路由选项

此选项要求数据报必须严格按照发送方规定的路径经过每一个路由器,这些路由器应该是一一相连的,每两个指定的路由器之间不能有其他为指定的路由器,且路由的顺序不能改变。如果数据包在传输的时候无法到达指定的下一跳路由器,就会产生一个源路由失败的目的地不可达的icmp报文。格式如下:

10001001

长度

指针

Ip地址1

Ip地址1(offset=4)

......

.......

Ip地址n

Ip地址n(offset=4n,n<9)


5、宽松源路由选项

此选项与严格源路由选项类似,不同的是,宽松源路由选项在选项的ip地址表中并不列出一条完整而严格的路径,而是只给出路径中的几个关键点。注:宽松,严格源路由选项都必须在ip分片的时候被复制


6、记录路由选项

该选项用于记录ip数据报从发送方到接收方所经过的路径上各个路由器的ip地址,如下图

10001001

长度

指针

Ip地址1

Ip地址1(offset=4)

......

.......

Ip地址n

Ip地址n(offset=4n,n<9)

注意:记录路由选项是有上限的,如果空间满了就不会记录后面的路由信息


7、时间戳选项

该选项用于记录数据报经过路由器时的当地时间。可以根据时间戳估算ip数据报从一个路由器到另一个路由器的所花的时间。如下图:

01000100

长度

指针

OF|FG

Ip地址1

时间戳

......

Ip地址n

时间戳

OF为溢出字段,如果空间不够,后面的路由信息也不会记录。FG标志字段用于定时时间戳选项的格式

FG               描述

0                  只记录时间戳,以连续的32为字存储

1                  记录ip地址和时间戳

3                  发送方对选项表进行初始化,存放了4个ip地和4个取值为0的时间戳,后续的路由器只有当匹配到ip地址才会记录时间戳


8、路由器警告选项

该选项提醒路由器需要更仔细的检查这个包,对内容需要做特殊处理,如下图:

1001010000000100路由器警告值
在linux内核中ip选项是通过ip_options结构来表示的:

struct ip_options {/* * 存在宽松源路由或严格源路由选项时,用来 * 记录下一跳的IP地址 */__be32faddr;/* * 标识IP首部中选项所占的字节数,包括__data之后的数据, * 如果有的话 */unsigned charoptlen;/* * 记录宽松源路由或严格源路由选项在IP首部中的偏移量, * 即选项的第一个字节的地址减去IP首部的第一个字节的地址 */unsigned charsrr;/* * 用于记录路径选项在IP首部中的偏移量 */unsigned charrr;/* * 用于记录时间戳选项在IP首部中的偏移量 */unsigned charts;/* * 标识该IP选项是否有数据,若有则存放在__data字段起始的 * 存储空间内,即紧跟在ip_option结构后面。这里的数据不只 * 是选项数据,而是整个选项内容 *//* * 标识该选项是IPOPT_SSRR,而不是IPOPT_LSRR */unsigned charis_strictroute:1,/* * 表示目的地址是从源路由选项选出的 */srr_is_hit:1,/* * 标识是否修改过IP首部,如果是则需要重新 * 计算IP首部校验和 */is_changed:1,/* * 标识有IPOPT_RR选项,需要记录IP地址。 */rr_needaddr:1,/* * ts_needtime标识有IPOPT_TIMESTAMP选项,需要 * 记录时间戳 * ts_needaddr标识有IPOPT_TIMESTAMP选项,需要 * 记录IP地址 */ts_needtime:1,ts_needaddr:1;/* * 标识IPOPT_RA选项。路由器警告选项,表示路由器 * 应该更仔细地检查这个数据包 */unsigned charrouter_alert;/* * 用于记录商业IP安全选项在IP首部中的偏移量 */unsigned charcipso;/* * 未使用 */unsigned char__pad2;/* * 若选项有数据则从该字段开始,使之紧跟在ip_option结构后面, * 最多不超过40B */unsigned char__data[0];};
代码中都有注释,其中注释来自于:http://blog.csdn.net/justlinux2010

构建ip选项是通过ip_iptions_build实现的

void ip_options_build(struct sk_buff * skb, struct ip_options * opt,    __be32 daddr, struct rtable *rt, int is_frag){unsigned char *iph = skb_network_header(skb);memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options));memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen);opt = &(IPCB(skb)->opt);if (opt->srr)memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4);if (!is_frag) {if (opt->rr_needaddr)ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, rt);if (opt->ts_needaddr)ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt);if (opt->ts_needtime) {struct timespec tv;__be32 midtime;getnstimeofday(&tv);midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC);memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);}return;}if (opt->rr) {memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]);opt->rr = 0;opt->rr_needaddr = 0;}if (opt->ts) {memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]);opt->ts = 0;opt->ts_needaddr = opt->ts_needtime = 0;}}
首先会获取ip首部,将源ip选项和后面紧跟的选项数据复制到skb对应额存储区域中。并将opt指向skb的ip_options。如果存在严格路由选项需要将目的地址复制到源路由选项地址列表中。如果数据包不是分片,且存在记录路由或者时间戳选项,通过输出路由缓存获取源地址填写到记录路由选项或者时间戳选项的地址部分,获取当前的时间填写时间戳。如果该数据包不是分片,但存在记录路由或时间戳选项则设置为无操作

而将数据报中选项复制到指定的ip_options中,需要调用ip_options_echo,这个函数处理也比较清晰,这里就不列举出来了。




0 0