UDP struct ifreq和struct ifconf获取IP地址
(一)获得本地ip地址时要用到两个结构体ifconf和ifreq(#include net/if.h),和一个函数ioctl,ifconf是用来保存所有接口信息的,ifreq用来保存某个接口的信息,具体结构如下:
/*
* Interface request structure used for socket
* ioctl's.All interface ioctl's must have parameter ifconf通常是用来保存所有接口信息的
* definitions which begin with ifr_name. The
* remainder may be interface specific.
*/
struct ifreq {
#define IFHWADDRLEN 6
union
{
char ifrn_name[IFNAMSIZ]; /* 网络接口名称 如eth0 */
} ifr_ifrn;
union {
struct sockaddr ifru_addr; /* 本地ip地址 */
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr; /* 广播ip地址 */
struct sockaddr ifru_netmask; /* 本地子网掩码 */
struct sockaddr ifru_hwaddr; /* 本地MAC地址 */
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;
};
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr/* other end of p-p lnk*/
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
#define ifr_flags ifr_ifru.ifru_flags /* flags */
#define ifr_metric ifr_ifru.ifru_ivalue /* metric */
#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
#define ifr_map ifr_ifru.ifru_map /* device map */
#define ifr_slave ifr_ifru.ifru_slave /* slave device */
#define ifr_data ifr_ifru.ifru_data /* for use by interface */
#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */
#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */
#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */
#define ifr_newname ifr_ifru.ifru_newname /* New name */
#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/
/*
* Structure used in SIOCGIFCONF request.
* Used to retrieve interface configuration ifreq用来保存某个接口的信息
* for machine (useful for programs which
* must know all networks accessible).
*/
struct ifconf {
int ifc_len; /* 缓冲区大小 ifr_buf */
union {
char __user *ifcu_buf;/* 缓冲区指针 input from user->kernel*/
struct ifreq __user *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 */
ioctl()函数是Linux下面与内核交互的一种办法,函数原型:
int ioctl( int fd, int request, …/* void arg / )
SIOCGIFCONF 是用来获得网络接口列表(struct ifconf)。SIOCGIFFLAGS是获得网络接口标志(struct ifreq)。在Linux系统中,ifconfig命令就是通过ioctl接口与内核通信。
具体办法如下:
1. 先通过ioctl获得本机所有接口的信息,并保存在ifconf中,3个参数(两个需要用户赋值,另一个参数赋值来自内核)
2. 再从ifconf中取出每一个ifreq赋值给定义的*ifr,然后遍历所有地址,依据网卡名可以获得指定网卡的相关参数,具体代码如下。
二 测试代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h> /*htonl htons ntohs */
#include <sys/ioctl.h>
#include <net/if.h>
int main()
{
int i=0,j=0;
int sock;
struct ifreq *ifr;
struct ifconf ifc;
char buf[512];
if((sock = socket(AF_INET, SOCK_DGRAM, 0))<0)
{
perror("socket");
exit(1);
}
/* 获取所有套接字接口 */
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0)
{
perror("ioctl-conf:");
return -1;
}
ifr = ifc.ifc_req;
for(i=(ifc.ifc_len/sizeof(struct ifreq)),j=1; i>0; i--,j++)
{
/* 获得第j个网络接口名称 */
ifr->ifr_ifindex = j;
if(ioctl(sock, SIOCGIFNAME, (char *)ifr)<0) {perror("NET Name error!");exit(-1);}
printf("name (SIOCGIFNAME)= %s\n", ifr->ifr_name);
/* 获得网卡eth0参数 */
if (!strcmp(ifr->ifr_name, "eth0"))
{
if (ioctl(sock, SIOCGIFFLAGS, (char *)ifr) < 0){perror("Find eth0 error!");exit(-1);}
printf("Find eth0 (SIOCGIFFLAGS) = %d\n", ifr->ifr_flags);
}
/* 获得MTU */
if(ioctl(sock, SIOCGIFMTU, (char *)ifr)<0) {perror("MTU error!");exit(-1);}
printf("MTU (SIOCGIFMTU)= %d\n", ifr->ifr_mtu);
/* 获得MAC地址 */
if(ioctl(sock, SIOCGIFHWADDR, (char *)ifr)<0) {perror("MAC error!");exit(-1);}
char *hw = ifr->ifr_hwaddr.sa_data;
printf("MAC (SIOCGIFHWADDR)= %02x:%02x:%02x:%02x:%02x:%02x\n", hw[0],hw[1]&0xff,hw[2],hw[3],hw[4],hw[5]);
/* 查询本地IP */
if(ioctl(sock, SIOCGIFADDR, (char *)ifr)<0) {perror("Local IP error!");exit(-1);}
printf("local addr (SIOCGIFADDR) = %s\n", inet_ntoa(((struct sockaddr_in*)&(ifr->ifr_addr))->sin_addr));
/* 查询广播IP */
if(ioctl(sock, SIOCGIFBRDADDR, (char *)ifr)<0) {perror("Broadcast error!");exit(-1);}
printf("broadcast addr (SIOCGIFBRDADDR) = %s\n", inet_ntoa(((struct sockaddr_in*)&(ifr->ifr_addr))->sin_addr));
/* 查询目的IP */
if(ioctl(sock, SIOCGIFDSTADDR, (char *)ifr)<0) {perror("Dst IP error!");exit(-1);}
printf("dst addr (SIOCGIFDSTADDR) = %s\n", inet_ntoa(((struct sockaddr_in*)&(ifr->ifr_addr))->sin_addr));
/* 查询子网掩码 */
if(ioctl(sock, SIOCGIFNETMASK, (char *)ifr)<0) {perror("SUB Mask error!");exit(-1);}
printf("mask addr (SIOCGIFNETMASK) = %s\n", inet_ntoa(((struct sockaddr_in*)&(ifr->ifr_addr))->sin_addr));
ifr++;
printf("\n");
}
return 0;
}
测试结果:
本文介绍了如何利用Linux下的ioctl函数、struct ifconf和struct ifreq来获取UDP接口的IP地址。通过SIOCGIFCONF请求获取所有接口信息,然后遍历找出所需网卡的IP地址。ifconfig命令也是通过这种方式与内核交互。

4631

被折叠的 条评论
为什么被折叠?



