/*
 *
 * Copyright 2000-2001 pilot <pilot@monkey.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "rule.h"
#define SEND_URI "GET / HTTP/1.0"

int
recvtimeoutr(int s, char *buf, int len, int timeout)
{
 fd_set fds;
 int n;
 struct timeval tv;
 FD_ZERO(&fds);
 FD_SET(s,&fds);
 tv.tv_sec=timeout;
 tv.tv_usec =0;

 n=select(s+1,&fds,NULL,NULL,&tv);
 if (n ==0) return -2;
 if (n ==-1) return -1;
 return recv(s,buf,len,0);
}


void
timed(int sig)
{
int sock;
close(sock);
}

void
scanrule(char *scanhost,unsigned int port,char *rulename,unsigned short int statuscode)
{

 FILE *fd;

 int  sock;
 struct sockaddr_in http;
 struct hostent *he;
 char response[700];

 char filebuf[3200],uri[2700];
 char hstatus[50],hrequest[50],request[2500],exp[100],patch[400];

 int  recvflags=0,jump=0;
 int  s=0,sc=0,scc=0;
 int  hr,hrc=0,hrcc=0;
 int  r,rc=0,rcc=0;
 int  e,ec=0,ecc=0;
 int  p,pc=0;

 unsigned short int cr,lf;

  if((fd=fopen(rulename,"rt")) == NULL){
         fprintf(stderr,"File %s open error\n",rulename);
         exit(1);
         }

  fprintf(stdout,"\nCheck Scan %s database\n\n",rulename);
         
         while(!feof(fd)){

         bzero(filebuf,sizeof(filebuf));
         bzero(uri,sizeof(uri));
         bzero(hstatus,sizeof(hstatus));
         bzero(hrequest,sizeof(hrequest));
         bzero(request,sizeof(request));
         bzero(exp,sizeof(exp));
         bzero(patch,sizeof(patch));

         fgets(filebuf,sizeof(filebuf),fd);
         cr=lf=0;

         if (filebuf[0]=='#'||filebuf[0]==' '||filebuf[0]==0x0a||filebuf[0]==0x0d||filebuf[0]==NULL)
         continue;

	 if (filebuf[0]=='O'  && filebuf[1]=='O' && filebuf[2]=='B'){
         recvflags=0x1;
         jump=jump+4;
         sc=sc+4;
         }
          
         if (filebuf[0]=='P' && filebuf[1]=='E' && filebuf[2]=='E' && filebuf[3]=='K'){
         recvflags=0x2;
         jump=jump+5;
         sc=sc+5;
         }

         if (filebuf[0]=='A' && filebuf[1]=='L' && filebuf[2]=='L'){
         recvflags=0x40;
         jump=jump+4;
         sc=sc+4;
         }
 
         for (s=jump;s<=sizeof(filebuf);s++){
                 if (filebuf[s]!='-'&&filebuf[s+1]!='>'){
                 hstatus[s-jump]=filebuf[s];
                 sc++;
             }
             else break;
           }

           scc=sc+3;
 
         for (hr=scc;hr<=sizeof(filebuf);hr++){
             if (filebuf[hr]!=':'){
                 hrequest[hrc]=filebuf[hr];
                 hrc++;
             }
             else break;
          }
          hrcc=scc+hrc+1;

         for (r=hrcc;r<=sizeof(filebuf);r++){
             if (filebuf[r]=='\\' && filebuf[r+1]=='r'){
             request[rc]=0x0d;
             cr=1;
             r++;
             rc++;
             hrcc++;
             continue;
             }

             if (filebuf[r]=='\\' && filebuf[r+1]=='n'){
             request[rc]=0x0a;
             lf=1;
             r++;
             rc++;
             hrcc++;
             continue;
             }
             if (filebuf[r]!='^'){
             request[rc]=filebuf[r];
             rc++;
             }
             else break;
           }
          rcc=hrcc+rc+1;

         for (e=rcc;e<=sizeof(filebuf);e++){
             if (filebuf[e]!=';'){
             exp[ec]=filebuf[e];
             ec++;
             }
             else break;
          }

         ecc=rcc+ec+1;

         for (p=ecc;p<=sizeof(filebuf);p++){
             if (filebuf[p]=='\\' && filebuf[p+1]=='n'){
             patch[pc]=0x0a;
             p++;
             pc++;
             continue;
             }
             if (filebuf[p]=='\\' && filebuf[p+1]=='t'){
             patch[pc]=0x09;
             p++;
             pc++;
             continue;
             }

              if (filebuf[p]!=';'){
              patch[pc]=filebuf[p];
              pc++;
              }
              else break;
          }

         jump=0;
         sc=scc=0;
         hrc=hrcc=0;
         rc=rcc=0;
         ec=ecc=0;
         pc=0;

       if ((he = gethostbyname(scanhost)) == NULL){
       perror("gethostbyname");
       exit(1);
        }
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1){
           perror("socket");
           exit(1);
        }
        http.sin_family = AF_INET;
        http.sin_port = htons(port);
        http.sin_addr= *((struct in_addr *)he->h_addr);
        bzero(&(http.sin_zero),8);

        if (connect(sock, (struct sockaddr *)&http, sizeof(struct sockaddr)) == -1){
        perror("connect");
        close(sock);
        exit(0);
        }
       
       if (statuscode==2&&(cr==0||lf==0))
       snprintf(uri,sizeof(uri),"%s%s%s\r\nHOST:%s\r\n\r\n",hrequest,request,HTTP_VER_1_1,scanhost);
       else if (statuscode==2&&cr&&lf) {cr=lf=0;continue;}


       if (cr&&lf&&statuscode==1)
       snprintf(uri,sizeof(uri),"%s%s",hrequest,request);
       else if (statuscode==1&&(cr==0||lf==0)) snprintf(uri,sizeof(uri),"%s%s%s\n\n",hrequest,request,HTTP_VER_1);

       cr=lf=0;
       bzero(response,sizeof(response));
       send(sock,uri,strlen(uri),0);
       recv(sock,response,sizeof(response),recvflags);
       if (( strstr(response,hstatus)) != 0){
       fprintf(stdout,"%6s-%s\n",hstatus,exp);
       fprintf(stdout,"        %s\n\n",patch);
       }
       recvflags=0;

    close(sock);
  } /*while close block*/
  fprintf(stdout,"\nEnd Check Scan %s database\n\n\n",rulename);
  fclose(fd);
}


        

