[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    [BusyBox] New pscan applet for busybox unstable
From:       Tito <farmatito () tiscali ! it>
Date:       2003-05-30 22:33:55
[Download RAW message or body]

Hi,
I've written this little portscanner implementation for busybox unstable branch.
I know that maybe it doesn't fit in the busybox philosophy as it is not
a standard GNU utility but, as it was funny  to write and very instructive
about the busyboxification process , I'm sending it in the same in the hope
it could be usefull for somebody.
It's a simple port scanner and its only goal is that it doesn't hang
until ETIMEOUT on firewalled ports and that it should be IPv4 and IPv6
safe.
It's not very fast doing 1024 ports in about 5 minutes.
I've tried to get nmapish speed, but the only way to achieve
this was to fork 32 processes and this looked not as a good
idea to me.
I've looked at the nmap sources but they are rather complex
and lit no lite in my brain.
Any feedback is welcome, especially about

A) IPv6 (as it is untested)
B) how to increase the speed without increasing the size
C) whatever you feel to say.

Patch is against CVS of 30-5-2003

Ciao to all
Tito
["pscan_patch_bb_unstable_20030530.txt" (text/plain)]

diff -urN busybox/include/usage.h busybox/include/usage.h
--- busybox/include/usage.h	2003-05-13 14:59:07.000000000 +0000
+++ busybox/include/usage.h	2003-01-03 01:25:18.000000000 +0000
@@ -1757,6 +1757,19 @@
 	"Move the current root file system to PUT_OLD and make NEW_ROOT\n" \
 	"the new root file system."

+#define pscan_trivial_usage \
+	"HOST [ -p MAX PORT ] [ -t TIMEOUT ]"
+#define pscan_full_usage \
+	"Scans host's ports printing all ports that accept\n" \
+	"connections, and if known, the service name.\n\n" \
+	"Options:\n" \
+	"\t-p MAX PORT\tScan up to this port (default=1024)." \
+	"\t-t TIMEOUT\tTimeout in microseconds (default=5000000 (5 seconds))."
+#define pscan_example_usage \
+	"$ pscan 127.0.0.1 -p 25 -t 2000000\n" \
+	"Scanning host 127.0.0.1 (127.0.0.1) - ports 1 through 25\n" \
+	"25/tcp                 smtp   is running.\n"
+
 #define poweroff_trivial_usage \
 	""
 #define poweroff_full_usage \
diff -urN busybox/include/usage.h busybox/include/usage.h
--- busybox/include/applets.h	2003-05-11 14:52:37.000000000 +0000
+++ busybox/include/applets.h	2003-05-17 23:42:22.000000000 +0000
@@ -448,6 +448,9 @@
 #ifdef CONFIG_PWD
 	APPLET(pwd, pwd_main, _BB_DIR_BIN, _BB_SUID_NEVER)
 #endif
