ioctl函数

一、函数原型

#include    <unistd.h>

int ioctl(int fd, int request, .../* void *arg */);

返回:成功返回0,否则为-1

二、和网络相关的请求(request)

 (1)套接字操作

 (2)文件操作

 (3)接口操作

 (4)ARP告诉缓存操作

 (5)路由表操作

 (6)流系统

三、request参数及arg地址必须指向的数据类型

四、案列:获取所有网络设备接口名称

#include    <stdio.h>
#include    <stdlib.h>
#include    <errno.h>
#include    <sys/ioctl.h>
#include    <sys/socket.h>
#include    <net/if.h>

struct ifreq *get_ifreq();

int main(int argc, char **argv)
{
    struct ifreq *ifr, *tobefree;

    ifr = tobefree = get_ifreq();
    
    do {
        printf("%s
", ifr->ifr_name);
        ifr++;
    } while (ifr->ifr_name[0] != 0);

    free(tobefree);

    exit(0);
}

struct ifreq *get_ifreq()
{
    int  sockfd, len, lastlen;
    char *buf;
    struct ifconf ifc;

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    lastlen = 0;
    len = 40 * sizeof(struct ifreq);        /* initial buffer size guess */
    for ( ; ; ) {
        buf = malloc(len);
        ifc.ifc_len = len;
        ifc.ifc_buf = buf;
        if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
            if (errno != EINVAL || lastlen != 0) {
                perror("ioctl");
                exit(-1);
            }
        } else {
            if (ifc.ifc_len == lastlen) {
                break;                      /* success, len has not changed */
            }
            lastlen = ifc.ifc_len;
        }
        len += 10 * sizeof(struct ifreq);   /* increment */
        free(buf);
    }
    
    return ((struct ifreq *)ifc.ifc_buf);
}

 五、关于ioctl函数应该注意

六、get_ifi_info函数

#include    "unpifi.h"

struct ifi_info *get_ifi_info(int family, int doaliases)
{
    int       sockfd, len, lastlen, flags, myflags, idx = 0, hlen = 0;
    char   *ptr, *buf, lastname[IFNAMSIZ], *cptr, *haddr, *sdlname;
    struct ifconf        ifc;
    struct ifreq        *ifr, ifrcopy;
    struct sockaddr_in    *sinptr;
    struct sockaddr_in6    *sin6ptr;
    struct ifi_info        *ifi, *ifihead, **ifipnext;


    sockfd = socket(family, SOCK_DGRAM, 0);

    lastlen = 0;
    len = 100 * sizeof(struct ifreq);     /* initial buffer size guess */
    for ( ; ; ) {
        buf = malloc(len);
        ifc.ifc_len = len;
        ifc.ifc_buf = buf;
        if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
            if (errno != EINVAL || lastlen != 0) {
                perror("ioctl");
                exit(-1);
            }
        } else {
            if (ifc.ifc_len == lastlen) {
                break;                    /* success, len has not changed */
            }
            lastlen = ifc.ifc_len;
        }
        len += 10 * sizeof(struct ifreq); /* increment */
        free(buf);
    }
    ifihead = NULL;
    ifipnext = &ifihead;
    lastname[0] = 0;
    sdlname = NULL;

    for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
        ifr = (struct ifreq *) ptr;

#ifdef    HAVE_SOCKADDR_SA_LEN
        len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len);
#else
        switch (ifr->ifr_addr.sa_family) {
#ifdef    IPV6
        case AF_INET6:    
            len = sizeof(struct sockaddr_in6);
            break;
#endif
        case AF_INET:    
        default:    
            len = sizeof(struct sockaddr);
            break;
        }
#endif    /* HAVE_SOCKADDR_SA_LEN */

        ptr += sizeof(ifr->ifr_name) + len + 8;    /* for next one in buffer */

