ioctl 函数
本函数影响由fd 参数引用的一个打开的文件。
#include<unistd.h>
int ioctl( int fd, int request, .../* void *arg */ );
返回0 :成功 -1 :出错
第三个参数总是一个指针,但指针的类型依赖于request 参数。
我们可以把和网络相关的请求划分为6 类:
套接字操作
文件操作
接口操作
ARP 高速缓存操作
路由表操作
流系统
下表列出了网络相关ioctl 请求的request 参数以及arg 地址必须指向的数据类型:
类别 | Request | 说明 | 数据类型 |
套 接 字 | SIOCATMARK SIOCSPGRP SIOCGPGRP | 是否位于带外标记 设置套接口的进程ID 或进程组ID 获取套接口的进程ID 或进程组ID | int int int |
文
件
| FIONBIN 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 |
流 | I_xxx |
利用SIOCGIFCONF ioctl 实现 get_ifi_info 函数,获取系统的所有处于UP状态的接口信息。
先介绍一下用到的2个结构体:
网络配置接口ifconf
struct ifconf{//网络配置结构体是一种缓冲区
int ifc_len;//缓冲区ifr_buf的大小
union{
char__user *ifcu_buf;//绘冲区指针
struct ifreq__user *ifcu_req;//指向ifreq指针
}ifc_ifcu;
};
#define ifc_buf ifc_ifcu.ifcu_buf;//缓冲区地址
#define ifc_req ifc_ifcu.ifcu_req;//ifc_req地址
网络接口请求结构ifreq
#define IFNAMSIZ16
#define IFHWADDRLEN 6
struct ifreq{
char ifrn_name[IFNAMESIZ];//网络接口名称
union{
struct sockaddr ifru_addr;//本地IP地址
struct sockaddr ifru_dstaddr;//目标IP地址
struct sockaddr ifru_broadaddr;//广播IP地址
struct sockaddr ifru_netmask;//本地子网掩码地址
struct sockaddr ifru_hwaddr;//本地MAC地址
short ifru_flags;//网络接口标记
int ifru_mtu;//最大传输单元
void __user *ifru_data;//用户数据
}ifr_ifru;
}
#define ifr_name ifr_ifrn.ifrn_name;//接口名称
#define ifr_hwaddr ifr_ifru.ifru_hwaddr;//MAC
#define ifr_addr ifr_ifru.ifru_addr;//本地IP
#define ifr_dstaddr ifr_ifru.dstaddr;//目标IP
#define ifr_broadaddr ifr_ifru.broadaddr;//广播IP
#define ifr_netmask ifr_ifru.ifru_netmask;//子网掩码
#define ifr_flags ifr_ifru.ifru_flags;//标志
#define ifr_mtu ifr_ifru.ifru_mtu;//最大传输单元
#define ifr_data ifr_ifru.ifru_data;//接口使用
如果想获得网络接口的相关信息,就传入ifreq结构体.
实例代码:
/*** ifinfo.h ***/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define IFI_NAME 16
#define IFI_HADDR 8
struct ifi_info{
char ifi_name[IFI_NAME];
short ifi_mtu;
short ifi_flags;
struct sockaddr *ifi_addr;
struct sockaddr *ifi_brdaddr;
struct sockaddr *ifi_dstaddr;
struct ifi_info *ifi_next;
};
struct ifi_info
*get_ifi_info()
{
int sockfd,len,flags;
char *buf,*ptr;
struct ifconf ifc;
struct ifreq *ifr,ifrcopy;
struct ifi_info *ifi,*ifihead, **ifipnext;
struct sockaddr_in *sinptr;
if((sockfd=socket(AF_INET,SOCK_DGRAM,0)) < 0){
printf("socket error\n");
return (struct ifi_info *)0;
}
len=10*sizeof(struct ifreq);
buf=malloc(len);
ifc.ifc_len=len;
ifc.ifc_buf=buf;
if(ioctl(sockfd,SIOCGIFCONF,&ifc) < 0){
printf("ioctl SIOCGIFCONF error\n");
return (struct ifi_info *)0;
}
ifihead=NULL;
ifipnext=&ifihead;
for(ptr=buf;ptr<buf+ifc.ifc_len;){
ifr=(struct ifreq *)ptr;
ptr += sizeof(ifr->ifr_name)+sizeof(struct sockaddr);
if(ifr->ifr_addr.sa_family != AF_INET)
continue;
ifrcopy=*ifr;
if(ioctl(sockfd,SIOCGIFFLAGS,&ifrcopy) < 0){
printf("ioctl SIOCGIFFLAGS error\n");
return (struct ifi_info *)0;
}
flags=ifrcopy.ifr_flags;
if((flags & IFF_UP) == 0)
continue;
ifi=malloc(sizeof(struct ifi_info));
*ifipnext=ifi;
ifipnext=&ifi->ifi_next;
ifi->ifi_flags=flags;
if(ioctl(sockfd,SIOCGIFMTU,&ifrcopy) < 0){
printf("ioctl SIOCGIFMTU error\n");
return (struct ifi_info *)0;
}
ifi->ifi_mtu=ifrcopy.ifr_mtu;
memcpy(ifi->ifi_name,ifr->ifr_name,IFI_NAME);
ifi->ifi_name[IFI_NAME]='\0';
sinptr=(struct sockaddr_in *)&ifr->ifr_addr;
ifi->ifi_addr=malloc(sizeof(struct sockaddr_in));
memcpy(ifi->ifi_addr,sinptr,sizeof(struct sockaddr_in));
if(flags &IFF_BROADCAST){
if(ioctl(sockfd,SIOCGIFBRDADDR,&ifrcopy) < 0){
printf("ioctl SIOCGIFBRDADDR error\n");
return (struct ifi_info *)0;
}
sinptr=(struct sockaddr_in *)&ifrcopy.ifr_broadaddr;
ifi->ifi_brdaddr=malloc(sizeof(struct sockaddr_in));
memcpy(ifi->ifi_brdaddr,sinptr,sizeof(struct sockaddr_in));
}
if(flags &IFF_POINTOPOINT){
if(ioctl(sockfd,SIOCGIFDSTADDR,&ifrcopy) < 0){
printf("ioctl SIOCGIFDSTADDR error\n");
return (struct ifi_info *)0;
}
sinptr=(struct sockaddr_in *)&ifrcopy.ifr_dstaddr;
ifi->ifi_dstaddr=malloc(sizeof(struct sockaddr_in));
memcpy(ifi->ifi_dstaddr,sinptr,sizeof(struct sockaddr_in));
}
}
free(buf);
return (ifihead);
}
void
free_ifi_info(struct ifi_info *ifihead)
{
struct ifi_info *ifi,*ifinext;
for(ifi=ifihead;ifi != NULL;ifi=ifinext){
if(ifi->ifi_addr != NULL)
free(ifi->ifi_addr);
if(ifi->ifi_brdaddr != NULL)
free(ifi->ifi_brdaddr);
if(ifi->ifi_dstaddr != NULL)
free(ifi->ifi_dstaddr);
ifinext=ifi->ifi_next;
free(ifi);
}
}
/*** ifinfo.c ***/
#include "ifinfo.h"
int
main(int argc ,char **argv)
{
struct ifi_info *ifi,*ifihead;
int i;
char buf[32];
struct sockaddr_in *sin;
for(ifihead=ifi=get_ifi_info();ifi != NULL;ifi=ifi->ifi_next){
printf("%s",ifi->ifi_name);
printf("<");
if(ifi->ifi_flags & IFF_UP) printf("UP ");
if(ifi->ifi_flags & IFF_BROADCAST) printf("BCAST ");
if(ifi->ifi_flags & IFF_MULTICAST) printf("MCAST ");
if(ifi->ifi_flags & IFF_LOOPBACK) printf("LOOP ");
if(ifi->ifi_flags & IFF_POINTOPOINT) printf("P2P ");
printf(">\n");
if(ifi->ifi_mtu != 0)
printf("MTU: %d\n",ifi->ifi_mtu);
if(ifi->ifi_addr != NULL){
sin=(struct sockaddr_in *)ifi->ifi_addr;
inet_ntop(AF_INET,&sin->sin_addr,buf,sizeof(buf));
printf("IP addr:%s\n",buf);
}
if(ifi->ifi_brdaddr != NULL){
sin=(struct sockaddr_in *)ifi->ifi_brdaddr;
inet_ntop(AF_INET,&sin->sin_addr,buf,sizeof(buf));
printf("broadcast addr:%s\n",buf);
}
if(ifi->ifi_dstaddr != NULL){
sin=(struct sockaddr_in *)ifi->ifi_dstaddr;
inet_ntop(AF_INET,&sin->sin_addr,buf,sizeof(buf));
printf("destination addr:%s\n",buf);
}
}
free_ifi_info(ifihead);
exit(0);
}