#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <linux/route.h>
#include <linux/if_ether.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <getopt.h>
#include <stdio.h>

char *pszProgram;

void usage (void)
  {
    fprintf (stderr, "usage: %s -{a|o|x} IP.ADDR.1 [IP.ADDR.2]\n");
  }

#define OP_AND   0
#define OP_OR    1
#define OP_XOR   2

int main (int argc, char **argv)
  {
    unsigned long  addr_1, addr_2;
    struct in_addr addr_result;
    int            opcode;
/*
 * The parameter count must be valid
 */
    pszProgram = argv[0];

    if (argc != 3 && argc != 4)
      {
	usage();
	return 1;
      }
/*
 * Determine the operation to be performed
 */
    if (strcmp (argv[1], "-a") == 0)
      {
	opcode = OP_AND;
      }
    else
      {
	if (strcmp (argv[1], "-o") == 0)
	  {
	    opcode = OP_OR;
	  }
	else
	  {
	    if (strcmp (argv[1], "-x") == 0)
	      {
		opcode = OP_XOR;
	      }
	    else
	      {
		usage();
		return 1;
	      }
	  }
      }
/*
 * Fetch the first parameter
 */
    addr_1 = ntohl (inet_addr (argv[2]));
/*
 * Determine the second parameter if one was given.
 */
    if (argc == 4)
      {
	addr_2 = ntohl (inet_addr (argv[3]));
      }
/*
 * Determine the second parameter based upon the data from the first
 */
    else
      {
	if ((addr_1 & 0x80000000) == 0)
	  {
	    addr_2 = 0xFF000000;
	  }
	else
	  {
	    if ((addr_1 & 0x40000000) == 0)
	      {
		addr_2 = 0xFFFF0000;
	      }
	    else
	      {
		if ((addr_1 & 0x20000000) == 0)
		  {
		    addr_2 = 0xFFFFFF00;
		  }
		else
		  {
		    addr_2 = 0xFFFFFFFF;
		  }
	      }
	  }
/*
 * If this is an XOR, then it is invalid.
 */
	if (opcode == OP_XOR)
	  {
	    usage();
	    return 1;
	  }
/*
 * It does not make much sense to do an OR with leading one bits. It
 * does make sense to do OR with lower one bits to form the broadcast
 * address. So, punt.
 */
	else
	  {
	    if (opcode == OP_OR)
	      {
		addr_2 ^= 0xFFFFFFFF;
	      }
	  }
      }
/*
 * Do the arithmetic
 */
    switch (opcode)
      {
      case OP_AND:
	addr_1 &= addr_2;
	break;

      case OP_OR:
	addr_1 |= addr_2;
	break;

      case OP_XOR:
	addr_1 ^= addr_2;
	break;
      }
/*
 * Print the value masked
 */
    addr_result.s_addr = htonl (addr_1);
    printf ("%s\n", inet_ntoa (addr_result));
    return 0;
  }
