/*
   Author:  styx^

   Source:  Ping SweepeR vers. 1.0

   License: GPL
            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.

   Email:   Write me for any problem or suggestion at: the.styx@gmail.com

   Date:    20/04/2005

   Read me: Just compile it with:

           Compile: gcc PSR.c -o PSR
	     Use: ./PSR -h

	      -r <ip1> <ip2> :scan a range of ip from ip1 to ip2.
                            ( ex. ./PSR -r 127.0.0.1 127.0.0.4 )
        	-s <speed>     :the less we listen for echo reply, the more the program is entrusted.
                            You can select speed from 1 to 10, where 1 is the highest speed and 10 is the lowest.
                            ( ex. ./PSR -r 127.0.0.1 127.0.0.3 -v 1 ) default: the speed is 1.
         	-l <file>      :"file" is the file in which the scan will log the results.
                 	          ( ex. ./PSR -r 127.0.0.1 127.0.0.3 -l log.txt )
         	-n             :number of echo request that you want send.
                            ( ex. ./PSR -r 127.0.0.1 127.0.0.3 -n 3 ) default: the number of echo request is 1.
         	-a             :shows only online host.
                	          ( ex. ./PSR -r 127.0.0.1 127.0.0.3 -a ) default off
         	-h             :the help page

	
	    PAY ATTENTION: This source is coded for only personal use. Don't
			   scan around. ;)

   Description: This is a ping sweeper. It scans a range of ip to see how many
		    host are online or not. With this code, you can know quickly
		    how many host there are into a network.  

   Greetings to:

	- hacklab's crew(hacklab.altervista.org);

*/

#include <stdio.h>
#include <string.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <config.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
#include <time.h>

#define TIME_RESPONCE 10

int i = 0, j = 0, k = 0, l = 0;
int a = 0, b = 0, c = 0, d = 0;
int thost = 0;
int vel = 1;
int npkg = 1;
int active = 0;
int wfile = 0;
FILE *flog;
int trasmitted = 0;
int received = 0;
int psend = 0;
int plost = 0;
int precv = 0;
int tfhost = 0;

void ping(char *);
unsigned short in_cksum(unsigned short *, int );
int recvtarget(int, int);
void separe(char *, char *);
void usage(char *);
void write_file(char *);
void author();

int main(int argn, char **argv)

