Chinaunix首页 | 论坛 | 博客
  • 博客访问: 8971
  • 博文数量: 3
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 22
  • 用 户 组: 普通用户
  • 注册时间: 2016-02-24 20:12
个人简介

只想静静地作只程序猿

文章存档

2016年(3)

我的朋友
最近访客

分类: C/C++

2016-06-01 21:35:06

这篇文章主要讲怎么通过编程获取Linux的网络参数:
    1、获取mac地址
    2、获取网络接口号
    3、获取ipv4地址
    4、获取ipv6地址
    5、获取子网掩码
    6、获取接口标志
    其中后面4个参数都可以通过getifaddrs()函数获取
代码中用到的一些宏定义

点击(此处)折叠或打开

  1. #define Print(fmt, args...) printf("[%s, %d] "fmt"\n", __func__, __LINE__, ##args)
  2. #define MAC_ADDR_SIZE 6
  3. #define IPV6_ADDR_LEN 16
1、获取本地mac地址

点击(此处)折叠或打开

  1. void get_mac_addr(int sockfd, char *devName, unsigned char *mac)
  2. {
  3.         struct ifreq ifr;

  4.         strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
  5.         if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0)
  6.         {
  7.                 Print("ioctl: %s", strerror(errno));
  8.                 return;
  9.         }

  10.         memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE);

  11.         printf("%s mac:%02x:%02x:%02x:%02x:%02x:%02x\n",
  12.               devName, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  13. }
2、获取网络接口号
    方法一:使用ioctl函数来实现,是我所见使用比较广泛的一种 方法

点击(此处)折叠或打开

  1. int get_ifindex1(int sockfd, char *devName)
  2. {
  3.         struct ifreq ifr;

  4.         strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
  5.         if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0)
  6.         {
  7.                 Print("ioctl: %s", strerror(errno));
  8.                 return -1;
  9.         }

  10.         printf("get ifindex1: %d\n", ifr.ifr_ifindex);
  11.         return ifr.ifr_ifindex;
  12. }
    方法二:是用if_nametoindex函数来实现,与之相反的函数是if_indextoname。个人感觉使用这种方式更为简洁,但很少看到有人用这种方式来实现。不知道为什么。

点击(此处)折叠或打开

  1. int get_ifindex2(char *devName)
  2. {
  3.         unsigned int ifindex;

  4.         if (0 == (ifindex = if_nametoindex(devName)))
  5.         {
  6.                 Print("if_nametoindex failed: %s", strerror(errno));
  7.                 return -1;
  8.         }

  9.         printf("get ifindex2: %d\n", ifindex);
  10.         return ifindex;
  11. }
3、获取ip地址

点击(此处)折叠或打开

  1. void get_ipaddr(int sockfd, char *devName)
  2. {
  3.         struct sockaddr_in *sin;
  4.         struct ifreq ifr;

  5.         memset(&ifr, 0, sizeof(ifr));
  6.         strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));

  7.         if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0)
  8.         {
  9.                 Print("ioctl SIOCGIFADDR: %s", strerror(errno));
  10.                 return;
  11.         }

  12.         sin = (struct sockaddr_in *)&ifr.ifr_addr;
  13.         printf("get ip address of %s: %s\n", devName, inet_ntoa(sin->sin_addr));
  14.         return;
  15. }
4、获取ipv6地址
    方法一:使用函数getifaddrs,实例参考man手册来的。显然这个函数也可以用来获取ipv4地址。但一定要记得释放内存。
    PS:第一次看到这么用“?:”运算符的,感觉很新颖。

