UDP struct ifreq和struct ifconf获取IP地址

本文介绍了如何利用Linux下的ioctl函数、struct ifconf和struct ifreq来获取UDP接口的IP地址。通过SIOCGIFCONF请求获取所有接口信息,然后遍历找出所需网卡的IP地址。ifconfig命令也是通过这种方式与内核交互。

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

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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值