#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <malloc.h>
#include <ctype.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <linux/if.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>

#define SOCKET_TYPE AF_INET
// #define SOCKET_TYPE PF_UNIX

int verbose = 0;

void pexit(char *extra)
{
   int old_errno = errno;
   fputs(extra, stderr);
   exit(old_errno);
}

char *inetaddr(u_int32_t ip)
{
   struct in_addr in;
   in.s_addr = ip;
   return inet_ntoa(in);
}

char *hwaddr(u_char * s)
{
   static char buf[30];
   snprintf(buf, sizeof(buf),
	    "%02X:%02X:%02X:%02X:%02X:%02X", s[0], s[1], s[2], s[3], s[4],
	    s[5]);
   return buf;
}

void ifsave_iface(char *iface)
{
   int rec, i;
   struct ifreq if_data;
   char *ifconfig;
   u_int8_t if_mac[6];
   u_int32_t if_ip, if_netmask, if_broadcast, ip;

   strncpy(if_data.ifr_name, iface, sizeof(if_data.ifr_name));	/* 16 ? */
   if ((rec = socket(SOCKET_TYPE, SOCK_DGRAM, 0)) < 0) {
      perror("socket");
      exit(0);
   }

   if (ioctl(rec, SIOCGIFADDR, &if_data) < 0)
      pexit("can't get IP addr of my interface!\n");

   ifconfig = (char *) getenv("IFCONFIG");

   memcpy((void *) &ip, (void *) &if_data.ifr_addr.sa_data + 2, 4);
   if_ip = ntohl(ip);
   printf("%s", ifconfig == NULL ? "" : ifconfig);
   printf(" %s", iface);
   printf(" %s ", inetaddr(ip));

   if (verbose) {
      if (ioctl(rec, SIOCGIFHWADDR, &if_data) < 0) {
	 printf("can't get HW addres of my interface!\n");
      } else {
	 memcpy(if_mac, if_data.ifr_hwaddr.sa_data, 6);
	 printf("hwaddr %s ", hwaddr(if_mac));
      }
   }

   if (ioctl(rec, SIOCGIFNETMASK, &if_data) < 0)
      pexit("Can't get NETMASK addres of my interface!\n");

   memcpy((void *) &ip, (void *) &if_data.ifr_netmask.sa_data + 2, 4);
   if_netmask = ntohl(ip);
   printf("netmask %s ", inetaddr(ip));

   if (ioctl(rec, SIOCGIFBRDADDR, &if_data) < 0)
      pexit("Can't get BROADCAST addres of my interface!\n");

   if (ioctl(rec, SIOCGIFMTU, &if_data) < 0) {
      pexit("Can't get MTU of my interface!\n");
   } else {
      printf("mtu %d ", if_data.ifr_mtu);
   }

#ifdef SIOCGIFGID
   if (ioctl(rec, SIOCGIFGID, &if_data) < 0)
      pexit("Can't figure out gid for device!\n");
   printf("gid %d ", if_data.ifr_gid);
#endif

   memcpy((void *) &ip, (void *) &if_data.ifr_broadaddr.sa_data + 2, 4);
   if_broadcast = ntohl(ip);
   printf("broadcast %s ", inetaddr(ip));

   puts("");
}


int main(int argc, char **argv)
{
   int s;
   char *buffer;
   struct ifconf ifc;
   char name[100];
   struct ifreq *ifptr, *end;
   struct ifreq ifr;
   int ifflags, selectflag = -1;
   int oldbufsize, bufsize = sizeof(struct ifreq);

   if (argc < 2) {
      fprintf(stderr, "Usage: %s <device/-a>\n", argv[0]);
      exit(1);
   }

   for (s = 1; s < argc; s++) {
      if (strcmp(argv[s], "-v") == 0) {
	 verbose++;
	 continue;
      }
      if (strcmp(argv[s], "-a") == 0)
	 goto sockit;
      ifsave_iface(argv[s]);
   }

   exit(0);

 sockit:

   s = socket(AF_INET, SOCK_DGRAM, 0);
   if (s < 0) {
      perror("ifconfig: socket");
      exit(1);
   }
   buffer = malloc(bufsize);
   ifc.ifc_len = bufsize;
   do {
      oldbufsize = ifc.ifc_len;
      bufsize += 1 + sizeof(struct ifreq);
      buffer = realloc((void *) buffer, bufsize);
      ifc.ifc_len = bufsize;
      ifc.ifc_buf = buffer;
      if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
	 perror("ifconfig (SIOCGIFCONF)");
	 exit(1);
      }
   }
   while (ifc.ifc_len > oldbufsize);
   ifflags = ifc.ifc_req->ifr_flags;
   end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
   ifptr = ifc.ifc_req;
   while (ifptr < end) {
      sprintf(ifr.ifr_name, "%s", ifptr->ifr_name);
      sprintf(name, "%s", ifptr->ifr_name);
      close(s);
      ifsave_iface(name);
      ifptr++;
   }
   return 0;
}
