/********************************************************************/ /* pscan.c -- Parallelized ping scanner */ /* */ /* (c) 1997 David Simmons, simmons@simmons.starkville.ms.us */ /* */ /* compile with: cc -o pscan pscan.c */ /* */ /* This program has only been tested under Linux. */ /* */ /********************************************************************/ /* include files */ #include #include #include #include #include #include /* useful defines */ #define DEFDATALEN (64 - 8) #define MAXIPLEN 60 #define MAXICMPLEN 76 #define MAXPACKET (65536 - 60 - 8) /* prototypes */ int in_cksum(u_short *addr, int len); void send_ping(); void ping16(); void finish(); char *niceip(); void usage(); /* global variables */ int s; /* icmp socket file descriptor */ int datalen = DEFDATALEN; /* data length */ struct sockaddr_in *in; /* current address to ping */ long ipstart; /* initial ip address */ unsigned char chart[256]; /* array representing hosts in network */ u_char outpack[MAXPACKET]; /* prepare for sending packet */ /* functions */ main(int argc, char **argv) { struct sockaddr targetaddr; struct protoent *proto; u_char *packet; int packlen; int hold, offset; /* clear hosts array */ bzero(chart,256); /* parse IP address */ if (argc != 2) usage(); ipstart = htonl(ntohl(inet_addr(argv[1])) & 0xFFFFFF00); /* set up initial address structure */ bzero((char *)&targetaddr, sizeof(struct sockaddr)); in = (struct sockaddr_in *)&targetaddr; in->sin_family = AF_INET; in->sin_addr.s_addr = ipstart; /* open and configure socket for icmp */ if (!(proto = getprotobyname("icmp"))) { fprintf(stderr, "pscan: unknown protocol icmp.\n"); exit(1); } if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { perror("pscan: socket"); exit(1); } hold=1; setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&hold, sizeof(hold)); hold=48*1024; setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); packlen = datalen+MAXIPLEN+MAXICMPLEN; if (!(packet = (u_char *)malloc((u_int)packlen))) { fprintf(stderr, "pscan: out of memory.\n"); exit(1); } /* prepare ping16() to fire up... T minus one second! */ signal(SIGALRM, ping16); alarm(1); /* pseudo-infinite loop to watch for icmp echo replies */ for (;;) { struct sockaddr_in from; int cc, fromlen; fromlen = sizeof(from); if ((cc = recvfrom(s, (char *)packet, packlen, 0, (struct sockaddr *)&from, &fromlen)) < 0) { if (errno == EINTR) continue; perror("pscan: recvfrom"); continue; } else { offset = ntohl(from.sin_addr.s_addr) - ntohl(ipstart); if ((offset > 0) && (offset < 255)) { chart[offset]=1; } } } } /* ip_checksum() -- calculate IP checksum for headers */ int ip_checksum(u_short *addr, int len) { register int nleft = len; register u_short *w = addr; register int sum = 0; u_short answer = 0; while (nleft > 1) { sum += *w++; nleft -= 2; } if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)w ; sum += answer; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } /* compatibility defines */ #define icmp_type type #define icmp_code code #define icmp_cksum checksum #define icmp_id un.echo.id #define icmp_seq un.echo.sequence #define icmp_gwaddr un.gateway #define ip_hl ihl #define ip_v version #define ip_tos tos #define ip_len tot_len #define ip_id id #define ip_off frag_off #define ip_ttl ttl #define ip_p protocol #define ip_sum check #define ip_src saddr #define ip_dst daddr /* send_ping() -- transmit an icmp echo request to a host */ void send_ping() { struct sockaddr *targetaddr = (struct sockaddr *)in; register struct icmphdr *icp; register int cc; int i; /* prepare packet */ icp = (struct icmphdr *)outpack; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_seq = 1; icp->icmp_id = 42; cc = datalen + 8; icp->icmp_cksum = ip_checksum((u_short *)icp, cc); /* send packet */ i = sendto(s, (char *)outpack, cc, 0, targetaddr, sizeof(struct sockaddr)); /* did everything go okay? */ if ((i<0) || (i!=cc)) { if (i < 0) { perror("pscan: sendto"); } } } /* ping16() -- ping 16 hosts at once */ void ping16() { static unsigned char octet = 0x00; /* current octet */ int i; /* convenient union to manipulate octets */ union { unsigned long l; unsigned char a[4]; } ipset; /* load ipset with address */ ipset.l = in->sin_addr.s_addr; /* informative message to stderr */ fprintf(stderr,"sending pings %02X - %02X\n",octet,octet+0x0F); /* iterate over the next 16 ip addresses, pinging each. */ for (i=0; i<16; i++) { if (((octet+i)!=0x00) && ((octet+i)!=0xFF)) { ipset.a[3] = octet+i; in->sin_addr.s_addr = ipset.l; send_ping(); } } /* bump octet count and set the alarm for 2 seconds in the future, when we will wake up to ping the next 16 ip addresses. */ octet+=0x10; if (octet == 0x00) { /* if finished, set the alarm to call finish() in 6 seconds, allowing time for any remaining echo replies to be received. */ signal(SIGALRM, finish); alarm(6); } else { signal(SIGALRM, ping16); alarm(2); } } /* finish() -- wrap it up and display chart. */ void finish() { int i; unsigned long fip; char *ipstring; struct sockaddr_in sin; struct hostent *hp; /* print heading */ printf("#\n# ping scan of network: %s\n#\n",niceip(ipstart)); /* iterate over chart elements, printing each host that we received an echo reply from. */ for (i=0; i<256; i++) { if (chart[i]) { fip = htonl((ntohl(ipstart) + i)); ipstring = niceip(fip); bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = fip; hp = gethostbyaddr((char*)&(sin.sin_addr),sizeof(sin.sin_addr),AF_INET); printf("%s",ipstring); if ((hp != NULL) && (hp->h_name != NULL)) { printf(" (%s)\n",hp->h_name); } else { printf("\n"); } } } exit(1); } /* niceip() -- print a network-order ipaddress in the standard human readable dotted-quad format. */ char *niceip(unsigned long ip) { static char ipstring[32]; union { unsigned long ip; unsigned char a[4]; } ipset; ipset.ip = ip; sprintf(ipstring,"%d.%d.%d.%d", ipset.a[0],ipset.a[1],ipset.a[2],ipset.a[3]); return ipstring; } /* offer some advice. */ void usage() { fprintf(stderr,"usage: pscan \n" " example: pscan 192.168.42.0\n"); exit(1); }