/****************
name            :       mig-httpd-scan.c

version         :       1.1
			1.0 - basic version
			1.1 - added multiple host
			      scanning ability

creation date   :       26th of September 2001

author          :       no1 ( greyhats.za.net )

description     :       httpd version scanner

usage           :       gcc mig-httpd-scan.c -o mig-httpd-scan
                        ./mig-httpd-scan

extra           :       simple httpd version query proggy.
                        if you have any comments or ideas,
                        mail me at no1@greyhats.za.net
                        or msg me at http://greyhats.za.net/guestbook/
****************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
int                      httpd_scan(char *ip, int time_out, int debug, FILE ** log, int log_check);
int                      Connect(int fd, char *ip, int port, int time_out, int debug);
int                      read_timer(int fd, char *ip, int port, int time_out, int debug);
int                      write_timer(int fd, char *ip, int port, int time_out, int debug);
int                      usage(char *arg);
int                      check = 0;
int main(int argc, char **argv)
{
  int                      TIMEOUT = 10;
  int                      CHILDREN = 10;
  int                      DEBUG = 0;
  int                      i = 0;
  int                      log_check = 0;
  int                      flag = 0;
  int                      status;
  FILE                    *fp;
  FILE                    *ld;
  char                     IP[16] = "127.0.0.1";
  char                     INPUT[256] = "./input318";
  char                     OUTPUT[256] = "./log";
  char                     opt;
  while((opt = getopt(argc, argv, "h:i:o:c:t:d")) != -1)
  {
    switch (opt)
    {
      case 'h':		// ip
      {
	flag++;
	bzero(IP, sizeof(IP));
	strcpy(IP, optarg);
	remove("./input318");
	fp = fopen(INPUT, "w");
	fprintf(fp, "%s\n", IP);
	fclose(fp);
	fp = fopen(INPUT, "r");
	break;
      }
      case 'i':		// file with ips
      {
	flag++;
	bzero(INPUT, sizeof(INPUT));
	strcpy(INPUT, optarg);
	fp = fopen(INPUT, "r");
	break;
      }
      case 'o':		// log file (stdout if not used)
      {
	log_check = 1;
	strcpy(OUTPUT, optarg);
	ld = fopen(OUTPUT, "w");
	break;
      }
      case 'c':		// number of children
      {
	CHILDREN = atoi(optarg);
	break;
      }
      case 't':		// timeout value for connect/read/write
      {
	TIMEOUT = atoi(optarg);
	break;
      }
      case 'd':		// debuging output
      {
	DEBUG = 1;
	break;
      }
    }
  }

  if((flag == 2) || (flag == 0))
  {
    usage(argv[0]);
    exit(1);
  }
  bzero(IP, sizeof(IP));
  while((fgets(IP, sizeof(IP), fp)) != NULL)
  {
    i++;
    IP[strlen(IP) - 1] = '\0';
      switch (fork())
      {
	case 0:
	{
	  httpd_scan(IP, TIMEOUT, DEBUG, &ld, log_check);
	  _exit(0);
	  break;
	}
	case -1:
	{
	  perror("fork error");
	  _exit(0);
	  break;
	}
	default:
	{
	  if(i > CHILDREN - 2)
	  {
	    wait(&status);
	    i--;
	  }
	  break;
	}
      }
    bzero(IP, sizeof(IP));
  }
  remove("./input318");
  return 0;
}
int httpd_scan(char *ip, int time_out, int debug, FILE ** log, int logcheck)
{
  FILE                    *logs = *log;
  int                      sockfd;
  char                     string[] = "HEAD / HTTP/1.0\n\n";
  char                     answer[256];
  int                      PORT = 80;
  char                    *pnt;
  bzero(answer, sizeof(answer));
  pnt = answer;
  if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][80]-> socket() error\n", ip);
    return (-1);
  }
  if(Connect(sockfd, ip, PORT, time_out, debug) == -1)
  {
    close(sockfd);
    return (-1);
  }
  if(write_timer(sockfd, ip, PORT, time_out, debug) == 1)
  {
    if(write(sockfd, string, sizeof(string)) <= 0)
    {
      if(debug == 1)
	fprintf(stderr, "\n[%s][80]-> write() failed", ip);
      close(sockfd);
      return (-1);
    }
  }
  if(read_timer(sockfd, ip, PORT, time_out, debug) == 1)
  {
    if(read(sockfd, answer, 256) <= 0)
    {
      if(debug == 1)
	fprintf(stderr, "\n[%s][80]-> read() failed", ip);
      close(sockfd);
      return (-1);
    }
  }
  if(*pnt != '\0')
    for(; *pnt != '\0';)
    {
      if((isascii(*pnt) != 0) && (isprint(*pnt) != 0))
      {
	if(*pnt == '\x53' && *(pnt + 1) == '\x65' && *(pnt + 2) == '\x72' && *(pnt + 3) == '\x76' && *(pnt + 4) == '\x65' && *(pnt + 5) == '\x72')
	{
	  pnt += 7;
	  if(logcheck == 1)
	  {
	    fprintf(logs, "[%s][80]", ip);
	    while(*pnt != '\n')
	      fprintf(logs, "%c", *pnt++);
	    fprintf(logs, "\n");
	    break;
	  }
	  else
	  {
	    fprintf(stdout, "[%s][80]", ip);
	    while(*pnt != '\n')
	      fprintf(stdout, "%c", *pnt++);
	    fprintf(stdout, "\n");
	    break;
	  }
	}
      }
      pnt++;
    }
  if(logcheck == 1)
    fflush(logs);
  else
    fflush(stdout);
  return 0;
}
int Connect(int fd, char *ip, int port, int time_out, int debug)
{
  int                      flags;
  int                      select_status;
  fd_set                   connect_read, connect_write;
  struct timeval           timeout;
  int                      getsockopt_length = 0;
  int                      getsockopt_error = 0;
  struct sockaddr_in       server;
  bzero(&server, sizeof(server));
  server.sin_family = AF_INET;
  inet_pton(AF_INET, ip, &server.sin_addr);
  server.sin_port = htons(port);
  if((flags = fcntl(fd, F_GETFL, 0)) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> fcntl() error getting socket flags\n", ip, port);
    close(fd);
    return (-1);
  }
  if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket non-blocking\n", ip, port);
    close(fd);
    return (-1);
  }
  timeout.tv_sec = time_out;
  timeout.tv_usec = 0;
  FD_ZERO(&connect_read);
  FD_ZERO(&connect_write);
  FD_SET(fd, &connect_read);
  FD_SET(fd, &connect_write);
  if((connect(fd, (struct sockaddr *) &server, sizeof(server))) < 0)
  {
    if(errno != EINPROGRESS)
    {
      if(debug == 1)
	fprintf(stderr, "\n[%s][%d]-> connect() error\n", ip, port);
      close(fd);
      return (-1);
    }
  }
  else
  {
    if(fcntl(fd, F_SETFL, flags) < 0)
    {
      if(debug == 1)
	fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket flags to original state\n", ip, port);
      close(fd);
      return (-1);
    }
    return (1);
  }
  select_status = select(fd + 1, &connect_read, &connect_write, NULL, &timeout);
  if(select_status == 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> connect() timed out\n", ip, port);
    close(fd);
    return (-1);
  }
  if(select_status == -1)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> select() error on connect()\n", ip, port);
    close(fd);
    return (-1);
  }
  if(FD_ISSET(fd, &connect_read) || FD_ISSET(fd, &connect_write))
  {
    if(FD_ISSET(fd, &connect_read) && FD_ISSET(fd, &connect_write))
    {
      getsockopt_length = sizeof(getsockopt_error);
      if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &getsockopt_error, &getsockopt_length) < 0)
      {
	errno = ETIMEDOUT;
	if(debug == 1)
	  fprintf(stderr, "\n[%s][%d]-> getsockopt() timed out on connect()\n", ip, port);
	close(fd);
	return (-1);
      }
      if(getsockopt_error == 0)
      {
	if(fcntl(fd, F_SETFL, flags) < 0)
	{
	  if(debug == 1)
	    fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket flags to original state\n", ip, port);
	  close(fd);
	  return (-1);
	}
	return (1);
      }
      else
      {
	errno = getsockopt_error;
	if(debug == 1)
	  fprintf(stderr, "\n[%s][%d]-> getsockopt() error on connect()\n", ip, port);
	close(fd);
	return (-1);
      }
    }
  }
  else
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> socket not readable or writable\n", ip, port);
    close(fd);
    return (-1);
  }
  if(fcntl(fd, F_SETFL, flags) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket flags to original state\n", ip, port);
    close(fd);
    return (-1);
  }
  return (1);
}
int read_timer(int fd, char *ip, int port, int time_out, int debug)
{
  int                      flags;
  int                      select_status;
  fd_set                   fdread;
  struct timeval           timeout;
  if((flags = fcntl(fd, F_GETFL, 0)) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> fcntl() error getting socket flags\n", ip, port);
    close(fd);
    return (-1);
  }
  if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket non-blocking\n", ip, port);
    close(fd);
    return (-1);
  }
  timeout.tv_sec = time_out;
  timeout.tv_usec = 0;
  FD_ZERO(&fdread);
  FD_SET(fd, &fdread);
  select_status = select(fd + 1, &fdread, NULL, NULL, &timeout);
  if(select_status == 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> read() timed out\n", ip, port);
    close(fd);
    return (-1);
  }
  if(select_status == -1)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> select() error on read()\n", ip, port);
    close(fd);
    return (-1);
  }
  if(FD_ISSET(fd, &fdread))
  {
    if(fcntl(fd, F_SETFL, flags) < 0)
    {
      if(debug == 1)
	fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket flags to original state\n", ip, port);
      close(fd);
      return (-1);
    }
    return (1);
  }
  else
  {
    errno = ETIMEDOUT;
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> select() timed out on read()\n", ip, port);
    close(fd);
    return (-1);
  }
}
int write_timer(int fd, char *ip, int port, int time_out, int debug)
{
  int                      flags;
  int                      select_status;
  fd_set                   fdwrite;
  struct timeval           timeout;
  if((flags = fcntl(fd, F_GETFL, 0)) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> fcntl() error getting socket flags\n", ip, port);
    close(fd);
    return (-1);
  }
  if(fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket non-blocking\n", ip, port);
    close(fd);
    return (-1);
  }
  timeout.tv_sec = time_out;
  timeout.tv_usec = 0;
  FD_ZERO(&fdwrite);
  FD_SET(fd, &fdwrite);
  select_status = select(fd + 1, NULL, &fdwrite, NULL, &timeout);
  if(select_status == 0)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> write() timed out\n", ip, port);
    close(fd);
    return (-1);
  }
  if(select_status == -1)
  {
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> select() error on write()\n", ip, port);
    close(fd);
    return (-1);
  }
  if(FD_ISSET(fd, &fdwrite))
  {
    if(fcntl(fd, F_SETFL, flags) < 0)
    {
      if(debug == 1)
	fprintf(stderr, "\n[%s][%d]-> fcntl() error setting socket flags to original state\n", ip, port);
      close(fd);
      return (-1);
    }
    return (1);
  }
  else
  {
    errno = ETIMEDOUT;
    if(debug == 1)
      fprintf(stderr, "\n[%s][%d]-> select() timed out on write()\n", ip, port);
    close(fd);
    return (-1);
  }
}
int usage(char *arg)
{
  printf("\n[0;32m*****************************************[0m\n");
  printf("[0;32m* MIG httpd Version Scanner v1.1 by [0;31mno1 [0;32m*[0m\n");
  printf("[0;32m*****************************************[0m\n");
  printf("\n%s [[-h <ip>] | [-i <file>]] [-o <file>] [-c <#>] [-t <#>] [-d]\n", arg);
  printf("\n [-h]\tsingle ip address to scan\n");
  printf(" [-i]\tfile with ip addresses to scan\n");
  printf(" [-o]\tlog file (defult: stdout)\n");
  printf(" [-c]\tnumber of children to spawn (default: 10)\n");
  printf(" [-t]\tconnect/read/write timeout value (default: 10)\n");
  printf(" [-d]\tfor debuging output (default: off)\n\n");
  return 0;
}
/*******************/
// greyhats.za.net //
/*******************/