#ifdef    HAVE_SOCKADDR_DL_STRUCT
        /* assumes that AF_LINK precedes AF_INET or AF_INET6 */
        if (ifr->ifr_addr.sa_family == AF_LINK) {
            struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
            sdlname = ifr->ifr_name;
            idx = sdl->sdl_index;
            haddr = sdl->sdl_data + sdl->sdl_nlen;
            hlen = sdl->sdl_alen;
        }
#endif

        if (ifr->ifr_addr.sa_family != family) {
            continue;      /* ignore if not desired address family */
        }

        myflags = 0;
        if ( (cptr = strchr(ifr->ifr_name, ':')) != NULL) {
            *cptr = 0;     /* replace colon with null */
        }
        if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) {
            if (doaliases == 0)
                continue;  /* already processed this interface */
            myflags = IFI_ALIAS;
        }
        memcpy(lastname, ifr->ifr_name, IFNAMSIZ);

        ifrcopy = *ifr;
        ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy);
        flags = ifrcopy.ifr_flags;
        if ((flags & IFF_UP) == 0) {
            continue;      /* ignore if interface not up */
        }

        ifi = calloc(1, sizeof(struct ifi_info));
        *ifipnext = ifi;              /* prev points to this new one */
        ifipnext = &ifi->ifi_next;    /* pointer to next one goes here */

        ifi->ifi_flags = flags;       /* IFF_xxx values */
        ifi->ifi_myflags = myflags;   /* IFI_xxx values */
#if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU)
        ioctl(sockfd, SIOCGIFMTU, &ifrcopy);
        ifi->ifi_mtu = ifrcopy.ifr_mtu;
#else
        ifi->ifi_mtu = 0;
#endif
        memcpy(ifi->ifi_name, ifr->ifr_name, IFI_NAME);
        ifi->ifi_name[IFI_NAME-1] = '';
        /* If the sockaddr_dl is from a different interface, ignore it */
        if (sdlname == NULL || strcmp(sdlname, ifr->ifr_name) != 0) {
            idx = hlen = 0;
        }
        ifi->ifi_index = idx;
        ifi->ifi_hlen = hlen;
        if (ifi->ifi_hlen > IFI_HADDR) {
            ifi->ifi_hlen = IFI_HADDR;
        }
        if (hlen) {
            memcpy(ifi->ifi_haddr, haddr, ifi->ifi_hlen);
        }

        switch (ifr->ifr_addr.sa_family) {
        case AF_INET:
            sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
            ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in));
            memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));

#ifdef    SIOCGIFBRDADDR
            if (flags & IFF_BROADCAST) {
                ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy);
                sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
                ifi->ifi_brdaddr = calloc(1, sizeof(struct sockaddr_in));
                memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
            }
#endif

#ifdef    SIOCGIFDSTADDR
            if (flags & IFF_POINTOPOINT) {
                ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
                sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
                ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in));
                memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
            }
#endif
            break;

        case AF_INET6:
            sin6ptr = (struct sockaddr_in6 *) &ifr->ifr_addr;
            ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
            memcpy(ifi->ifi_addr, sin6ptr, sizeof(struct sockaddr_in6));

#ifdef    SIOCGIFDSTADDR
            if (flags & IFF_POINTOPOINT) {
                ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy);
                sin6ptr = (struct sockaddr_in6 *) &ifrcopy.ifr_dstaddr;
                ifi->ifi_dstaddr = calloc(1, sizeof(struct sockaddr_in6));
                memcpy(ifi->ifi_dstaddr, sin6ptr, sizeof(struct sockaddr_in6));
            }
#endif
            break;

        default:
            break;
        }
    }
    free(buf);
    return (ifihead);    /* pointer to first structure in linked list */
}

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;    /* can't fetch ifi_next after free() */
        free(ifi);                  /* the ifi_info{} itself */
    }
}

struct ifi_info *Get_ifi_info(int family, int doaliases)
{
    struct ifi_info    *ifi;

