/* Public domain ARP based passive "ping" to collect a list of */ /* active hosts on your subnet. In the example MY_FILTER, your */ /* router is 10.0.0.1 and your PC is 10.0.0.99. Conceived 2001. */ #define MY_FILTER "arp host 10.0.0.1 or arp host 10.0.0.99" /* Compile with gcc -Wall THIS.c /usr/lib/libpcap.a -o THIS */ /* -Lsomedir -lpcap seems not to work :( */ #include #include #include #include #include /* memcpy */ #include #include #include #include #define ESRC(ep) ((ep)->ether_shost) #define EDST(ep) ((ep)->ether_dhost) #define SHA(ap) ((ap)->arp_sha) #define THA(ap) ((ap)->arp_tha) #define SPA(ap) ((ap)->arp_spa) #define TPA(ap) ((ap)->arp_tpa) #define DEB(msg) (void)fprintf(stderr,"Debug: %s\n",msg) #undef DETAIL #define EXPERIMENT 42 int main(int, char **); void process_ether(u_char *, const struct pcap_pkthdr *, const u_char *); char *e2str(u_char *); static u_int32_t net; static u_int32_t netmask; int bits[256] = { 0, }; int main(int argc, char **argv) { // register char *cp; register int snaplen, timeout, linktype, status; register pcap_t *pd; register char *interface; struct bpf_program code; char errbuf[PCAP_ERRBUF_SIZE]; net = 0; netmask = 0; interface = pcap_lookupdev(errbuf); if (interface==NULL) { pcap_perror(pd,"pcap_lookupdev"); exit(1); }; if (pcap_lookupnet(interface, &net, &netmask, errbuf) < 0) { pcap_perror(pd,"pcap_lookupnet"); exit(1); }; snaplen = sizeof(struct ether_header) + sizeof(struct ether_arp); timeout = 1000; pd = pcap_open_live(interface, snaplen, 0, timeout, errbuf); /* int is promisc, timeout in ms */ if (pd==NULL) { pcap_perror(pd,"pcap_open_live"); exit(1); }; linktype = pcap_datalink(pd); /* get link layer type */ if (linktype != DLT_EN10MB) { exit(1); }; /* only handle eth */ if (pcap_compile(pd, &code, MY_FILTER /* "arp or rarp" */, 1, netmask) < 0) /* string format as on command line for tcpdump !? */ { pcap_perror(pd,"pcap_compile"); exit(1); }; if (pcap_setfilter(pd, &code) < 0) /* activate filter */ { pcap_perror(pd,"pcap_compile"); exit(1); }; status = pcap_loop(pd, 0, process_ether, NULL); /* loop listening until N packets or error, neg for forever, */ /* 0 for till timeout, EOF or error */ if (status < 0) { pcap_perror(pd,"pcap_loop"); exit(1); }; pcap_close(pd); exit(0); } /* END OF MAIN */ void process_ether(register u_char *u, register const struct pcap_pkthdr *h, register const u_char *p) { register struct ether_header *eh; register struct ether_arp *ea; register u_char *sea, *sha, *dea; // register u_char *dha; // register time_t t; // u_int32_t sia; struct in_addr mysia; int len, i, j; eh = (struct ether_header *)p; ea = (struct ether_arp *)(eh + 1); len = h->caplen; if (len < sizeof(*eh) + sizeof(*ea)) { DEB("short"); return; /* short packet */ }; if ((ntohs(ea->arp_hrd) != ARPHRD_ETHER) || (ntohs(ea->arp_pro) != ETHERTYPE_IP)) { DEB("no ip/eth"); fprintf(stderr,"arp_hrd: %d arp_pro: %d\n", ntohs(ea->arp_hrd),ntohs(ea->arp_pro)); return; /* wrong proto, strange */ }; if ((ea->arp_hln != 6) || (ea->arp_pln != 4)) /* bytes */ { DEB("bad hln/pln"); return; /* bad proto/hardware addr len */ }; if (ntohs(eh->ether_type) != ETHERTYPE_ARP) { DEB("not arp"); printf("ether_type: %d\n",ntohs(eh->ether_type)); return; /* not interested in others */ }; /* or: REVARP... REVARP_REQUEST... */ if ( (ntohs(ea->arp_op) != ARPOP_REQUEST) && (ntohs(ea->arp_op) != ARPOP_REPLY) ) /* REQ=1 REPL=2 RREQ=3 RREPL=4 */ { DEB("not normal ARP - maybe RARP"); fprintf(stderr,"arp_op: %d\n",ntohs(ea->arp_op)); return; /* only requests for now */ }; /* Source hardware ethernet address */ sea = (u_char *)ESRC(eh); /* Source ip address */ sha = (u_char *)SHA(ea); /* Destination ethernet address */ dea = (u_char *)EDST(eh); // /* Destination host ip address */ // dha = (u_char *)THA(ea); /* ** sea should be same as sha ** */ /* 000000000000 or ffffffffffff means broadcast */ if ( ntohs(ea->arp_op) == ARPOP_REPLY ) { memcpy(&mysia,&TPA(ea),4); #ifdef EXPERIMENT printf("[arp-ping: %d has asked for me]\n", ((unsigned char *)&mysia)[3] ); #endif fprintf(stderr,"reply to ip=%s eth=%s -> ", inet_ntoa(mysia),e2str(dea)); }; memcpy(&mysia,&SPA(ea),4); /* so show intoa(sia) and e2str(sea) */ fprintf(stderr,"arp: ip=%s eth=%s\n", inet_ntoa(mysia),e2str(sea)); if ( ntohs(ea->arp_op) == ARPOP_REPLY ) { return; /* no statistics on replies */ }; /* And now for the fun part: statistics! */ i = ((unsigned char *)&mysia)[3]; bits[i]++; len=0; for (i=0; i<256; i++) { #ifdef DETAIL if (bits[i]) printf("%3.3d ",i); #endif if (bits[i]>len) len=bits[i]; }; #ifdef DETAIL printf("\n"); #endif if (len>3) { #ifdef DETAIL printf("Max count reached - decrementing counts."); #endif printf("\nHosts: "); for (j=i=0; i<256; i++) { if (bits[i]) { printf("%3.3d ",i); j++; } if (bits[i]>0) bits[i]--; }; printf("=> %d\n",j); }; #ifdef DETAIL if (len==1) { printf("Counting has started - Active:\n"); for (i=0; i<256; i++) { if (bits[i]) printf("%3.3d ",i); }; printf("\n"); }; #endif return; }; char * e2str(register u_char *e) { static char str[32]; (void)sprintf(str, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", e[0], e[1], e[2], e[3], e[4], e[5]); return (str); }