// hostcheck-ng.c // // Copyright 2010 phocean <jc@phocean.net> // Copyright 2010 phocean <jc@phocean.net> // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1301, USA. // // Compilation : // gcc hostcheck-ng.c -o hostcheck-ng -pthread -g -O1 // - with debug : // gcc hostcheck-ng.c -o hostcheck-ng -pthread -g -O1 -DDEBUG #include <stdio.h> /* stderr, stdout */ #include <errno.h> /* errno */ #include <netdb.h> /* hostent struct, gethostbyname() */ #include <string.h> /* memset */ #include <sys/socket.h> /* socket handling */ #include <arpa/inet.h> /* inet_ntoa() to format IP address */ #include <netinet/in.h> /* in_addr structure */ #include <assert.h> /* assert */ #include <fcntl.h> /* socket non blocking */ #include <stdlib.h> /* malloc, free, etc. */ #include <pthread.h> /* threading */ #define MAX_THREADS 3 #define IPBUF 16 struct myHost { int port; char ip[IPBUF]; int state; }; /* resolve FQDN */ char *resolv(char *name) { struct in_addr h_addr; /* internet address */ struct hostent *host; /* host information */ if ( (host = gethostbyname(name) ) == NULL) { printf( "(!) Wrong parameter, exiting\n" ); return NULL; } h_addr.s_addr = *((unsigned long *) host->h_addr_list[0]); #ifdef DEBUG printf ("(-) %s resolved as %s\n",name,inet_ntoa(h_addr)); #endif return (inet_ntoa(h_addr)); } /* socket functions */ int init_socket(struct sockaddr_in *addr, char *ip, int *port) { int fd; /* create TCP INET socket */ fd = socket( AF_INET, SOCK_STREAM, 0 ); /* Initialize structure content */ memset( addr, 0, sizeof(*addr) ); addr->sin_family = AF_INET; addr->sin_port = htons ( *port ); //printf("%d\n%d\n", *port, addr->sin_port); addr->sin_addr.s_addr = inet_addr( ip ); return(fd); } /* set socket as non-blocking */ int set_nonblock(int fd) { int flags; flags = fcntl(fd,F_GETFL,0); assert(flags != -1); if ( (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) { perror("(!) Error setting non-blocking socket"); return 1; } return 0; } /* socket timeout option */ int set_options(int fd, fd_set *rst, struct timeval *tm) { //struct timeval tv; /*timeout */ /* Options */ tm->tv_sec = 2; tm->tv_usec = 0; if ( (setsockopt( fd, SOL_SOCKET, SO_RCVTIMEO, tm, sizeof(*tm))) != 0) { perror("(!) Error setting socket options"); return 1; } FD_ZERO(rst); FD_SET(fd, rst); return 0; } /* scan thread */ void *scanThread( void *arg ) { struct myHost *args = arg; int port = args->port; char *ip = args->ip; /* file descriptor and socket structure */ int connFd, ret, ret2, valopt, lon; //struct hostent *host; /* host information */ struct sockaddr_in *servaddr; struct timeval tv; /*timeout */ fd_set rset; connFd = ret = ret2 = valopt = lon = 0; /* detachable thread */ //pthread_detach( pthread_self() ); servaddr = (struct sockaddr_in*)malloc(sizeof(*servaddr)); if (servaddr == NULL) { printf( "(!) %s - Error allocating %ld bytes of memory\n",ip,sizeof(*servaddr)); goto bad; } connFd = init_socket( servaddr, ip, &port ); /* set socket as non-blocking */ if ( (set_nonblock(connFd)) != 0 ) goto bad; /* set options (timeout) */ if ( (set_options( connFd, &rset, &tv)) != 0) goto bad; /* Connect */ #ifdef DEBUG printf( "(-) %s - Trying to open port %d\n", ip, port ); #endif ret = connect ( connFd, (struct sockaddr *)servaddr, sizeof(*servaddr) ); /* not connected yet */ if (ret < 0) { /* errno : operation in progress */ if (errno == EINPROGRESS) { #ifdef DEBUG fprintf(stderr, "(-) %s - EINPROGRESS in connect() - selecting\n",ip); #endif /* select loop */ do { ret2 = select(connFd+1, NULL, &rset, NULL, &tv); /* error which is not an interruption */ if (ret2 < 0 && errno != EINTR) { fprintf(stderr, "(!) %s - Error from select()\n", ip, errno, strerror(errno)); goto bad; } /* socket selected : host up */ else if (ret2 > 0) { // Socket selected for write lon = sizeof(int); if (getsockopt(connFd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) { fprintf(stderr, "(!) %s - Error in getsockopt() %d - %s\n", ip, errno, strerror(errno)); goto bad; } // Check the value returned... /*if (valopt) { fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)); //free_exit( connFd, servaddr, 1 ); //return NULL; }*/ #ifdef DEBUG printf("(-) %s:%d is open (selected)\n",ip,port); #endif args->state=1; break; } /* timeout case */ else { #ifdef DEBUG printf("(!) %s:%d is down (timeout)\n",ip,port); #endif args->state=0; break; } } while (1); } /* any other errno : host down */ else { #ifdef DEBUG printf("(!) %s:%d is down (connect error)\n",ip,port); #endif args->state=0; } } /* connected */ else if (ret == 0) { #ifdef DEBUG printf("(-) %s:%d is up\n",ip,port); #endif args->state=1; } /* should not get here */ else { printf("(-) Unexpected error\n"); } close(connFd); free(servaddr); pthread_exit( NULL ); bad: if (connFd) close(connFd); if (servaddr) free(servaddr); pthread_exit((void *)1); } int main( int argc, char *argv[] ) { int status,nbHosts,i,j; int posHost=0; int numHost=0; pthread_t threadIds[MAX_THREADS]; struct myHost *hosts; /* Arg sanity check */ if (argc < 3) { printf("Usage: %s <dst ip> <dst port>\n", argv[0]); printf("\nCoded by phocean (/).\n"); exit(-1); } nbHosts = (argc-1)/2; hosts = (struct myHost*)calloc(nbHosts,sizeof(struct myHost)); /* resolv hostname */ for (i=0,j=0; i < argc - 1; i=i+2, j++) { hosts[j].port = atoi(argv[i+2]); strncpy(hosts[j].ip, resolv(argv[i+1]), sizeof(hosts[j].ip)-1); hosts[j].ip[IPBUF] = '\0'; } #ifdef DEBUG printf ("(-) Going to scan:\n"); for (i = 0; i < nbHosts; i++) { printf ("\t%s:%d\n",hosts[i].ip,hosts[i].port); } #endif /* for all hosts */ printf ("(-) Scanning...\n"); /* Loop for processing all hosts */ while (numHost < nbHosts) { /* save the first host processed */ posHost = numHost; /* Loop for the configured number of threads */ i = 0; while (i < MAX_THREADS && i < (nbHosts - numHost)) { /* Loop to create the max number of threads minus the already processed hosts */ do { if ( (pthread_create( &threadIds[i],NULL,scanThread,&hosts[numHost])) != 0 ) printf( "(!) Thread %d failed to start\n", (int)threadIds[i] ); i++; numHost++; } while (i < (nbHosts - posHost - 1) && i < MAX_THREADS); /* joining threads */ for (j = 0; j < i; j++) { if ( (pthread_join(threadIds[j],(void **)&status)) != 0 ) printf( "(!) Thread %d - Error joining\n", (int)threadIds[j] ); else if (status == 1) { printf( "(!) Thread %d terminated in error, status = %d\n", (int)threadIds[j], status ); } else { #ifdef DEBUG printf( "(-) Thread %d - done, status = %d\n", (int)threadIds[j], status ); #endif } } } } printf ("(+) Scan result:\n"); for (i = 0; i < nbHosts; i++) { if (hosts[i].state == 0) printf ("\t%s:%d\tCLOSED\n",hosts[i].ip,hosts[i].port); else if (hosts[i].state == 1) printf ("\t%s:%d\tOPEN\n",hosts[i].ip,hosts[i].port); else printf ("\t%s:%d\tERROR\n",hosts[i].ip,hosts[i].port); } printf ("(-) All done\n"); free(hosts); return 0; }