惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The Cloudflare Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
The Blog of Author Tim Ferriss
G
Google Developers Blog
小众软件
小众软件
J
Java Code Geeks
V
Visual Studio Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
美团技术团队
阮一峰的网络日志
阮一峰的网络日志
V
V2EX
博客园 - 叶小钗
N
Netflix TechBlog - Medium
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
T
The Exploit Database - CXSecurity.com
The Hacker News
The Hacker News
Cisco Talos Blog
Cisco Talos Blog
Hacker News: Ask HN
Hacker News: Ask HN
Hacker News - Newest:
Hacker News - Newest: "LLM"
AWS News Blog
AWS News Blog
Webroot Blog
Webroot Blog
The Last Watchdog
The Last Watchdog
T
Threatpost
I
Intezer
T
Tenable Blog
L
LINUX DO - 热门话题
T
Tailwind CSS Blog
Scott Helme
Scott Helme
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
C
Cybersecurity and Infrastructure Security Agency CISA
Engineering at Meta
Engineering at Meta
S
Schneier on Security
Recent Announcements
Recent Announcements
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
F
Fortinet All Blogs
腾讯CDC
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Troy Hunt's Blog
量子位
H
Hacker News: Front Page
V2EX - 技术
V2EX - 技术
Google Online Security Blog
Google Online Security Blog
人人都是产品经理
人人都是产品经理
博客园 - 【当耐特】
博客园 - Franky
www.infosecurity-magazine.com
www.infosecurity-magazine.com

博客园 - 川川籽

GO面试题:new 和 map 的区别 minikube dashboard ImagePullBackOff 失败问题的解决方法 hashicorp/raft模块实现的raft集群存在节点跨集群身份冲突问题 macos 13安装openvpn - 川川籽 [转发] Go pprof内存指标含义备忘录 自己搭建一个https的dns,让不同的浏览器使用不同的DNS,使用相同的域名访问到不同的主机上 记一次docker buildx build 推送到本地私有仓库出现 connection refused 的问题 Mac M1 安装python3.6.x golang map 和 interface 的一些记录 MacOS M1 安装python3.5 使用php的openssl_encrypt和python的pycrypt进行跨语言的对称加密和解密问题 golang random string 【转载】coroutine 与 goroutine 区别 python简单的time ticker 'invalid flag in #cgo LDFLAGS: -w' 问题解决 记录一次python的mysqlclient依赖库报错问题 airflow当触发具有多层subDAG的任务的时候,出现[Duplicate entry ‘xxxx’ for key dag_id]的错误的问题处理 Python3并发写文件 python hash 每次调用结果不一样
Linux C 获取本机IPV4和IPV6地址列表
川川籽 · 2023-05-26 · via 博客园 - 川川籽

有时候设备网卡上有多个IPv6,其中只有一个是可用的,另外一个是内网地址,无法使用,如果程序需要绑定一个V6地址的时候,需要获取网卡上的V6地址,并且要求是可用的。

通过ifconfig可用看到,eth0网卡上有2个IP地址,其中只有第一个V6地址的ScopeGlobal

eth0      Link encap:Ethernet  HWaddr 52:54:00:1D:79:D1
          inet addr:192.168.121.120  Bcast:192.168.121.255  Mask:255.255.255.0
          inet6 addr: 2001:250:250:250:250:250:250:222/64 Scope:Global
          inet6 addr: fe80::5054:ff:fe1d:79d1/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:5999959 errors:0 dropped:0 overruns:0 frame:0
          TX packets:104610 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:317521212 (302.8 MiB)  TX bytes:8564391 (8.1 MiB)

那么如何用C获取IPv6地址,并且过滤其中Scope为Global的地址:

#define _GNU_SOURCE    # required for NI_NUMERICHOST
#include <arpa/inet.h>
#include <sys/socket.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <netdb.h>

