这篇文章主要讲怎么通过编程获取Linux的网络参数:
1、获取mac地址
2、获取网络接口号
3、获取ipv4地址
4、获取ipv6地址
5、获取子网掩码
6、获取接口标志
其中后面4个参数都可以通过getifaddrs()函数获取
代码中用到的一些宏定义
-
#define Print(fmt, args...) printf("[%s, %d] "fmt"\n", __func__, __LINE__, ##args)
-
#define MAC_ADDR_SIZE 6
-
#define IPV6_ADDR_LEN 16
1、获取本地mac地址
-
void get_mac_addr(int sockfd, char *devName, unsigned char *mac)
-
{
-
struct ifreq ifr;
-
-
strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
-
if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0)
-
{
-
Print("ioctl: %s", strerror(errno));
-
return;
-
}
-
-
memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE);
-
-
printf("%s mac:%02x:%02x:%02x:%02x:%02x:%02x\n",
-
devName, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
-
}
2、获取网络接口号
方法一:使用ioctl函数来实现,是我所见使用比较广泛的一种 方法
-
int get_ifindex1(int sockfd, char *devName)
-
{
-
struct ifreq ifr;
-
-
strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
-
if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0)
-
{
-
Print("ioctl: %s", strerror(errno));
-
return -1;
-
}
-
-
printf("get ifindex1: %d\n", ifr.ifr_ifindex);
-
return ifr.ifr_ifindex;
-
}
方法二:是用if_nametoindex函数来实现,与之相反的函数是if_indextoname。个人感觉使用这种方式更为简洁,但很少看到有人用这种方式来实现。不知道为什么。
-
int get_ifindex2(char *devName)
-
{
-
unsigned int ifindex;
-
-
if (0 == (ifindex = if_nametoindex(devName)))
-
{
-
Print("if_nametoindex failed: %s", strerror(errno));
-
return -1;
-
}
-
-
printf("get ifindex2: %d\n", ifindex);
-
return ifindex;
-
}
3、获取ip地址
-
void get_ipaddr(int sockfd, char *devName)
-
{
-
struct sockaddr_in *sin;
-
struct ifreq ifr;
-
-
memset(&ifr, 0, sizeof(ifr));
-
strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
-
-
if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0)
-
{
-
Print("ioctl SIOCGIFADDR: %s", strerror(errno));
-
return;
-
}
-
-
sin = (struct sockaddr_in *)&ifr.ifr_addr;
-
printf("get ip address of %s: %s\n", devName, inet_ntoa(sin->sin_addr));
-
return;
-
}
4、获取ipv6地址
方法一:使用函数getifaddrs,实例参考man手册来的。显然这个函数也可以用来获取ipv4地址。但一定要记得释放内存。
PS:第一次看到这么用“?:”运算符的,感觉很新颖。
-
void get_ip6addr1()
-
{
-
struct ifaddrs *ifaddr, *ifa;
-
int family, s;
-
char host[NI_MAXHOST];
-
-
if (getifaddrs(&ifaddr) == -1)
-
{
-
Print("getifaddr failed: %s", strerror(errno));
-
return;
-
}
-
-
/*walk through linked list, maintaining head pointer
-
so we can free list later*/
-
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next)
-
{
-
if (NULL == ifa->ifa_addr)
-
{
-
continue;
-
}
-
-
family = ifa->ifa_addr->sa_family;
-
printf("%s address family: %d%s\n",
-
ifa->ifa_name, family,
-
(AF_PACKET == family) ? "(AF_PACKET)" :
-
(AF_INET == family) ? "(AF_INET)" :
-
(AF_INET6 == family) ? "(AF_INET6)" : "");
-
-
if ((AF_INET == family) || (AF_INET6 == family))
-
{
-
s = getnameinfo(ifa->ifa_addr,
-
(AF_INET == family) ? sizeof(struct sockaddr_in) :
-
sizeof(struct sockaddr_in6),
-
host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
-
if (0 != s)
-
{
-
Print("getnameinfo failed: %s\n", gai_strerror(s));
-
return;
-
}
-
printf("\taddress: <%s>\n", host);
-
}
-
}
-
freeifaddrs(ifaddr);//释放内存,不要忘了
-
-
return;
-
}
下面是这个函数在我的虚拟机上运行的结果:
-
lo address family: 17(AF_PACKET)
-
eth0 address family: 17(AF_PACKET)
-
lo address family: 2(AF_INET)
-
address: <127.0.0.1>
-
eth0 address family: 2(AF_INET)
-
address: <192.168.1.104>
-
lo address family: 10(AF_INET6)
-
address: <::1>
-
eth0 address family: 10(AF_INET6)
-
address: <fe80::20c:29ff:fedc:a8f6%eth0>
方法二:这种方法是从以前某个版本的busybox中的ifconfig源码中看到的,直接分析/proc/net/if_inet6文件
-
void get_ip6addr2(char *ifname)
-
{
-
unsigned char addr[IPV6_ADDR_LEN];
-
char devname[20];
-
int if_idx, dad_status, scope, plen, prelen;
-
char addr6p[8][5];
-
char addrStr[40];
-
FILE *f;
-
-
if (NULL == (f = fopen("/proc/net/if_inet6", "r")))
-
{
-
Print("open if_inet6 err failed");
-
return;
-
}
-
-
while (EOF != fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
-
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
-
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
-
&if_idx, &plen, &scope, &dad_status, devname))
-
{
-
if (strcmp(devname, ifname))
-
{
-
continue;
-
}
-
-
sprintf(addrStr, "%s:%s:%s:%s:%s:%s:%s:%s",
-
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
-
addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
-
-
printf("get ipv6 address of %s: %s\n", ifname, addrStr);
-
inet_pton(AF_INET6, addrStr, addr);
-
}
-
}
5、获取子网掩码
方法一:使用ioctl函数
-
void get_netMask1(int sockfd, char *devName)
-
{
-
struct ifreq ifr;
-
struct sockaddr_in *mask = NULL;
-
-
memset(&ifr, 0, sizeof(ifr));
-
strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
-
-
if(ioctl(sockfd, SIOCGIFNETMASK, &ifr) < 0)
-
{
-
Print("ioctl SIOCGIFNETMASK: %s", strerror(errno));
-
return;
-
}
-
-
mask = (struct sockaddr_in *)&(ifr.ifr_netmask);
-
printf("get net mask of %s: %s\n", devName, inet_ntoa(mask->sin_addr));
-
}
方法二:使用getifaddrs函数
-
void get_netMask2(char *devName)
-
{
-
struct ifaddrs *ifaddr = NULL, *ifa = NULL;
-
struct sockaddr_in *addr = NULL, *mask = NULL;
-
char addrStr[16], maskStr[16];
-
-
if (getifaddrs(&ifaddr) < 0)
-
{
-
Print("getifaddrs failed: %s", strerror(errno));
-
return;
-
}
-
-
for (ifa = ifaddr; NULL != ifa; ifa = ifa->ifa_next)
-
{
-
if (strcmp(ifa->ifa_name, devName))
-
{
-
continue;
-
}
-
-
if (ifa->ifa_addr->sa_family != AF_INET)
-
{
-
continue;
-
}
-
-
if ((NULL == ifa->ifa_addr) || (NULL == ifa->ifa_netmask))
-
{
-
continue;
-
}
-
-
addr = (struct sockaddr_in *)ifa->ifa_addr;
-
mask = (struct sockaddr_in *)ifa->ifa_netmask;
-
strncpy(addrStr, inet_ntoa(addr->sin_addr), sizeof(addrStr));
-
strncpy(maskStr, inet_ntoa(mask->sin_addr), sizeof(maskStr));
-
-
printf("dev-%s addr-%s mask-%s\n", devName, addrStr, maskStr);
-
}
-
-
freeifaddrs(ifaddr);
-
}
6、获取接口标志
方法一:使用ioctl,通过man netdevice可以获得更多关于ioctl以及标志的说明
-
void get_flags1(int sockfd, char *devName)
-
{
-
struct ifreq ifr;
-
unsigned int flags;
-
-
memset(&ifr, 0, sizeof(ifr));
-
strncpy(ifr.ifr_name, devName, sizeof(ifr.ifr_name));
-
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
-
{
-
Print("ioctl SIOCGIFFLAGS: %s", strerror(errno));
-
return;
-
}
-
-
flags = ifr.ifr_flags;
-
-
printf("get flags of %s: %08x\n", devName, flags);
-
if (flags & IFF_UP) printf("UP ");
-
if (flags & IFF_BROADCAST) printf("BROADCAST ");
-
if (flags & IFF_DEBUG) printf("DEBUG ");
-
if (flags & IFF_LOOPBACK) printf("LOOPBACK ");
-
/*更多标志可通过man netdevice获取*/
-
printf("\n");
-
}
方法二:使用getifaddrs函数
-
void get_flags2(char *devName)
-
{
-
struct ifaddrs *ifaddr = NULL, *ifa = NULL;
-
unsigned int flags;
-
-
if (getifaddrs(&ifaddr) < 0)
-
{
-
Print("getifaddrs failed: %s", strerror(errno));
-
return;
-
}
-
-
for (ifa = ifaddr; NULL != ifa; ifa = ifa->ifa_next)
-
{
-
if (!strcmp(ifa->ifa_name, devName))
-
{
-
break;
-
}
-
}
-
if (NULL != ifa)
-
{
-
flags = ifa->ifa_flags;
-
printf("get flags of %s: %08x\n", devName, flags);
-
}
-
-
freeifaddrs(ifaddr);
-
}
从上面不难看出,如果只需要获取一个网络参数,使用ioctl比较简单。如果需要同时获取多个参数,推荐使用getifaddrs方法。
阅读(1137) | 评论(0) | 转发(0) |