    if ( (ifi = get_ifi_info(family, doaliases)) == NULL) {
        printf("get_ifi_info error
");
        exit(-1);
    }
    return(ifi);
}

七、unpifi.h头文件

#ifndef    __unp_ifi_h
#define    __unp_ifi_h

#include    <stdio.h>
#include    <errno.h>
#include    <stdlib.h>
#include    <string.h>
#include    <net/if.h>
#include    <netinet/in.h>
#include    <sys/ioctl.h>

#define    IFI_NAME    16          /* same as IFNAMSIZ in <net/if.h> */
#define    IFI_HADDR   8           /* allow for 64-bit EUI-64 in future */

struct ifi_info {
  char    ifi_name[IFI_NAME];      /* interface name, null-terminated */
  short   ifi_index;               /* interface index */
  short   ifi_mtu;                 /* interface MTU */
  u_char  ifi_haddr[IFI_HADDR];    /* hardware address */
  u_short ifi_hlen;                /* # bytes in hardware address: 0, 6, 8 */
  short   ifi_flags;               /* IFF_xxx constants from <net/if.h> */
  short   ifi_myflags;             /* our own IFI_xxx flags */
  struct sockaddr  *ifi_addr;      /* primary address */
  struct sockaddr  *ifi_brdaddr;   /* broadcast address */
  struct sockaddr  *ifi_dstaddr;   /* destination address */
  struct ifi_info  *ifi_next;      /* next of these structures */
};

#define    IFI_ALIAS    1          /* ifi_addr is an alias */

/* function prototypes */
char   *sock_ntop_host(const struct sockaddr *, socklen_t);
void   free_ifi_info(struct ifi_info *);
struct ifi_info    *get_ifi_info(int, int);
struct ifi_info    *Get_ifi_info(int, int);

#endif    /* __unp_ifi_h */

八、sock_ntop_host函数

#include    <stdio.h>
#include    <string.h>
#include    <arpa/inet.h>
#include    <sys/un.h>

#ifdef    HAVE_SOCKADDR_DL_STRUCT
#include    <net/if_dl.h>
#endif

char *sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
{
    static char str[128];        /* Unix domain is largest */

    switch (sa->sa_family) {
    case AF_INET: {
        struct sockaddr_in    *sin = (struct sockaddr_in *) sa;

        if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL)
            return(NULL);
        return(str);
    }

#ifdef    IPV6
    case AF_INET6: {
        struct sockaddr_in6    *sin6 = (struct sockaddr_in6 *) sa;

        if (inet_ntop(AF_INET6, &sin6->sin6_addr, str, sizeof(str)) == NULL)
            return(NULL);
        return(str);
    }
#endif

#ifdef    AF_UNIX
    case AF_UNIX: {
        struct sockaddr_un    *unp = (struct sockaddr_un *) sa;

            /* OK to have no pathname bound to the socket: happens on
               every connect() unless client calls bind() first. */
        if (unp->sun_path[0] == 0)
            strcpy(str, "(no pathname bound)");
        else
            snprintf(str, sizeof(str), "%s", unp->sun_path);
        return(str);
    }
#endif

#ifdef    HAVE_SOCKADDR_DL_STRUCT
    case AF_LINK: {
        struct sockaddr_dl    *sdl = (struct sockaddr_dl *) sa;

        if (sdl->sdl_nlen > 0)
            snprintf(str, sizeof(str), "%*s",
                     sdl->sdl_nlen, &sdl->sdl_data[0]);
        else
            snprintf(str, sizeof(str), "AF_LINK, index=%d", sdl->sdl_index);
        return(str);
    }
#endif
    default:
        snprintf(str, sizeof(str), "sock_ntop_host: unknown AF_xxx: %d, len %d",
                 sa->sa_family, salen);
        return(str);
    }
    return (NULL);
}
原文地址:https://www.cnblogs.com/soldierback/p/10784462.html