我无法以IPv6 /前缀格式显示所有IPv6地址。 我怎样才能做到这一点? 我正在使用getifaddrs获取所有接口的IPv6地址,然后我应该使用什么?
谢谢!
只是粗略地展示我想要实现的目标:
struct ifaddrs *ifa = NULL;
struct ifaddrs *ifap = NULL;
int res = 0;
void *p = NULL;
char addressOutputBuffer[INET6_ADDRSTRLEN];
res = getifaddrs(&ifa);
...
for (ifap = ifa; ifap != NULL; ifap = ifap->ifa_next) {
// Filter out by AF
if (ifap->ifa_addr->sa_family != AF_INET6) {
continue;
}
p = &((struct sockaddr_in6 *)ifap->ifa_addr)->sin6_addr;
inet_ntop(ifap->ifa_addr->sa_family, p,addressOutputBuffer,sizeof(addressOutputBuffer));
// I want to display IPv6/prefix format
}
答案 0 :(得分:3)
执行您所要求的方法是使用netlink机制直接从Linux内核获取所需信息。这避免了我在之前的评论中提出的hackery,但是不可移植。我想,选择你的毒药。
有关详细信息,请查看netlink和rtnetlink的手册页。
在我的机器上,以下代码生成:
::1/128
fe80::222:4dff:fe9d:3dd9/64
匹配ifconfig的输出。
#include <asm/types.h>
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char ** argv) {
char buf[16384];
// Our message will be a header followed by an address payload
struct {
struct nlmsghdr nlhdr;
struct ifaddrmsg addrmsg;
} msg;
struct nlmsghdr *retmsg;
// Set up the netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
// Fill in the message
// NLM_F_REQUEST means we are asking the kernel for data
// NLM_F_ROOT means provide all the addresses
// RTM_GETADDR means we want the addresses of interfaces
// AF_INET6 means limit the response to ipv6 addresses
memset(&msg, 0, sizeof(msg));
msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg.nlhdr.nlmsg_type = RTM_GETADDR;
msg.addrmsg.ifa_family = AF_INET6;
// Send the netlink message
send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
int len;
// Get the netlink reply
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
// Loop through the reply messages (one for each address)
// Each message has a ifaddrmsg structure in it, which
// contains the prefix length as a member. The ifaddrmsg
// structure is followed by one or more rtattr structures,
// some of which (should) contain raw addresses.
while NLMSG_OK(retmsg, len) {
struct ifaddrmsg *retaddr;
retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
struct rtattr *retrta;
retrta = (struct rtattr *)IFA_RTA(retaddr);
int attlen;
attlen = IFA_PAYLOAD(retmsg);
char pradd[128];
// Loop through the routing information to look for the
// raw address.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFA_ADDRESS) {
inet_ntop(AF_INET6, RTA_DATA(retrta), pradd, sizeof(pradd));
printf("%s/%u\n", pradd, retaddr->ifa_prefixlen);
}
retrta = RTA_NEXT(retrta, attlen);
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
答案 1 :(得分:0)
以下是通过getifaddrs()API显示所有IPv4 / IPv6地址的示例。
# ip addr show
1: lo: ...
inet 127.0.0.1/8 ...
inet6 ::1/128 ...
2: eth0: ...
inet 10.254.52.242/19 ...
inet6 fe80::d20d:7bff:feb3:7e41/64 ...
# gcc get_ip.c && ./a.out
lo: 127.0.0.1/8
eth0: 10.254.52.242/19
lo: ::1/128
eth0: fe80::d20d:7bff:feb3:7e41/64
===========================================
# cat get_ip.c
#define _GNU_SOURCE
#include <stdlib.h> //exit()
#include <stdio.h> //printf(),perror()
#include <string.h> //memset
#include <ifaddrs.h> //struct ifaddrs,getifaddrs()
#include <arpa/inet.h> //INET6_ADDRSTRLEN,inet_ntop()
#include <netinet/in.h> //sockaddr_in,sockaddr_in6
void die(char * s)
{
perror(s);
exit(1);
}
void print_all_ip()
{
struct ifaddrs *ifaddr, *ifa;
char ip_str[INET6_ADDRSTRLEN];
if (getifaddrs(&ifaddr) < 0) {
die("getifaddrs");
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL) { continue; }
switch (ifa->ifa_addr->sa_family) {
case AF_INET: {
struct sockaddr_in *a = (struct sockaddr_in *)ifa->ifa_addr;
inet_ntop(AF_INET, &(a->sin_addr), ip_str, INET_ADDRSTRLEN);
uint32_t n = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr.s_addr;
int i = 0;
while (n > 0) {
if (n & 1) i++;
n = n >> 1;
}
printf("%s: %s/%d\n", ifa->ifa_name, ip_str, i);
break;
}
case AF_INET6: {
struct sockaddr_in6 *a = (struct sockaddr_in6 *)ifa->ifa_addr;
inet_ntop(AF_INET6, &(a->sin6_addr), ip_str, INET6_ADDRSTRLEN);
unsigned char *c = ((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr.s6_addr;
int i = 0, j = 0;
unsigned char n = 0;
while (i < 16) {
n = c[i];
while (n > 0) {
if (n & 1) j++;
n = n/2;
}
i++;
}
printf("%s: %s/%d\n", ifa->ifa_name, ip_str, j);
break;
}
default:
break;
}
}
freeifaddrs(ifaddr);
return;
}
int main()
{
print_all_ip();
exit(0);
}