网络ioctl实践1:获取网卡的MAC和IP
网络ioctl实践1:获取网卡的MAC和IP
网络ioctl实践2:获取网卡的广播地址和子网掩码
网络ioctl实践3:设置网卡的mac、ip、子网掩码、广播地址
前言
如果设备控制没有好的解决办法,那么ioctl就可能是最终答案。如果要说IOCTL能干什么,那就是任何事情,都可以做。
一 ioctl函数原型
它是一个变参函数,第二个是命令类型,第三个是命令对应的参数。函数成功返回0,失败返回-1.
NAMEioctl - control device
SYNOPSIS#include <sys/ioctl.h>int ioctl(int fd, unsigned long request, ...);
参数fd表示文件描述符,如果要获取网卡信息,这个fd就是套接字描述符,就是socket函数的返回值。
NAMEsocket - create an endpoint for communication
SYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int socket(int domain, int type, int protocol);
domain参数:我们只关注两个值,AF_UNIX和AF_INET,AF_UNIX用于本地通进程间信,AF_INET既可以用于本机进程间通信新,也可以用于主机间进程通信。
type 参数:我们只关注两个值,SOCK_STREAM和SOCK_DGRAM,SOCK_STREAM用于TCP,SOCK_DGRAM用于UDP。
protocol参数:值为0时,会自动选择type类型对应的默认协议。
获取网络描述符的语句如下所示:
int fd = socket(AF_INET,SOCK_DGRAM,0);
好了,万事具备了。就差给ioctl一个合适的命令和一个合适的参数了。
类别 |
Request |
说明 |
数据类型 |
套 接 口 |
SIOCATMARK SIOCSPGRP SIOCGPGRP |
是否位于带外标记 设置套接口的进程ID 或进程组ID 获取套接口的进程ID 或进程组ID |
int int int |
文 件 |
FIONBIO FIOASYNC FIONREAD FIOSETOWN FIOGETOWN |
设置/ 清除非阻塞I/O 标志 设置/ 清除信号驱动异步I/O 标志 获取接收缓存区中的字节数 设置文件的进程ID 或进程组ID 获取文件的进程ID 或进程组ID |
int int int int int |
接 口 |
SIOCGIFCONF SIOCSIFADDR SIOCGIFADDR SIOCSIFFLAGS SIOCGIFFLAGS SIOCSIFDSTADDR SIOCGIFDSTADDR SIOCGIFBRDADDR SIOCSIFBRDADDR SIOCGIFNETMASK SIOCSIFNETMASK SIOCGIFMETRIC SIOCSIFMETRIC SIOCGIFMTU SIOCxxx |
获取所有接口的清单 设置接口地址 获取接口地址 设置接口标志 获取接口标志 设置点到点地址 获取点到点地址 获取广播地址 设置广播地址 获取子网掩码 设置子网掩码 获取接口的测度 设置接口的测度 获取接口MTU (还有很多取决于系统的实现) |
struct ifconf struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq struct ifreq |
ARP |
SIOCSARP SIOCGARP SIOCDARP |
创建/ 修改ARP 表项 获取ARP 表项 删除ARP 表项 |
struct arpreq struct arpreq struct arpreq |
路 由 |
SIOCADDRT SIOCDELRT |
增加路径 删除路径 |
struct rtentry struct rtentry |
二 网络相关的IOCTL命令-内核中的宏定义
直接把文件copy过来sockios.h (include\uapi\linux),如果能这些IOCTL挨个试一遍,那么网络控制这块,(⊙o⊙)…就算入魔了吧,这么多啊。下面这个宏定义和上面表格是一样的。
/** INET An implementation of the TCP/IP protocol suite for the LINUX* operating system. INET is implemented using the BSD Socket* interface as the means of communication with the user level.** Definitions of the socket-level I/O control calls.** Version: @(#)sockios.h 1.0.2 03/09/93** Authors: Ross Biro* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version* 2 of the License, or (at your option) any later version.*/
#ifndef _LINUX_SOCKIOS_H
#define _LINUX_SOCKIOS_H#include <asm/sockios.h>/* Linux-specific socket ioctls */
#define SIOCINQ FIONREAD
#define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) *//* Routing table calls. */
#define SIOCADDRT 0x890B /* add routing table entry */
#define SIOCDELRT 0x890C /* delete routing table entry */
#define SIOCRTMSG 0x890D /* call to routing system *//* Socket configuration controls. */
#define SIOCGIFNAME 0x8910 /* get iface name */
#define SIOCSIFLINK 0x8911 /* set iface channel */
#define SIOCGIFCONF 0x8912 /* get iface list */
#define SIOCGIFFLAGS 0x8913 /* get flags */
#define SIOCSIFFLAGS 0x8914 /* set flags */
#define SIOCGIFADDR 0x8915 /* get PA address */
#define SIOCSIFADDR 0x8916 /* set PA address */
#define SIOCGIFDSTADDR 0x8917 /* get remote PA address */
#define SIOCSIFDSTADDR 0x8918 /* set remote PA address */
#define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */
#define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */
#define SIOCGIFNETMASK 0x891b /* get network PA mask */
#define SIOCSIFNETMASK 0x891c /* set network PA mask */
#define SIOCGIFMETRIC 0x891d /* get metric */
#define SIOCSIFMETRIC 0x891e /* set metric */
#define SIOCGIFMEM 0x891f /* get memory address (BSD) */
#define SIOCSIFMEM 0x8920 /* set memory address (BSD) */
#define SIOCGIFMTU 0x8921 /* get MTU size */
#define SIOCSIFMTU 0x8922 /* set MTU size */
#define SIOCSIFNAME 0x8923 /* set interface name */
#define SIOCSIFHWADDR 0x8924 /* set hardware address */
#define SIOCGIFENCAP 0x8925 /* get/set encapsulations */
#define SIOCSIFENCAP 0x8926
#define SIOCGIFHWADDR 0x8927 /* Get hardware address */
#define SIOCGIFSLAVE 0x8929 /* Driver slaving support */
#define SIOCSIFSLAVE 0x8930
#define SIOCADDMULTI 0x8931 /* Multicast address lists */
#define SIOCDELMULTI 0x8932
#define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */
#define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */
#define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */
#define SIOCGIFPFLAGS 0x8935
#define SIOCDIFADDR 0x8936 /* delete PA address */
#define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */
#define SIOCGIFCOUNT 0x8938 /* get number of devices */#define SIOCGIFBR 0x8940 /* Bridging support */
#define SIOCSIFBR 0x8941 /* Set bridging options */#define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */
#define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length *//* SIOCGIFDIVERT was: 0x8944 Frame diversion support */
/* SIOCSIFDIVERT was: 0x8945 Set frame diversion options */#define SIOCETHTOOL 0x8946 /* Ethtool interface */#define SIOCGMIIPHY 0x8947 /* Get address of MII PHY in use. */
#define SIOCGMIIREG 0x8948 /* Read MII PHY register. */
#define SIOCSMIIREG 0x8949 /* Write MII PHY register. */#define SIOCWANDEV 0x894A /* get/set netdev parameters */#define SIOCOUTQNSD 0x894B /* output queue size (not sent only) *//* ARP cache control calls. *//* 0x8950 - 0x8952 * obsolete calls, don't re-use */
#define SIOCDARP 0x8953 /* delete ARP table entry */
#define SIOCGARP 0x8954 /* get ARP table entry */
#define SIOCSARP 0x8955 /* set ARP table entry *//* RARP cache control calls. */
#define SIOCDRARP 0x8960 /* delete RARP table entry */
#define SIOCGRARP 0x8961 /* get RARP table entry */
#define SIOCSRARP 0x8962 /* set RARP table entry *//* Driver configuration calls */#define SIOCGIFMAP 0x8970 /* Get device parameters */
#define SIOCSIFMAP 0x8971 /* Set device parameters *//* DLCI configuration calls */#define SIOCADDDLCI 0x8980 /* Create new DLCI device */
#define SIOCDELDLCI 0x8981 /* Delete DLCI device */#define SIOCGIFVLAN 0x8982 /* 802.1Q VLAN support */
#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options *//* bonding calls */#define SIOCBONDENSLAVE 0x8990 /* enslave a device to the bond */
#define SIOCBONDRELEASE 0x8991 /* release a slave from the bond*/
#define SIOCBONDSETHWADDR 0x8992 /* set the hw addr of the bond */
#define SIOCBONDSLAVEINFOQUERY 0x8993 /* rtn info about slave state */
#define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */
#define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave *//* bridge calls */
#define SIOCBRADDBR 0x89a0 /* create new bridge device */
#define SIOCBRDELBR 0x89a1 /* remove bridge device */
#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
#define SIOCBRDELIF 0x89a3 /* remove interface from bridge *//* hardware time stamping: parameters in linux/net_tstamp.h */
#define SIOCSHWTSTAMP 0x89b0 /* set and get config */
#define SIOCGHWTSTAMP 0x89b1 /* get config *//* Device private ioctl calls *//** These 16 ioctls are available to devices via the do_ioctl() device* vector. Each device should include this file and redefine these names* as their own. Because these are device dependent it is a good idea* _NOT_ to issue them to random objects and hope.** THESE IOCTLS ARE _DEPRECATED_ AND WILL DISAPPEAR IN 2.5.X -DaveM*/#define SIOCDEVPRIVATE 0x89F0 /* to 89FF *//** These 16 ioctl calls are protocol private*/#define SIOCPROTOPRIVATE 0x89E0 /* to 89EF */
#endif /* _LINUX_SOCKIOS_H */
三 打印网卡MAC地址:SIOCGIFHWADDR命令
它对应的结构体是struct ifreq ifr;很多人搞不懂这个命令主要是不了解这个结构体,如果看到这个结构体的定义,如下所示,那就理解起来,(⊙o⊙)…,也不轻松。
#define IFNAMSIZ 16
struct ifreq {
#define IFHWADDRLEN 6union{char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */} ifr_ifrn;union {struct sockaddr ifru_addr;struct sockaddr ifru_dstaddr;struct sockaddr ifru_broadaddr;struct sockaddr ifru_netmask;struct sockaddr ifru_hwaddr;short ifru_flags;int ifru_ivalue;int ifru_mtu;struct ifmap ifru_map;char ifru_slave[IFNAMSIZ]; /* Just fits the size */char ifru_newname[IFNAMSIZ];void __user * ifru_data;struct if_settings ifru_settings;} ifr_ifru;
}
根据名字,ifru_hwaddr应该是用来表示硬件MAC地址的。看下struct sockaddr的结构体定义:
/** 1003.1g requires sa_family_t and that sa_data is char.*/
typedef unsigned short __kernel_sa_family_t;
typedef __kernel_sa_family_t sa_family_t;
struct sockaddr {sa_family_t sa_family; /* address family, AF_xxx */char sa_data[14]; /* 14 bytes of protocol address */
};
sa_family_t 成员本质上是unsigned short,取值就是socket的第一个参数。
如果是取MAC地址,data中保存的就是mac地址值:原理如下:
int i = 0;
struct ifreq ifr;
ioctl(fd,SIOCGIFHWADDR,&ifr);for(i = 0;i < IFHWADDRLEN;i++)
{if(i == IFHWADDRLEN - 1){printf("0x%02x",ifr.ifr_hwaddr.sa_data[i]);}else{printf("0x%02x:",ifr.ifr_hwaddr.sa_data[i]);}
}
获取网卡实例1:ioctl.c
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <net/if.h>
int main(int argc,char *argv[])
{int fd;int i;struct ifreq ifr;fd = socket(AF_INET,SOCK_DGRAM,0);if(fd < 0){perror("socket");exit(-1);}if(i = ioctl(fd,SIOCGIFHWADDR,&ifr)){perror("ioctl");close(fd);exit(-2);}for(i = 0;i < 6;i++){if(i == 55555){printf("0x%02x",ifr.ifr_hwaddr.sa_data[i]);}else{printf("0x%02x:",ifr.ifr_hwaddr.sa_data[i]);}}close(fd);return 0;
}
编译gcc ioctl.c -o ioctl,运行./ioctl,结果如下所示:
csdn@ubuntu:~$ ./a.out
ioctl: No such device
csdn@ubuntu:~$
提示没有设备,这是因为它需要我们让内核知道,我们需要哪一个网卡的mac地址,假设现在你知道网卡的名字是ens33,根据结构体的struct ifreq 定义可知,成员ifrn_name用于保存网卡名字,且名字最大长度是16;如下所示:
sprintf(ifr.ifr_ifrn.ifrn_name,"%s","ens33");
修改后的代码:ioctl.c
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <net/if.h>
#include <stdint.h>
int get_mac_by_name(int fd,char *name)
{int i = 0;struct ifreq ifr;sprintf(ifr.ifr_ifrn.ifrn_name,"%s",name);if(i = ioctl(fd,SIOCGIFHWADDR,&ifr)){perror("ioctl");close(fd);exit(-2);}for(i = 0;i < 6;i++){if(i == 5){printf("0x%02x\n",(uint8_t)ifr.ifr_ifru.ifru_hwaddr.sa_data[i]);}else{printf("0x%02x:",(uint8_t)ifr.ifr_ifru.ifru_hwaddr.sa_data[i]);}}return 0;
}
int main(int argc,char *argv[])
{int fd;int i;fd = socket(AF_INET,SOCK_DGRAM,0);if(fd < 0){perror("socket");exit(-1);}get_mac_by_name(fd,"ens33");close(fd);return 0;
}
编译gcc ioctl.c -o app,运行./app,运行结果:与ifconfig结果相比,准确无误。
csdn@ubuntu:~$ ./app
0x00:0x0c:0x29:0x8c:0x05:0x15
csdn@ubuntu:~$ ifconfig | sed -n '/ens33/,+1p'
ens33 Link encap:以太网 硬件地址 00:0c:29:8c:05:15inet 地址:192.168.0.11 广播:192.168.0.255 掩码:255.255.255.0
csdn@ubuntu:~$
三 遍历网卡的名字:SIOCGIFCONF命令
SIOCGIFCONF全名大概是Socket IO Control InterFace CONFigure。或者是 Socket IO Control Internet Family CONFigure。也可能是Socket IO Control Internet inteface Family CONFigure。这都不重要,咱又不考研,知道它是获取信息的就够了。
给它的ioctl的参数是struct ifconf结构体指针。
/** Structure used in SIOCGIFCONF request.* Used to retrieve interface configuration* for machine (useful for programs which* must know all networks accessible).*/struct ifconf {int ifc_len; /* size of buffer */union {char __user *ifcu_buf;struct ifreq __user *ifcu_req;} ifc_ifcu;
}
由定义可知,ifcu_req成员可以作为一个数组来看待,ifc_len返回的就是这个数组的长度。
遍历名字,就是下面这样的,如果不知道struct ifconf结构体的定义,这个代码是看不明白的。
struct ifconf ifconf;
ioctl(fd,SIOCGIFCONF,&ifconf);
for(i = 0;i < iconf.ifc_len;i++){printf("%s",ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name);
}
实例验证:ioctl.c,所需头文件和前例相同。
int main(int argc,char *argv[])
{int fd;int i;struct ifconf ifconf;fd = socket(AF_INET,SOCK_DGRAM,0);if(fd < 0){perror("socket");exit(-1);}if(i = ioctl(fd,SIOCGIFCONF,&ifconf)){perror("ioctl");printf("ret = %d\n",i);close(fd);exit(-1);}printf("ifconf.ifc_len = %d\n",ifconf.ifc_len);for(i = 0;i < ifconf.ifc_len;i++){printf("%d:%s\n",i,ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name);}close(fd);return 0;
}
编译gcc ioctl.c -o app,运行./app,结果如下所示:
csdn@ubuntu:~$ ./app
ioctl: Bad address
ret = -1
csdn@ubuntu:~$
报错,这是为什么呢?上面的分析有误,ifc_len 表示的是 size of buffer ,char __user *ifcu_buf;
ifcu_buf成员需要指向用户空间等待缓存,所以要提前给它分配空间。我们暂且给他分配1024字节。并给这个内存清零,这样最多可以获取的接口数就是:1024/sizeof(struct ifreq)。为了简单,我们直接计算返回的网卡名字的长度,如果长度为0,说明已经获取信息完毕。
ifconf.ifc_len = 1024;ifconf.ifc_ifcu.ifcu_buf = malloc(1024);memset(ifconf.ifc_ifcu.ifcu_buf,0,1024);if(i = ioctl(fd,SIOCGIFCONF,&ifconf)){perror("ioctl");printf("ret = %d\n",i);close(fd);exit(-1);}for(i = 0;i < ifconf.ifc_len/sizeof(struct ifreq);i++){if(strlen(ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name) == 0)break;printf("%d:%s\n",i,ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name);}
完整的实例代码:ioctl.c
int main(int argc,char *argv[])
{int fd;int i;struct ifconf ifconf;fd = socket(AF_INET,SOCK_DGRAM,0);if(fd < 0){perror("socket");exit(-1);}ifconf.ifc_len = 1024;ifconf.ifc_ifcu.ifcu_buf = malloc(1024);memset(ifconf.ifc_ifcu.ifcu_buf,0,1024);if(i = ioctl(fd,SIOCGIFCONF,&ifconf)){perror("ioctl");printf("ret = %d\n",i);close(fd);exit(-1);}for(i = 0;i < ifconf.ifc_len/sizeof(struct ifreq);i++){if(strlen(ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name) == 0)break;printf("%d:%s\n",i,ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name);}free(ifconf.ifc_ifcu.ifcu_buf);close(fd);return 0;
}
编译gcc ioctl.c -o app,运行./app,结果如下所示:
csdn@ubuntu:~$ ./app
0:lo
1:ens33
2:ens38
csdn@ubuntu:~$
使用ifconfig获取网卡名字:和我们./app执行结果比较,完全正确是吧。
csdn@ubuntu:~$ ifconfig | sed -n '/Link encap/p'
ens33 Link encap:以太网 硬件地址 00:0c:29:8c:05:15
ens38 Link encap:以太网 硬件地址 00:0c:29:8c:05:1f
lo Link encap:本地环回
csdn@ubuntu:~$
四 获取IP地址:SIOCGIFADDR命令
理论上SIOCGIFCONF也可以获取IP地址,但是ifr_ifru这个共用体,我还不知道它里面哪个才是有效,至少还缺少理论知识支撑。和获取MAC地址思路相同,需要提供名字,从struct ifreq结构题定义可知,ifru_addr就是返回的IP地址信息。需要将它转换struct sockaddr_in 结构体。
struct sockaddr_in {__kernel_sa_family_t sin_family; /* Address family */__be16 sin_port; /* Port number */struct in_addr sin_addr; /* Internet address *//* Pad to size of `struct sockaddr'. */unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -sizeof(unsigned short int) - sizeof(struct in_addr)];
};
在这里端口信息无效,所以只关系struct in_addr sin_addr,根据内存的布局特点,sin_addr成员对应ifru_addr.sa_data[2-5],好了,代码大概如下所示:
实例代码:ioctl.c
int get_ip_by_name(int fd,char *name)
{int i = 0;struct ifreq ifr;sprintf(ifr.ifr_ifrn.ifrn_name,"%s",name);if(i = ioctl(fd,SIOCGIFADDR,&ifr)){perror("ioctl");close(fd);exit(-2);}for(i = 0;i < 4;i++){if(i == 3){printf("%d\n",(uint8_t)ifr.ifr_ifru.ifru_addr.sa_data[2 + i]);}else{printf("%d:",(uint8_t)ifr.ifr_ifru.ifru_addr.sa_data[2 + i]);}}return 0;
}
int main(int argc,char *argv[])
{int fd;int i;fd = socket(AF_INET,SOCK_DGRAM,0);if(fd < 0){perror("socket");exit(-1);}get_ip_by_name(fd,"ens33");close(fd);return 0;
}
编译gcc ioctl.c -o app,运行./app,结果如下所示:
csdn@ubuntu:~$ ./app
192:168:0:11
csdn@ubuntu:~$
使用ifconfig验证结果:sed -n '/ens33/,+1p'表示匹配ens33所在的行,并多显示一行。
csdn@ubuntu:~$ ifconfig | sed -n '/ens33/,+1p'
ens33 Link encap:以太网 硬件地址 00:0c:29:8c:05:15inet 地址:192.168.0.11 广播:192.168.0.255 掩码:255.255.255.0
csdn@ubuntu:~$
五 综合:遍历MAC+IP实例
借助本章学到的三个命令,写一个遍历网口名字、MAC地址和IP地址的小代码:ioctl.c
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <net/if.h>
#include <stdint.h>int get_mac_by_name(int fd,char *name)
{int i = 0;struct ifreq ifr;sprintf(ifr.ifr_ifrn.ifrn_name,"%s",name);if(i = ioctl(fd,SIOCGIFHWADDR,&ifr)){perror("ioctl");close(fd);exit(-2);}for(i = 0;i < 6;i++){if(i == 5){printf("0x%02x\n",(uint8_t)ifr.ifr_ifru.ifru_hwaddr.sa_data[i]);}else{printf("0x%02x:",(uint8_t)ifr.ifr_ifru.ifru_hwaddr.sa_data[i]);}}return 0;
}
int get_ip_by_name(int fd,char *name);
int show_all_net_interface_name(int fd)
{int i = 0;struct ifconf ifconf;ifconf.ifc_len = 1024;ifconf.ifc_ifcu.ifcu_buf = malloc(1024);memset(ifconf.ifc_ifcu.ifcu_buf,0,1024);if(i = ioctl(fd,SIOCGIFCONF,&ifconf)){perror("ioctl");printf("ret = %d\n",i);close(fd);exit(-1);}for(i = 0;i < ifconf.ifc_len/sizeof(struct ifreq);i++){if(strlen(ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name) == 0)break;printf("%d:%s\n",i,ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name);printf("ip:");get_ip_by_name(fd,ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name);printf("mac:");get_mac_by_name(fd,ifconf.ifc_ifcu.ifcu_req[i].ifr_ifrn.ifrn_name);printf("\n");}free(ifconf.ifc_ifcu.ifcu_buf);return 0;
}
int get_ip_by_name(int fd,char *name)
{int i = 0;struct ifreq ifr;sprintf(ifr.ifr_ifrn.ifrn_name,"%s",name);if(i = ioctl(fd,SIOCGIFADDR,&ifr)){perror("ioctl");close(fd);exit(-2);}for(i = 0;i < 4;i++){if(i == 3){printf("%d\n",(uint8_t)ifr.ifr_ifru.ifru_addr.sa_data[2 + i]);}else{printf("%d:",(uint8_t)ifr.ifr_ifru.ifru_addr.sa_data[2 + i]);}}return 0;
}
int main(int argc,char *argv[])
{int fd;int i;fd = socket(AF_INET,SOCK_DGRAM,0);if(fd < 0){perror("socket");exit(-1);}show_all_net_interface_name(fd);close(fd);return 0;
}
编译gcc ioctl.c -o app,运行./app,结果如下所示:
csdn@ubuntu:~$ ./app
0:lo
ip:127:0:0:1
mac:0x00:0x00:0x00:0x00:0x00:0x001:ens33
ip:192:168:0:11
mac:0x00:0x0c:0x29:0x8c:0x05:0x152:ens38
ip:192:168:31:148
mac:0x00:0x0c:0x29:0x8c:0x05:0x1fcsdn@ubuntu:~$
使用ifconfig验证结果:ifconfig | sed -n '/Link encap/,+1p'
csdn@ubuntu:~$ ifconfig | sed -n '/Link encap/,+1p'
ens33 Link encap:以太网 硬件地址 00:0c:29:8c:05:15inet 地址:192.168.0.11 广播:192.168.0.255 掩码:255.255.255.0
ens38 Link encap:以太网 硬件地址 00:0c:29:8c:05:1finet 地址:192.168.31.148 广播:192.168.31.255 掩码:255.255.255.0
lo Link encap:本地环回inet 地址:127.0.0.1 掩码:255.0.0.0
csdn@ubuntu:~$
小结
第二篇:网络ioctl实践2:获取网卡的广播地址和子网掩码
网络ioctl实践1:获取网卡的MAC和IP相关推荐
- 网络ioctl实践3:设置网卡的mac、ip、子网掩码、广播地址
前言 网络ioctl实践1:获取网卡的MAC和IP 网络ioctl实践2:获取网卡的广播地址和子网掩码 本文使用的命令是: Request 说明 数据类型 对应的union成员 SIOCSIFADDR ...
- Python # 扫描端口功能 # 获取网卡的Mac地址 # 局域网扫描器IP地址和MAC地址,获取网卡名称和其ip地址
#!/usr/bin/env python # -*- coding: utf-8 -*- # 开发人员: # time: 2021-09-07 20:37 # 开发工具: PyCharm # Ver ...
- 结合WMI和DeviceIoControl获取网卡原生MAC地址和当前MAC地址
虽然Win32_NetworkAdapter包含了属性PermanentAddress,但是在当前的WMI里只是个空值,微软目前还没有实现这个属性值.但是我们仍可以通过结合WMI和DeviceIoCo ...
- java获取网卡正真的mac_java获取网卡的mac地址
为了项目的安全,有时候需要得到电脑的唯一码,比如:网卡的mac地址.和大家分享一下,下面是项目中用到的工具类:/** * 获取Mac地址 * @return */ public String getM ...
- Windows上获取网卡的mac地址
最近,搞了一个Windows工具,需要获取网卡mac, 这个太熟悉了,之前也经常玩,搞起: #include <stdio.h> #include <winsock2.h> # ...
- java获取网卡的mac地址
为了项目的安全,有时候需要得到电脑的唯一码,比如:网卡的mac地址.和大家分享一下,下面是项目中用到的工具类: import java.io.BufferedReader; import java.i ...
- iphone开发之获取网卡的MAC地址和IP地址
这是获取网卡的硬件地址的代码,如果无法编译通过,记得把下面的这几个头文件加上把. #include <sys/socket.h> // Per msqr #include <sys/ ...
- Android中获取手机 IMEI Mac地址 IP地址
一.获取手机IMEI 手机在生产时,每部手机均有一个唯一的标识(ID),国际上采用国际移动设备身份码(IMEI, International Mobile Equipment Identity).IM ...
- qt准确获取本机mac和ip地址
前言 公司服务器有多个mac地址,是用网上的代码获取时总是不准确,只能自己封装一下.qt通过QNetworkInterface类来获取网络接口的各种信息,我是通过解析QNetworkInterface ...
最新文章
- redis 代理工具Predixy安装部署
- Microbiome:所谓的“富集培养”获得的微生物真的都是被“富集”出来的吗?
- 第11章:项目风险管理(2)—章节重点
- hadoop基石HDFS
- ORA-00020:maximum number of processes (150) exceeded 错误解决方法
- vs2005 vc++ 生成非托管的 不需要.net运行环境的exe程序方法
- 解决VSCODE因为在此系统上禁止运行脚本报错
- 怎么测试本地网页在不同分辨率下电脑显示效果_汇总一波百万高清壁纸站,8K分辨率的都有...
- 朝会資料 幕末の歴史の簡単紹介 2010年8月30日
- CRM 实施计划和准备的8个步骤!
- Android 上千实例源码分析以及开源分析
- 项目管理工具与技术---项目风险管理中的工具与技术
- Abaqus设置初始地应力场
- Centos 7 Opencv安装使用
- 狂热分子——码头工人的哲学沉思录
- turtle绘制奥运五环
- 树莓派4b主板特点_树莓派4B的入手操作
- 基于SSM的培训班管理系统
- Linux系统更改时区
- unicode转中文