点击(此处)折叠或打开

  1. void get_ip6addr1()
  2. {
  3.         struct ifaddrs *ifaddr, *ifa;
  4.         int family, s;
  5.         char host[NI_MAXHOST];

  6.         if (getifaddrs(&ifaddr) == -1)
  7.         {
  8.                 Print("getifaddr failed: %s", strerror(errno));
  9.                 return;
  10.         }

  11.         /*walk through linked list, maintaining head pointer
  12.          so we can free list later*/
  13.         for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
  14.         {
  15.                 if (NULL == ifa->ifa_addr)
  16.                 {
  17.                         continue;
  18.                 }

  19.                 family = ifa->ifa_addr->sa_family;
  20.                 printf("%s address family: %d%s\n",
  21.                         ifa->ifa_name, family,
  22.                         (AF_PACKET == family) ? "(AF_PACKET)" :
  23.                         (AF_INET == family) ? "(AF_INET)" :
  24.                         (AF_INET6 == family) ? "(AF_INET6)" : "");
  25.                 
  26.                 if ((AF_INET == family) || (AF_INET6 == family))
  27.                 {
  28.                         s = getnameinfo(ifa->ifa_addr,
  29.                                 (AF_INET == family) ? sizeof(struct sockaddr_in) :
  30.                                                       sizeof(struct sockaddr_in6),
  31.                                 host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
  32.                         if (0 != s)
  33.                         {
  34.                                 Print("getnameinfo failed: %s\n", gai_strerror(s));
  35.                                 return;
  36.                         }
  37.                         printf("\taddress: <%s>\n", host);
  38.                 }
  39.         }
  40.         freeifaddrs(ifaddr);//释放内存,不要忘了

  41.         return;
  42. }
    下面是这个函数在我的虚拟机上运行的结果:

点击(此处)折叠或打开

  1. lo address family: 17(AF_PACKET)
  2. eth0 address family: 17(AF_PACKET)
  3. lo address family: 2(AF_INET)
  4.     address: <127.0.0.1>
  5. eth0 address family: 2(AF_INET)
  6.     address: <192.168.1.104>
  7. lo address family: 10(AF_INET6)
  8.     address: <::1>
  9. eth0 address family: 10(AF_INET6)
  10.     address: <fe80::20c:29ff:fedc:a8f6%eth0>
    方法二:这种方法是从以前某个版本的busybox中的ifconfig源码中看到的,直接分析/proc/net/if_inet6文件

点击(此处)折叠或打开

  1. void get_ip6addr2(char *ifname)
  2. {
  3.         unsigned char addr[IPV6_ADDR_LEN];
  4.         char devname[20];
  5.         int if_idx, dad_status, scope, plen, prelen;
  6.         char addr6p[8][5];
  7.         char addrStr[40];
  8.         FILE *f;

  9.         if (NULL == (f = fopen("/proc/net/if_inet6", "r")))
  10.         {
  11.                 Print("open if_inet6 err failed");
  12.                 return;
  13.         }

  14.         while (EOF != fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
  15.                 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
  16.                 addr6p[4], addr6p[5], addr6p[6], addr6p[7],
  17.                 &if_idx, &plen, &scope, &dad_status, devname))
  18.         {
  19.                 if (strcmp(devname, ifname))
  20.                 {
  21.                         continue;
  22.                 }

  23.                 sprintf(addrStr, "%s:%s:%s:%s:%s:%s:%s:%s",
  24.                         addr6p[0], addr6p[1], addr6p[2], addr6p[3],
  25.                         addr6p[4], addr6p[5], addr6p[6], addr6p[7]);

  26.                 printf("get ipv6 address of %s: %s\n", ifname, addrStr);
  27.                 inet_pton(AF_INET6, addrStr, addr);
  28.         }
  29. }
5、获取子网掩码
    方法一:使用ioctl函数

点击(此处)折叠或打开

  1. void get_netMask1(int sockfd, char *devName)
  2. {
  3.         struct ifreq ifr;
  4.         struct sockaddr_in *mask = NULL;

  5.         memset(&ifr, 0, sizeof(ifr));
  6.         strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));

  7.         if(ioctl(sockfd, SIOCGIFNETMASK, &ifr) < 0)
  8.         {
  9.                 Print("ioctl SIOCGIFNETMASK: %s", strerror(errno));
  10.                 return;
  11.         }

  12.         mask = (struct sockaddr_in *)&(ifr.ifr_netmask);
  13.         printf("get net mask of %s: %s\n", devName, inet_ntoa(mask->sin_addr));
  14. }
    方法二:使用getifaddrs函数

