/*
 * arpme.c
 *
 * Sample program using SIOCGARP ioctl
 * Steve Buer <sabuer@syr.edu>
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License    
 * as published by the Free Software Foundation; either version  
 * 2 of the License, or (at your option) any later version.    
 *
 */

#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/if_arp.h>
#include <netinet/in.h>

struct option longopts[] = {

	{"help", 	0, NULL, 0},
	{"verbose", 	0, NULL, 0},
	{"interface", 	1, NULL, 0},
	{0}

};

void usage()
{

	fprintf(stderr, "Usage: arpme [-v] [-i] <ip>\n");
	fprintf(stderr, "	--verbose	-v\n");
	fprintf(stderr, "	--interface	-i\n");
	fprintf(stderr, "	--help		-h\n");

}

int main(int argc, char **argv)
{

     	int sockfd, c;
	int verbose = 0;
	int errflg  = 0;
     	struct arpreq arpreq;
	struct sockaddr_in addr;
	char *theInterface = "eth0";
	char *theIP = NULL;
	u_char *p;

	while ((c = getopt_long(argc, argv, "vhi:", longopts, 0)) != EOF) {


                switch (c) {

                        case 'v':

                                verbose++;
                                break;

                        case 'h':

                                errflg++;
                                break;

			case 'i':

				theInterface = optarg;
				break;

                        default:
                        
                                errflg++;
                                break;

                } //switch

        } // while

	if (errflg) {
	
		usage();
		exit(1);

	}

	if (optind < argc) {

                theIP = argv[optind++];

	} else {

		usage();
		exit(1);

	}

	///////////////////////////////
	// build arpreq structure

	memset(&addr, '\0', sizeof(struct sockaddr_in));

     	addr.sin_family = AF_INET;

	if (inet_aton(theIP, &addr.sin_addr.s_addr) == 0) {

		fprintf(stderr, "Invalid IP\n");
		exit(1);
	
	}

     	memset(&arpreq, '\0', sizeof(struct arpreq));
     	memcpy(&arpreq.arp_pa, &addr, sizeof(struct sockaddr_in));
     	memcpy(&arpreq.arp_dev, theInterface, strlen(theInterface));

	////////////////////////////
	// ioctl()

     	if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {

        	perror("socket");
        	exit(1);
     
	}

     	if (ioctl(sockfd, SIOCGARP, (char *)&arpreq) < 0) {

        	perror("ioctl");
        	exit(1);
     
	}

	////////////////////////////
	// output

	p = (char *)&arpreq.arp_ha.sa_data[0];

	printf("%x:%x:%x:%x:%x:%x", *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5));

	if (verbose) {

		if (arpreq.arp_flags & ATF_PERM)
			printf(" PERM");

		if (arpreq.arp_flags & ATF_PUBL)
			printf(" PUBL");

		if (arpreq.arp_flags & ATF_COM)
			printf(" COMPLETE");

		if (arpreq.arp_flags & ATF_DONTPUB)
			printf(" DONTPUB");
		
		if (arpreq.arp_flags & ATF_USETRAILERS)
			printf(" USETRAILERS");
	}

	putchar('\n');

     	return 0;
  
}

/*
 * compile with 'gcc -o arpme arpme.c'
 */