void
scanruleP(char *scanhost,unsigned int port,char *rulename,unsigned short int statuscode,unsigned short int process)
{
 
 FILE *fd;
 int pcount=0;
 int  sock;
 struct sockaddr_in http;
 struct hostent *he;
 char response[700];
 
 char filebuf[3200],uri[2750];
 char hstatus[50],hrequest[50],request[2500],exp[100],patch[400];
 
 int  recvflags=0,jump=0;
 int  s,sc=0,scc=0; 
 int  hr,hrc=0,hrcc=0;
 int  r,rc=0,rcc=0;
 int  e,ec=0,ecc=0; 
 int  p,pc=0;
 
 unsigned short int cr,lf;

  if((fd=fopen(rulename,"rt")) == NULL){
         fprintf(stderr,"File %s open error\n",rulename);
         exit(1);
         }

  fprintf(stdout,"\nCheck Scan %s database\n\n",rulename);
 
      signal(SIGALRM,timed);
         pcount=0;
 

	 while(!feof(fd)){

	 bzero(filebuf,sizeof(filebuf));
	 bzero(uri,sizeof(uri));
	 bzero(hstatus,sizeof(hstatus));
	 bzero(hrequest,sizeof(hrequest));
	 bzero(request,sizeof(request));
	 bzero(exp,sizeof(exp)); 
         bzero(patch,sizeof(patch));
 
	 fgets(filebuf,sizeof(filebuf),fd);
          
         cr=lf=0;

         if (filebuf[0]=='#'||filebuf[0]==' '||filebuf[0]==0x0a||filebuf[0]==0x0d||filebuf[0]==NULL)
	 continue;
         
         if (filebuf[0]=='O'  && filebuf[1]=='O' && filebuf[2]=='B'){
	  recvflags=0x1;
	  jump=jump+4;
	  sc=sc+4;
    	  }
 
	  if (filebuf[0]=='P' && filebuf[1]=='E' && filebuf[2]=='E' && filebuf[3]=='K'){
	  recvflags=0x2;
	  jump=jump+5;
	  sc=sc+5;
  	  }
 
	  if (filebuf[0]=='A' && filebuf[1]=='L' && filebuf[2]=='L'){
	  recvflags=0x40;
          jump=jump+4;
          sc=sc+4;
          }                                

	 for (s=jump;s<=sizeof(filebuf);s++){
             if (filebuf[s]!='-'&&filebuf[s+1]!='>'){
                 hstatus[s-jump]=filebuf[s];
                 sc++;
             }
             else break;
           }
           scc=sc+3;

         for (hr=scc;hr<=sizeof(filebuf);hr++){
             if (filebuf[hr]!=':'){
                 hrequest[hrc]=filebuf[hr];
                 hrc++;
             }
             else break;
	  }
          hrcc=scc+hrc+1;
	     		
	 for (r=hrcc;r<=sizeof(filebuf);r++){
             if (filebuf[r]=='\\' && filebuf[r+1]=='r'){
             request[rc]=0x0d;
             cr=1;
             r++;
             rc++;
             hrcc++;
             continue;
             }
             if (filebuf[r]=='\\' && filebuf[r+1]=='n'){
             request[rc]=0x0a;
             lf=1;
             r++;
             rc++;
             hrcc++;
             continue;
             }
             if (filebuf[r]!='^'){
             request[rc]=filebuf[r];
             rc++;
             }
	     else break;
           }
          rcc=hrcc+rc+1;

	 for (e=rcc;e<=sizeof(filebuf);e++){
             if (filebuf[e]!=';'){
             exp[ec]=filebuf[e];
             ec++;
             }
             else break;
          }

         ecc=rcc+ec+1;

         for (p=ecc;p<=sizeof(filebuf);p++){
             if (filebuf[p]=='\\' && filebuf[p+1]=='n'){
             patch[pc]=0x0a;
             p++;
             pc++;
             continue;
             }
             if (filebuf[p]=='\\' && filebuf[p+1]=='t'){
             patch[pc]=0x09;
             p++;
             pc++;
             continue;
             }

              if (filebuf[p]!=';'){
              patch[pc]=filebuf[p];
              pc++;
              }
              else break;
          }   
         jump=0; 
         sc=scc=0;
         hrc=hrcc=0;
         rc=rcc=0;
         ec=ecc=0; 
         pc=0;
        
       if ( pcount>= process) wait(NULL);

        switch(fork()) {
                  case 0:
                  alarm(2);

       if ((he = gethostbyname(scanhost)) == NULL){
       close(sock);
       exit(0);
        }
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1){
           close(sock);
           exit(0);
        }
        http.sin_family = AF_INET;
        http.sin_port = htons(port);
        http.sin_addr= *((struct in_addr *)he->h_addr);
        bzero(&(http.sin_zero),8);

        if (connect(sock, (struct sockaddr *)&http, sizeof(struct sockaddr)) == -1){
        close(sock);
        exit(0);
        }


       if (statuscode==2&&(cr==0||lf==0)) 
       snprintf(uri,sizeof(uri),"%s%s%s\r\nHOST:%s\r\n\r\n",hrequest,request,HTTP_VER_1_1,scanhost); 
       else if (statuscode==2&&cr&&lf) {cr=lf=0;continue;}
       
   
       if (cr&&lf&&statuscode==1)
       snprintf(uri,sizeof(uri),"%s%s",hrequest,request);
       else if (statuscode==1&&(cr==0||lf==0)) snprintf(uri,sizeof(uri),"%s%s%s\n\n",hrequest,request,HTTP_VER_1);

       cr=lf=0;

       bzero(response,sizeof(response));
       send(sock,uri,strlen(uri),0);
       recv(sock,response,sizeof(response),recvflags);
       if (( strstr(response,hstatus)) != 0){
       fprintf(stdout,"%6s-%s\n        %s\n\n",hstatus,exp,patch);
       }
    recvflags=0;
    close(sock);
    exit(0);    
    
    case -1:
    perror("fork err");
    exit(-1);

    default:
    pcount++;
    break;

    }
          
  } /*while close block*/
  fclose(fd);
  while(pcount--) wait(NULL);
   fprintf(stdout,"\nEnd Check Scan %s database\n\n\n",rulename);



}



