/* 9110 */
/* VULnerability sCAN.c  -  
 (C)1997-2001 Nelson Murilo, Pangeia Informatica, AMS Foundation and others.
 All rights reserved

First Beta public version:
   2001/11/23, Nelson Murilo <nelson@pangeia.com.br> 
*/

#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#include <stdlib.h>
#endif
#include <memory.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>

#ifndef WIN32
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#else
#include <fcntl.h>
#include <io.h>
#include <conio.h>
#include <winsock.h>
#define sleep _sleep
#define close closesocket
#define write(a,b,c) send(a,b,c,0)
#define read(a,b,c) recv(a,b,c,0)
#endif

#define MAXBUF 1024
#define MINBUF 128
#define TBUF 64

#define SEND_CMD "SC"
#define VULNERABLE_LINE "VL"
#define NEW_LINE "NL"
#define NEWLINE "\n\r"
#define CMP "CMP"

struct R
{
   char host[TBUF];
   int count; // Future use
   struct R *next;
};

int sv (FILE *, char*, char *);
int os (FILE *, char *, short);
struct R *parser (char *);
char *getvar(FILE *, char *);
char *getip(char *);
void getnewline(FILE *, int);

#ifdef WIN32
void alarm(int);
#endif

int verbose;

int main (int argc, char* argv[])
{
   FILE *fd;
   short port;
   struct R *preg;

#ifdef WIN32
   WSADATA WSAData;
#endif
   char arq[MAXBUF], host[MINBUF];

   verbose = port = 0;

   if (argc < 6)
   {
      fprintf(stderr, "Vulcan V0.2b Usage: vulcan [-vd] -f vulfile -p port <iprange>\n");
      exit (-1);
   }  

   while (--argc)
   {
      argv++;
      if (!memcmp(*argv, "-f", 2))
      {
         strncpy(arq, *(++argv), MAXBUF-1);
         --argc;
      }
      else if (!memcmp(*argv, "-p", 2))
      {
         port = atoi(*(++argv));
         --argc;
      }
      else if (!memcmp(*argv, "-h", 2))
      {
         strncpy(host, *(++argv), MINBUF-1);
         --argc;
      }
      else if (!memcmp(*argv, "-v", 2))
      {
         verbose++;
      }
   }
   if (isdigit(**argv) || isalpha(**argv))
      preg = parser(*argv);
   else
   {
      fprintf(stderr, "1) parse args error\n");
      exit (-2);
   }
   
   fd = fopen (arq, "r");
   if (!fd)
   {
      fprintf(stderr, "Can't open %s\n", arq);
      exit (-1);
   } 

#ifdef WIN32
   if(WSAStartup (MAKEWORD(1,1), &WSAData) != 0) 
   {
      printf("WSAStartup failed.\n");
      WSACleanup();
      exit(-1);
   }
#endif
   
      while (preg->count)
      {
         os(fd, preg->host, port);
         preg = preg->next;
      }

   fclose (fd);
   return 0;
}

int sv(FILE * fd, char* host, char *msg)
{
   char mbuf[MAXBUF];
   char *p;
   int cmp = 0;

   rewind(fd);
   p = getvar(fd, CMP); // Get compare method 
   if (p && !memcmp(p, "EX", 2))
      cmp = 1;
      
   while ((fgets(mbuf, MAXBUF-1, fd)))
   {
      if (*mbuf == '#') // Commentaries
         continue;

      p = strrchr(mbuf, ':');
      if (p)
         *p='\0';
#if DEBUG
printf("msg = %s, mbuf = %s\n", msg, mbuf);
#endif
         if (cmp)
         {
           if  (!memcmp(mbuf, msg, strlen(msg)))
              printf ("%s: %s - %s", host, mbuf, p+1);
         }
         else
         {
           if (strstr(msg, mbuf))
              printf ("%s: %s - %s", host, mbuf, p+1);
         }
   }
   return 0;
}