点击(此处)折叠或打开

  1. void get_netMask2(char *devName)
  2. {
  3.         struct ifaddrs *ifaddr = NULL, *ifa = NULL;
  4.         struct sockaddr_in *addr = NULL, *mask = NULL;
  5.         char addrStr[16], maskStr[16];

  6.         if (getifaddrs(&ifaddr) < 0)
  7.         {
  8.                 Print("getifaddrs failed: %s", strerror(errno));
  9.                 return;
  10.         }

  11.         for (ifa = ifaddr; NULL != ifa; ifa = ifa->ifa_next)
  12.         {
  13.                 if (strcmp(ifa->ifa_name, devName))
  14.                 {
  15.                         continue;
  16.                 }

  17.                 if (ifa->ifa_addr->sa_family != AF_INET)
  18.                 {
  19.                         continue;
  20.                 }

  21.                 if ((NULL == ifa->ifa_addr) || (NULL == ifa->ifa_netmask))
  22.                 {
  23.                         continue;
  24.                 }

  25.                 addr = (struct sockaddr_in *)ifa->ifa_addr;
  26.                 mask = (struct sockaddr_in *)ifa->ifa_netmask;
  27.                 strncpy(addrStr, inet_ntoa(addr->sin_addr), sizeof(addrStr));
  28.                 strncpy(maskStr, inet_ntoa(mask->sin_addr), sizeof(maskStr));

  29.                 printf("dev-%s addr-%s mask-%s\n", devName, addrStr, maskStr);
  30.         }

  31.         freeifaddrs(ifaddr);
  32. }
6、获取接口标志
    方法一:使用ioctl,通过man netdevice可以获得更多关于ioctl以及标志的说明

点击(此处)折叠或打开

  1. void get_flags1(int sockfd, char *devName)
  2. {
  3.         struct ifreq ifr;
  4.         unsigned int flags;

  5.         memset(&ifr, 0, sizeof(ifr));
  6.         strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
  7.         if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
  8.         {
  9.                 Print("ioctl SIOCGIFFLAGS: %s", strerror(errno));
  10.                 return;
  11.         }

  12.         flags = ifr.ifr_flags;

  13.         printf("get flags of %s: %08x\n", devName, flags);
  14.         if (flags & IFF_UP) printf("UP ");
  15.         if (flags & IFF_BROADCAST) printf("BROADCAST ");
  16.         if (flags & IFF_DEBUG) printf("DEBUG ");
  17.         if (flags & IFF_LOOPBACK) printf("LOOPBACK ");
  18.         /*更多标志可通过man netdevice获取*/
  19.         printf("\n");
  20. }
    方法二:使用getifaddrs函数

点击(此处)折叠或打开

  1. void get_flags2(char *devName)
  2. {
  3.         struct ifaddrs *ifaddr = NULL, *ifa = NULL;
  4.         unsigned int flags;

  5.         if (getifaddrs(&ifaddr) < 0)
  6.         {
  7.                 Print("getifaddrs failed: %s", strerror(errno));
  8.                 return;
  9.         }

  10.         for (ifa = ifaddr; NULL != ifa; ifa = ifa->ifa_next)
  11.         {
  12.                 if (!strcmp(ifa->ifa_name, devName))
  13.                 {
  14.                         break;
  15.                 }
  16.         }
  17.         if (NULL != ifa)
  18.         {
  19.                 flags = ifa->ifa_flags;
  20.                 printf("get flags of %s: %08x\n", devName, flags);
  21.         }

  22.         freeifaddrs(ifaddr);
  23. }
    从上面不难看出,如果只需要获取一个网络参数,使用ioctl比较简单。如果需要同时获取多个参数,推荐使用getifaddrs方法。
阅读(1137) | 评论(0) | 转发(0) |
1

上一篇:没有了

下一篇:给虚拟机中的ubuntu安装新内核

给主人留下些什么吧!~~