ifaddrs结构体定义如下:
ifa_next指向链表的下一个成员;ifa_name是接口名称,以0结尾的字符串,比如eth0,lo;ifa_flags是接口的标识位(比如当IFF_BROADCAST或IFF_POINTOPOINT设置到此标识位时,影响联合体变量ifu_broadaddr存储广播地址或ifu_dstaddr记录点对点地址);ifa_netmask存储该接口的子网掩码;结构体变量存储广播地址或点对点地址(见括弧介绍ifa_flags);ifa_data存储了该接口协议族的特殊信息,它通常是NULL(一般不关注他)。
    函数getifaddrs(int getifaddrs (struct ifaddrs **__ifap))获取本地网络接口信息,将之存储于链表中,链表头结点指针存储于__ifap中带回,函数执行成功返回0,失败返回-1,且为errno赋值。
    很显然,函数getifaddrs用于获取本机接口信息,比如最典型的获取本机IP地址。
这 是一项不太清晰而且没有多大意义的工作。一个原因是网络地址的设置非常灵活而且都是允许用户进行个性化设置的,比如一台计算机上可以有多块物理网卡或者虚 拟网卡,一个网卡上可以绑定多个IP地址,用户可以为网卡设置别名,可以重命名网卡,用户计算机所在网络拓扑结构未知,主机名设置是一个可选项并且同样可 以为一个计算机绑定多个主机名等,这些信息都会有影响。脱离了网络连接,单独的网络地址没有任何意义。编程中遇到必须获取计算机IP的场景,应该考虑将这 一选项放到配置文件中,由用户自己来选择。
通过google,编程获取IP地址大约有以下三种思路:
1. 通过gethostname()和gethostbyname()
#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
    char hname[128];
    struct hostent *hent;
    int i;
    gethostname(hname, sizeof(hname));
    //hent = gethostent();
    hent = gethostbyname(hname);
    printf("hostname: %s/naddress list: ", hent->h_name);
    for(i = 0; hent->h_addr_list[i]; i++) {
        printf("%s/t", inet_ntoa(*(struct in_addr*)(hent->h_addr_list[i])));
    }
    return 0;
}
运行:
[whb@jcwkyl c]$ ./local_ip 
hostname: jcwkyl.jlu.edu.cn
address list: 10.60.56.90       
2. 通过枚举网卡,API接口可查看man 7 netdevice
/*代码来自StackOverflow: http://stackoverflow.com/questions/212528/linux-c-get-the-ip-address-of-local-computer */
#include <stdio.h>      
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h> 
#include <string.h> 
#include <arpa/inet.h>
int main (int argc, const char * argv[]) {
    struct ifaddrs * ifAddrStruct=NULL;
    void * tmpAddrPtr=NULL;
    getifaddrs(&ifAddrStruct);
    while (ifAddrStruct!=NULL) {
        if (ifAddrStruct->ifa_addr->sa_family==AF_INET) { // check it is IP4
            // is a valid IP4 Address
            tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            printf("%s IP Address %s/n", ifAddrStruct->ifa_name, addressBuffer); 
        } else if (ifAddrStruct->ifa_addr->sa_family==AF_INET6) { // check it is IP6
            // is a valid IP6 Address
            tmpAddrPtr=&((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
            char addressBuffer[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            printf("%s IP Address %s/n", ifAddrStruct->ifa_name, addressBuffer); 
        } 
        ifAddrStruct=ifAddrStruct->ifa_next;
    }
    return 0;
}
运行 :
[whb@jcwkyl c]$ ./local_ip2 
lo IP Address 127.0.0.1
eth0 IP Address 10.60.56.90
eth0:1 IP Address 192.168.1.3
lo IP Address ::
eth0 IP Address ::2001:da8:b000:6213:20f:1fff
eth0 IP Address 0:0:fe80::20f:1fff
3. 打开一个对外界服务器的网络连接,通过getsockname()反查自己的IP
//获取本机IP地址函数
//修改本机IP地址的函数
//获取子网掩码的函数
//修改子NETMASK的函数
//获去GateWay
//设置网关
有时候,写程序的时候需要获取计算机的网络信息,比如IP地址、电脑名称、DNS等信息。IP地址和电脑名称是比较容易获取到的,而要想获取地址掩码、DNS、网关等信息就有些麻烦了。
在Windows下我们一般都是通过从注册表读取这些信息。在Linux怎么做呢?其实,Linux下更加容易一些。因为我们可以拿现成的程序看它的源代码。通过阅读其源代码找到解决该问题的方法。那么,看哪个程序的源代码呢?如果你使用过Linux,并且比较熟悉的话就肯定知道一个命令ifconfig。这个命令和Windows下的ipconfig差不多,都可以输出网卡的信息,其中就包含DNS、掩码等信息。所以,我们可以通过看它的源代码来找到解决该问题的方法。
并没有那个系统调用提供网卡数量的获取。但是,我们可以通过强大的proc文件系统获取网卡数量的信息。实际上,ifconfig也是这样做的,请看示例代码如下:
0001 #include <stdio.h>
0002 #include <string.h>
0003 #include <errno.h>
0004
0005 int GetNetCardCount()
0006 {
0007 int nCount = 0;
0008     FILE* f = fopen("/proc/net/dev", "r");
0009 if (!f)
0010     {
0011 fprintf(stderr, "Open /proc/net/dev failed!errno:%d\n", errno);
0012 return nCount;
0013 }
0014
0015 char szLine[512];
0016
0017 fgets(szLine, sizeof(szLine), f); /* eat line */
0018 fgets(szLine, sizeof(szLine), f);
0019
0020 while(fgets(szLine, sizeof(szLine), f))
0021     {
0022         char szName[128] = {0};
0023 sscanf(szLine, "%s", szName);
0024 int nLen = strlen(szName);
0025 if (nLen <= 0)continue;
0026 if (szName[nLen - 1] == ‘:‘) szName[nLen - 1] = 0;
0027 if (strcmp(szName, "lo") == 0)continue;
0028 nCount++;
0029 }
0030
0031 fclose(f);
0032 f = NULL;
0033 return nCount;
0034 }
0035
0036 int main(int argc, char* argv[])
0037 {
0038     printf("NetCardCount: %d\n", GetNetCardCount());
0039 return 0;
0040 }
获取IP、掩码、MAC和广播地址是比较容易的,只需要调用对应的IOCTL即可。只是大家对Linux下的IOCTL可能不太熟悉。却看示例代码:
0001 void DispNetInfo(const char* szDevName)
0002 {
0003 int s = socket(AF_INET, SOCK_DGRAM, 0);
0004 if (s < 0)
0005     {
0006 fprintf(stderr, "Create socket failed!errno=%d", errno);
0007 return;
0008 }
0009
0010 struct ifreq ifr;
0011 unsigned char mac[6];
0012 unsigned long nIP, nNetmask, nBroadIP;
0013
0014     printf("%s:\n", szDevName);
0015
0016 strcpy(ifr.ifr_name, szDevName);
0017 if (ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
0018     {
0019 return;
0020 }
0021 memcpy(mac, ifr.ifr_hwaddr.sa_data, sizeof(mac));
0022     printf("\tMAC: %02x-%02x-%02x-%02x-%02x-%02x\n",
0023 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
0024
0025 strcpy(ifr.ifr_name, szDevName);
0026 if (ioctl(s, SIOCGIFADDR, &ifr) < 0)
0027     {
0028 nIP = 0;
0029 }
0030 else
0031     {
0032 nIP = *(unsigned long*)&ifr.ifr_broadaddr.sa_data[2];
0033 }
0034     printf("\tIP: %s\n", inet_ntoa(*(in_addr*)&nIP));
0035
0036 strcpy(ifr.ifr_name, szDevName);
0037 if (ioctl(s, SIOCGIFBRDADDR, &ifr) < 0)
0038     {
0039 nBroadIP = 0;
0040 }
0041 else
0042     {
0043 nBroadIP = *(unsigned long*)&ifr.ifr_broadaddr.sa_data[2];
0044 }
0045     printf("\tBroadIP: %s\n", inet_ntoa(*(in_addr*)&nBroadIP));
0046
0047 strcpy(ifr.ifr_name, szDevName);
0048 if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0)
0049     {
0050 nNetmask = 0;
0051 }
0052 else
0053     {
0054 nNetmask = *(unsigned long*)&ifr.ifr_netmask.sa_data[2];
0055 }
0056     printf("\tNetmask: %s\n", inet_ntoa(*(in_addr*)&nNetmask));
0057 close(s);
0058 }
那么如何获取网关地址呢?更加容易,但是,好像很少有人知道。反正我在网上没有找到有人知道。最后看了nslookup的源代码以后才知道正确的做法。代码如下:
res_init();
for (int i = 0; i < _res.nscount; i++)
{
struct sockaddr* server = (struct sockaddr*)&_res.nsaddr_list[i];
printf("Server: %s\n", inet_ntoa(*(in_addr*)&(server->sa_data[2])));
}
代码很简单,就不做解释了。
怎么获取网关呢?这个稍微有点麻烦一些,不过和获取网卡数量相似,都是通过proc文件系统。这次分析的/proc/net/route文件。我就不再贴出示例代码了。
最后,我把运行示例程序获取到的信息附上,以供大家有个直观的认识:
eth0:
MAC: 08-00-27-98-bf-f3
IP: 192.168.1.106
BroadIP: 255.255.255.255
Netmask: 255.255.255.0
Gateway: 192.168.1.1
eth1:
MAC: 08-00-27-16-f4-bf
IP: 192.168.1.108
BroadIP: 192.168.1.255
Netmask: 255.255.255.0
Gateway: 0.0.0.0
eth2:
MAC: 08-00-27-37-9c-91
IP: 0.0.0.0
BroadIP: 0.0.0.0
Netmask: 0.0.0.0
Gateway: 0.0.0.0
eth3:
MAC: 08-00-27-5a-d2-39
IP: 0.0.0.0
BroadIP: 0.0.0.0
Netmask: 0.0.0.0
Gateway: 0.0.0.0
NetCardCount: 4
DNS 0: 218.2.135.1
DNS 1: 61.147.37.1
| 
 Linux下的网络配置包含三个要素,分别是IP地址、子网掩码和网关。本文将介绍如何在C语言中进行网络的配置和配置信息的获取。 
 
 【配置】 
 
 方法一 
 
 使用system()或exec*()调用ifconfig和route命令进行配置。这种方法的优点是使用简单,缺点是效率比较低,且依赖于ifconfig与route命令。 
 示例: 见所附代码中的函数ip_config_system()和ip_config_exec()。 
 
 方法二 
 
 建立一个socket,用ioctl()进行配置。这种方法的优点是效率较高,缺点是程序实现起来比较麻烦。 
 示例: 见所附代码中的函数ip_config_ioctl()。 
 
 【获取】 
 
 方法一 
 
 用popen()建立一个管道,管道的一端执行命令ifconfig和route,管道的另一端读取收到的数据并进行相应的解析。这种方法的优点是使用简单,缺点是效率比较低,且依赖于ifconfig与route命令。 
 示例: 见所附代码中的函数ip_get_pipe()。 
 
 方法二 
 
 用fopen()打开/proc/net/route,可以获取网关(在/proc/net中尚未发现比较好的获取IP地址和掩码的方法,知道的请发邮件至cugfeng at gamil.com,谢谢)。这种方法的优点是使用简单,效率比执行命令高,缺点是依赖于proc文件系统。 
 示例: 见所附代码中的函数ip_get_proc()。 
 
 方法三 
 
 建立一个socket,用ioctl()进行获取(用ioctl()尚未发现比较好的获取网关的方法,知道的请发邮件至cugfeng at gamil.com,谢谢)。这种方法的优点是效率较高,缺点是程序实现起来比较麻烦。 
 示例: 见所附代码中的函数ip_get_ioctl()。 
 
 BTW,用ioctl()的方法还可以获取MAC地址,ioctl()命令为SIOCGIFHWADDR,具体用法与ioctl()获取IP地址的方法相同,这里就不多说了。 | 
 ioctl及getifaddrs读取IPv4,IPv6网卡信息
 ioctl及getifaddrs读取IPv4,IPv6网卡信息使用ioctl的SIOCGIFCONF可以读取所有网卡信息。ioctl调用后返回指向ifconf的结构链表,其中包含了指向ifreq的结构指针。ifconf及ifreq定义在net/if.h中。
《UNIX网络编程》中提供了get_ifi_info函数的实现方法,使用这种方式来获取网络信息。在LINUX下,这种方式不能获得IPV6的网卡信息。《UNIX网络编程》中有如下描述:
在支持IPV6的系统中,没有关于对SIOCGIFCONF请求是否返回IPV6地址的标准。我们给支持IPV6的新系统增加了一个case语句, 这是为了预防万一。问题在于ifreq中的联合把返回的地址定义成一个通用的16字节套接口地址结构,适合16字节的IPV4 socket_in结构,但对于24字节的IPV6 socket_in6结构太小了。如果返回IPV6地址,将可能破环现有的在每个ifreq结构中采用固定大小的套接口地址结构的代码。
经测试,在fedor6-2.6.18kernel中无法返回ipv6地址,事实上,返回的地址簇总是AF_INET,而并非AF_INET6。
这种方法的实现代码如下:
net_if.h
#ifndef __NET_INF_H
#define __NET_INF_H
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define IFI_NAME 16
#define IFI_HADDR 8
typedef struct ifi_info
{
  char ifi_name[IFI_NAME];
  u_char ifi_haddr[IFI_HADDR];
  u_short ifi_hlen;
  short ifi_flags;
  short ifi_myflags;
  struct sockaddr *ifi_addr;
  struct sockaddr *ifi_brdaddr;
  struct sockaddr *ifi_dstaddr;
  struct ifi_info *ifi_next;
}ifi_info;
#define IFI_ALIAS 1
struct ifi_info *get_ifi_info(int, int);
void free_ifi_info(struct ifi_info *);
#endif
net_if.c
#include "net_if.h"
ifi_info *get_ifi_info(int family, int doaliases)
{
  ifi_info *ifi, *ifihead, **ifipnext;
  int sockfd, len, lastlen, flags, myflags;
  char *ptr, *buf, lastname[IFNAMSIZ], *cptr;
  struct ifconf ifc;
  struct ifreq *ifr, ifrcopy;
  struct sockaddr_in *sinptr;
  if ((sockfd=socket(family, SOCK_DGRAM, 0))<0)
  {
    printf("socket error.\n");
    exit(1);
  }
  lastlen = 0;
  len = 10*sizeof(struct ifreq);
  while (1)
  {
    buf = (char*)malloc(len);
    ifc.ifc_len = len;
    ifc.ifc_buf = buf;
    if (ioctl(sockfd, SIOCGIFCONF, &ifc)<0)
    {
      if (errno!=EINVAL||lastlen!=0)
      {
        printf("ioctl error.\n");
      }
    }
    else
    {
      if (ifc.ifc_len == lastlen)
        break;
      lastlen = ifc.ifc_len;
    }
    len += 10*sizeof(struct ifreq);
    free(buf);
  }
  ifihead = NULL;
  ifipnext = &ifihead;
  lastname[0] = 0;
  for (ptr = buf; ptrifr->ifr_addr.sa_len?sizeof(struct sockaddr):ifr->ifr_addr.sa_len;
#else
    switch (ifr->ifr_addr.sa_family)
    {
#ifdef IPV6
    case AF_INET6:
      len = sizeof(struct sockaddr_in6);
      break;
#endif
    case AF_INET:
    default:
      len = sizeof(struct sockaddr);
      break;
    }
#endif
    ptr += sizeof(ifr->ifr_name) + len;
    if (ifr->ifr_addr.sa_family != family)
      continue;
    myflags = 0;
    if ((cptr=strchr(ifr->ifr_name, ‘:‘))!=NULL)
      *cptr = 0;
    if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ)==0)
    {
      if (doaliases == 0)
        continue;
      myflags = IFI_ALIAS;
    }
    memcpy(lastname, ifr->ifr_name, IFNAMSIZ);
    ifrcopy = *ifr;
    ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
    flags = ifrcopy.ifr_flags;
    if ((flags&IFF_UP)==0)
      continue;
    /*
    if ((flags&IFF_BROADCAST)==0)
      continue;
    */
    ifi = calloc(1, sizeof(struct ifi_info));
    *ifipnext = ifi;
    ifipnext = &ifi->ifi_next;
    ifi->ifi_flags = flags;
    ifi->ifi_myflags = myflags;
    memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
    ifi->ifi_name[IFI_NAME-1] = ‘\0‘;
    switch (ifr->ifr_addr.sa_family)
    {
    case AF_INET:
      sinptr = (struct sockaddr_in *)&ifr->ifr_addr;
      if (ifi->ifi_addr == NULL)
      {
        ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in));
        memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
#ifdef SIOCGIFBRDADDR
        if (flags & IFF_BROADCAST)
        {
          ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
          sinptr = (struct sockaddr_in *)&ifrcopy.ifr_broadaddr;
          ifi->ifi_brdaddr = calloc(1, sizeof(struct sockaddr_in));
          memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
        }
#endif
#ifdef SIOCGIFDSTADDR
        if (flags & IFF_POINTOPOINT)
        {
          ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
          sinptr = (struct sockaddr_in*)&ifrcopy.ifr_dstaddr;
          ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in));
          memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
        }
#endif
      }
      break;
    default:
      break;
    }
  }
  free(buf);
  return(ifihead);
}
void free_ifi_info(ifi_info *ifihead)
{
  ifi_info *ifi, *ifinext;
  for (ifi=ifihead; ifi!=NULL; ifi=ifinext)
  {
    if (ifi->ifi_addr!=NULL)
      free(ifi->ifi_addr);
    if (ifi->ifi_brdaddr!=NULL)
      free(ifi->ifi_brdaddr);
    if (ifi->ifi_dstaddr!=NULL)
      free(ifi->ifi_dstaddr);
    ifinext = ifi->ifi_next;
    free(ifi);
  }
}
char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
  char portstr[7];
  static char str[128];
  switch (sa->sa_family)
  {
  case AF_INET:
    {
      struct sockaddr_in *sin = (struct sockaddr_in *)sa;
      if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))==NULL)
        return NULL;
      if (ntohs(sin->sin_port)!=0)
      {
        snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port));
        strcat(str, portstr);
      }
      return str;
    }
    break;
  case AF_INET6:
    {
      struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa;
      if (inet_ntop(AF_INET6, &sin->sin6_addr, str, sizeof(str))==NULL)
        return NULL;
      if (ntohs(sin->sin6_port)!=0)
      {
        snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin6_port));
        strcat(str, portstr);
      }
      return str;
    }
    break;
  default:
    return NULL;
    break;
  }
}
int main(int argc, char *argv[])
{
  ifi_info *ifi, *ifihead;
  struct sockaddr *sa;
  u_char *ptr;
  int i, family, doaliases;
  if (argc!=3)
  {
    printf("usage: ./prifinfo  ");
    exit(1);
  }
  if (strcmp(argv[1], "inet4") == 0)
    family = AF_INET;
#ifdef IPV6
  else if (strcmp(argv[1], "inet6") == 0)
    family =AF_INET6;
#endif
  else
  {
    printf("invalid
");
    exit(1);
  }
  doaliases = atoi(argv[2]);
  for(ifihead = ifi = get_ifi_info(family, doaliases);
      ifi!=NULL;ifi=ifi->ifi_next)
  {
    printf("%s:<", ifi->ifi_name);
    if (ifi->ifi_flags&IFF_UP) printf("UP");
    if (ifi->ifi_flags&IFF_BROADCAST) printf("BCAST");
    if (ifi->ifi_flags&IFF_MULTICAST) printf("MCAST");
    if (ifi->ifi_flags&IFF_LOOPBACK) printf("LOOP");
    if (ifi->ifi_flags&IFF_POINTOPOINT) printf("P2P");
    printf(">\n");
    if ((i=ifi->ifi_hlen)>0)
    {
      ptr = ifi->ifi_haddr;
      do
      {
        printf("%s%x", (i==ifi->ifi_hlen)?" ":":", *ptr++);
      }while(--i>0);
      printf("\n");
    }
    if ((sa=ifi->ifi_addr)!=NULL)
      printf(" IP addr: %s\n",
             sock_ntop(sa, sizeof(*sa)));
    if ((sa=ifi->ifi_brdaddr)!=NULL)
      printf(" broadcast addr: %s\n",
             sock_ntop(sa, sizeof(*sa)));
    if ((sa=ifi->ifi_dstaddr)!=NULL)
      printf(" destnation addr: %s\n",
             sock_ntop(sa, sizeof(*sa)));
  }
  free_ifi_info(ifihead);
  exit(0);
}
使用gcc net_if.c -o net_if -DIPV6编译,在IPV4模式下运行输出为:
[root@localhost net_if]./net_if inet4 1
lo:
IP addr: 127.0.0.1
eth1:
IP addr: 192.168.1.2
broadcast addr: 192.168.1.255
eth0:
IP addr: 192.168.125.99
broadcast addr: 192.168.125.255
执行./net_if inet6 1在输出为空。
第二种方式是使用getifaddrs函数获取,需要包含ifaddrs.h头文件,这种方式可以获得IPV6地址,改写的《UNIX网络编程》中的get_ifi_info函数如下所示:
znet.h
#ifndef __ZNET_H__
#define __ZNET_H__
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define	IFI_NAME	16			/* same as IFNAMSIZ in  */
#define	IFI_HADDR	 8			/* allow for 64-bit EUI-64 in future */
struct ifi_info {
  char    ifi_name[IFI_NAME];	/* interface name, null-terminated */
  short   ifi_index;			/* interface index */
  short   ifi_flags;			/* IFF_xxx constants from  */
  struct sockaddr  *ifi_addr;	/* primary address */
  struct sockaddr  *ifi_brdaddr;/* broadcast address */
  struct ifi_info  *ifi_next;	/* next of these structures */
};
struct ifi_info* get_ifi_info(int, int);
void free_ifi_info(struct ifi_info *);
#endif
znet.c
#include "znet.h"
struct ifi_info* get_ifi_info(int family, int doaliases) {
	struct ifi_info		*ifi, *ifihead, **ifipnext,*p;
	struct sockaddr_in	*sinptr;
	struct sockaddr_in6	*sin6ptr;
	struct ifaddrs *ifas;
//	char addr[128];
	int sockfd;
	ifihead = NULL;
	ifipnext = &ifihead;
	if(getifaddrs(&ifas)!=0)
		return ;
	for(;ifas!=NULL;ifas=(*ifas).ifa_next) {
		if (((*ifas).ifa_addr)->sa_family != family)
			continue;	// ignore if not desired address family
/*
		printf("%s %d\n",(*ifas).ifa_name,((*ifas).ifa_addr)->sa_family);
		if(((*ifas).ifa_addr)->sa_family!=AF_INET6)
			inet_ntop(AF_INET,&(((struct sockaddr_in *)((*ifas).ifa_addr))->sin_addr),addr,sizeof(addr));
		else
			inet_ntop(AF_INET6,&(((struct sockaddr_in6 *)((*ifas).ifa_addr))->sin6_addr),addr,sizeof(addr));
		printf("%s\t",addr);
		printf("\n");
*/
		ifi = (struct ifi_info*)calloc(1,sizeof(struct ifi_info));
		*ifipnext = ifi;
		ifipnext = &ifi->ifi_next;	
		ifi->ifi_flags = (*ifas).ifa_flags;
		memcpy(ifi->ifi_name, (*ifas).ifa_name, IFI_NAME);
		ifi->ifi_name[IFI_NAME-1] = ‘\0‘;
		switch (((*ifas).ifa_addr)->sa_family) {
			case AF_INET:
				sinptr = (struct sockaddr_in *) (*ifas).ifa_addr;
				ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
				memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
#ifdef	SIOCGIFBRDADDR
				if (ifi->ifi_flags & IFF_BROADCAST) {
					sinptr = (struct sockaddr_in *) (*ifas).ifa_broadaddr;
					ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
					memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
				}
#endif
				break; 
			case AF_INET6:
				sin6ptr = (struct sockaddr_in6 *) (*ifas).ifa_addr;
				ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
				memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6));
				break; 
			default:
				break;
		}
	}
	freeifaddrs(ifas);	
	return(ifihead);
}
int main(int argc, char *argv[]) {
	int family;
	if (argc!=2) {
	    printf("usage: ./znet \n");
	    exit(1);
	}
	if (strcmp(argv[1], "inet4") == 0)
		family = AF_INET;
	else if (strcmp(argv[1], "inet6") == 0)
		family =AF_INET6;
	else {
    printf("invalid
\n");
    exit(1);
    	}
	char addr[128];
	struct ifi_info	*ifi, *ifihead;
	printf("name\tflag\tIP\t\tbroadcastaddr\n");
	for (ifihead = ifi = get_ifi_info(family,1); ifi != NULL; ifi = ifi->ifi_next) {
		printf("%s\t",ifi->ifi_name);
		printf("%d\t",ifi->ifi_flags);
		if((ifi->ifi_addr)->sa_family!=AF_INET6)
			inet_ntop(AF_INET,&(((struct sockaddr_in *)(ifi->ifi_addr))->sin_addr),addr,sizeof(addr));
		else
			inet_ntop(AF_INET6,&(((struct sockaddr_in6 *)(ifi->ifi_addr))->sin6_addr),addr,sizeof(addr));
		printf("%s\t",addr);
#ifdef	SIOCGIFBRDADDR
		if ((ifi->ifi_flags & IFF_BROADCAST) && (ifi->ifi_addr)->sa_family!=AF_INET6) {
			inet_ntop(AF_INET,&(((struct sockaddr_in *) (ifi->ifi_brdaddr))->sin_addr),addr,sizeof(addr));
			printf("%s\t",addr);
		}
#endif
		printf("\n+++++++++++++++++++++++++++++++++++++++++++\n");
	}
	return 0;
}
这段代码输出如下:
[root@localhost net_if]./znet inet4
name flag IP broadcastaddr
lo 73 127.0.0.1
++++++++++++++++++++++++++++++
eth1 4099 192.168.1.2 192.168.1.255
++++++++++++++++++++++++++++++
eth0 4163 192.168.125.99 192.168.125.255
++++++++++++++++++++++++++++++
[root@localhost net_if]./znet inet6
name flag IP broadcastaddr
lo 73 ::1
++++++++++++++++++++++++++++++
eth1 4163 2001:250:1800:1::1
++++++++++++++++++++++++++++++
eth0 4163 2001:250:1888:1::1
原文:http://www.cnblogs.com/lidabo/p/5344760.html