1 在Linux系统中需要编程获取某个接口的IPv4地址比较常见, 可以使用ioctl函数等方法, 但是要获取IPv6地址, 以前的一些方法就不一定适合,
从网上查找了很多方法, 有两种我试过都可以得到相应的IPv6地址,
此处直接以一段代码做示例展示如何获取指定接口的(IPv6)本地链路地址(注意, 前提是你的Linux支持IPv6, 目前流行的大多数Linux系统早已支持IPv6).
2 #include <stdio.h>
3 #include <string.h>
4 #include <error.h>
5 #include <stdlib.h>
6
7 #define DEBUG
8 //#define UNSUPPORT_IFADDRS
9
10 /* struct in6_addr */
11 #include <netinet/in.h>
12 /* getifaddrs, freeifaddrs */
13 #include <sys/types.h>
14 #ifndef UNSUPPORT_IFADDRS
15 #include <ifaddrs.h>
16 #endif
17 /* inet_ntop, inet_pton */
18 #include <arpa/inet.h>
19
20 #if defined(DEBUG)
21 #define DG(a, b...) printf("[%s][%s][%d]"a, __FILE__, __func__, __LINE__, ##b)
22 #else
23 #define DG(a, b...)
24 #endif
25
26 #define ER(a, b...) printf("[%s][%s][%d]"a, __FILE__, __func__, __LINE__, ##b)
27
28 #ifndef UNSUPPORT_IFADDRS
29 /**
30 * Whlie head file is not existed in you include directory, just define
31 * macro UNSUPPORT_IFADDRS to disable this function.
32 * Because of function getifaddrs() and freeifaddrs() are declared in this head file,
33 * the function can't pass compiling process if lack in your system.
34 */
35 int get_linklocal_ipv6addr(struct in6_addr *addr6, char *iface)
36 {
37 struct ifaddrs *ifa, *p;
38 int family;
39 char address[200];
40
41 if (!addr6 || !iface) {
42 ER("addr6 and iface can't be NULL!\n");
43 return -1;
44 }
45
46 if (getifaddrs(&ifa)) {
47 ER("");
48 perror("getifaddrs error");
49 return -1;
50 }
51
52 for (p = ifa; p != NULL; p = p->ifa_next) {
53 DG("ifa_name = %s, family = 0x%X(%s)\n", p->ifa_name, family,
54 (family == AF_PACKET) ? "AF_PACKET" :
55 (family == AF_INET) ? "AF_INET" :
56 (family == AF_INET6) ? "AF_INET6" : "");
57
58 family = p->ifa_addr->sa_family;
59 /* Just check IPv6 address */
60 if (family != AF_INET6)
61 continue;
62
63 *addr6 = ((struct sockaddr_in6 *)(p->ifa_addr))->sin6_addr;
64 /* Just get IPv6 linklocal address of the interface */
65 if (!strcmp(iface, p->ifa_name) && IN6_IS_ADDR_LINKLOCAL(addr6)) {
66 if (inet_ntop(AF_INET6, addr6, address, sizeof(address))) {
67 DG("find out %s's linklocal IPv6 address: %s\n", iface, address);
68 }
69 break;
70 }
71 }
72
73 freeifaddrs(ifa);
74 return 0;
75 }
76 #else
77 /**
78 * If head file is not existed in your system, you could get information of IPv6 address
79 * in file /proc/net/if_inet6.
80 *
81 * Contents of file "/proc/net/if_inet6" like as below:
82 * 00000000000000000000000000000001 01 80 10 80 lo
83 * fe8000000000000032469afffe08aa0f 08 40 20 80 ath0
84 * fe8000000000000032469afffe08aa0f 07 40 20 80 wifi0
85 * fe8000000000000032469afffe08aa0f 05 40 20 80 eth1
86 * fe8000000000000032469afffe08aa0f 03 40 20 80 br0
87 * fe8000000000000032469afffe08aa10 04 40 20 80 eth0
88 *
89 * +------------------------------+ ++ ++ ++ ++ +---+
90 * | | | | | |
91 * 1 2 3 4 5 6
92 *
93 * There are 6 row items parameters:
94 * 1 => IPv6 address without ':'
95 * 2 => Interface index
96 * 3 => Length of prefix
97 * 4 => Scope value (see kernel source "include/net/ipv6.h" and "net/ipv6/addrconf.c")
98 * 5 => Interface flags (see kernel source "include/linux/rtnetlink.h" and "net/ipv6/addrconf.c" "linux/include/if_addr.h")
99 * 6 => Device name
100 *
101 * Note that all values of row 1~5 are hexadecimal string
102 */
103
104
105 int get_linklocal_ipv6addr(struct in6_addr *addr6, char *iface)
106 {
107 #define IF_INET6 "/proc/net/if_inet6"
108 char str[128], address[64];
109 char *addr, *index, *prefix, *scope, *flags, *name;
110 char *delim = " \t\n", *p, *q;
111 FILE *fp;
112 int count;
113
114 if (!addr6 || !iface) {
115 ER("addr6 and iface can't be NULL!\n");
116 return -1;
117 }
118
119 if (NULL == (fp = fopen(IF_INET6, "r"))) {
120 ER("");
121 perror("fopen error");
122 return -1;
123 }
124
125 #define IPV6_ADDR_LINKLOCAL 0x0020U
126 while (fgets(str, sizeof(str), fp)) {
127 DG("str:%s", str);
128 addr = strtok(str, delim);
129 index = strtok(NULL, delim);
130 prefix = strtok(NULL, delim);
131 scope = strtok(NULL, delim);
132 flags = strtok(NULL, delim);
133 name = strtok(NULL, delim);
134 DG("addr:%s, index:0x%s, prefix:0x%s, scope:0x%s, flags:0x%s, name:%s\n",
135 addr, index, prefix, scope, flags, name);
136
137 if (strcmp(name, iface))
138 continue;
139
140 /* Just get IPv6 linklocal address */
141 if (IPV6_ADDR_LINKLOCAL != (unsigned int)strtoul(scope, NULL, 16))
142 continue;
143
144 memset(address, 0x00, sizeof(address));
145 p = addr;
146 q = address;
147 count = 0;
148 while (*p != '') {
149 if (count == 4) {
150 *q++ = ':';
151 count = 0;
152 }
153 *q++ = *p++;
154 count++;
155 }
156 DG("find out %s's linklocal IPv6 address: %s\n", iface, address);
157
158 inet_pton(AF_INET6, address, addr6);
159 break;
160 }
161 #undef IPV6_ADDR_LINKLOCAL
162
163 fclose(fp);
164 return 0;
165 }
166 #endif
167
168 int main (int argc, char *argv[])
169 {
170 struct in6_addr addr6;
171 char *ifname = "eth0";
172 char address[64];
173
174 if (get_linklocal_ipv6addr(&addr6, ifname)) {
175 printf("\nGet IPv6 linklocal address of %s failed :(\n", ifname);
176 return -1;
177 }
178 if (inet_ntop(AF_INET6, &addr6, address, sizeof(address)))
179 printf("\nIPv6 linklocal address of %s is %s :)\n", ifname, address);
180
181 return 0;
182 }
183
184
185
186 注意:
187
188 关于Interface flags
189
190 /* ifa_flags */
191 #define IFA_F_SECONDARY 0x01
192 #define IFA_F_TEMPORARY IFA_F_SECONDARY
193
194 #define IFA_F_NODAD 0x02
195 #define IFA_F_OPTIMISTIC 0x04
196 #define IFA_F_HOMEADDRESS 0x10
197 #define IFA_F_DEPRECATED 0x20
198 #define IFA_F_TENTATIVE 0x40
199 #define IFA_F_PERMANENT 0x80
200
201 一般请情况下flag的值应为0x80,如果为其他值应该怀疑interface在init的时候是否有起来
202
203 bug record:
204
205 flag=0xc0, init 不对,导致这个interface sendmsg 出错(22)
206
207
208
209 转自:http://yangxy84.blog.163.com/blog/static/708443020119171265179/