内核支持socket相关系统调用

概述

IPv6地址长度扩展到128比特,所以有足够的IPv6地址可供分配使用。同时IPv6头相比IPv4头进行了简化,并增强了IPv6的自动配置功能。IPv6地址分为单播地址,组播地址和任意播地址。常用的单播地址又包含:链路本地地址(link-local address),唯一本地地址(Unique local address)和全局地址(global address)。由于IPv6的全局地址十分充足,唯一本地地址一般不被使用(其前身为站点本地地址(site-local address),已于2004年被废弃)。当前主要使用的单播地址为:链路本地地址(link-local address)和全局地址(global address)。当前内核支持socket系统调用,在使用单播地址的链路本地地址和全局地址时存在差异。

link-local地址和global地址在socket调用时的差异

RFC 2553: Basic Socket Interface Extensions for IPv6 定义sockaddr_in6的数据结构如下;

  1. struct sockaddr_in6 {
  2. uint8_t sin6_len; /* length of this struct */
  3. sa_family_t sin6_family; /* AF_INET6 */
  4. in_port_t sin6_port; /* transport layer port # */
  5. uint32_t sin6_flowinfo; /* IPv6 flow information */
  6. struct in6_addr sin6_addr; /* IPv6 address */
  7. uint32_t sin6_scope_id; /* set of interfaces for a scope */
  8. };

内核支持socket相关系统调用 - 图1 说明:
sin6_scope_id: 32位整型,对于链路本地地址(link-local address),对于链路范围的sin6_addr,它可以用来标识指定的接口索引号。如果是站点范围的sin6_addr,则用来作为站点的标识符(站点本地地址已被抛弃)。

在使用link-local地址进行socket通信时,在构造目的地址时,需要制定该地址所对应的接口索引号。一般可以通过if_nametoindex函数将接口名转化为接口索引号。具体方式如下,

  1. int port = 1234;
  2. int sk_fd;
  3. int iff_index = 0;
  4. char iff_name[100] = "enp3s0";
  5. char * ll_addr[100] = "fe80::123:456:789";
  6. struct sockaddr_in6 server_addr;
  7. memset(&server_addr,0,sizeof(structsockaddr_in6));
  8. iff_index=if_nametoindex(iff_name);
  9. server_addr.sin6_family=AF_INET6;
  10. server_addr.sin6_port=htons(port);
  11. server_addr.sin6_scope_id=iff_index;
  12. inet_pton(AF_INET6, ll_addr, &(server_addr.sin6_addr));
  13. sk_fd=socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
  14. connect(sk_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in6));