ifconfig工具与驱动交互解析(ioctl)

news/2024/11/28 21:36:59/

Linux ifconfig(network interfaces configuring)

  • Linux ifconfig命令用于显示或设置网络设备。ifconfig可设置网络设备的状态,或是显示目前的设置。
  • 同netstat一样,ifconfig源码也位于net-tools中。
  • 源码位于net-tools工具包中,这是linux网络的基本工具包,此外还有arp,hostname,route等命令。

PS

此文章不考虑ifconfig的具体功能介绍,而是侧重与驱动和内核的交互,下面简单描述下该工具的使用实例,并且代码并不包含对于ifconfig的标准实现,仅是注重实现过程。

实例

$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0c:29:e7:65:70inet addr:192.168.101.128  Bcast:192.168.101.255  Mask:255.255.255.0inet6 addr: fe80::20c:29ff:fee7:6570/64 Scope:LinkUP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1RX packets:17080658 errors:73 dropped:2 overruns:0 frame:0TX packets:17346739 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000RX bytes:4038046913 (4.0 GB)  TX bytes:2731849230 (2.7 GB)Interrupt:19 Base address:0x2000lo        Link encap:Local Loopbackinet addr:127.0.0.1  Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING  MTU:65536  Metric:1RX packets:58049 errors:0 dropped:0 overruns:0 frame:0TX packets:58049 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0RX bytes:5540611 (5.5 MB)  TX bytes:5540611 (5.5 MB)

启动关闭指定网卡

# ifconfig eth0 down
# ifconfig eth0 up

用ifconfig修改MAC地址

# ifconfig eth0 down //关闭网卡
# ifconfig eth0 hw ether 00:AA:BB:CC:DD:EE //修改MAC地址
# ifconfig eth0 up //启动网卡

配置IP地址

# ifconfig eth0 192.168.1.56 
//给eth0网卡配置IP地址
# ifconfig eth0 192.168.1.56 netmask 255.255.255.0 
// 给eth0网卡配置IP地址,并加上子掩码
# ifconfig eth0 192.168.1.56 netmask 255.255.255.0 broadcast 192.168.1.255
// 给eth0网卡配置IP地址,加上子掩码,加上个广播地址

启用和关闭ARP协议

# ifconfig eth0 arp  //开启
# ifconfig eth0 -arp  //关闭

/proc/net/dev

$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmitface |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressedlo: 5558739   58239    0    0    0     0          0         0  5558739   58239    0    0    0     0       0          0eth0: 4038107838 17081103   73    2    0     0          0         0 2731895950 17347146    0    0    0     0       0          0
  • 这里列出了所有网络设备的其属性状态和收发包情况。ifconfig会open这个设备查找匹配信息。

那知道了如何使用该工具,那么具体是怎么实现的呢???
就到了下面的源码分析

代码分析

先来个简单的查看信息,如下是获取ip的流程

  1. 先通过ioctl获得本地所有接口的信息,并保存在ifconf中
  2. 再从ifconf中取出每一个ifreq中表示ip地址的信息

