/* nosys-scan-0.2.c

  nosys-scan v0.2 by CoKi
  -----------------------
  
  This is a scanner of the most common
  ports that a server uses (21, 22, 23, 
  25, 80, 110) and shows to us if this
  open or closed.
  
  Use: ./nosys-scan-0.2 <host>
  
  No System Group - http://www.nosystem.com.ar
  coki@nosystem.com.ar

*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>

#define DATAMAX 300
#define ERROR -1
#define TIMEOUT 3

int connect_timeout(int sfd, struct sockaddr *serv_addr, socklen_t addrlen,
  int timeout);

int main(int argc, char *argv[]) {

  int sockfd, i;
  char buf[DATAMAX];
  struct hostent *he;
  struct sockaddr_in dest_dir;
  unsigned int port[] = { 21, 22, 23, 25, 80, 110 };
  
  printf("\nnosys-scan v0.2 by CoKi\n");
  printf("-----------------------\n\n");

  if(argc!=2) {
    printf("Use: %s <host>\n\n", argv[0]);
    exit(1);
  }

  if((he=gethostbyname(argv[1])) == NULL) {
    herror("Error");
    printf("\n");
    exit(1);
  }

  for(i=0; i<6; i++) {
  
    if((sockfd=socket(AF_INET, SOCK_STREAM, 0)) == ERROR) {
      perror("Error");
      printf("\n");
      exit(1);
    }

    dest_dir.sin_family = AF_INET;
    dest_dir.sin_port = htons(port[i]);
    dest_dir.sin_addr = *((struct in_addr *)he->h_addr);
    bzero(&(dest_dir.sin_zero), 8);
    
    printf("Port %u:\t", port[i]);
    fflush(stdout);

    if(connect_timeout(sockfd, (struct sockaddr *)&dest_dir, sizeof(struct sockaddr), TIMEOUT) == ERROR) {
      printf("Closed\n");
    }
    
    else printf("Open\n");
  
    close(sockfd);
  }
  printf("\n");
}

int connect_timeout(int sfd, struct sockaddr *serv_addr, socklen_t addrlen,
  int timeout) {

  int res, slen, flags;
  struct timeval tv;
  struct sockaddr_in addr;
  fd_set rdf, wrf;

  fcntl(sfd, F_SETFL, O_NONBLOCK);

  res = connect(sfd, serv_addr, addrlen);

  if (res >= 0) return res;

  FD_ZERO(&rdf);
  FD_ZERO(&wrf);

  FD_SET(sfd, &rdf);
  FD_SET(sfd, &wrf);
  bzero(&tv, sizeof(tv));
  tv.tv_sec = timeout;

  if (select(sfd + 1, &rdf, &wrf, 0, &tv) <= 0)
    return -1;

  if (FD_ISSET(sfd, &wrf) || FD_ISSET(sfd, &rdf)) {
    slen = sizeof(addr);
    if (getpeername(sfd, (struct sockaddr*)&addr, &slen) == -1)
    return -1;

    flags = fcntl(sfd, F_GETFL, NULL);
    fcntl(sfd, F_SETFL, flags & ~O_NONBLOCK);

    return 0;
  }

  return -1;
}

