Saturday, May 12, 2007

Finding out available FTP servers on LAN : Part 2

I talked about finding ftp servers on a LAN using nmap in a previous post. Well, looks like I got a better alternative to nmap. And what is it? Well its no great software.. its just a small 50 lines program that attempts to connect on port 21 to PCs on LAN. If you can connect, then this PC has an FTP server hosted on it... add it to the list. I takes about 1.5 minutes on my network to scan 8960 IPs.
I was surprised how such a small and simple program could outperform a giant GNU tool like nmap. Or may be I could not fine-tune nmap to my needs. Anyway, this is the exact fine-tuned nmap command I was using that takes about 3.7 minutes to scan a list of 8960 IPs:-

$ nmap -n -P0 -p 21 --max_rtt_timeout 100 --max_retries 0 -oG ftpLog.gnmap -iL IPs.txt

I also tried using min_parallelism option and min_hostgroup option but they didn't provide any speedup. May be some nmap expert could comment on it. One more thing to be said is that if remove -P0 option or in other words enable pinging .. it takes only 1.5 mins! A great improvement.. but it misses out some FTP servers(those whose firewall disable ping scanning). So I had no resort but to use my own program.
This is the program in case someone is interested:-

/*
* NetworkScanner.c
*
* A fast network scanner that scans for a specified open port.
*
* It is an enhanced version of propecia.c created by Troy Robinson
* Created : 02/05/2007
* Author : Sandeep Kumar aka Turbo : http://students.iiit.ac.in/~sandeep_kr
*
* Usage: ./a.out
* Examples of Ip in ipfile:-
* 172.16-31.*.*
* 192.168.36.200
* 172.*.*.*
* 172.16.0-255.0-255
*
* Sample Usage: ./a.out 21 255 IP_List.txt Out.txt
*
*/

#include
#include
#include
#include
#include
#include
#include
int ParseIPPart(char *ipPart, int n, int *s, int *e, int startCtr, int dashCtr);
int ParseIP(char *ip, int s[4], int e[4]);
int main (int argc, char *argv[])
{
if (argc <> \n", argv[0]);
printf("Examples of Ip in ipfile:-\n172.16-31.*.*\n192.168.36.200\n172.*.*.*\n172.16.0-255.0-255\n");
printf("Sample Usage: %s 21 255 IP_List.txt Out.txt\n",argv[0]);
exit(1);
}
int port = atoi(argv[1]); // Port to scan
int parallelLimit = atoi(argv[2]); // Max no. parallel processes (using fork)
char *fname = argv[3]; // input filename
char *outFname = argv[4]; // output filename
int procCtr = 0; // current count of parallel propcesses
char ip[20]; // scanned ip string from input file
int s[4],e[4]; //ip range as parsed from scanned ip string ip.
char host[16];
int i1,i2,i3,i4;
int sockfd, result;
struct sockaddr_in address;
FILE *fp = fopen(fname,"r");
if(fp==NULL)
{
perror("fopen");
exit(0);
}
FILE *fw = fopen(outFname,"w");
if(fw==NULL)
{
perror("fopen");
exit(0);
}
while(fscanf(fp," %s",ip)!=EOF)
{
if(ParseIP(ip,s,e)==-1)
{
fprintf(stderr,"Invalid IP Range: %s\n",ip);
continue;
}
//printf("Range is:%d-%d.%d-%d.%d-%d.%d-%d\n",s[0],e[0],s[1],e[1],s[2],e[2],s[3],e[3]);
for(i1=s[0];i1<=e[0];i1++)for(i2=s[1];i2<=e[1];i2++)for(i3=s[2];i3<=e[2];i3++)for(i4=s[3];i4<=e[3];i4++) { sprintf (host, "%d.%d.%d.%d", i1,i2,i3,i4); if(procCtr>=parallelLimit)
{
wait(NULL);
procCtr--;
}
int childPid = fork();
if(childPid>=0) // fork succeeded
{
if (childPid == 0) //child
{
address.sin_family = AF_INET;
address.sin_port = htons (port);
address.sin_addr.s_addr = inet_addr (host);
sockfd = socket (AF_INET, SOCK_STREAM, 0);
if (sockfd < result =" connect" result ="="">0)
{
wait(NULL);
procCtr--;
}
close (sockfd);
exit(0);
}
// Parses one part of an IP. An IP has 4 parts separated by dots.
int ParseIPPart(char *ipPart, int n, int *s, int *e, int starCtr, int dashCtr)
{
int i,j;
if(starCtr) // For *
{
if(n!=1)return -1;
*s=0;*e=255;return 0;
}
if(dashCtr==0) // For normal number without star or dash
{
if(n==0||n>3)return -1;
*s=0;for(j=0;j255)return -1;
*e=*s;
return 0;
}
else if(dashCtr==1) // For dash
{
for(i=0;i3||n-1-i>3)return -1;
*s=0;for(j=0;j255)return -1;
*e=0;for(j=i+1;j255)return -1;
return 0;
}
else if(dashCtr>1) return -1;
}
// Parses an IP into the IP format: a-b.c-d.e-f.g-h
int ParseIP(char *ip, int s[4], int e[4])
{
int last=0,partCtr=0,starCtr=0,dashCtr=0,i;
for(i=0;1;i++)
{
if(ip[i]=='.'||ip[i]=='\0')
{
if(last==i || starCtr+dashCtr>1)return -1;
if(ParseIPPart(ip+last,i-last,&s[partCtr],&e[partCtr],starCtr,dashCtr)==-1)return -1;
starCtr=0,dashCtr=0;
last = i+1;
partCtr++;
if(ip[i]=='\0')break;
if(partCtr==4)return -1;
}
else if(isdigit(ip[i]));
else if(ip[i]=='*')starCtr++;
else if(ip[i]=='-')dashCtr++;
else return-1;
}
if(partCtr!=4)return -1;
return 0;
}

This could be used for scanning any port, not just FTP port(21). The comments in the code says all about the program.

PS: I wonder why Blogspot does not provide code tags. Users have asked for it since ages. But Blogger just ignores us all. Need to move to Wordpress.

1 comment:

Anton Arhipov said...

Try www.angryziber.com