分析一:(获取ip地址)
接下来我们只需要从一个一个的接口信息获取ip地址信息即可。

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/if.h>int main()
{int i=0;int sockfd;struct ifconf ifconf;unsigned char buf[512];struct ifreq *ifreq;//初始化ifconfifconf.ifc_len = 512;ifconf.ifc_buf = buf;if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0){exit(1);}ioctl(sockfd, SIOCGIFCONF, &ifconf); //获取所有接口信息//接下来一个一个的获取IP地址ifreq = (struct ifreq*)buf;for (i=(ifconf.ifc_len/sizeof (struct ifreq)); i>0; i--){// if(ifreq->ifr_flags == AF_INET){ //for ipv4printf("name = [%s]\n" , ifreq->ifr_name);printf("local addr = [%s]\n" ,inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));ifreq++;
// }}
return 0;

执行结果

ifconfig_achieve$ ./ifconfig_wlan_ip.o
name = [lo]
local addr = [127.0.0.1]
name = [ens33]
local addr = [192.168.101.137]

解析:

  • ifc_len:表示用来存放所有接口信息的缓冲区长度
  • ifc_buf:表示存放接口信息的缓冲区
  • 用ioctl获得本地ip地址时要用到两个结构体ifconf和ifreq,我们需要在程序开始时对ifconf的ifc_len和ifc_buf进行初始化
  • 使用ioctl获取所有接口信息,完成后ifc_len内存放实际获得的接口信息总长度
    并且信息被存放在ifc_buf中。
  • struct ifconf:通常是用来保存所有接口信息的
  • struct ifreq:这个结构定义在include/net/if.h,用来配置ip地址,激活接口,配置MTU等接口信息的
  • 想要获取当前网口网线插入状态,需要用到ifreq结构体,获取网卡的信息,然后socket结合网卡驱动的ioctl,就可以得到与网线插入状态相关的数据。

简单部分罗列下上面的结构体:

//ifconf通常是用来保存所有接口信息的
struct ifconf
{int ifc_len; /* size of buffer */union{char *ifcu_buf; /* input from user->kernel*/struct ifreq *ifcu_req; /* return from kernel->user*/} ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures *///ifreq用来保存某个接口的信息
struct ifreq 
{char ifr_name[IFNAMSIZ];union {struct sockaddr ifru_addr;struct sockaddr ifru_dstaddr;struct sockaddr ifru_broadaddr;short ifru_flags;int ifru_metric;caddr_t ifru_data;} ifr_ifru;
};
#define ifr_addr ifr_ifru.ifru_addr
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
#define ifr_broadaddr ifr_ifru.ifru_broadaddr

分析二(获取基础信息,并更改设置ip)

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <linux/if.h>
#include <string.h>#define INTERFACE "ens33"void port_status(unsigned int flags)  { if(flags & IFF_UP)    {  printf("is up\n");        }  if(flags & IFF_BROADCAST)     {  printf("is broadcast\n");     }  if(flags & IFF_LOOPBACK)      {  printf("is loop back\n");     }  if(flags & IFF_POINTOPOINT)   {  printf("is point to point\n");    }  if(flags & IFF_RUNNING)   {  printf("is running\n");   }  if(flags & IFF_PROMISC)   {  printf("is promisc\n");   }  }  int main()
{int fd;struct ifreq buf[5];    //这个结构定义在/usr/include/net/if.h,用来配置和获取ip地址,掩码,MTU等接口信息的。 ifreq用来保存某个接口的信息 struct ifconf ifc;  //ifconf通常是用来保存所有接口信息的int ret = 0,i=0,j=0;      ifc.ifc_len = sizeof(buf);  ifc.ifc_buf = (caddr_t) buf;  uint32_t ip = 0x8165a8c0;//192.168.101.129struct sockaddr_in sin;if ((fd = socket(AF_INET, SOCK_DGRAM, 0))<0){perror("socket" );exit(1);}elseprintf("----------fd:%d-----------\n",fd);ret = ioctl(fd, SIOCGIFCONF, (char*)&ifc);  if(ret)  {  printf("get if config info failed");  return -1;  }  for (i=(ifc.ifc_len/sizeof (struct ifreq)); i>0; i--){printf("--------------name = [%s]------------\n" , buf[j].ifr_name);if(strcmp(buf[j].ifr_name,"ens33")==0){printf("--------------ens33网卡---------------\n");strncpy(buf[j].ifr_name, INTERFACE, 5);memset(&sin, 0, sizeof(struct sockaddr));sin.sin_family = AF_INET;sin.sin_addr.s_addr = ip;memcpy(&buf[j].ifr_addr, &sin, sizeof(struct sockaddr));ret = ioctl(fd, SIOCSIFADDR, (char*)&buf[j]);if(ret)  continue;      }ret = ioctl(fd, SIOCGIFADDR, (char*)&buf[j]);  if(ret)  continue;printf("----------local addr = [%s]----------\n" ,inet_ntoa(((struct sockaddr_in*)&(buf[j].ifr_addr))->sin_addr));ret = ioctl(fd, SIOCGIFFLAGS, (char*)&buf[j]);  if(ret)  continue;  port_status(buf[j].ifr_flags);printf("--------------ifr_flags = [%d]------------\n" , buf[j].ifr_flags);ret = ioctl(fd, SIOCGIFMTU, (char*)&buf[j]);  if(ret)  continue;printf("-------mtu:%d----------\n",(unsigned int)(buf[j].ifr_ifru.ifru_mtu));/* 获取当前网卡的mac 命令cat /sys/class/net/eth0/address*/  ret = ioctl(fd, SIOCGIFHWADDR, (char*)&buf[j]);  if(ret)  continue;printf("%02x:%02x:%02x:%02x:%02x:%02x\n\n",  (unsigned char)buf[j].ifr_hwaddr.sa_data[0],  (unsigned char)buf[j].ifr_hwaddr.sa_data[1],  (unsigned char)buf[j].ifr_hwaddr.sa_data[2],  (unsigned char)buf[j].ifr_hwaddr.sa_data[3],  (unsigned char)buf[j].ifr_hwaddr.sa_data[4],  (unsigned char)buf[j].ifr_hwaddr.sa_data[5]  );j++;}close(fd);
return 0;
}

运行结果

./ifconfig_wlan.o
----------fd:3-----------
--------------name = [lo]------------
----------local addr = [127.0.0.1]----------
is up
is loop back
is running
--------------ifr_flags = [73]------------
-------mtu:65536----------
00:00:00:00:00:00--------------name = [ens33]------------
--------------ens33网卡---------------
----------local addr = [192.168.101.129]----------
is up
is broadcast
is running
--------------ifr_flags = [4163]------------
-------mtu:1500----------
00:0c:29:24:11:8b

注意:
通过

gcc  ifconfig_wlan.c  -o ifconfig_wlan.o

命令编译出来的可执行文件本身是无法直接执行的,debug如下:

strace ./ifconfig_wlan.o

失败 log:
在这里插入图片描述
是由于编译的可执行文件权限不足导致ioctl设置失败,如下是解决流程:

1. gcc ifconfig_wlan_information.c -o ifconfig_wlan_information.o2. sudo cp ifconfig_wlan_information.o ifconfig_wlan.o3. sudo chmod u+s ifconfig_wlan.o4. strace ./ifconfig_wlan.o

如下为再次执行后的结果:
在这里插入图片描述

结语

如上主要讲的是设置和获取,希望能够抛砖引玉,让大家学到更多


http://www.ppmy.cn/news/105063.html

相关文章

《消息队列高手课》课程笔记(七)

如何使用异步设计提升系统性能&#xff1f; 异步设计如何提升系统性能&#xff1f; 假设我们要实现一个转账的微服务 Transfer(accountFrom, accountTo, amount)&#xff0c;这个服务有三个参数&#xff1a;分别是转出账户、转入账户和转账金额。 这个例子的实现过程中&…

Vue登录界面精美模板分享

文章目录 &#x1f412;个人主页&#x1f3c5;Vue项目常用组件模板仓库&#x1f4d6;前言&#xff1a;&#x1f380;源码如下&#xff1a; &#x1f412;个人主页 &#x1f3c5;Vue项目常用组件模板仓库 &#x1f4d6;前言&#xff1a; 本篇博客主要提供vue组件之登陆组件源码…

S7-1200 和 CP342-5 PROFIBUS DP主从通信例程

S7-1200 与 CP342-5 之间 PROFIBUS DP主从通信的几种可能情况分别提供了例程&#xff1a; 1. 同一项目中S7-1200 与 S7-300 CP342-5 之间 DP 主从通信&#xff0c;S7-1200 通过CM1243-5作为 DP 主站&#xff0c;CP342-5作为 DP 从站&#xff1b; 2. 不同项目中S7-1200 与 S7-3…

2022年软件测试人员调查统计

1、软件测试从业人员的年龄分布 测试行业的主力军年龄分布主要是集中在 26-30 岁这个区间&#xff0c;这部分的群体承担着行 业发展的主导力量&#xff0c;占 43.2%。根据数据显示&#xff0c;被调查者中占比最多的是 26-30 岁区间的软件测试从业人员&#xff0c;26-30 岁的测试…

spring入门-bean

Spring 是一个开源的、轻量级的企业级 Java 应用程序框架&#xff0c;它提供了一种全新的、基于 IoC &#xff08;控制反转&#xff09;和 AOP&#xff08;面向切面编程&#xff09;的软件开发方式&#xff0c;以及众多的企业级应用程序开发组件和 API。使用 Spring 框架可以大…

辅助驾驶功能开发-功能规范篇(26)-1-紧急转向辅助ESA

1.前言 1.1.目的 本文档定义了高级驾驶辅助领域中紧急转向辅助的基本控制功能及性能需求,适用于紧急转向辅助功能的功能性能开发和测试验证。 1.2.缩写及术语 ELK Emergency Lane Keeping 紧急车道保持 ESA

数据传输选Ajax还是Axios

前言 随着Web应用程序的发展&#xff0c;越来越多的开发人员需要通过JavaScript与服务器进行交互。在前端开发过程中&#xff0c;Ajax和Axios是两种最为常见的数据请求方式。虽然它们可以实现同样的目的&#xff0c;但却有一些重要的不同点和优劣势。 Ajax和Axios的介绍 Aja…

2023-05-30 Unity 2进制6——Excel写入器ExcelWriter

文章目录 一、Epplus 使用二、ExcelWriter&#xff08;一&#xff09;文件结构&#xff08;二&#xff09;操作说明&#xff08;三&#xff09;操作示例&#xff08;四&#xff09;完整代码 一、Epplus 使用 &#xff08;一&#xff09;获取 Excel 文件 string filePath App…