探秘:如何判断当前网络是否支持 IPv6 服务?

本程序旨在通过检查当前网络是否支持 IPv6 服务,以及判断指定的网络接口是否拥有全局 IPv6 地址。以下是程序的主要思路和函数概述。

1. getInterfaceNameFromSockaddr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
std::string getInterfaceNameFromSockaddr(const struct sockaddr_in &sockAddr)
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
return "";
}

struct ifconf ifc;
char buf[1024]; // 大小根据实际情况调整
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;

if (ioctl(sockfd, SIOCGIFCONF, (char *)&ifc) == -1)
{
close(sockfd);
return "";
}

std::string interfaceName = "";
int num = ifc.ifc_len / sizeof(struct ifreq);
struct ifreq *ifr = ifc.ifc_req;

for (int i = 0; i < num; ++i)
{
struct sockaddr_in *addr = reinterpret_cast<struct sockaddr_in *>(&ifr[i].ifr_addr);

if (addr->sin_family == AF_INET)
{
char ipStr[INET_ADDRSTRLEN];
const char *ip = inet_ntop(AF_INET, &(addr->sin_addr), ipStr, INET_ADDRSTRLEN);
std::cout << "guess IP address: " << ip << std::endl;

if (ip != nullptr && std::memcmp(&(sockAddr.sin_addr), &(addr->sin_addr), sizeof(struct in_addr)) == 0)
{
interfaceName = ifr[i].ifr_name;
std::cout << "guessed!" << std::endl;
break;
}
}
}

close(sockfd);
return interfaceName;
}

思路:

  • 通过创建一个 IPv4 套接字,建立到一个虚拟地址的连接。
  • 获取本地套接字的信息,即获取与之连接的本地 IP 地址。
  • 遍历系统网络接口信息,根据 IP 地址的匹配找到对应的网络接口名称。

函数功能:

  • 获取与指定 sockaddr_in 地址关联的网络接口名称。

2. hasGlobalIPv6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
bool hasGlobalIPv6(const char *interfaceName)
{
FILE *f = nullptr;
if ((f = fopen("/proc/net/if_inet6", "r")) != nullptr)
{
char addr6[40], devname[21];
int plen, scope, dad_status, if_idx;
char addr6p[8][5];
bool found = false;

while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %08x %02x %02x %02x %20s\n",
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
&if_idx, &plen, &scope, &dad_status, devname) != EOF)
{

if (scope == 0 && strcmp(interfaceName, devname) == 0)
{
// Break when global scope is found
found = true;
break;
}
}

fclose(f);
return found;
}

return false;
}

思路:

  • 通过读取 /proc/net/if_inet6 文件,获取所有网络接口的 IPv6 地址信息。
  • 针对指定的网络接口名称,检查是否存在具有全局作用域的 IPv6 地址。

函数功能:

  • 检查指定网络接口是否拥有全局 IPv6 地址。

3. getCurrentNetworkInterface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
std::string getCurrentNetworkInterface()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd == -1)
{
return "";
}

struct sockaddr_in destAddr;
std::memset(&destAddr, 0, sizeof(destAddr));
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(80);
inet_pton(AF_INET, "1.2.3.4", &(destAddr.sin_addr));

if (connect(sockfd, (struct sockaddr *)&destAddr, sizeof(destAddr)) == 0)
{
struct sockaddr_in localAddr;
socklen_t localAddrLen = sizeof(localAddr);
if (getsockname(sockfd, (struct sockaddr *)&localAddr, &localAddrLen) == 0)
{
return getInterfaceNameFromSockaddr(localAddr);
}
}

close(sockfd);
return "";
}

思路:

  • 创建一个 IPv4 套接字并连接到一个虚拟地址,获取本地套接字信息。
  • 调用 getInterfaceNameFromSockaddr 函数,从本地套接字信息中获取网络接口名称。

函数功能:

  • 获取当前网络接口名称。

4. main

思路:

  • 调用 getCurrentNetworkInterface 函数,获取当前网络接口名称。
  • 如果接口名称不为空,输出当前网络接口名称。
  • 调用 hasGlobalIPv6 函数,判断当前网络接口是否拥有全局 IPv6 地址。
  • 根据 IPv6 地址判断结果,输出相应信息。

通过以上函数,程序可以判断当前网络是否支持 IPv6 服务,并检查指定的网络接口是否拥有全局 IPv6 地址。整个程序通过与虚拟地址建立连接以及检查文件来获取网络信息,提供了一种简单的方法来判断网络是否支持 IPv6,以及网络接口是否拥有全局 IPv6 地址。

nephen wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!