UDP struct ifreq和struct ifconf获取IP地址

来源:互联网 发布:网络托管 编辑:程序博客网 时间:2024/05/12 03:32

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;}

测试结果:
这里写图片描述

0 0
原创粉丝点击