+#ifdef CONFIG_PSCAN
+	APPLET(pscan, pscan_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
+#endif
 #ifdef CONFIG_RDATE
 	APPLET(rdate, rdate_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER)
 #endif
diff -urN busybox/networking/Config.in busybox/networking/Config.in
--- busybox/networking/Config.in	2003-05-26 14:06:01.000000000 +0000
+++ busybox/networking/Config.in	2003-05-17 23:42:22.000000000 +0000
@@ -407,6 +413,12 @@
 	help
 	  Please submit a patch to add help text for this item.

+config CONFIG_PSCAN
+	bool "pscan"
+	default n
+	help
+	  Pscan is a mini internet port scanner implementation.
+
 config CONFIG_ROUTE
 	bool "route"
 	default n
diff -urN busybox/networking/Makefile.in busybox_orig/networking/Makefile.in
--- busybox/networking/Makefile.in	2003-02-09 06:51:14.000000000 +0000
+++ busybox/networking/Makefile.in	2003-05-17 23:42:22.000000000 +0000
@@ -43,6 +43,7 @@
 NETWORKING-$(CONFIG_NSLOOKUP)	+= nslookup.o
 NETWORKING-$(CONFIG_PING)		+= ping.o
 NETWORKING-$(CONFIG_PING6)		+= ping6.o
+NETWORKING-$(CONFIG_PSCAN)		+= pscan.o
 NETWORKING-$(CONFIG_ROUTE)		+= route.o
 NETWORKING-$(CONFIG_TELNET)		+= telnet.o
 NETWORKING-$(CONFIG_TELNETD)	+= telnetd.o
diff -urN busybox/networking/pscan.c busybox_orig/networking/pscan.c
--- busybox/networking/pscan.c	1970-01-01 00:00:00.000000000 +0000
+++ busybox/networking/pscan.c	2003-01-03 01:25:54.000000000 +0000
@@ -0,0 +1,224 @@
+/*
+ * Pscan is a mini internet port scanner implementation
+ *
+ * This program will scan a host's ports printing all ports that accept
+ * connections, and if known, the service name.
+ *
+ * This program is based on pscan.c Kopywrong (K) Aug. 25, '94 pluvius@io.org
+ * from mulinux13r2 sources and on some ideas from nmap by fyodor,
+ * and blaster scanner by polos.
+ *
+ * Hacked and busyboxed by Tito Ragusa <farmatito@tiscali.it>
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "libbb.h"
+#include "busybox.h"
+
+/* set default for roundtrip time arbitrarily  to 5 sec */
+int timeout=5000000;
+int rtt=0;
+int port_closed=0;
+int port_open=0;
+struct timeval begin, end;
+
+
+int get_time(void){return (((end.tv_sec * 1000000 )+ end.tv_usec ) - ((begin.tv_sec \
* 1000000 ) + begin.tv_usec));} +
+void print_port( int i )
+{
+	struct servent  *server;
+
+	server = getservbyport(htons(i),NULL);
+
+	if(server)
+		printf("%5d%s%s\t%s\t%s\n",i,"/",server->s_proto ,"open",server->s_name);
+	else
+		printf("%5d    \t%s\t%s\n",i,"open","unknown");
+	/* reset errno here as it could get caught by a bb_error_msg_and_die() later on */
+	errno=EXIT_SUCCESS;
+}
+
+void scan(const char *host, int  i )
+{
+	int s=0;
+	char port[5];
+
+	struct addrinfo  hints;
+	struct addrinfo *res;
+	struct addrinfo *addr_info;
+
+	int retval=0;
+
+	/* Transform port number to string */
+	snprintf(port,5,"%d",i);
+
+	/* set-up hints structure */
+	memset(&hints, 0, sizeof(hints));
+	/*  no network host address lookups as we have done it already */
+	hints.ai_flags = AI_NUMERICHOST;
+
+	hints.ai_family = PF_UNSPEC;
+	hints.ai_socktype = SOCK_STREAM;
+
+	if(getaddrinfo(host, port, &hints, &res)==-1)
+		bb_error_msg_and_die(gai_strerror(errno));
+	addr_info=res;
+
+	if((s=socket(res->ai_family, res->ai_socktype, res->ai_protocol))<0)
+		bb_error_msg_and_die("socket()");
+	/* Unblock socket : if the  socket  is  non-blocking  and the
+		connection cannot be completed immediately,  we don't need
+		to wait until an ETIMEOUT is issued.
+	*/
+	if((fcntl(s, F_SETFL, O_NONBLOCK))==-1)
+		bb_error_msg_and_die("fcntl()");
+	/* Start point needed to calculate some rough roundtrip time and tune timeout */
+	gettimeofday(&begin, NULL);
+	/* No error checking on connect(), if some bad error
+		occurs it will be caught by switch(errno) in pscan_main.
+		BTW here we have always  EINPROGRESS or EAGAIN with O_NONBLOCK.
+	*/
+	connect(s, res->ai_addr ,INET6_ADDRSTRLEN);
+	do{
+retry:
+		gettimeofday(&end, NULL);
+		/* Endpoint needed to calculate some rough round trip time and tune timeout */
+		if( errno==ECONNREFUSED ){
+			 port_closed++;
+			/* This attempts to calculate the roundtrip time (rtt) to a host by timing a
+				connect() to a port which isn't listening.  A better approach is to time a
+				ping (since it is more likely to get through firewalls (note, this isn't
+				always true nowadays --fyodor).
+			*/
+			rtt=get_time();
+			break;
+		}
+		retval=write( s," ",1);
+		if(((rtt * 2) - get_time())<=0){
+			/* set rtt to (rtt *  2) to avoid some false negative ports due to network \
performance decrease */ +			if(rtt<timeout)
+			{
+			/* WE HAD SOME RESPONSE FROM THE HOST BEFORE AS RTT IS < THAN DEFAULT VALUE
+				SO WE RETRY ONE TIME RESETTING RTT TO DEFAULT */
+				/*printf("retry port %d\n",i);*/ /* debug */
+				rtt=timeout;
+				goto retry;
+			}
+			/*else time expired */
+			break;
+		}
+	}while(retval<=0 );
+	close(s);
+	if(retval>0)
+	{
+		port_open++;
+		print_port(i);
+	}
+	freeaddrinfo(addr_info);
+}
+
+void print_stats(int maxport)
+{
+	if((port_open + port_closed) > 0)
+	{
+		printf("Port stats: %d firewalled, %d unfirewalled, %d closed, %d \
open.\n",	maxport - (port_closed + port_open), \
+																												port_closed + port_open, \
+																												port_closed, +																												port_open);
+	}
+	else
+		printf("Host seems down or is using a firewall\n");
+}
+
+int pscan_main( int argc, char **argv)
+{
+	int i;
+	int max_port = 1024;
+	char buf[INET6_ADDRSTRLEN];
+	struct hostent *host;
+
+	while ((i = getopt(argc, argv, "p:t:")) > 0)
+		switch(i)
+		{
+			case 'p':
+				max_port=bb_xgetlarg(optarg, 10, 1, 65535);
+				break;
+			case 't':
+				timeout=bb_xgetlarg(optarg, 10, 1, INT_MAX); /* in microseconds */
+				break;
+			default:
+				bb_show_usage();
+		}
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc == 0 )
+		bb_show_usage();
+
+	host=xgethostbyname(argv[0]);
+	inet_ntop((host->h_addrtype == AF_INET6) ? AF_INET6 : AF_INET , \
host->h_addr_list[0],buf,INET6_ADDRSTRLEN); +
+	printf("Scanning host %s (%s) - ports 1 through %d\n Port    \
\tState\tService\n",host->h_name,buf, max_port); +
+	for(i=1;i<=max_port;i++)
+	{
+		scan(buf, i);
+		switch(errno)
+		{
+			case ECONNREFUSED:	/* PORT_CLOSED 		*/
+			case EXIT_SUCCESS:	/* PORT_OPEN 			*/
+			case EHOSTUNREACH:	/* PORT_FIREWALLED ?	*/
+			case ETIMEDOUT:		/* PORT_FIREWALLED ?	*//* unlikely to happen ?*/
+			case EHOSTDOWN:		/* PORT_FIREWALLED ?	*/
+			case EAGAIN:			/* PORT_FIREWALLED ?	*//* from  O_NONBLOCK */
+			case EINPROGRESS:		/* PORT_FIREWALLED ?	*//* from  O_NONBLOCK */
+				break;
+			case ENETDOWN:			/* something bad happened ? */
+			case ENETUNREACH:		/* something bad happened ? */
+			case ENETRESET:		/* something bad happened ? */
+			case ECONNABORTED:	/* something bad happened ? */
+			/* falltrough */
+			default:
+				bb_error_msg_and_die(strerror(errno));
+		}
+	}
+	print_stats(max_port);
+	return EXIT_SUCCESS;
+}
+/* END OF CODE */
+
+
+
+
+
+



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic