如何在c中显示所有接口的IPv6 /前缀地址

时间:2014-10-23 08:38:41

标签: c linux ipv6

我无法以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


}

2 个答案:

答案 0 :(得分:3)

执行您所要求的方法是使用netlink机制直接从Linux内核获取所需信息。这避免了我在之前的评论中提出的hackery,但是不可移植。我想,选择你的毒药。

有关详细信息,请查看netlinkrtnetlink的手册页。

在我的机器上,以下代码生成:

::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);
}