/* This code is in the public domain. */

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <net/if.h>
#ifndef linux
#include <net/if_dl.h>
#endif

#include <arpa/inet.h>

#include <ifaddrs.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef linux
#define SA_LEN(a) 	16
#else
#define SA_LEN(a) 	(a->sa_len)
#endif

char *mangle(char *addr)               /* addr is xx0:addr, strip xx0: bit */
{
  char *colon;

  colon = strchr(addr, ':');
  if (colon == NULL)
    return addr;                       /* no link addr */
  return colon + 1;
}

int main(int argc, char *argv[])
{
  struct ifaddrs *ifaddr;
  struct sockaddr *a;
  int ret;
  int specific;

  ret = getifaddrs(&ifaddr);
  if (ret != 0) {
    perror("getifaddrs");
    exit(1);
  }

  specific = (argc == 2);

  /* ugly code follows, rewrite as needed */
  for (a = ifaddr->ifa_addr; ifaddr->ifa_next;
       ifaddr = ifaddr->ifa_next, a = ifaddr->ifa_addr)
    switch(a->sa_family) {
#ifndef linux
      case AF_LINK:
        if (!specific || (specific && strcmp(ifaddr->ifa_name, argv[1]) == 0))
          printf("%s link %s\n", ifaddr->ifa_name,
                 mangle(link_ntoa((struct sockaddr_dl *)a)));
        break;
#endif
      case AF_INET:
        if (!specific || (specific && strcmp(ifaddr->ifa_name, argv[1]) == 0)) {
          char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

          getnameinfo(a, SA_LEN(a), hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
                      NI_NUMERICHOST | NI_NUMERICSERV);
          printf("%s inet %s\n", ifaddr->ifa_name, hbuf);
        }
        break;
#ifndef linux
      case AF_INET6:
        if (!specific || (specific && strcmp(ifaddr->ifa_name, argv[1]) == 0)) {
          char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];

          getnameinfo(a, SA_LEN(a), hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
                      NI_NUMERICHOST | NI_NUMERICSERV);
          printf("%s inet6 %s\n", ifaddr->ifa_name, hbuf);
        }
        break;
#endif
#if 0
      default:
        if (!specific || (specific && strcmp(ifaddr->ifa_name, argv[1]) == 0)) {
          int i;

          printf("%s %d ", ifaddr->ifa_name, a->sa_family);
          for (i = 0; i < SA_LEN(a); i++)
            putchar(a->sa_data[i]);
          putchar('\n');
        }
#endif
    }
  exit(0);
}

/* eof */
