Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1782148
  • 博文数量: 297
  • 博客积分: 285
  • 博客等级: 二等列兵
  • 技术积分: 3006
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-06 22:04
个人简介

Linuxer, ex IBMer. GNU https://hmchzb19.github.io/

文章分类

全部博文(297)

文章存档

2020年(11)

2019年(15)

2018年(43)

2017年(79)

2016年(79)

2015年(58)

2014年(1)

2013年(8)

2012年(3)

分类: C/C++

2017-01-08 11:54:15

这一段主要是来自于: 
Suppose that you wish to display the IPv4 address of a network interface. The variable if_name points to a null-terminated string containing the name of the interface (for example, eth0).

On Linux-based systems, one way to obtain the IPv4 address of an interface is to use the ioctl command SIOCGIFADDR. The method described here has four steps:

    Create an ifreq structure for passing data in and out of ioctl.
    Provide an open socket descriptor with the address family AF_INET.
    Invoke ioctl.
    Extract the IP address from the ifreq structure.

The following header files are needed when using this method:

点击(此处)折叠或打开

  1. #include <sys/ioctl.h>
  2. #include <net/if.h>
  3. #include <netinet/in.h>
In addition, this particular implementation makes use of:

点击(此处)折叠或打开

  1. #include <errno.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <arpa/inet.h>
Please note that whilst this method can be used with some network protocols other than IPv4, the Linux implementation does not support IPv6. Furthermore it is only able to return a single result for any given network protocol, so will only return one of the addresses of an interface that has several. It is not necessarily portable to other POSIX-compatible systems, and is no longer the preferred method on Linux.
Create an ifreq structure for passing data in and out of ioctl
The ifreq structure should initially contain the name of the interface to be queried, which should be copied into the ifr_name field. Since this is a fixed-length buffer you should take care to ensure that the name does not cause an overrun:

点击(此处)折叠或打开

  1. struct ifreq ifr;
  2. size_t if_name_len=strlen(if_name);
  3. if (if_name_len<sizeof(ifr.ifr_name)) {
  4.     memcpy(ifr.ifr_name,if_name,if_name_len);
  5.     ifr.ifr_name[if_name_len]=0;
  6. } else {
  7.     die("interface name is too long");
  8. }
Provide an open socket descriptor with the address family AF_INET
All ioctl calls need a file descriptor to act on. In the case of SIOCGIFADDR this must refer to a socket (as opposed to, for example, a regular file) and must be of the address family that you wish to obtain (AF_INET in this instance). Otherwise any type of socket would suffice, but it should preferably not be one that requires any obscure kernel modules to be loaded. For this example a UDP socket will be used:

点击(此处)折叠或打开

  1. int fd=socket(AF_INET,SOCK_DGRAM,0);
  2. if (fd==-1) {
  3.     die("%s",strerror(errno));
  4. }
Invoke ioctl
Once you have the ifreq structure and socket descriptor then you are ready to invoke ioctl:

点击(此处)折叠或打开

  1. if (ioctl(fd,SIOCGIFADDR,&ifr)==-1) {
  2.     int temp_errno=errno;
  3.     close(fd);
  4.     die("%s",strerror(temp_errno));
  5. }
  6. close(fd)
If this completes without error then the hardware address of the interface should have been returned in ifr.ifr_addr in the form of a struct sockaddr_in.
Extract the IP address from the ifreq structure
If an address was returned at all then it ought to be an IPv4 address, because that was the address family of the socket. To obtain the numerical value of the address you should:

    Cast the returned address to a struct sockaddr_in.
    Extract the sin_addr field of this structure to obtain a struct in_addr.
    Extract the s_addr field of the in_addr structure to obtain an in_addr_t (equivalent to a uint32_t).
    Finally, convert the s_addr field (which is in network byte order) into whatever representation you require.

点击(此处)折叠或打开

  1. struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr;
  2. printf("IP address: %s\n",inet_ntoa(ipaddr->sin_addr))
连在一起就是下面整个代码:
注: err_sys是APUE里面的error.c提供的函数。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/ioctl.h>
  3. #include <arpa/inet.h>
  4. #include <net/if.h>
  5. #include <netinet/in.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <limits.h>
  9. #include <errno.h>
  10. #include <error.c>

  11. int main(){
  12.     struct ifreq ifr;
  13.     char * if_name= "eth0";
  14.     size_t if_name_len=strlen(if_name);
  15.     if(if_name_len < sizeof(ifr.ifr_name)){
  16.         memcpy(ifr.ifr_name, if_name, if_name_len);
  17.         ifr.ifr_name[if_name_len]=0;
  18.     }else{
  19.         err_sys("interface name is too long");
  20.     }
  21.     int fd=socket(AF_INET, SOCK_DGRAM,0);
  22.     if (fd==-1){
  23.         err_sys("socket error");
  24.     }

  25.     if(ioctl(fd, SIOCGIFADDR, &ifr)==-1){
  26.         close(fd);
  27.         err_sys("ioctl error");
  28.    }
  29.    close(fd);

  30.    struct sockaddr_in* ipaddr=(struct sockaddr_in*)&ifr.ifr_addr;
  31.    printf("IP address: %s\n",inet_ntoa(ipaddr->sin_addr))

当然我后来发现有很多更简单的代码:
如这个: 
还有

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <limits.h>
  5. #include <string.h> /* for strncpy */
  6. #include <sys/types.h>
  7. #include <sys/socket.h>
  8. #include <sys/ioctl.h>
  9. #include <netinet/in.h>
  10. #include <net/if.h>
  11. #include <arpa/inet.h>

  12. int main()
  13. {
  14.     int fd;
  15.     struct ifreq ifr;
  16.     char* ifname="wlan0";
  17.     fd = socket(AF_INET, SOCK_DGRAM, 0);
  18.     /* I want to get an IPv4 IP address */
  19.     ifr.ifr_addr.sa_family = AF_INET;
  20.     /* I want IP address attached to "eth0" */
  21.     strncpy(ifr.ifr_name, ifname, IFNAMSIZ-1);
  22.     ioctl(fd, SIOCGIFADDR, &ifr);
  23.     close(fd);
  24.     /* display result */
  25.     printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr));
  26.     return 0;
  27. }
后面是python 3的代码

点击(此处)折叠或打开

  1. import socket
  2. import fcntl
  3. import struct

  4. def get_ip_address(ifname):
  5.     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  6.     return socket.inet_ntoa(fcntl.ioctl(
  7.         s.fileno(),0x8915, # SIOCGIFADDR
  8.         struct.pack('256s', ifname.encode('utf-8')[:15])
  9.         #struct.pack('256s', ifname.encode('ascii')[:15])
  10.     )[20:24])

  11. print(get_ip_address('lo'))
  12. print(get_ip_address('eth0'))
  13. print(get_ip_address('wlan0'))

  14. def get_mac_address(ifname):
  15.     s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  16.     info=fcntl.ioctl(s.fileno(),0x8927, struct.pack('256s',ifname.encode('ascii')[:15]))
  17.     mac_address=''.join(['%02x:' % char for char in info[18:24]])
  18.     return mac_address


  19. print(get_mac_address('lo'))
  20. print(get_mac_address('eth0'))
  21. print(get_mac_address('wlan0'))


阅读(1776) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~