#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "parse_ip.h"

struct ipstr *parse_ip(char *);
void add_parse_ip(struct ipstr **, char *);
char *ip_ntoa(u_long in);

/*
 * Parse list of IP address or hostnames to scan (comma deliminated)
 *
 * Sanity checking is done on every case and should not return any invalid
 * addresses.
 *
 * Valid data is:
 *
 * hostname              anklebiter.secnet.com
 * ipaddress             127.0.0.1
 * ipaddress-ipaddress   127.0.0.1-127.0.0.20
 * ipaddress-digit       127.0.0.1-20
 * digit                 10 (expands to 127.0.0.10);
 * digit-digit           1-10 (expands to 127.0.0.1-127.0.0.10)
 *
 * For digit expansion, a CLASS C address must be present first somewhere,
 * for expansion to work.
 *
 * A valid line would be:
 *
 * anklebiter, 127.0.0.1-3,11, 14-16, 17,127.0.0.20-127.0.0.21
 *
 * This would return
 * anklebiters IP, 127.0.0.1, 127.0.0.2, 127.0.0.3, 127.0.0.11, 127.0.0.14,
 * 127.0.0.15, 127.0.0.16, 127.0.0.17, 127.0.0.20, 127.0.0.21
 * 
 * Oliver
 */
struct ipstr *parse_ip(input)
char *input;
{
   char *one = NULL, *dup = NULL;    /* a single specified address or range */
   char *r1 = NULL, *r2 = NULL;      /* for a range */
   u_long ip1 = 0, ip2 = 0;
   u_char start = 0, stop = 0;
   struct hostent *hp = NULL;
   int count = 0;
   struct ipstr *ip = NULL;
   char tmpip[20];

   dup = strdup(input);
   one = strtok(dup, ",");
   while (one) {
      while(isspace(*one) && *one)
         one++;
      /*
       * If first char is not a digit, assume this is a hostname
       */
      if (*one && !isdigit(*one)) {
         hp = NULL;
         hp = gethostbyname(one);
         if (hp) {
            memcpy((char *)&ip1, hp->h_addr, sizeof(ip1));
            sprintf(tmpip, "%s", ip_ntoa(ip1));
            add_parse_ip(&ip, tmpip);
            count++;
         } else {
           /*
            * Invalid data, can't resolve hostname, what is this?
            */
           natprintf("[*]--- Unknown host: %s\n", one);
         }
         one = strtok(NULL, ",");
         continue;
      }
      /*
       * If '-' is in the string, assume it's a range
       */
      if (*one && strstr(one, "-")) {
         r1 = one;
         for (r2 = one; *r2 && *r2 != '-'; r2++);
         *r2 = '\0';
         r2++; 

         /*
          * A range specified as x.x.x.x-x.x.x.x
          */
         if (r2 && *r2 && r1 && *r1 && strlen(r1) > 6) {
            ip1 = inet_addr(r1);
            ip2 = inet_addr(r2);
            if (ip1 != -1 && ip2 != -1) {
               start = (u_char)(ip1 >> 24);
               stop = (u_char)(ip2 >> 24);
               if (start <= stop && ip1 != -1 && ip2 != -1) {
                  while (start <= stop && start > 0) {
                     sprintf(tmpip, "%d.%d.%d.%d", (u_char)(ip1),
                            (u_char)(ip1 >> 8), (u_char)(ip1 >> 16), start);
                     add_parse_ip(&ip, tmpip);
                     count++;
                     start++;
                  }
               }
            }
         } else {
            /*
             * A range specified as x-x (class C is prepended)
             * Make sure ip1 contains the beginning of a sensible class C
             */
            if ((u_char)(ip1) != 0 && r2 && *r2 && r1 && *r1) {
               start = atoi(r1);
               stop = atoi(r2);
               if (start < stop) {
                  while(start <= stop && start > 0) {
                     sprintf(tmpip, "%d.%d.%d.%d", (u_char)(ip1),
                            (u_char)(ip1 >> 8), (u_char)(ip1 >> 16), start);
                     add_parse_ip(&ip, tmpip);
                     count++;
                     start++;
                  }
               }
            }
         }
         one = strtok(NULL, ",");
         continue;
      }
      /*
       * If we're here, it's a lonely IP address, check to see if it's valid
       */
      if (*one && (ip2 = inet_addr(one)) != -1 && strlen(one) > 6) {
         ip1 = ip2;
         sprintf(tmpip, "%s", ip_ntoa(ip1));
         add_parse_ip(&ip, tmpip);
         count++;
      } else {
         if (!strstr(one, ".")) {
            sprintf(tmpip, "%d.%d.%d.%d", (u_char)(ip1), (u_char)(ip1 >> 8),
                           (u_char)(ip1 >> 16), atoi(one));
            add_parse_ip(&ip, tmpip);
            count++;
         }
      }
      one = strtok(NULL, ",");
   }
   return(ip);
}

/*
 * Adds the specified IP to an array of IP address strings
 */
void add_parse_ip(ip, new)
struct ipstr **ip;
char *new;
{
   struct ipstr *newitem, *tmp;

   newitem = (struct ipstr *)malloc(sizeof(struct ipstr));
   newitem->name = strdup(new);
   newitem->next = NULL;

   if (!*ip) {
      *ip = newitem;
   } else {
      for (tmp = *ip; tmp->next; tmp = tmp->next);
      tmp->next = newitem;
   }

   return;
}

char *ip_ntoa(in)
        u_long in;
{
        static char b[18];
        register char *p;

        p = (char *)&in;
#define UC(b)   (((int)b)&0xff)
        (void)sprintf(b, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3]));
        return (b);
}

