【问题标题】:How to display all interfaces IPv6/prefix addresses in c如何在c中显示所有接口IPv6 /前缀地址
【发布时间】:2014-10-23 08:38:40
【问题描述】:

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


}

【问题讨论】:

  • 你目前有什么代码?
  • 当您说“IPv6/前缀”时,表明您可以通过该名称找到显示格式的标准。我没有在 Wikipedia 上的 IPv6 Presentation 或其他地方看到它作为演示格式的名称。谷歌也没有任何意义。这就是为什么为示例案例展示您的程序所需输出的具体示例 非常重要的原因之一。您希望看到输出什么字符串?
  • 如果你抓住&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr 并遍历地址的 16 个字节,从末尾开始,你可以数零位数以获得前缀,然后将其添加到末尾addressOutputBuffer。这确实很脏。

标签: c linux ipv6


【解决方案1】:

按照您的要求进行操作的一种方法是使用 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);       
    }

}

【讨论】:

    【解决方案2】:

    这是一个通过 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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-09
      • 1970-01-01
      • 1970-01-01
      • 2010-11-17
      相关资源
      最近更新 更多