{

	int list;
	extern int optind;
	char initip[16], finip[16];
	time_t s, iniz, fini;
	char msg[100];

	memset(initip, 0x0, sizeof(initip));
	memset(finip, 0x0, sizeof(finip));
	memset(msg, 0x0, sizeof(msg));

	if(getuid())
	{
		printf("You must be root to run this program!\n" );
		exit(-1);
	}

	if( argn < 4 ) {
		usage(argv[0]);
		exit(-1);
	}
	
	printf("\n");

	while ((list = getopt(argn, argv, "rlhans")) != -1)

		switch (list)	{

				case 's':

					if( argn-1 < optind) {
						printf("I can't find the speed...\n");
						usage(argv[0]);
						exit(-1);
					} 

					vel = atoi(argv[optind]);

					if( vel == 0 ) {
						
						printf("You can't choice like speed 0..\n");
						exit(-1);

					}

					break;


				case 'n':

					if( argn-1 < optind) {
						printf("I can't find the number of packets that you want to send...\n");
						usage(argv[0]);
						exit(-1);
					} 

					npkg = atoi(argv[optind]);

					if( npkg == 0 ) {
						
						printf("You can't choice the number of packets to send like 0..\n");
						exit(-1);

					}

					break;


				case 'r':

					if( argn-1 < optind+1 ) {

						printf("I can't find the final ip...\n");
						usage(argv[0]);
						exit(-1);

					}

					separe(argv[optind],argv[optind+1]);
					
	
					break;
				
				case 'l':
				
					if( argn-1 < optind ) {

						printf("You must specify the file's name...\n");
						usage(argv[0]);
						exit(-1);

					}

					if(( flog = fopen(argv[optind], "a+")) == NULL ) {
					
						printf("I cannot open the file...\n");
						exit(-1);
						
					}
					
					printf("I'll print the scan's results into %s\n", argv[optind]);
					
					write_file("+---------------------------------------------------------------+\n");
					s = time(NULL);
					write_file("|	Scan of: ");
					write_file(asctime(localtime(&s)));
					write_file("+--------------------------------------------------------------+\n|\n");
					
					wfile++;
					
					break;

				case 'a':

					active = 1;

					break;

				case 'h':
	
					usage(argv[0]);

					break;

		}

	sprintf(finip,"%d.%d.%d.%d",a,b,c,d);
	sprintf(initip, "%d.%d.%d.%d", i, j, k, l);

	author();

	printf("Speed selected: %d\n", vel);
	printf("Number of packets to send: %d\n", npkg);

	if( active != 0 ) 
		printf("I'll show you only the host online.\n");

	printf("Now I'm scanning from %s to %s...\n\n\n", initip, finip);

	sleep(1);
	time(&iniz);

	while(1) {
			
		sprintf(initip, "%d.%d.%d.%d", i, j, k, l);

		ping(initip);

		if ( strcmp(initip, finip) == 0) {
			break;
		}

		l++;

		if ( l == 256) { 
			l = 0;
			k++;
			if ( k == 256) {
				k = 0;
				j++;
				if (j == 256) {
					j = 0;
					i++;
				}
			}
		}	

	}


	time(&fini);

	printf("\n\n\nSCAN FINISHED! in %d sec\n", (int)(fini - iniz));
	printf("%d packets trasmitted, %d packets received, %d packets lost\n", psend, precv, plost);
	printf("In the range scanned, there are %d hosts online, %d offline.\n\n", thost, tfhost);
		
	if( wfile != 0 ) {

		sprintf(msg, "|\n|\n|\n|SCAN FINISHED! in %d sec\n|", (int)(fini - iniz));
		write_file(msg);
		sprintf(msg, "%d packets trasmitted, %d packets received, %d packets lost\n|", psend, precv, plost);
		write_file(msg);
		sprintf(msg, "In the range scanned, there are %d hosts online, %d offline.\n|\n", thost, tfhost);
		write_file(msg);
		sprintf(msg, "+---------------------------------------------------------------+\n");
		write_file(msg);
		
		fclose(flog);
		
	}
		
	
	return 0;

}

void separe(char *ip,char *ip2)

{

	char *t = '\0';
	int f = 0;

	t = strtok(ip,".");
	i = atoi(t);

	while( t != NULL) {
		
		t = strtok(NULL, ".");
		f++;
		if ( f == 1) j = atoi(t);
		else if (f == 2) k = atoi(t);
		else if (f == 3) l = atoi(t);
	
	}	

	t = '\0';
	f = 0;

	t = strtok(ip2,".");
	a = atoi(t);

	while( t != NULL) {
		
		t = strtok(NULL, ".");
		f++;
		if ( f == 1) b = atoi(t);
		else if (f == 2) c = atoi(t);
		else if (f == 3) d = atoi(t);
	
		}
	
	return;

}

void ping(char *ip_)

{

	int sock, optval;
	char *packet, *buffer;
	int select_time = TIME_RESPONCE * 10;     // 1000
	int i = 0;
	int fhost = 0, nfhost = 0;
	char msg[30];

	struct icmphdr *icmp;

	struct sockaddr_in host;
        struct iphdr *ip;


        ip = (struct iphdr *) malloc(sizeof(struct iphdr));
        icmp     = (struct icmphdr *) malloc(sizeof(struct icmphdr));
        packet  = (char *) malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
        buffer  = (char *) malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));


	ip = (struct iphdr *) packet;
        icmp = (struct icmphdr *) (packet + sizeof(struct iphdr));
	memset(msg, 0x0, 20);
	
	
	sock = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
	setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int));

      ip->ihl     = 5;
      ip->version = 4;
      ip->tos     = 0;
      ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
	ip->id      = htons(getuid());
	ip->ttl      = 64;
	ip->protocol = IPPROTO_ICMP;
	ip->saddr    = INADDR_ANY;
	ip->daddr    = inet_addr(ip_);

	icmp->type = ICMP_ECHO;
	icmp->code = 0;
	icmp->un.echo.id = 0;
	icmp->un.echo.sequence = 0;
	icmp->checksum = 0;

	icmp->checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));

      ip->check  = in_cksum((unsigned short *)ip, sizeof(struct iphdr));

	host.sin_family = AF_INET;
	host.sin_addr.s_addr = inet_addr(ip_);

	for ( i = 1; i <= npkg; i++) {

		sendto(sock,packet,ip->tot_len,0,(struct sockaddr *)&host,sizeof(struct sockaddr));
		
		psend++;
	
		if( recvtarget(sock, select_time) == 0 ) {
			fhost++;
			precv++;
		}
	
		else {
		
			plost++;
			if( active == 0 )
				nfhost++;

		}
	}

	if ( fhost != 0 ) {

		printf("%s	  %s\n", ip_ , "[OK]");
		thost++;
		fhost = 0;
		
		if( wfile != 0 ) {
				
			sprintf(msg, "|	%s 	 %s\n", ip_ , "[OK]");
			write_file(msg);
		}
	}

	if ( nfhost != 0 ) {


		printf("%s	  %s\n", ip_ , "[NO]");
		tfhost++;
		nfhost = 0;

		if( wfile != 0 ) {
				
			sprintf(msg, "|	%s 	 %s\n", ip_ , "[NO]");
			write_file(msg);
		}
	}
		
	close(sock);
	return;

}