int main ()
{
  struct ifaddrs *ifap, *ifa;
  struct sockaddr_in6 *sa;
  struct sockaddr_in *sa4;
  char addr[INET6_ADDRSTRLEN];
  char addr4[INET_ADDRSTRLEN];

  getifaddrs (&ifap);
  for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    if (!ifa->ifa_addr) {
      continue;
    }
    if (ifa->ifa_addr->sa_family==AF_INET6) {
      sa = (struct sockaddr_in6 *) ifa->ifa_addr;
      getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), addr,
                  sizeof(addr), NULL, 0, NI_NUMERICHOST);
      printf("Interface: %5s\tAddress: %s, scope: ", ifa->ifa_name, addr);

      // struct sockaddr_in6 sa;
      if (IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
        printf ("link-local ");
      }
      if (IN6_IS_ADDR_SITELOCAL(&sa->sin6_addr)) {
        printf ("site-local ");
      }
      if (IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr)) {
        printf ("v4mapped ");
      }
      if (IN6_IS_ADDR_V4COMPAT(&sa->sin6_addr)) {
        printf ("v4compat ");
      }
      if (IN6_IS_ADDR_LOOPBACK(&sa->sin6_addr)) {
        printf ("host ");
      }
      if (IN6_IS_ADDR_UNSPECIFIED(&sa->sin6_addr)) {
        printf ("unspecified ");
      }
      if (IN6_IS_ADDR_MC_GLOBAL(&sa->sin6_addr)){
        printf ("global ");
      }
      printf("\n");
    } else if(ifa->ifa_addr->sa_family == AF_INET){
		  sa4 = (struct sockaddr_in *)ifa->ifa_addr;
		  getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), addr4,
                  sizeof(addr4), NULL, 0, NI_NUMERICHOST);
		  /*inet_ntop(AF_INET, sa4, addr4, INET_ADDRSTRLEN);*/
		  printf("Interface: %5s\tAddress: %s\n", ifa->ifa_name, addr4);
	  }
  }

  freeifaddrs(ifap);
  return 0;
}

编译下:

gcc -o ipa ipa.c

运行输出:

# ./ipa
Interface:    lo	Address: 127.0.0.1
Interface:  eth0	Address: 192.168.121.120
Interface:  eth1	Address: 10.24.0.114
Interface:    lo	Address: ::1, scope: host
Interface:  eth0	Address: 2001:250:250:250:250:250:250:222, scope:
Interface:  eth0	Address: fe80::5054:ff:fe1d:79d1%eth0, scope: link-local
Interface:  eth1	Address: fe80::5054:ff:fedb:bdd7%eth1, scope: link-local

啊,可见IN6_IS_ADDR_MC_GLOBAL无法判断global的地址,我们只能用排除法了,将IN6_IS_ADDR_MC_GLOBAL判断修改为如下代码:

      // if (IN6_IS_ADDR_MC_GLOBAL(&sa->sin6_addr)){
      //   printf ("global ");
      // }
      if (!(IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) && !(IN6_IS_ADDR_SITELOCAL(&sa->sin6_addr)) && 
          !(IN6_IS_ADDR_V4MAPPED(&sa->sin6_addr)) && !(IN6_IS_ADDR_LOOPBACK(&sa->sin6_addr)) &&
          !(IN6_IS_ADDR_UNSPECIFIED(&sa->sin6_addr))
      ) {
        printf ("global ");
      }

重新编译输出:

# ./ipa
Interface:    lo	Address: 127.0.0.1
Interface:  eth0	Address: 192.168.121.120
Interface:  eth1	Address: 10.24.0.114
Interface:    lo	Address: ::1, scope: host
Interface:  eth0	Address: 2001:250:250:250:250:250:250:222, scope: global
Interface:  eth0	Address: fe80::5054:ff:fe1d:79d1%eth0, scope: link-local
Interface:  eth1	Address: fe80::5054:ff:fedb:bdd7%eth1, scope: link-local