#include <stdio.h>	/* printf, etc */
#include <stdlib.h>	/* atoi, etc */
#include <string.h>	/* strlcpy, etc */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#if !defined(USE_INET_ATON)
#define inet_aton(a, n) ((inet_pton(AF_INET, a, n)==1)?1:0)
#endif

char *ultobstr(unsigned long u, int bitlen, char *str, size_t z)
{ /* convert value to binary string */
  int l = 0;
  char buf[z];

  strlcpy(buf, "", z);
  do {
    strlcpy(str, (u & 1UL) ? "1" : "0", z);
    strlcat(str, buf, z);
    strlcpy(buf, str, z);
    u >>= 1;
  } while ((bitlen < 0) ? u : (++l < bitlen));
  return str;
}

int main(int argc, char *argv[])
{
  int a;
  char net_addrs[16] = "210.154.62.64", addrs[16] = "210.154.62.67";
  int net_mask_len = 29;
  struct in_addr net_addr, net_mask, end_addr, addr;
  char buf[1024], *p;

  for (a=1; a<argc; a++)
    if (strcmp(argv[a], "-h") == 0) {
      fprintf(stderr, "usage:\n"
	      "\t%s [-n net_address/mask_len] [-a address]\n", argv[0]);
      return 1;
    }
    else if (strcmp(argv[a], "-n") == 0 && a+1 < argc) {
      strlcpy(net_addrs, argv[++a], sizeof(net_addrs));
      if ((p = strchr(net_addrs, '/'))) *p = '\0';
      if ((p = strchr(argv[a], '/'))) {
	net_mask_len = atoi(p+1);
      }
    }
    else if (strcmp(argv[a], "-a") == 0 && a+1 < argc) {
      strlcpy(addrs, argv[++a], sizeof(addrs));
    }

  /* マスク長lからネットマスク(network byte order)を作成 */
  net_mask.s_addr = htonl(~0UL << (32 - net_mask_len));
  printf("net_mask_len:\t%d\n", net_mask_len);
  printf("net_mask:\t%s\t%s\n", inet_ntoa(net_mask),
	 ultobstr(ntohl(net_mask.s_addr), 32, buf, sizeof(buf)));

  /* マスク長lのアドレス空間のサイズ */
  printf("space size:\t%llu\n", 1ULL<<(32 - net_mask_len));

  /* 指定されたネットワークアドレス文字列をバイナリ(network byte order)へ変換 */
  if (inet_aton(net_addrs, &net_addr) == 0)
    perror("inet_aton(net_addrs,..)");
  printf("net_addr:\t%s\t%s\n", inet_ntoa(net_addr),
	 ultobstr(ntohl(net_addr.s_addr), 32, buf, sizeof(buf)));

  /* ネットマスクからネットワークアドレスを補正 */
  net_addr.s_addr = net_addr.s_addr & net_mask.s_addr;
  printf("net_addr:\t%s\t%s\n", inet_ntoa(net_addr),
	 ultobstr(ntohl(net_addr.s_addr), 32, buf, sizeof(buf)));

  /* ネットマスクとネットワークアドレスからネットワーク終端アドレスを生成 */
  end_addr.s_addr = net_addr.s_addr | ~net_mask.s_addr;
  printf("end_addr:\t%s\t%s\n", inet_ntoa(end_addr),
	 ultobstr(ntohl(end_addr.s_addr), 32, buf, sizeof(buf)));

  /* アドレス空間のサイズ=ネットワーク終端アドレス-ネットワークアドレス+1 */
  printf("range size:\t%llu\n",
	 (unsigned long long)ntohl(end_addr.s_addr)-ntohl(net_addr.s_addr)+1);

  /* 指定されたアドレス文字列をバイナリ(network byte order)へ変換 */
  if (inet_aton(addrs, &addr) == 0)
    perror("inet_aton(addrs,..)");
  printf("addr:\t\t%s\t%s\n", inet_ntoa(addr),
	 ultobstr(ntohl(addr.s_addr), 32, buf, sizeof(buf)));

  /* 指定されたアドレスがネットワーク空間に属するか、の判定 */
  printf("addr in net_addr:\t%s\n",
	 (/*ntohl(net_addr.s_addr) <= ntohl(addr.s_addr) &&
	    ntohl(addr.s_addr) <= ntohl(end_addr.s_addr)*/
	  (addr.s_addr & net_mask.s_addr) ==
	  (net_addr.s_addr & net_mask.s_addr)
	  ) ? "yes" : "no");

  return 0;
}