int recvtarget(int sock, int time)

{
	int nfound, n;
	struct timeval to;
	fd_set readset, writeset;

	to.tv_sec = time / 600000;
	to.tv_usec = ( time - ( to.tv_sec * 1000) ) * (6500 * vel);  //650000

	FD_ZERO( &readset );
	FD_ZERO( &writeset );
	FD_SET( sock, &readset );
	
	nfound = select(( sock + 1), &readset, &writeset, NULL, &to );
	
	if( nfound <= 0 )

		return -1;

	else return 0;
	
	return n;

}

void write_file(char *msg) 

{

	fprintf(flog, "%s", msg);
	
	return;
	
}

void usage(char *prog) 

{

	printf("\nusage: \n\n");
	printf("         -r <ip1> <ip2> :scan a range of ip from ip1 to ip2.\n");
	printf("                         ( ex. %s -r 127.0.0.1 127.0.0.4 ) \n", prog);
	printf("         -s <speed>     :the less we listen for echo reply, the more the program is entrusted.\n");
	printf("                         You can select speed from 1 to 10, where 1 is the highest speed and 10 is the lowest.\n");
	printf("                         ( ex. %s -r 127.0.0.1 127.0.0.3 -v 1 ) default: the speed is 1.\n", prog);
	printf("         -l <file>      :\"file\" is the file in which the scan will log the results.\n");
	printf("                         ( ex. %s -r 127.0.0.1 127.0.0.3 -l log.txt )\n", prog);
	printf("         -n             :number of echo request that you want send.\n");	
	printf("                         ( ex. %s -r 127.0.0.1 127.0.0.3 -n 3 ) default: the number of echo request is 1.\n", prog);
	printf("	 -a		:shows only online host.\n");
	printf("                         ( ex. %s -r 127.0.0.1 127.0.0.3 -a ) default off\n", prog);
	printf("         -h		:this page :)\n\n");

}

unsigned short in_cksum(unsigned short *addr, int len) {

	register int sum = 0;
	u_short answer = 0;
	register u_short *w = addr;
	register int nleft = len;

	while (nleft > 1) {

		  sum += *w++;
		  nleft -= 2;
	      }

	    /* mop up an odd byte, if necessary */
	if (nleft == 1)
	      {
		  *(u_char *) (&answer) = *(u_char *) w;
		  sum += answer;
	      }
	    /* add back carry outs from top 16 bits to low 16 bits */
	sum = (sum >> 16) + (sum & 0xffff);		/* add hi 16 to low 16 */
	sum += (sum >> 16);		/* add carry */
	answer = ~sum;		/* truncate to 16 bits */
	return (answer);

}


void author()

{

	printf("\n\n");
	printf("+--------------------------------------------+\n");
	printf("|                                            |\n");
	printf("|             styx^ ping sweep               |\n");
	printf("|  			PSR vers. 1.0 	     |\n");
	printf("|                                            |\n");
	printf("+--------------------------------------------+\n\n");

	return;

}



