#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <sys/types.h>

unsigned char hex2dec(unsigned char hex)
{
	hex = toupper(hex);
	hex -= (hex - 48 > 9) ? 55 : 48;
	return hex;
}

int hexstr_to_int(char *hex)
{
	int i, j;

	union {
		int l;
		unsigned char ch[4];
	} num;

	j = 0;
	for (i = 0; i < 8; i += 2)
		num.ch[j++] = hex2dec(hex[i]) * 16 + hex2dec(hex[i + 1]);

	return htonl(num.l);
}

char *get_gateway_str(void)
{
	FILE *fp;
	char *rt_file = "/proc/net/route";
	char str[256];

	char dst[9];
	char *dst_bgn;

	static char gw_str[9];
	char *gw_bgn;

	fp = fopen(rt_file, "r");
	if (fp == NULL) {
		printf("Cannot open file: %s\n", rt_file);
		perror("fopen()");
		exit(EXIT_FAILURE);
	}

	while (fgets(str, 255, fp) != NULL) {
		dst_bgn = strchr(str, '\11') + 1;
		memcpy(dst, dst_bgn, 8);
		dst[8] = '\0';
		if (strcmp(dst, "00000000") == 0) {
			gw_bgn = dst_bgn + 8 + 1;
			memcpy(gw_str, gw_bgn, 8);
		}
	}

	fclose(fp);
	return gw_str;
}

static char *get_gateway_iface(void)
{
	FILE *fp;
	char *rt_file = "/proc/net/route";
	char str[256];

	char dst[9];
	char *dst_bgn;

	static char iface_str[9];

	fp = fopen(rt_file, "r");
	if (fp == NULL) {
		printf("Cannot open file: %s\n", rt_file);
		perror("fopen()");
		exit(EXIT_FAILURE);
	}

	while (fgets(str, 255, fp) != NULL) {
		dst_bgn = strchr(str, '\11') + 1;
		memcpy(dst, dst_bgn, 8);
		dst[8] = '\0';
		if (strcmp(dst, "00000000") == 0) {
			memcpy(iface_str, str, dst_bgn - str - 1);
			iface_str[dst_bgn - str - 1] = '\0';
		}
	}

	fclose(fp);
	return iface_str;
}

void show_header(unsigned char header[14])
{
	int i;
	for (i = 0; i < 14; i++) {
		if (i > 0)
			printf(" ");
		printf("%02X", header[i] & 0x00FF);
	}
	printf("\n");
}

static unsigned char *get_mac_arpcache(char *ip_str, char *iface)
{
	int s;
	struct arpreq areq;
	struct sockaddr_in *sin;
	struct in_addr ipaddr;

	/* static unsigned char *mac_bin = (unsigned char *) areq.arp_ha.sa_data; */
	static unsigned char *mac_bin;
	mac_bin = (unsigned char *)areq.arp_ha.sa_data;

	/* Get an internet domain socket. */
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
		perror("socket");
		exit(1);
	}

	/* Make the ARP request. */
	memset(&areq, 0, sizeof(areq));
	sin = (struct sockaddr_in *)&areq.arp_pa;
	sin->sin_family = AF_INET;

	if (inet_aton(ip_str, &ipaddr) == 0) {
		fprintf(stderr, "-- Error: invalid IP address %s.\n", ip_str);
		exit(1);
	}

	sin->sin_addr = ipaddr;
	sin = (struct sockaddr_in *)&areq.arp_ha;
	sin->sin_family = ARPHRD_ETHER;

	strncpy(areq.arp_dev, iface, 15);

	if (ioctl(s, SIOCGARP, (caddr_t) & areq) == -1) {
		perror("-- Error: unable to make ARP request, error");
		exit(1);
	}

	return mac_bin;
}

int get_dev_mac(char *dev, unsigned char mac[6])
{
	int i;
	int status;
	int sock;
	struct ifreq ifr;

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock == -1) {
		perror("socket() ERROR");
		return -1;
	}

	strcpy(ifr.ifr_name, dev);

	status = ioctl(sock, SIOCGIFHWADDR, (char *)&ifr);
	if (status == -1) {
		perror("ioctl(SIOCGIFHWADDR) ERROR");
		return -1;
	}

	memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
	close(sock);
	return 0;
}

static unsigned char *create_eth_header(void)
{
	int i;
	char *ip;
	char *iface;
	unsigned char gw_mac[6];
	unsigned char eth_mac[6];
	static unsigned char eth_header[14];

	/* Findout gateway IP address */
	ip = (char *)inet_ntoa(hexstr_to_int(get_gateway_str()));

	/* Findout gateway interface name */
	iface = get_gateway_iface();

	/* Read gateway mac address from arp cache */
	memcpy(gw_mac, get_mac_arpcache(ip, iface), 6);

	/* Findout local eth mac addrsss */
	get_dev_mac(iface, eth_mac);

	for (i = 0; i < 6; i++) {
		eth_header[i] = gw_mac[i];
		eth_header[i + 6] = eth_mac[i];
	}
	eth_header[12] = 8;
	eth_header[13] = 0;

	return eth_header;
}

int main()
{
	show_header(create_eth_header());
	return 0;
}