/**********************************************************\
|               AzteK-onnect Scanner v1.1                  |
|  TCP COMPLETE CONNECTION (Triple Handshake Connection)   |
|                                                          |
| Written by A. Alejandro Hernandez Hernandez              |
| nitrous@danitrous.org                                    |
| www.danitrous.org                                        |
| Mexico - 20/Oct/2004                                     |
|                                                          |
| 14/Jun/2005 -- Added getbanner() && quit_newline() funcs |
| $gcc -O3 this.c -o aztek                                 |
\**********************************************************/

#include<stdio.h>
#include<stdint.h>
#include<stdlib.h>
#include<unistd.h>
#include<netinet/in.h>
#include<netdb.h>
#include<sys/time.h>
#include<sys/types.h>
#include<sys/socket.h>

#define VERSION "1.1"
#define MAXBANNERSIZE	40

uint32_t usage(char *);
void header(struct in_addr);
uint8_t Connect_Routine(uint32_t);
char *getbanner(uint32_t);
char *quit_newline(char *);

struct sockaddr_in target;
uint32_t socket_fd;
uint16_t open_Counter=0;

main(int argc, char **argv)
{
	struct hostent *host2ip;  /* struct with hostname info */
	struct servent *servname; /* struct with service info (/etc/services) */

	uint32_t begin,end,counter;
	char *currentBanner= (char *) malloc(MAXBANNERSIZE);

	if((argc<2) || (argc>4))
		return usage(argv[0]);

	if((host2ip=gethostbyname(argv[1])) == NULL)
	{
		fprintf(stderr,"Sorry !, Can't resolve %s\n",argv[1]);
		perror("gethostbyname()");
		exit(EXIT_FAILURE);
	}

	/* Setting  TARGET's struct sockaddr_in */
	target.sin_family = AF_INET;
	target.sin_addr = *((struct in_addr *)host2ip->h_addr);
	bzero(&(target.sin_zero),8);

	switch(argc)
	{
	case 2:
		header(target.sin_addr);
		for(counter=1;counter<= 65535;counter++)
		{
			if(Connect_Routine(counter))
			{
				servname=getservbyport(htons(counter),"tcp");
				printf(" %d\t\t%s\t\t",counter,(servname!=NULL)?servname->s_name:"");
				currentBanner= getbanner(counter);
				printf("%s\n",(currentBanner!=NULL)?currentBanner:"");
				
			}
			close(socket_fd);
		}
		printf("\nTotal open ports: %d\n",open_Counter);
		break;
	case 3:
		begin=atoi(argv[2]);
		if((begin < 1) || (begin > 65535))
            	{
			fprintf(stderr,"The port number is Wrong!...Valid range:{1..65535}\n");
                  	exit(EXIT_FAILURE);
            	}

            	header(target.sin_addr);
		if(Connect_Routine(begin))
		{
			servname=getservbyport(htons(begin),"tcp");
			printf(" %d\t\t%s\t\t",begin,(servname!=NULL)?servname->s_name:"");
			currentBanner= getbanner(begin);
			printf("%s\n",(currentBanner!=NULL)?currentBanner:"");
            	}
		else
			printf("Port %d is Closed !\n",begin);
		break;
	case 4:
		begin=atoi(argv[2]);
		end=atoi(argv[3]);

		if((begin>end) || (begin<1) || (end>65535))
		{
			fprintf(stderr,"The port range is Wrong!...Valid range:{1..65535}\n");
			exit(EXIT_FAILURE);
		}

            	header(target.sin_addr);
		for(counter=begin;counter<=end;counter++)
		{
			if(Connect_Routine(counter))
			{
				servname=getservbyport(htons(counter),"tcp");
				printf(" %d\t\t%s\t\t",counter,(servname!=NULL)?servname->s_name:"");
				currentBanner= getbanner(counter);
				printf("%s\n",(currentBanner!=NULL)?currentBanner:"");
			}
			close(socket_fd);
		}
            	printf("\nTotal open ports: %d\n",open_Counter);
		break;
	}

	exit(EXIT_SUCCESS);
}

uint32_t usage(char *proggy)
{
printf("AzteK-onnect Scanner v%s\n"
"Usage: \n"
       "%s hostname|ip (Simplest option, scan from 1 to 65535 tcp port)\n"
       "%s hostname|ip begin_port end_port (Set a range of ports to scan)\n"
       "%s hostname|ip port_number (Just check if 'port_number' is open)\n\n"
"Example: %s www.f00.com 1 1024 (scan 1 to 1024 ports against www.f00.com)\n",
VERSION,proggy,proggy,proggy,proggy);
}

void header(struct in_addr address)
{
printf("\n"
"            =====================================================\n"
"            =             AzteK-onnect Scanner v%s             =\n"
"            =     connect() (Triple Handshake Connection)       =\n"
"            =                                                   =\n"
"            =    A. Alejandro Hernandez <nitrous@danitrous.org> =\n"
"            =            http://www.danitrous.org               =\n"
"            =====================================================\n\n"
"Initializing Scan - target: %s\n"
"OPEN PORT\tSERVICE NAME\tBANNER\n\n",VERSION,inet_ntoa(address));
}

uint8_t Connect_Routine(uint32_t port_number)
{
	target.sin_port = htons(port_number);

	if((socket_fd=socket(AF_INET,SOCK_STREAM,0))==-1)
	{
		perror("socket():");
		exit(EXIT_FAILURE);
	}

	if((connect(socket_fd,(struct sockaddr *) &target, sizeof(target))) < 0)
                return 0;
	else
	{
		open_Counter++;
		return 1;
	}
}

char *getbanner(uint32_t port_number)
{
	char *recvstuff= (char *) malloc(256);
	char *tmpban= (char *) malloc(MAXBANNERSIZE);
	char *http_request="HEAD / HTTP/1.0\n\n";

	fd_set canread;
	struct timeval tv;

	switch(port_number)
	{
		case 37:
			tmpban= NULL;
			break;
		case 80:
		case 8080:
			send(socket_fd, http_request, strlen(http_request), 0);
			recv(socket_fd, recvstuff, 255, 0);
			recvstuff= strstr(recvstuff, "Server:");
			recvstuff= strstr(recvstuff, ":");

			tmpban= quit_newline(recvstuff);
			break;
		default:
			tv.tv_sec= 0;
			tv.tv_usec= 100000;	// 100 miliseconds [timeout]

			FD_ZERO(&canread);
			FD_SET(socket_fd, &canread);

			select(socket_fd+1, &canread, NULL, NULL, &tv);

			if(FD_ISSET(socket_fd, &canread))
			{
				recv(socket_fd, recvstuff, 255, 0);
				tmpban= quit_newline(recvstuff);
			}
			else
				tmpban=NULL;
	}

	return tmpban;
}

char *quit_newline(char *rec)
{
	char foo;
	char *tmp= (char *) malloc(MAXBANNERSIZE);

	for(foo=0; (tmp[foo]=rec[foo]) != '\n'; foo++)
		;

	tmp[foo]='\0';

	return tmp;
}
