IPv6 tcp socket HBH扩展报头设置

一、扩展报头粘性选项介绍

根据RFC 3542中的说明,存在两种机制可以用于发送携带HBH扩展报头的IPv6数据包,分别为:

  1. 使用ancillary data,可以为单个数据包指定扩展报头的选项内容;
  2. 使用setsockopt函数,可以为一个socket指定扩展报头的选项内容。设置完毕后,可以使该socket发出的所有数据包都携带指定的选项内容,所以也被称为粘性选项("sticky" options)。再次调用setsockopt函数后,可以对扩展报头的选项内容进行更新。

二、设置函数

设置HBH扩展报头的粘性选项需要依次使用4种函数,分别为inet6_opt_init(),inet6_opt_append(),inet6_opt_set_val(),inet6_opt_finish(),且其中3种需要被调用2次。

2.1变量定义

    #define OPT_X 0x3c // 定义TLV选项类型,此处自定义为0x3c

    void* extbuf; // extension buffer,扩展报头缓存指针

    socklen_t extlen; // extension length,扩展报头长度

    int currentlen; // 当前长度

    void* databuf; // data buffer,扩展报头数据部分缓存指针

    int offset; // 偏移

    uint32_t value4; // 4字节数据变量

    uint64_t value8; // 8字节数据变量

    int datalen; // TLV选项数据长度

2.2 第一次调用设置函数

第一次调用函数,用于获得扩展报头长度,为扩展报头分配内存空间,以便第二次调用时存放数据。

2.2.1 inet6_opt_init ()

int inet6_opt_init(void *extension_buffer,

                   socklen_t extension_length)

该函数返回扩展报头所需的字节数。

currentlen = inet6_opt_init(NULL, 0);

第一次调用该函数,用于开始计算扩展报头大小。

2.2.2 inet6_opt_append()

int inet6_opt_append(void *extension_buffer,

                      socklen_t extension_length,

                      int offset,

                      uint8_t option_type,

                      socklen_t option_length,

                      uint32_t alignment,

                      void **data_bufferp)

该函数返回添加了新TLV选项和对齐后的扩展报头新长度。

currentlen = inet6_opt_append(NULL, 0, currentlen, OPT_X, datalen, 8, NULL);

第一次调用该函数,根据准备设置的TLV选项的类型、数据长度等信息,更新扩展报头长度。OPT_X表示需要设置的TLV选项类型,datalen表示设置该选项的数据部分长度为12字节,8表示该TLV选项是8字节对齐。

2.2.3 inet6_opt_finish()

int inet6_opt_finish(void *extension_buffer,
                 socklen_t extension_length,
                 int offset)

该函数返回IPv6扩展报头增加填充字节后的长度,使扩展报头满足字节对齐要求。

currentlen = inet6_opt_finish(NULL, 0, currentlen);

第一次调用该函数,计算增加了填充选项(Pad1PadN)后的长度,使扩展报头长度满足字节对齐要求

2.3第二次调用设置函数

首先,应根据第一次调用3种函数后计算得到的扩展报头长度对变量进行更新:

extlen = currentlen; // 更新扩展报头长度

extbuf = malloc(extlen); // 为扩展报头分配内存空间

2.3.1 inet6_opt_init()

currentlen = inet6_opt_init(extbuf, extlen);

第二次调用该函数,基于extlen初始化extbuf。

此时extbuf指向的扩展报头内存空间中,前2字节为HBH头部,第一字节表示下一头部类型,函数暂不设置;第二字节表示扩展报头长度,函数通过extlen设置。

2.3.2 inet6_opt_append()

currentlen = inet6_opt_append(extbuf, extlen, currentlen, OPT_X, datalen, 8, &databuf);

第二次调用该函数,为扩展报头添加TLV选项,并使databuf指向扩展报头内存空间中的数据部分的起始字节处。

此时extbuf指向的扩展报头内存空间中,第三字节被函数填充为TLV选项类型OPT_X,第四字节为TLV选项数据长度,函数通过datalen设置,故databuf实际指向第5字节处。(注意,此处简化分析,实际情况可能并非从第三字节开始填充TLV选项,因为系统会先根据扩展报头长度和对齐要求填充Pad1或PanN选项)。

重复使用该函数,可以为同一个扩展报头添加多个TLV选项。

2.3.3 inet6_opt_set_val()

offset = 0;

value4 = 0x12345678; // 为4字节变量赋值

offset = inet6_opt_set_val(databuf, offset,&value4, sizeof(value4));

value8 = 0x0102030405060708; // 为8字节变量赋值

    offset = inet6_opt_set_val(databuf, offset,&value8, sizeof(value8));

两次调用该函数,分别将value4和value8的数据填入databuf指向的扩展报头内存空间的数据部分。

2.3.4 inet6_opt_finish()

currentlen = inet6_opt_finish(extbuf, extlen, currentlen);

第二次调用该函数,系统根据扩展报头长度和对齐要求在扩展报头内存空间中填充Pad1或PanN选项,使满足对齐要求。

2.4 setsockopt()

int setsockopt(int socket_descriptor,

            int level,

            int option_name,

            char *option_value,

            int option_length)

该函数用于设置socket。

setsockopt(m_sock, IPPROTO_IPV6,IPV6_HOPOPTS,extbuf, currentlen);

在上述函数调用完毕后,为socket设置HBH扩展头,设置level为IPPROTO_IPV6;option_name为IPV6_HOPOPTS;extbuf指向扩展报头内存空间,使socket能访问HBH扩展头数据。

三、扩展报头内容修改

在依次调用inet6_opt_init(),inet6_opt_append(),inet6_opt_set_val(),inet6_opt_finish()和setsockopt函数后,socket发出的数据包都将带有设置好的HBH扩展报头。

如果需要修改扩展报头内容,而不改变数据长度,再次调用inet6_opt_set_val()和setsockopt即可;如果需要修改数据长度,则需要全部重新设置。在重新设置完成后,socket发出的数据包的HBH扩展报头都会被更新。

参考文献:

IBM Documentation

RFC 3542 - Advanced Sockets Application Program Interface (API) for IPv6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值