/*

..: The
    _____ _   _  _____    ____  __ _ _   _ _ _______ _    _ _ _   _  _____ 
   / ____| \ | |/ ____|  / /  \/  (_) \ | (_)__   __| |  | (_) \ | |/ ____|
  | |    |  \| | (___   / /| \  / |_|  \| |_   | |  | |__| |_|  \| | (___  
  | |    | . ` |\___ \ / / | |\/| | | . ` | |  | |  |  __  | | . ` |\___ \ 
  | |____| |\  |____) / /  | |  | | | |\  | |  | |  | |  | | | |\  |____) |
   \_____|_| \_|_____/_/   |_|  |_|_|_| \_|_|  |_|  |_|  |_|_|_| \_|_____/ 
                                                                         
                                                                     CReW :.. 
                                presents ...

                 www.minithins.net (playskool, 3 years old)

It is a banner grabber ... just try it:

$ gcc -o bgrab bgrab.c -pthread -Wall -DMAX_THREADS=32 -D_THREAD_SAFE -ggdb
$ ./bgrab -p 21 195.132.202.0/24
195.132.202.16: 220 WorkStation Microsoft FTP Service (Version 5.0).
195.132.202.35: 220 w2k-fra-lv614 Microsoft FTP Service (Version 5.0).
...
$ cat /tmp/ftp.scanned
195.132.202.16: 220 WorkStation Microsoft FTP Service (Version 5.0).
195.132.202.35: 220 w2k-fra-lv614 Microsoft FTP Service (Version 5.0).
...

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>

#include <pthread.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#include <sys/time.h>
#include <errno.h>

#ifndef MAX_THREADS
#define MAX_THREADS 32 
#endif

#define PORT 21

extern int errno;

#ifndef _SYS_TYPES_H_ 
typedef u_int32_t in_addr_t;
#endif

int numthreads;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

struct sigaction fear;
struct in_addr dest, ldest;
int myfile;
int fearport;


extern char *optarg;
extern int optind;
extern int opterr;

void init(int sig);
int parse_host(char *hostname);
struct in_addr resolv(char *hostname);
int get_next_host(void);
void scan(in_addr_t ip);

void
init (int sig)
{
printf("FIN - signal: %i - actuel: %s - fin: %s\n\n",sig, inet_ntoa(dest), 
			inet_ntoa(ldest));
exit(0);
}

int main(int argc, char **argv)
{
pthread_t mesthreads[MAX_THREADS];
int i, arg, fin = 0;
numthreads = 0;

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

fear.sa_handler = init;
sigemptyset (&fear.sa_mask);
sigaction (SIGINT, &fear, NULL);

fearport = PORT;

while ((arg = getopt(argc, argv, "p:")) != EOF)
	{
	switch(arg)
		{
		case 'p':
			fearport = atoi(optarg);
		break;
		}
	}

parse_host(argv[argc-1]);

myfile = open("/tmp/ftp.scanned", O_RDWR | O_APPEND | O_CREAT, 0644);
//close(2);

while (!fin)
	{
	usleep(100000);
	for(i=0; i<MAX_THREADS && !fin; i++)
		{
		if (//pthread_detach(mesthreads[i]) &&
			 numthreads < MAX_THREADS
			&& i < MAX_THREADS)
				{
				if (!fin)
					{
					//pthread_mutex_lock (&lock);
					pthread_create(&(mesthreads[i]),NULL,
						(void*)scan, (void*)dest.s_addr);
					//pthread_mutex_unlock (&lock);
					usleep(100000);
					}
				if (get_next_host()) fin = 1;
				}
		}
	}

/*
 * End
 */
i = numthreads;
while (numthreads && i)
	{
	sleep(1);
	i --;
	if (i>numthreads) i = numthreads;

/* segt fault (after adding select())
	for(i=0;i<MAX_THREADS;i++)
		pthread_join(mesthreads[i],NULL);*/
	}

return(0);
}

int parse_host(char *hostname)
{
char *ptr;
int mask;

if ((ptr = strchr(hostname, '/')))
	*ptr = 0;

dest = resolv(hostname);
if (ptr == NULL)
	{
	ldest = dest;
	mask = 32;
	} else {
	mask = atoi(ptr+1);     
	if (!(mask > 0 && mask < 32))
		{
		ldest = dest;
		mask = 32;
		return(0);
		}
	dest.s_addr = ntohl(dest.s_addr);
	ldest.s_addr = dest.s_addr;
	dest.s_addr &= ~(u_int32_t) ((2 << (31 - mask)) - 1);
	ldest.s_addr |= (u_int32_t) ((2 << (31 - mask)) - 1);
	if (((unsigned char) (dest.s_addr & 0x000000ff) == 0) ||
		((unsigned char) (dest.s_addr & 0x000000ff) == 255))
		dest.s_addr ++;
	dest.s_addr = htonl(dest.s_addr);
	ldest.s_addr = htonl(ldest.s_addr);
	}
return(0);
}

struct in_addr resolv(char *hostname)
{
struct in_addr in;
struct hostent *hp;

if( (in.s_addr = inet_addr(hostname)) == -1)
	{
	if( (hp = gethostbyname(hostname)) )
		bcopy(hp->h_addr, &in.s_addr, hp->h_length);
	else {
		perror("Can't resolv hostname");
		exit(-1);
		}
	}
return in;
}

int get_next_host(void)
{
unsigned char tmp;
dest.s_addr = ntohl(dest.s_addr);
again:
	if (dest.s_addr == ntohl(ldest.s_addr))
		{
		dest.s_addr = htonl(dest.s_addr);
		return(1);
		}
	dest.s_addr ++;
	tmp = (unsigned char) (dest.s_addr & 0x000000ff);
	if (tmp == 0 || tmp == 255)
		goto again;

dest.s_addr = htonl(dest.s_addr);
return(0);
}

void scan(in_addr_t ip)
{
int s,n,i;
struct sockaddr_in phear;
char *buffer, *result;
int len;
int flags;
struct timeval tv;
fd_set lala, lulu;

pthread_mutex_lock (&lock);
numthreads ++;
pthread_mutex_unlock (&lock);

phear.sin_family = PF_INET; 
phear.sin_port = htons(fearport);
phear.sin_addr.s_addr = ip;

len = sizeof(phear);
result = (char*)malloc(sizeof(char) * 1048);
s = socket(PF_INET, SOCK_STREAM, 6);
n = s;

flags = fcntl(s, F_GETFL, 0);
fcntl(s, F_SETFL, flags | O_NONBLOCK);
tv.tv_sec = 15;
tv.tv_usec = 0;

FD_ZERO(&lala);
FD_SET(s, &lala);
lulu = lala;
connect(s,(struct sockaddr*)&phear,len);

if (select(s + 1, &lulu, &lala, NULL, &tv) != 0) 
	{
	fcntl(s, F_SETFL, flags);
	buffer = (char*)malloc(sizeof(char) * 2048);
	i = read(s,buffer,2048);

	if (i >= 0)
		{
		sprintf(result,"%s: %s", inet_ntoa(phear.sin_addr), buffer);
		printf(result);
		free(buffer);
		write(myfile,result,strlen(result));
		}
	}

free(result);
close(s);
pthread_mutex_lock(&lock);
numthreads --;
pthread_mutex_unlock(&lock);
pthread_exit(0);
}