void
scanruleWP(unsigned long host,unsigned int port,char *rulename,unsigned short int statuscode,unsigned short int process)
{
 
 FILE *fd;
 int pcount=0;
 int  sock,nb;
 struct sockaddr_in http;
 char response[700];
 
 char filebuf[3200],uri[2700];
 char hstatus[50],hrequest[50],request[2500],exp[100],patch[400];
 
 int  recvflags=0,jump=0;
 int  s,sc=0,scc=0;
 int  hr,hrc=0,hrcc=0;
 int  r,rc=0,rcc=0;
 int  e,ec=0,ecc=0;
 int  p,pc=0;

 unsigned short int cr,lf;


char osfinger[20];
char headBuff[180];

char *ptr,*ptr2,*buffer_pointer;

        signal(SIGALRM,timed);
        alarm(2);
        sock = socket(AF_INET,SOCK_STREAM,0);
        http.sin_family = AF_INET;
        http.sin_port = htons(port);
        http.sin_addr.s_addr= htonl(host);

        if (connect(sock, (struct sockaddr *)&http, sizeof(struct sockaddr)) == -1){
        close(sock);
        return;
        }
        snprintf(osfinger,sizeof(osfinger),"%s\n\n",SEND_URI);

        send(sock,osfinger,strlen(osfinger),0);
        nb=recvtimeoutr(sock,headBuff,sizeof(headBuff),10);

        if (nb== -1 || nb== -2) {
        fprintf(stdout,"\n%s\nmaybe router,unknown network device\n\n",inet_ntoa(http.sin_addr));
        close(sock);
        return;
        }
 
        if(strstr(headBuff,"Server Error")!=NULL){
        close(sock);
        return;
        }
        ptr = strstr(headBuff,"Server");

        if (ptr == NULL) {
        fprintf(stderr,"%s\nCan't find Server in Header\n",inet_ntoa(http.sin_addr));
        }
        else{ 
        ptr2 = strstr(ptr,"\n");
        *ptr2 = '\0';
        buffer_pointer = strdup(ptr);
        *ptr2 = '\n';
        fprintf(stdout,"\n%s\n%s\n",inet_ntoa(http.sin_addr),buffer_pointer);
        free(buffer_pointer);
        }
        fprintf(stdout,"\n");

        close(sock);


 
  if((fd=fopen(rulename,"rt")) == NULL){
         fprintf(stderr,"File %s open error\n",rulename);
         exit(1);
         }
         
         fprintf(stdout,"\nCheck Scan %s database\n\n",rulename); 
         signal(SIGALRM,timed);
         pcount=0;

  
	 while(!feof(fd)){

	 bzero(filebuf,sizeof(filebuf));
	 bzero(uri,sizeof(uri));
	 bzero(hstatus,sizeof(hstatus));
	 bzero(hrequest,sizeof(hrequest));
	 bzero(request,sizeof(request));
	 bzero(exp,sizeof(exp)); 
         bzero(patch,sizeof(patch));
 
	 fgets(filebuf,sizeof(filebuf),fd);
         
         cr=lf=0;

         if (filebuf[0]=='#'||filebuf[0]==' '||filebuf[0]==0x0a||filebuf[0]==0x0d||filebuf[0]==NULL)
	 continue;
         
         if (filebuf[0]=='O'  && filebuf[1]=='O' && filebuf[2]=='B'){
         recvflags=0x1;
         jump=jump+4;
         sc=sc+4;
         }

         if (filebuf[0]=='P' && filebuf[1]=='E' && filebuf[2]=='E' && filebuf[3]=='K'){
         recvflags=0x2;
         jump=jump+5;
         sc=sc+5;
         }

         if (filebuf[0]=='A' && filebuf[1]=='L' && filebuf[2]=='L'){
         recvflags=0x40;
         jump=jump+4;
         sc=sc+4;
         }

	 for (s=jump;s<=sizeof(filebuf);s++){
             if (filebuf[s]!='-'&&filebuf[s+1]!='>'){
                 hstatus[s-jump]=filebuf[s];
                 sc++;
             }
             else break;
           }
           scc=sc+3;

         for (hr=scc;hr<=sizeof(filebuf);hr++){
             if (filebuf[hr]!=':'){
                 hrequest[hrc]=filebuf[hr];
                 hrc++;
             }
             else break;
	  }
          hrcc=scc+hrc+1;
	     		
	 for (r=hrcc;r<=sizeof(filebuf);r++){
             if (filebuf[r]=='\\' && filebuf[r+1]=='r'){
             request[rc]=0x0d;
             cr=1;
             r++;
             rc++;
             hrcc++;
             continue;
             }
             if (filebuf[r]=='\\' && filebuf[r+1]=='n'){
             request[rc]=0x0a;
             lf=1;
             r++;
             rc++;
             hrcc++;
             continue;
             }
             if (filebuf[r]!='^'){
             request[rc]=filebuf[r];
             rc++;
             }
	     else break;
           }
          rcc=hrcc+rc+1;

	 for (e=rcc;e<=sizeof(filebuf);e++){
             if (filebuf[e]!=';'){
             exp[ec]=filebuf[e];
             ec++;
             }
             else break;
          }
         
          ecc=rcc+ec+1;
           
          for (p=ecc;p<=sizeof(filebuf);p++){
             if (filebuf[p]=='\\' && filebuf[p+1]=='n'){
             patch[pc]=0x0a;
             p++;
             pc++;
             continue;
             }
             if (filebuf[p]=='\\' && filebuf[p+1]=='t'){
             patch[pc]=0x09;
             p++;
             pc++;
             continue;
             }

              if (filebuf[p]!=';'){
              patch[pc]=filebuf[p];
              pc++;
              }
              else break;
          }

         jump=0;        
         sc=scc=0;
         hrc=hrcc=0;
         rc=rcc=0;
         ec=ecc=0; 
         pc=0; 

         
         if ( pcount>= process) wait(NULL);

        switch(fork()) {
                  case 0:
                  alarm(2);

        sock = socket(AF_INET, SOCK_STREAM, 0);
        http.sin_family = AF_INET;
        http.sin_port = htons(port);
        http.sin_addr.s_addr= htonl(host);

        if (connect(sock, (struct sockaddr *)&http, sizeof(struct sockaddr)) == -1){
    /*    perror("connect");*/
        close(sock);
        exit(0);
        }

         
/*       if (statuscode==2&&(cr==0||lf==0))
       snprintf(uri,sizeof(uri),"%s%s%s\r\nHOST:localhost\r\n\r\n",hrequest,request,HTTP_VER_1_1);
       else if (statuscode==2&&cr&&lf) {cr=lf=0;continue;}*/

       if (cr&&lf&&statuscode==1)
       snprintf(uri,sizeof(uri),"%s%s",hrequest,request);
       else if (statuscode==1&&(cr==0||lf==0)) snprintf(uri,sizeof(uri),"%s%s%s\n\n",hrequest,request,HTTP_VER_1);

       cr=lf=0;
 
       bzero(response,sizeof(response));
       send(sock,uri,strlen(uri),0);
       recv(sock,response,sizeof(response),recvflags);

       if (( strstr(response,hstatus)) !=0){
       fprintf(stdout,"%6s-%s\n        %s\n\n",hstatus,exp,patch); 
       }
      recvflags=0;
      close(sock);
      exit(0);

    case -1:
         perror("fork err");
         exit(-1);

   default:
         pcount++;
         break;

         }

  } /*while close block*/
  fclose(fd);
  while(pcount--) wait(NULL);
  fprintf(stdout,"\nEnd Check Scan %s database\n\n\n",rulename);
}

