欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Linux下IPV6 Connect

程序员文章站 2022-07-12 13:11:27
...

最近在模拟测试IPv6客户端连接服务器(使用的是链路本地地址fe80::20c:29ff:fe98:77d2),但是总会报参数不正确,后来我使用strace追踪java-SocketTest(ipv6测试工具)的连接发现Connect需要初始化sin6_scope_id字段,才可以Connect success

struct sockaddr_in6
 {
    u_char sin6_len; 
    u_char sin6_family; 
    u_int16_t sin6_port; 
    u_int32_t sin6_flowinfo; 
    struct in6_addr sin6_addr;
    u_int32_t sin6_scope_id;
}
server_addr.sin6_scope_id = if_nametoindex("eth0");

sin6_scope_id is an ID depending on the scope of the address.  It is new in Linux 2.4.Linux supports it only for link-local addresses, in that case sin6_scope_id contains the interface index.

在IPv6地址结构中(对应于IPv4的struct sockaddr_in),有一个我们非常陌生的字段scope_id,这个字段在我们使用链路本地地址来编程的时候是必须要使用的,这个字段表示我们需要选择接口ID。为什么需要需要有这么一个字段,那是因为链路本地地址的特殊性,一个网络节点可以有多个网络接口,多个网络接口可以有相同的链路本地地址,例如我们需要bind一个本地链路地址,这个时候就会有冲突,操作系统无法决策需要绑定的是哪个接口的本地链路地址。又例如,如果我们在直连的2个主机之间直接用链路本地地址ping的话,会ping失败。因此IPv6引入了scope_id来解决这个问题,scope_id指定了使用哪个网络接口。

if_nametoindex函数定义:

#include <net/if.h>
unsigned if_nametoindex(const char *ifname);
char *if_indextoname(unsigned ifindex, char *ifname);
struct if_nameindex *if_nameindex(void);
void if_freenameindex(struct if_nameindex *ptr);

if_nametoindex():指定网络接口名称字符串作为参数;若该接口存在,则返回相应的索引,否则返回0

if_indextoname():指定网络接口索引以及一块长度至少为IF_NAMESIZE(16)字节的内存区域作为参数;若索引对应的网络接口存在,则在内存区域中返回该接口的名称字符串,否则返回NULL,并将errno设置为相应的值

if_nameindex():返回动态分配的struct if_nameindex结构数组,数组中的每一个元素分别对应一个本地网络接口;struct if_nameindex结构的if_index字段为接口索引,if_name字段为接口名称字符串;索引为0且名称字符串为NULL表示结构数组的末尾;调用出错时,返回NULL,并将errno设置为相应的值

if_freenameindex():通过if_nameindex()获取完毕接口名称与索引后,调用该函数以释放动态分配的内存区域。