Shammer's Philosophy

My private adversaria

ioctl で NIC の情報を取得

特定NICのIPアドレスを取得する関数 - Shammerismのようにgetifaddrs 関数を使用しても取得できるが、IPv4 の情報であれば ioctl も使用できるようだ。struct ifreq が使用される。

#include <arpa/inet.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdio.h>      
#include <stdlib.h>
#include <string.h> 
#include <sys/types.h>
#include <sys/ioctl.h>
#include <unistd.h>

int getifipv4addr(char * value, const char * device) {
    int status, fd;
    struct ifreq ifreq;
    struct sockaddr_in addr;
    strcpy(ifreq.ifr_name, device);
    fd = socket(PF_INET, SOCK_DGRAM, 0);
    status = ioctl(fd, SIOCGIFADDR, &ifreq);
    if( status == -1 ){
	perror("ioctl(SIOCGIFADDR)\n");
	return 1;
    }
    else if( ifreq.ifr_addr.sa_family != AF_INET ){
	// Not IPv4
    }
    else {
	memcpy(&addr, &ifreq.ifr_addr, sizeof(struct sockaddr_in));
	strcpy(value, inet_ntoa(addr.sin_addr));
    }
	
    close(fd);
    return 0;
}

void getifipv6addr(char * value, const char * device) {
    struct ifaddrs * if_list = NULL;
    struct ifaddrs * ifa = NULL;
    void * tmp = NULL;
    getifaddrs(&if_list);
    for( ifa = if_list ; ifa != NULL ; ifa = ifa->ifa_next ){
	if( strcmp(ifa->ifa_name, device) == 0 ){ // Target device
	    if( !ifa->ifa_addr ){
		// This interface is NOT assigned IP Address? or not linked up?
		continue;
	    }
	    else {
		if( ifa->ifa_addr->sa_family == AF_INET6 ) { // Check IPv6 Address
		    tmp = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
		    inet_ntop(AF_INET6, tmp, value, INET6_ADDRSTRLEN);
		    break;
		}
		else {
		    // For example, reach here the cases
		    // sa_family is AF_PACKET(17).
		    // sa_family is AF_INET6(23).
		}
	    }
	}
    }
    freeifaddrs(if_list);
}

int main(int argc, const char * args[]){
    char ipv4_addr[INET_ADDRSTRLEN];
    memset(ipv4_addr, 0, sizeof(ipv4_addr));
    getifipv4addr(ipv4_addr, args[1]);
    printf("%s IPv4 address is %s.\n", args[1], ipv4_addr);
    char ipv6_addr[INET6_ADDRSTRLEN];
    memset(ipv6_addr, 0, sizeof(ipv6_addr));
    getifipv6addr(ipv6_addr, args[1]);
    printf("%s IPv6 address is %s.\n", args[1], ipv6_addr);
    return 0;
}

実行結果は以下。

$ ./a.out eth0
eth0 IPv4 address is 192.168.128.101.
eth0 IPv6 address is fe80::863a:4bff:fedc:280.
$ 

ioctl はもっといろいろできるようだ。