/*
  ipcalc2.c - IP Subnet Calculator
  by Marcin Ulikowski <elceef@itsec.pl>
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>

u_char dotip[16];
u_int ip, mask, decmask, netaddr, broadcast, hostno;

void usage(u_char *exec) {
  printf("Usage: %s <IPADDR/NETMASK>\nExample: %s 10.0.0.1/24\n", exec, exec);
  exit(1);  
}

static char *dot_addr(int inetaddr) {
  static u_char ip[16];
  char *pip = ip;
  u_char *p = (u_char *)&inetaddr;

  snprintf(ip, sizeof(ip), "%u.%u.%u.%u", p[0], p[1], p[2], p[3]);

  return pip;
}

int main(int argc, char *argv[]) {
  u_int net, i, k;
  
  if (argc == 1) usage(argv[0]);
  if (strchr(argv[1], '/')) sscanf(argv[1], "%[^/]/%u", dotip, &mask);
  if (mask > 32) usage(argv[0]);
  if ((ip = inet_addr(dotip)) == INADDR_NONE) usage(argv[0]);

  decmask = mask;
  mask = (mask == 0) ? 0 : htonl((UINT_MAX << (32-mask)));
  netaddr = ip & mask;
  broadcast = ip | ~mask;
  hostno = ntohl(~mask) - 1;

  printf("Address: %s - ", dot_addr(ip));
  if ((ip & (128)) == (0)) printf("class A");
  if ((ip & (128+64)) == (128)) printf("class B");
  if ((ip & (128+64+32)) == (128+64)) printf("class C");
  if ((ip & (128+64+32+16)) == (128+64+32)) printf("class D");
  if ((ip & (128+64+32+16+8)) == (128+64+32+16)) printf("class E");
  if ((ip & (64+32+16+8+4+2+1)) == (127)) printf(", loopback");
  if ((ntohl(inet_addr("10.0.0.0"))    <= ntohl(ip) && ntohl(ip) <= ntohl(inet_addr("10.255.255.255"))) ||
      (ntohl(inet_addr("172.16.0.0"))  <= ntohl(ip) && ntohl(ip) <= ntohl(inet_addr("172.31.255.255"))) ||
      (ntohl(inet_addr("192.168.0.0")) <= ntohl(ip) && ntohl(ip) <= ntohl(inet_addr("192.168.255.255")))) printf(", private");
  printf("\nNetmask: %s\n", dot_addr(mask));

  if (mask != UINT_MAX) {
    printf("Network: %s\n", dot_addr(netaddr));
    printf("Broadcast: %s\n", dot_addr(broadcast));
    printf("Hosts/Net: %u ", hostno);
    printf("(%s ", dot_addr(htonl(ntohl(netaddr) | 1)));
    printf("- %s)\n", dot_addr(htonl(ntohl(broadcast)-1)));
  } else {
    printf("This is single host, not network!\n");
  }

  putchar('\n');

  if (decmask != 0 && decmask < 31) {  
    for (i = 2; (hostno/i)-1 >= 2; i = i*2) {
      printf("Subnets: %u (%u)\nHosts/Subnet: %u\n", i, i-2, (hostno/i)-1);
      printf("Overall usage: %u%% (%u IP)\n", 100*(i*((hostno/i)-1))/hostno, i*((hostno/i)-1));
      net = netaddr;
      decmask++;
      k = 0;
      printf("List: ");
      while (k < hostno) {
        printf("%s/%u ", dot_addr(net), decmask);
        net = htonl(ntohl(net) + (hostno/i) + 1);
        k += (hostno/i)+1;
      }
      printf("\n\n");
    }
  }

  return 0;
}

