#include #include #include #include #include #include /* Standard defines */ #include "config.h" /* Network includes and defines */ #include "netconfig.h" #include "functions.h" #include /* ALL GLOBALS START WITH A CAPITAL LETTER */ /* Command line option switches */ u_short BatchSize = DEFAULT_BATCHSIZE; u_short NumPings = DEFAULT_NUMPINGS; u_short Sleep = DEFAULT_SLEEP; u_short FlgDebug = 0; u_short FlgExtraDebug = 0; /* Globals that everything should access. My CS teacher would hate me */ pid_t PidSender = -1; pid_t PidListener = -1; struct host *Head; /* First host in link list of alive hosts */ u_long NumAlive = 0; /* Number of hosts in link list */ u_short NumToPing = 0; /* Number of hosts to ping */ char *Device; /* The device we listen on */ u_short PcapOffset; /* Offset to IP - dependent on device */ u_short MaxMTU = DEFAULT_MAXMTU; /* Maximum MTU for link */ u_long PcapTO = DEFAULT_PCAPTO; /* Timeout to wait between pcap read */ u_long TO = DEFAULT_TO; /* Default timeout for select calls */ u_short NumSends = DEFAULT_NUMSENDS; /* Number of times to send packet */ u_short ConfigNum=0; /* Number of config file read/sends read */ /* ICMP send/receive link list */ struct icmp_item *ICMP_Send = NULL; struct icmp_item *ICMP_Recv = NULL; /* UDP send/receive link list */ struct udp_item *UDP_Send = NULL; struct udp_item *UDP_Recv = NULL; /* We have these here so we don't have to keep recreating them. */ int RawSock; /* Our raw socket */ fd_set RawFD; /* Same as above */ struct host *ToPing; /* Hosts to ping */ int main(int argc, char *argv[]) { extern int optind; /* option index */ extern char *optarg; /* option argument */ int cai; /* Current argument index in getopt */ char *filename; /* input filename */ char *start_ip; /* start IP if scanning network */ char *stop_ip; /* start IP if scanning network */ FILE *in; /* actual input file of hosts */ char *tptr; /* temp pointer into char array -used in parsing command args */ char line[BUFSIZE]; /* Input line from file */ char perr[PCAP_ERRBUF_SIZE]; /* Generic error's in pcap routines */ struct protoent *proto; /* Protocol for ICMP */ int dlink; /* PCAP data link ID */ pcap_t *listener; /* Listener process pcap interface */ int optval, optlen; /* Max recv buffer size per nmap */ struct bpf_program lcode; /* Compiled pcap code */ u_int netmask; /* The netmask for this host */ u_int localnet; /* Needed for pcap_compile */ char l_filter[BUFSIZE]=""; /* Text code for pcap to compile */ extern FILE * yyin; /* STDIN for a grammer to read */ char *YYIN=NULL; /* File for our lang to read */ int ret; /* Return value from function calls */ struct icmp_item *temp = NULL; /* Initialize everything */ filename=start_ip=stop_ip=NULL; /* check to make sure we're root */ if(getuid()!=0) { fprintf(stderr, "You must be root to run %s\n", argv[0]); exit(FAILURE); } PidSender = getpid() & 0xFFFF; if((proto=getprotobyname("icmp"))==NULL){ fprintf(stderr, "System doesn't understand ICMP. *aborting*\n"); exit(FAILURE); } if((RawSock = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0){ fprintf(stderr, "Can't allocate raw ICMP socket. *aborting*\n"); exit(FAILURE); } /* Set socket buffer as large as possible to help prevent packet loss */ optval = MAX_RECV_BUF; optlen = sizeof(int); if(setsockopt(RawSock, SOL_SOCKET, SO_RCVBUF, (void *) &optval, optlen) != 0) fprintf(stderr, "Problem setting max recv buffer. ping may loose packets\n"); /* Set socket to non-blocking */ optval = O_NONBLOCK | fcntl(RawSock, F_GETFL); fcntl(RawSock, F_SETFL, optval); /* Broadcast socket */ optval = 1; if(setsockopt(RawSock, SOL_SOCKET, SO_BROADCAST, (void *)&optval, optlen) != 0) fprintf(stderr, "Problem broadcasting socket. continuing..\n"); /* Process input arguments */ while((cai=getopt(argc, argv, "ndbDtchfs:")) != EOF) { switch(cai){ case 'f': if(optarg == NULL) { usage(argv[0]); exit(FAILURE); } filename = optarg; optind++; break; case 't': Sleep = atoi(argv[optind]); optind++; break; case 'd': FlgDebug = 1; break; case 'D': FlgDebug = 1; FlgExtraDebug=1; break; case 'h': usage(argv[0]); exit(SUCCESS); break; case 'b': BatchSize = atoi(argv[optind]); optind++; break; case 's': MaxMTU = atoi(argv[optind]); optind++; break; case 'c': YYIN = argv[optind]; optind++; break; case 'n': NumSends = atoi(argv[optind]); optind++; break; default : usage(argv[0]); exit(FAILURE); break; } } /* Get config data */ if(YYIN == NULL) yyin = fopen(DEFAULT_YYIN, "r"); else yyin = fopen(YYIN, "r"); if(yyin==NULL){ fprintf(stderr, "Couldn't open config file: %s\n", YYIN); exit(FAILURE); } ret = yyparse(); if(ret != 0){ fprintf(stderr, "Error in config file. *aborting*\n"); exit(FAILURE); } /* Allocate a buffer to hold a simple list of a batch of hosts to ping */ ToPing = malloc(sizeof(struct host) * BatchSize); if(ToPing == NULL){ fprintf(stderr, "malloc error. *aborting*\n"); exit(FAILURE); } /* * Are there command line ranges/hosts? We only take a list or a filename, * not both */ if( (optind >= argc) && (filename==NULL) ) { usage(argv[0]); exit(FAILURE); } while(optind < argc){ /* A dash in anywhere not as an option means we have a range of hosts */ if((tptr = strchr(argv[optind], '-')) != NULL) { *tptr='\0'; start_ip=argv[optind]; stop_ip = ++tptr; generate_ip(start_ip, stop_ip); } /* Anything else is a single host */ else { /* if(FlgDebug) printf("Adding %s\n", argv[optind]); */ add_ip(argv[optind]); } optind++; } if(filename != NULL){ in=fopen(filename, "r"); while(fgets(line, sizeof(line), in)) { /* magic to avoid comments */ if((!*line) || (line[0]=='#') || (line[0]=='\'') || (line[0]==';')) continue; /* take off newline */ line[strlen(line)-1]='\0'; /* if(FlgDebug) printf("Adding %s\n", line); */ add_ip(line); } } /* clean out the remainders - Anythign less than batchsize*/ pingsweep(NumToPing); if(FlgExtraDebug) printf("Number of hosts alive: %d\n", NumAlive); /* * Initialize pcap device and open. */ if((Device = pcap_lookupdev(perr)) == NULL){ fprintf(stderr, "Couldn't find acceptable device. *aborting*\n"); exit(FAILURE); } if(FlgDebug) printf("Using device: %s\n", Device); if((listener = pcap_open_live(Device, DEFAULT_MAXMTU, 0, PcapTO,perr)) == NULL){ fprintf(stderr, "Couln't open ping listener: %s\n", pcap_geterr(listener)); exit(FAILURE); } if((dlink = pcap_datalink(listener)) < 0){ fprintf(stderr, "Cannot obtain datalink info for device %s\n", Device); exit(FAILURE); } switch(dlink){ case DLT_EN10MB: PcapOffset = 14; break; case DLT_IEEE802: PcapOffset = 22; break; case DLT_NULL: PcapOffset = 4; break; case DLT_RAW: PcapOffset = 4; break; default: PcapOffset = 14; printf("Don't know data offset for device %s", Device); printf(". Taking wild guess it's ethernet-like\n"); break; } if(pcap_lookupnet(Device, &localnet, &netmask, perr) < 0){ fprintf(stderr, "Error looking up localnet: %s\n", perr); exit(FAILURE); } if (pcap_compile(listener, &lcode, l_filter, 0, netmask) < 0){ fprintf(stderr, "Error compiling our pcap filter: %s\n", pcap_geterr(listener)); exit(FAILURE); } if (pcap_setfilter(listener, &lcode) < 0 ){ fprintf(stderr, "Failed to set the pcap filter: %s\n", pcap_geterr(listener)); exit(FAILURE); } if(FlgDebug) printlist(); switch(PidListener=fork()){ case -1: /* error in forking */ fprintf(stderr, "Error in forking: %s\n", strerror(errno)); exit(FAILURE); break; case 0: dolisten(listener); /* Child */ break; default: sleep(2); /* Wait for child to start executing */ sender(); sleep(Sleep); /* Wait for all responses before exiting */ kill(PidListener, SIGTERM); waitpid(PidListener, NULL, NULL); break; } return SUCCESS; } void add_ip(char *ip) { struct hostent *hp = NULL; hp = gethostbyname(ip); if(hp == NULL){ if(FlgDebug) printf ("Omitting host: %s\n", ip); return; } ToPing[NumToPing].sad.sin_family=AF_INET; ToPing[NumToPing].sad.sin_addr.s_addr = (*(u_long *) hp->h_addr); NumToPing++; if(NumToPing == BatchSize){ /* Every time we get a batch, ping sweep and clean out non-responding hosts */ pingsweep(NumToPing); } } void generate_ip(char *start, char *end){ struct in_addr first, second, myaddr; long x; first.s_addr = inet_addr(start); second.s_addr = inet_addr(end); for (x = ntohl(first.s_addr); x <= ntohl(second.s_addr); x++) { /* Skip broadcasts */ if ((x & 0xff) == 0) x++; myaddr.s_addr = htonl(x); /* if(flgreallydebug) printf(" Adding %s\n", inet_ntoa(myaddr)); */ /* I know, this is inefficent. But good guys are doing this, right? */ add_ip((char *)inet_ntoa(myaddr)); } } void usage(char *progname) { printf("%s usage:\n", progname); printf("%s \n"); printf(" -f : Filename containing host list, one per line\n"); printf(" -t : Time to wait for responses before exiting. Default=30\n"); printf(" -b : Batchsize to send to at once. There is a small "); printf(" pause between each batch\n"); printf(" -s : Size of bytes to snarf up. See tcpdump man page\n"); printf(" -c : File containing patterns to match\n"); printf(" -n : Number of pings to send to determine if host is up\n"); printf(" -h: This screen\n"); printf("Copyright Jan 21 2000 David Brumley \n"); printf("All Rights Reserved\n"); printf("URL: http://www.stanford.edu/~dbrumley\n"); }