int os(FILE *fd, char *host, short port)
{
   int sd, err;
   struct sockaddr_in sa;
   char buf[MAXBUF], *pb, *p;
   fd_set fds_read, fds_write;
//   struct timeval t;

//   t.tv_sec  = 10;
//   t.tv_usec = 0;

   sd = socket (AF_INET, SOCK_STREAM, 0);       
   memset (&sa, '\0', sizeof(sa));
   sa.sin_family      = AF_INET;
   sa.sin_addr.s_addr = inet_addr(host);      /* Server IP */
   sa.sin_port        = htons(port);          /* Server Port number */

#ifdef WIN32
   WSASetLastError(0);
#endif

   FD_ZERO(&fds_read);
   FD_ZERO(&fds_write);
   FD_SET(sd, &fds_read);
   FD_SET(sd, &fds_write);

   err = connect(sd, (struct sockaddr*) &sa, sizeof(sa));                   
   if (err < 0 )
   {
      perror("accept");
      return (-1);
   }
   pb = getvar(fd, SEND_CMD);
   if (FD_ISSET(sd, &fds_write))
   {
      err = write (sd, pb, strlen(pb));
      if (err < 0 )
         return (-1);
      getnewline(fd, sd);  // Check if have NewLine entries 
      pb = getvar(fd, VULNERABLE_LINE);
   }
   if (FD_ISSET(sd, &fds_read))
   {
      while ((err = read (sd, buf, MAXBUF - 1)) > 0) 
      {
         if ((p = strrchr(buf, '\n')))
            *p = '\0';
         if ((p = strrchr(buf, '\r')))
            *p = '\0';
         if ((p = strrchr(pb, '\n')))
            *p = '\0';
         if ((p = strrchr(pb, '\r'))) 
            *p = '\0';
         if (strstr(buf, pb))
            break;
      }
      if (errno < 0)
      {
         perror("read");
         exit(-4);
      }
      if (verbose)
         printf ("debug: %s > %s\n", host, buf); 
     
      if (*buf && buf)
         sv (fd, host, buf);
   }
   close (sd);
   return 1;
}

struct R *parser(char *host)
{
   static struct R Reg, *preg;
   char *p, *ph;
   u_long hstart, hend, i;
   struct in_addr in;

   preg = &Reg;

   if (!strchr(host, '-') && !strchr(host, ',')) // Only one host
   {
      if (isalpha(*host))
         host = getip(host);
      strncpy(preg->host, host, TBUF);
      preg->count = 1;
      preg->next = (struct R *) malloc(sizeof(struct R));
      preg=preg->next;
      preg->count=0; 
      return (struct R *) &Reg;
   }

   p = ph = host; 

   while (p && *p)
   {
      while (*p != ',' && *p != '-' && *p != '\0')
          p++;
      if (*p == ',')
      {
         strncpy(preg->host, getip(strtok(ph, ",")), TBUF);
         preg->count=1; 

         while ((p = strtok(NULL, ",")))
         {
            preg->next = (struct R *) malloc(sizeof(struct R));
            if (!preg->next)
            {
               fprintf(stderr, "malloc error\n");
               exit (-1);
            }
            preg=preg->next; 
            strncpy(preg->host, getip(p), TBUF);
            preg->count=1; 
         }
         preg->next = (struct R *) malloc(sizeof(struct R));
         preg=preg->next; 
      }
      else
      {
         strncpy(preg->host, strtok(ph, ",-"), TBUF);
         hstart = inet_addr(preg->host);
         strncpy(preg->host, strtok(NULL, ",-"), TBUF);
         hend = inet_addr(preg->host);
         if (!hend || hend <= hstart)
         {
            printf("2) Parser args error\n");
            exit (-3);
         }

         for (i = htonl(hstart); htonl(i) <= hend; i++)
         {
            in.s_addr = htonl(i);
            strncpy(preg->host, inet_ntoa(in), TBUF);
            preg->count = 1;
            preg->next = (struct R *) malloc(sizeof(struct R));
            if (!preg->next)
            {
               fprintf(stderr, "malloc error\n");
               exit (-1);
            }
            preg=preg->next; 
         }
      }
      if (p && *p)
         ph = ++p;
      else
         p = NULL;
   }
   preg->count = 0;
   preg->next = (struct R *)0;
   return (struct R *)&Reg;
}

char *getvar(FILE *fd, char *cmd)
{
   static char mbuf[MAXBUF];

   rewind(fd);
   while ((fgets(mbuf, MAXBUF-1, fd)))
   {
      if (!(memcmp(mbuf, cmd, strlen(cmd))))
         return strchr(mbuf, '=')+1; 
   }
   return NULL;
}

void getnewline(FILE * fd, int sd)
{
   char mbuf[MAXBUF];

   rewind(fd);
   while ((fgets(mbuf, MAXBUF-1, fd)))
   {
      if (!(memcmp(mbuf, NEW_LINE, strlen(NEW_LINE))))
         write (sd, NEWLINE, strlen(NEWLINE));
   }
}


char *getip(char *host)
{
   struct hostent *hp;
   struct in_addr in;

   if (isdigit(*host))
      return host;

   if ((hp = gethostbyname(host)) == 0)
   {
       fprintf(stderr, "host not found: %s", host);
       exit (-5);
   }
   if (hp->h_addrtype != AF_INET)
   {
       fprintf(stderr, "unexpected address family: %d", hp->h_addrtype);
       exit (-6);
   }
   if (hp->h_length != sizeof(in))
   {
       fprintf(stderr, "unexpected address length %d", hp->h_length);
       exit (-6);
   }
   memcpy((char *)&in, hp->h_addr, hp->h_length);
   return inet_ntoa(in);   
}


