getmac : Retrieve physical MAC address on Solaris without being root
Download: getmac.c
Author: paulie
License: n/a
Description:
- Uses libdlpi and arp to obtain the MAC address of a given network interface
- Written in C
/*
 * getmac.c
 *	Retrieves the MAC address for a given network interface on Solaris
 *	platforms using two methods: arp and dlpi.  Please note that dlpi
 *	requires root to retrieve an address.
 * Compile
 *	gcc getmac.c -o getmac -lsocket -ldlpi
 * Run
 * 	./getmac <interface_name>
 * Ex: ./getmac e1000g0
 *
 *	Written by Paul Johnson
 *	paulie@pauliesworld.org
 */

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <libdlpi.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>

static char*
get_physical_address_arp(char* nicname)
{
	int i, j, sock, nicount;
	char octet[3];
	char* finaladdress;
	struct arpreq arpreq;
	struct ifreq nicnumber[24];
	struct ifconf ifconf;

	if ((sock=socket(AF_INET,SOCK_DGRAM,0)) > -1) {
		ifconf.ifc_buf = (caddr_t)nicnumber;
		ifconf.ifc_len = sizeof(nicnumber);
	} else {
		return("Could not create socket.");
	}
        
	if (!ioctl(sock,SIOCGIFCONF,(char*)&ifconf)) {
            	nicount = ifconf.ifc_len/(sizeof(struct ifreq));

		for (i=0; i<=nicount; i++) { 
			if (!strcmp(nicnumber[i].ifr_name,nicname)) {
				break;
			}

			if (i == (nicount-1)) {
				close(sock);
				return("No such interface.");
			}
		}
	} else {
		close(sock);
		return("ioctl error.");
	}

        ((struct sockaddr_in*)&arpreq.arp_pa)->sin_addr.s_addr=
	((struct sockaddr_in*)&nicnumber[i].ifr_addr)->sin_addr.s_addr;

	if (!(ioctl(sock,SIOCGARP,(char*)&arpreq))) {
		finaladdress = (char*)malloc(48);
			
		for (j=0; j<=5; j++) {
			snprintf(octet,sizeof(octet),"%02x",
			(unsigned char)arpreq.arp_ha.sa_data[j]);
			strcat (finaladdress,octet);
		}
		close (sock);
		return (finaladdress);
	} else {
		return ("Could not determine MAC address.");
	}
}

static char*
get_physical_address_dlpi(char* nicname)
{
        int i, physaddrlen=DLPI_PHYSADDR_MAX;
        char octet[3];
        char physaddr[DLPI_PHYSADDR_MAX];
        char*  finaladdress;
        dlpi_handle_t dh;

        if (dlpi_open(nicname, &dh, 0) != DLPI_SUCCESS) {
                return("dlpi failure, are you root?");
        }
   
        if (dlpi_get_physaddr(dh, DL_CURR_PHYS_ADDR, physaddr, &physaddrlen) !=
        DLPI_SUCCESS) {
                dlpi_close(dh);
                return("Could not retrieve physical address.");
        }

	finaladdress = (char*)malloc(48);

        for (i=0; i<physaddrlen; i++) {
                snprintf(octet,sizeof(octet),"%02x",(unsigned char)physaddr[i]);
                strcat(finaladdress,octet);
        }

        dlpi_close(dh);
	return(finaladdress);
}

int
main(int argc, char** argv)
{
	char* physaddress_arp;
	char* physaddress_dlpi;

	if (argc != 2) {
        	printf("./getmac <interface>\n\n");
        	return 0;
	}

	physaddress_arp = get_physical_address_arp(argv[1]);
	physaddress_dlpi = get_physical_address_dlpi(argv[1]);
	printf("arp:\t%s\ndlpi:\t%s\n",physaddress_arp,physaddress_dlpi);

	return(0);
}