--- embedaddon/arping/src/arping.c 2013/07/22 00:12:50 1.1.1.1.2.1 +++ embedaddon/arping/src/arping.c 2014/06/15 16:26:43 1.1.1.2 @@ -2,7 +2,7 @@ * * arping * - * By Thomas Habets + * By Thomas Habets * * ARP 'ping' utility * @@ -11,11 +11,11 @@ * you don't yet have routing to. Then again, if you have no idea what I'm * talking about then you prolly don't need it. * - * Also finds out IP of specified MAC + * Also finds out IP of specified MAC. * */ /* - * Copyright (C) 2000-2010 Thomas Habets + * Copyright (C) 2000-2011 Thomas Habets * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public @@ -37,6 +37,8 @@ #include #include +#include +#include #include #if HAVE_UNISTD_H @@ -51,6 +53,10 @@ #include #endif +#if HAVE_TIME_H +#include +#endif + #if HAVE_SYS_TIME_H #include #endif @@ -75,15 +81,17 @@ #include #endif -#if HAVE_NET_BPF_H -#include -#endif - #if HAVE_WIN32_LIBNET_H #include #endif + +#if HAVE_NET_BPF_H +#include +#endif #include +#include "arping.h" + #ifndef ETH_ALEN #define ETH_ALEN 6 #endif @@ -96,49 +104,117 @@ #define WIN32 0 #endif +#ifndef CLOCK_MONOTONIC +#define CLOCK_MONOTONIC CLOCK_REALTIME +#endif + /** * OS-specific interface finding using routing table. See findif_*.c */ const char * -arping_lookupdev(const char *ifname, - uint32_t srcip, - uint32_t dstip, - char *ebuf); +arping_lookupdev(uint32_t srcip, uint32_t dstip, char *ebuf); +const char * +arping_lookupdev_default(uint32_t srcip, uint32_t dstip, char *ebuf); + static const char *version = VERSION; /* from autoconf */ static libnet_t *libnet = 0; -static struct timeval lastpacketsent; +static struct timespec lastpacketsent; -uint32_t srcip, dstip; +/* target string */ +static char *target = "huh? bug in arping?"; -static int beep = 0; -static int reverse_beep = 0; -static int verbose = 0; -static int alsototal = 0; -/*static int pingmac = 0; */ -static int finddup = 0; -static int dupfound = 0; -static unsigned int numsent = 0; -static unsigned int numrecvd = 0; -static unsigned int numdots = 0; -static int addr_must_be_same = 0; +/* + * Ping IP mode: cmdline target + * Ping MAC mode: 255.255.255.255, override with -T + */ +static uint32_t dstip; + +/* + * Ping IP mode: ethxmas, override with -t + * Ping MAC mode: cmdline target + */ +static uint8_t dstmac[ETH_ALEN]; + +static uint32_t srcip; /* autodetected, override with -S/-b/-0 */ +static uint8_t srcmac[ETH_ALEN]; /* autodetected, override with -s */ + +static int beep = 0; /* beep when reply is received. -a */ +static int reverse_beep = 0; /* beep when expected reply absent. -e */ +static int alsototal = 0; /* print sent as well as received. -u */ +static int addr_must_be_same = 0; /* -A */ +static int unsolicited = 0; /* -U */ + +static int finddup = 0; /* finddup mode. -d */ +static int dupfound = 0; /* set to 1 if dup found */ +static char lastreplymac[ETH_ALEN]; /* if last different from this then dup */ + +static unsigned int numsent = 0; /* packets sent */ +static unsigned int numrecvd = 0; /* packets received */ +static unsigned int numdots = 0; /* dots that should be printed */ + +static double stats_min_time = -1; +static double stats_max_time = -1; +static double stats_total_time = 0; +static double stats_total_sq_time = 0; + /* RAWRAW is RAW|RRAW */ -static enum { NORMAL, QUIET, RAW, RRAW, RAWRAW, DOT } display = NORMAL; -static char *target = "huh? bug in arping?"; -static uint8_t ethnull[ETH_ALEN]; -static uint8_t ethxmas[ETH_ALEN]; -static char srcmac[ETH_ALEN]; -static char dstmac[ETH_ALEN]; -static char lastreplymac[ETH_ALEN]; +static enum { NORMAL, /* normal output */ + QUIET, /* No output. -q */ + RAW, /* Print MAC when pinging IP. -r */ + RRAW, /* Print IP when pinging IP. -R */ + RAWRAW, /* Print both. -r and -R */ + DOT /* Print '.' and '!', Cisco-style. -D */ +} display = NORMAL; -/* doesn't need to be volatile */ -volatile int time_to_die = 0; +static const uint8_t ethnull[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; +static const uint8_t ethxmas[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +int verbose = 0; /* Increase with -v */ + +/* Doesn't really need to be volatile, but doesn't hurt. */ +static volatile sig_atomic_t time_to_die = 0; + /** + * Some stupid OSs (Solaris) think it's a good idea to put network + * devices in /dev and then play musical chairs with them. * + * Since libpcap doesn't seem to have a workaround for that, here's arpings + * workaround. + * + * E.g. if the network interface is called net0, pcap will fail because it + * fails to open /dev/net, because it's a directory. */ +static pcap_t* +do_pcap_open_live(const char *device, int snaplen, + int promisc, int to_ms, char *errbuf) +{ + pcap_t* ret; + char buf[PATH_MAX]; + + if ((ret = pcap_open_live(device, snaplen, promisc, to_ms, errbuf))) { + return ret; + } + + snprintf(buf, sizeof(buf), "/dev/%s", device); + if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) { + return ret; + } + + snprintf(buf, sizeof(buf), "/dev/net/%s", device); + if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) { + return ret; + } + + /* Call original again to reset the error message. */ + return pcap_open_live(device, snaplen, promisc, to_ms, errbuf); +} + +/** + * + */ static void count_missing_dots() { @@ -149,29 +225,31 @@ count_missing_dots() } /** - * - */ + * Init libnet with specified ifname. Destroy if already inited. + */ void do_libnet_init(const char *ifname) { char ebuf[LIBNET_ERRBUF_SIZE]; if (verbose > 1) { - printf("libnet_init(%s)\n", ifname?ifname:""); + printf("libnet_init(%s)\n", ifname ? ifname : ""); } if (libnet) { - /* prolly going to switch interface from temp to real */ + /* Probably going to switch interface from temp to real. */ libnet_destroy(libnet); libnet = 0; } - if (getuid() && geteuid()) { - fprintf(stderr, "arping: must run as root\n"); - exit(1); - } + /* Try libnet_init() even though we aren't root. We may have + * a capability or something. */ if (!(libnet = libnet_init(LIBNET_LINK, (char*)ifname, ebuf))) { - fprintf(stderr, "arping: libnet_init(): %s\n", ebuf); + fprintf(stderr, "arping: %s\n", ebuf); + if (getuid() && geteuid()) { + fprintf(stderr, + "arping: you may need to run as root\n"); + } exit(1); } } @@ -179,52 +257,35 @@ do_libnet_init(const char *ifname) /** * */ -const char * -arping_lookupdev_default(const char *ifname, - uint32_t srcip, uint32_t dstip, - char *ebuf) +void +sigint(int i) { -#if WIN32 - WCHAR buf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE]; - WCHAR* ret = (WCHAR*)pcap_lookupdev((char*)buf); - if (ret != NULL) { - wcstombs(ebuf, ret, LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE); - return ebuf; - } - return NULL; -#else - return pcap_lookupdev(ebuf); -#endif -} - -#if WIN32 -static BOOL WINAPI arping_console_ctrl_handler(DWORD dwCtrlType) -{ - if(verbose) { - printf("arping_console_ctrl_handler( %d )\n", (int)dwCtrlType); - } time_to_die = 1; - -#if 0 - /* if SetConsoleCtrlHandler() does what I think, this isn't needed */ - if (display == NORMAL) { - printf("\n--- %s statistics ---\n" - "%d packets transmitted, %d packets received, %3.0f%% " - "unanswered\n",target,numsent,numrecvd, - 100.0 - 100.0 * (float)(numrecvd)/(float)numsent); - } -#endif - return TRUE; } -#endif - /** - * + * idiot-proof clock_gettime() wrapper */ -static void sigint(int i) +static void +getclock(struct timespec *ts) { - time_to_die = 1; +#if HAVE_CLOCK_MONOTONIC + if (-1 == clock_gettime(CLOCK_MONOTONIC, ts)) { + fprintf(stderr, + "arping: clock_gettime(): %s\n", + strerror(errno)); + sigint(0); + } +#else + struct timeval tv; + if (-1 == gettimeofday(&tv, NULL)) { + fprintf(stderr, "arping: gettimeofday(): %s\n", + strerror(errno)); + sigint(0); + } + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; +#endif } /** @@ -252,7 +313,7 @@ extended_usage() " -d Find duplicate replies. Exit with 1 if there are " "answers from\n" " two different MAC addresses.\n" - " -D Display answers as dots and missing packets as exclamation points.\n" + " -D Display answers as exclamation points and missing packets as dots.\n" " -e Like -a but beep when there is no reply.\n" " -F Don't try to be smart about the interface name. (even if this\n" " switch is not given, -i overrides smartness)\n" @@ -280,9 +341,10 @@ extended_usage() " \"own\" the MAC address you are using.\n" " -u Show index=received/sent instead of just index=received when\n" " pinging MACs.\n" + " -U Send unsolicited ARP.\n" " -v Verbose output. Use twice for more messages.\n" " -w Time to wait between pings, in microseconds.\n"); - printf("Report bugs to: thomas@habets.pp.se\n" + printf("Report bugs to: thomas@habets.se\n" "Arping home page: \n" "Development repo: http://github.com/ThomasHabets/arping\n"); } @@ -293,9 +355,9 @@ extended_usage() static void standard_usage() { - printf("ARPing %s, by Thomas Habets \n", + printf("ARPing %s, by Thomas Habets \n", version); - printf("usage: arping [ -0aAbdDeFpqrRuv ] [ -w ] " + printf("usage: arping [ -0aAbdDeFpqrRuUv ] [ -w ] " "[ -S ]\n" " " "[ -T stats_max_time) { + stats_max_time = sample; + } + stats_total_time += sample; + stats_total_sq_time += sample * sample; +} + +/** * + */ +static double +timespec2dbl(const struct timespec *tv) +{ + return tv->tv_sec + (double)tv->tv_nsec / 1000000000; +} + +/** + * max size of buffer is intsize + 1 + intsize + 4 = 70 bytes or so + * * Still, I'm using at least 128bytes below * * (because snprintf() sadly isn't as portable, that's why) */ -static char *tv2str(const struct timeval *tv, const struct timeval *tv2, +static char *ts2str(const struct timespec *tv, const struct timespec *tv2, char *buf) { double f,f2; int exp = 0; - f = tv->tv_sec + (double)tv->tv_usec / 1000000; - f2 = tv2->tv_sec + (double)tv2->tv_usec / 1000000; - f = (f2 - f) * 1000000; + f = timespec2dbl(tv); + f2 = timespec2dbl(tv2); + f = (f2 - f) * 1000000000; while (f > 1000) { - exp+= 3; + exp += 3; f /= 1000; } switch (exp) { case 0: - sprintf(buf, "%.3f usec", f); + sprintf(buf, "%.3f nsec", f); break; case 3: - sprintf(buf, "%.3f msec", f); + sprintf(buf, "%.3f usec", f); break; case 6: - sprintf(buf, "%.3f sec", f); + sprintf(buf, "%.3f msec", f); break; case 9: + sprintf(buf, "%.3f sec", f); + break; + case 12: sprintf(buf, "%.3f sec", f*1000); break; default: /* huh, uh, huhuh */ - sprintf(buf, "%.3fe%d sec", f, exp-6); + sprintf(buf, "%.3fe%d sec", f, exp-9); } return buf; } @@ -433,17 +520,11 @@ static char *tv2str(const struct timeval *tv, const st /** Send directed IPv4 ICMP echo request. * - * \param srcmac Source MAC. From -s switch or autodetected - * \param dstmac Destination/target MAC. Target command line. - * \param srcip From -S switch or autodetected - * \param dstip From -D switch, or 255.255.255.255 * \param id IP id * \param seq Ping seq */ static void -pingmac_send(uint8_t *srcmac, uint8_t *dstmac, - uint32_t srcip, uint32_t dstip, - uint16_t id, uint16_t seq) +pingmac_send(uint16_t id, uint16_t seq) { static libnet_ptag_t icmp = 0, ipv4 = 0,eth=0; int c; @@ -491,40 +572,26 @@ pingmac_send(uint8_t *srcmac, uint8_t *dstmac, libnet_geterror(libnet)); sigint(0); } - if(verbose>1) { - if (-1 == gettimeofday(&lastpacketsent, NULL)) { - fprintf(stderr, "arping: gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } - printf("arping: sending packet at time %d %d\n", - lastpacketsent.tv_sec, - lastpacketsent.tv_usec); + if (verbose > 1) { + getclock(&lastpacketsent); + printf("arping: sending packet at time %ld.%09ld\n", + (long)lastpacketsent.tv_sec, + (long)lastpacketsent.tv_nsec); } if (-1 == (c = libnet_write(libnet))) { fprintf(stderr, "arping: libnet_write(): %s\n", libnet_geterror(libnet)); sigint(0); } - if (-1 == gettimeofday(&lastpacketsent, NULL)) { - fprintf(stderr, "arping: gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } + getclock(&lastpacketsent); numsent++; } /** Send ARP who-has. * - * \param srcmac -s or autodetected - * \param dstmac -t or ff:ff:ff:ff:ff:ff - * \param srcip -S or autodetected - * \param dstip -T or or cmdline - * */ static void -pingip_send(uint8_t *srcmac, uint8_t *dstmac, - uint32_t srcip, uint32_t dstip) +pingip_send() { static libnet_ptag_t arp=0,eth=0; if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER, @@ -534,7 +601,7 @@ pingip_send(uint8_t *srcmac, uint8_t *dstmac, ARPOP_REQUEST, srcmac, (uint8_t*)&srcip, - ethnull, + unsolicited ? (uint8_t*)ethxmas : (uint8_t*)ethnull, (uint8_t*)&dstip, NULL, 0, @@ -555,26 +622,18 @@ pingip_send(uint8_t *srcmac, uint8_t *dstmac, libnet_geterror(libnet)); sigint(0); } - if(verbose>1) { - if (-1 == gettimeofday(&lastpacketsent, NULL)) { - fprintf(stderr, "arping: gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } - printf("arping: sending packet at time %d %d\n", - lastpacketsent.tv_sec, - lastpacketsent.tv_usec); + if (verbose > 1) { + getclock(&lastpacketsent); + printf("arping: sending packet at time %ld.%09ld\n", + (long)lastpacketsent.tv_sec, + (long)lastpacketsent.tv_nsec); } if (-1 == libnet_write(libnet)) { fprintf(stderr, "arping: libnet_write(): %s\n", libnet_geterror(libnet)); sigint(0); } - if (-1 == gettimeofday(&lastpacketsent, NULL)) { - fprintf(stderr, "arping: gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } + getclock(&lastpacketsent); numsent++; } @@ -584,23 +643,19 @@ pingip_send(uint8_t *srcmac, uint8_t *dstmac, * \param packet packet data */ static void -pingip_recv(const char *unused, struct pcap_pkthdr *h, - uint8_t *packet) +pingip_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet) { struct libnet_802_3_hdr *heth; struct libnet_arp_hdr *harp; - struct timeval arrival; + struct timespec arrival; int c; - if(verbose>2) { + if (verbose > 2) { printf("arping: received response for ip ping\n"); } - if (-1 == gettimeofday(&arrival, NULL)) { - fprintf(stderr, "arping: gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } + getclock(&arrival); + heth = (void*)packet; harp = (void*)((char*)heth + LIBNET_ETH_H); @@ -616,6 +671,8 @@ pingip_recv(const char *unused, struct pcap_pkthdr *h, return; } if (dstip == ip) { + update_stats(timespec2dbl(&arrival) + - timespec2dbl(&lastpacketsent)); switch(display) { case DOT: numdots++; @@ -637,9 +694,10 @@ pingip_recv(const char *unused, struct pcap_pkthdr *h, printf("/%u", numsent-1); } printf(" time=%s", - tv2str(&lastpacketsent, - &arrival,buf)); - break; } + ts2str(&lastpacketsent, + &arrival,buf)); + break; + } case QUIET: break; case RAWRAW: @@ -691,24 +749,19 @@ pingip_recv(const char *unused, struct pcap_pkthdr *h, * \param packet packet data */ static void -pingmac_recv(const char *unused, struct pcap_pkthdr *h, - uint8_t *packet) +pingmac_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet) { struct libnet_802_3_hdr *heth; struct libnet_ipv4_hdr *hip; struct libnet_icmpv4_hdr *hicmp; - struct timeval arrival; + struct timespec arrival; int c; if(verbose>2) { printf("arping: received response for mac ping\n"); } - if (-1 == gettimeofday(&arrival, NULL)) { - fprintf(stderr, "arping: gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } + getclock(&arrival); heth = (void*)packet; hip = (void*)((char*)heth + LIBNET_ETH_H); @@ -725,6 +778,8 @@ pingmac_recv(const char *unused, struct pcap_pkthdr *h return; } } + update_stats(timespec2dbl(&arrival) + - timespec2dbl(&lastpacketsent)); switch(display) { case QUIET: break; @@ -737,8 +792,8 @@ pingmac_recv(const char *unused, struct pcap_pkthdr *h (c<5)?':':')'); } printf(": icmp_seq=%d time=%s", - htons(hicmp->icmp_seq),tv2str(&lastpacketsent, - &arrival,buf)); + htons(hicmp->icmp_seq),ts2str(&lastpacketsent, + &arrival,buf)); break; } case RAW: printf("%s", @@ -769,126 +824,101 @@ pingmac_recv(const char *unused, struct pcap_pkthdr *h } } - -#if WIN32 /** - * untested for a long time. Maybe since arping 2.05 or so. - */ -static void -ping_recv_win32(pcap_t *pcap,uint32_t packetwait, pcap_handler func) -{ - struct timeval tv,tv2; - char done = 0; - /* windows won't let us do select() */ - if (-1 == gettimeofday(&tv2,NULL)) { - fprintf(stderr, "arping: gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } - while (!done && !time_to_die) { - struct pcap_pkthdr *pkt_header; - u_char *pkt_data; - if (pcap_next_ex(pcap, &pkt_header, &pkt_data) == 1) { - func(pcap, pkt_header, pkt_data); - } - if (-1 == gettimeofday(&tv,NULL)) { - fprintf(stderr, "arping: " - "gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } - /* - * setup next timeval, not very exact - */ - tv.tv_sec = (packetwait / 1000000) - - (tv.tv_sec - tv2.tv_sec); - tv.tv_usec = (packetwait % 1000000) - - (tv.tv_usec - tv2.tv_usec); - while (tv.tv_usec < 0) { - tv.tv_sec--; - tv.tv_usec += 1000000; - } - usleep(10); - if (tv.tv_sec < 0) { - done=1; - } - } -} -#endif - -/** - * while negative microseconds, take from whole seconds. + * while negative nanoseconds, take from whole seconds. * help function for measuring deltas. */ static void -fixup_timeval(struct timeval *tv) +fixup_timespec(struct timespec *tv) { - while (tv->tv_usec < 0) { + while (tv->tv_nsec < 0) { tv->tv_sec--; - tv->tv_usec += 1000000; + tv->tv_nsec += 1000000000; } } /** - * idiot-proof gettimeofday() wrapper + * try to receive a packet for 'packetwait' microseconds */ static void -gettv(struct timeval *tv) +ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_handler func) { - if (-1 == gettimeofday(tv,NULL)) { - fprintf(stderr, "arping: " - "gettimeofday(): %s\n", - strerror(errno)); - sigint(0); - } -} - - -/** - * - */ -static void -ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_handler func) -{ - struct timeval tv; - struct timeval endtime; + struct timespec ts; + struct timespec endtime; char done = 0; + int fd; + int old_received; - gettv(&tv); - endtime.tv_sec = tv.tv_sec + (packetwait / 1000000); - endtime.tv_usec = tv.tv_usec + (packetwait % 1000000); - fixup_timeval(&endtime); + if (verbose > 3) { + printf("arping: receiving packets...\n"); + } - int fd; + getclock(&ts); + endtime.tv_sec = ts.tv_sec + (packetwait / 1000000); + endtime.tv_nsec = ts.tv_nsec + 1000 * (packetwait % 1000000); + fixup_timespec(&endtime); fd = pcap_get_selectable_fd(pcap); + old_received = numrecvd; for (;!done;) { int trydispatch = 0; - gettv(&tv); - tv.tv_sec = endtime.tv_sec - tv.tv_sec; - tv.tv_usec = endtime.tv_usec - tv.tv_usec; - fixup_timeval(&tv); - if (tv.tv_sec < 0) { - tv.tv_sec = 0; - tv.tv_usec = 1; + getclock(&ts); + ts.tv_sec = endtime.tv_sec - ts.tv_sec; + ts.tv_nsec = endtime.tv_nsec - ts.tv_nsec; + fixup_timespec(&ts); + if (verbose > 2) { + printf("listen for replies for %ld.%09ld sec\n", + (long)ts.tv_sec, (long)ts.tv_nsec); + } + + /* if time has passed, do one last check and then we're done. + * this also triggers if not using monotonic clock and time + * is set forwards */ + if (ts.tv_sec < 0) { + ts.tv_sec = 0; + ts.tv_nsec = 1; done = 1; } + + /* if wait-for-packet time is longer than full period, + * we're obviously not using a monotonic clock and the system + * time has been changed. + * we don't know how far we're into the waiting, so just end + * it here */ + if ((ts.tv_sec > packetwait / 1000000) + || ((ts.tv_sec == packetwait / 1000000) + && (ts.tv_nsec/1000 > packetwait % 1000000))) { + ts.tv_sec = 0; + ts.tv_nsec = 1; + done = 1; + } + + /* check for sigint */ if (time_to_die) { return; } /* try to wait for data */ { - struct pollfd p; + fd_set fds; int r; - p.fd = fd; - p.events = POLLIN | POLLPRI; + struct timeval tv; + tv.tv_sec = ts.tv_sec; + tv.tv_usec = ts.tv_nsec / 1000; - r = poll(&p, 1, tv.tv_sec * 1000 + tv.tv_usec / 1000); + FD_ZERO(&fds); + FD_SET(fd, &fds); + + r = select(fd + 1, &fds, NULL, NULL, &tv); switch (r) { case 0: /* timeout */ + if (display == NORMAL) { + if (numrecvd == old_received) { + printf("Timeout\n"); + } + } done = 1; break; case -1: /* error */ @@ -896,7 +926,7 @@ ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ done = 1; sigint(0); fprintf(stderr, - "arping: poll() failed: %s\n", + "arping: select() failed: %s\n", strerror(errno)); } break; @@ -908,9 +938,9 @@ ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ if (trydispatch) { int ret; - if (1 != (ret = pcap_dispatch(pcap, 1, - func, - NULL))) { + if (0 > (ret = pcap_dispatch(pcap, -1, + func, + NULL))) { /* rest, so we don't take 100% CPU... mostly hmm... does usleep() exist everywhere? */ usleep(1); @@ -918,7 +948,7 @@ ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ /* weird is normal on bsd :) */ if (verbose > 3) { fprintf(stderr, - "arping: poll says ok, " + "arping: select says ok, but " "pcap_dispatch=%d!\n", ret); } @@ -928,23 +958,6 @@ ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ } /** - * - */ -static void -ping_recv(pcap_t *pcap,uint32_t packetwait, pcap_handler func) -{ - if(verbose>3) { - printf("arping: receiving packets...\n"); - } - -#if WIN32 - ping_recv_win32(pcap,packetwait,func); -#else - ping_recv_unix(pcap,packetwait,func); -#endif -} - -/** * */ int main(int argc, char **argv) @@ -962,7 +975,7 @@ int main(int argc, char **argv) int dont_use_arping_lookupdev=0; struct bpf_program bp; pcap_t *pcap; - static enum { NONE, PINGMAC, PINGIP } mode = NONE; + enum { NONE, PINGMAC, PINGIP } mode = NONE; unsigned int packetwait = 1000000; for (c = 1; c < argc; c++) { @@ -973,14 +986,11 @@ int main(int argc, char **argv) } } - memset(ethnull, 0, ETH_ALEN); - srcip = 0; dstip = 0xffffffff; - memset(dstmac, 0xff, ETH_ALEN); - memset(ethxmas, 0xff, ETH_ALEN); + memcpy(dstmac, ethxmas, ETH_ALEN); - while (EOF!=(c=getopt(argc,argv,"0aAbBc:dDeFhi:I:pqrRs:S:t:T:uvw:"))) { + while (EOF!=(c=getopt(argc,argv,"0aAbBc:dDeFhi:I:pqrRs:S:t:T:uUvw:"))) { switch(c) { case '0': srcip = 0; @@ -1109,6 +1119,14 @@ int main(int argc, char **argv) case 'u': alsototal = 1; break; + case 'U': + if (mode == PINGMAC) { + fprintf(stderr, "arping: -U can only be used " + "in IP ping mode\n"); + exit(1); + } + unsolicited = 1; + break; case 'v': verbose++; break; @@ -1120,6 +1138,17 @@ int main(int argc, char **argv) } } + if (verbose > 1) { +#if HAVE_CLOCK_MONOTONIC + struct timespec ts; + clock_getres(CLOCK_MONOTONIC, &ts); + printf("clock_getres() = %ld %ld\n", + (long)ts.tv_sec, (long)ts.tv_nsec); +#else + printf("Using gettimeofday() for time measurements\n"); +#endif + } + if (display == DOT) { setvbuf(stdout, NULL, _IONBF, 0); } @@ -1228,15 +1257,24 @@ int main(int argc, char **argv) * Get some good iface. */ if (!ifname) { - if (dont_use_arping_lookupdev) { - ifname = arping_lookupdev_default(ifname, - srcip,dstip,ebuf); - } else { - ifname = arping_lookupdev(ifname,srcip,dstip,ebuf); + if (!dont_use_arping_lookupdev) { + ifname = arping_lookupdev(srcip, dstip, ebuf); + } + if (!ifname) { + ifname = arping_lookupdev_default(srcip, dstip, ebuf); + if (!dont_use_arping_lookupdev) { + fprintf(stderr, + "arping: Unable to automatically find " + "interface to use. Is it on the local " + "LAN?\n" + "arping: Use -i to manually " + "specify interface. " + "Guessing interface %s.\n", ifname); + } } if (!ifname) { - fprintf(stderr, "arping: arping_lookupdev(): %s\n", - ebuf); + fprintf(stderr, "arping: Gave up looking for interface" + " to use: %s\n", ebuf); exit(1); } /* FIXME: check for other probably-not interfaces */ @@ -1258,7 +1296,7 @@ int main(int argc, char **argv) /* * pcap init */ - if (!(pcap = pcap_open_live((char*)ifname, 100, promisc, 10, ebuf))) { + if (!(pcap = do_pcap_open_live(ifname, 100, promisc, 10, ebuf))) { fprintf(stderr, "arping: pcap_open_live(): %s\n",ebuf); exit(1); } @@ -1266,12 +1304,12 @@ int main(int argc, char **argv) fprintf(stderr, "arping: pcap_set_nonblock(): %s\n", ebuf); exit(1); } - if (verbose) { - printf("pcap_get_selectable(): %d\n", + if (verbose > 1) { + printf("pcap_get_selectable_fd(): %d\n", pcap_get_selectable_fd(pcap)); } -#if HAVE_NET_BPF_H +#ifdef BIOCIMMEDIATE { uint32_t on = 1; if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE, @@ -1314,17 +1352,16 @@ int main(int argc, char **argv) } if (!srcip_given) { if (-1 == (srcip = libnet_get_ipaddr4(libnet))) { - fprintf(stderr, "arping: libnet_get_ipaddr4(libnet): " - "%s\n", libnet_geterror(libnet)); + fprintf(stderr, + "arping: Unable to get the IPv4 address of " + "interface %s:\narping: %s" + "arping: " + "Use -S to specify address manually.\n", + ifname, libnet_geterror(libnet)); exit(1); } } -#if WIN32 - /* SetConsoleCtrlHandler(NULL, TRUE); */ - SetConsoleCtrlHandler(arping_console_ctrl_handler, TRUE); -#else - signal(SIGINT, sigint); -#endif + do_signal_init(); if (verbose) { printf("This box: Interface: %s IP: %s MAC address: ", @@ -1348,7 +1385,7 @@ int main(int argc, char **argv) unsigned int c; unsigned int r; for (c = 0; c < maxcount && !time_to_die; c++) { - pingip_send(srcmac, dstmac, srcip, dstip); + pingip_send(); r = numrecvd; ping_recv(pcap,packetwait, (pcap_handler)pingip_recv); @@ -1361,7 +1398,7 @@ int main(int argc, char **argv) unsigned int c; unsigned int r; for (c = 0; c < maxcount && !time_to_die; c++) { - pingmac_send(srcmac, dstmac, srcip, dstip, rand(), c); + pingmac_send(rand(), c); r = numrecvd; ping_recv(pcap,packetwait, (pcap_handler)pingmac_recv); @@ -1385,7 +1422,18 @@ int main(int argc, char **argv) "unanswered (%d extra)\n", target,numsent,numrecvd, (succ < 0.0) ? 0.0 : succ, - (succ < 0.0) ? (numrecvd - numsent): 0); + (succ < 0.0) ? (numrecvd - numsent): 0); + if (numrecvd) { + double avg = stats_total_time / numrecvd; + printf("rtt min/avg/max/std-dev = " + "%.3f/%.3f/%.3f/%.3f ms", + 1000*stats_min_time, + 1000*avg, + 1000*stats_max_time, + 1000*sqrt(stats_total_sq_time/numrecvd + -avg*avg)); + } + printf("\n"); } if (finddup) { @@ -1394,3 +1442,9 @@ int main(int argc, char **argv) return !numrecvd; } } +/* ---- Emacs Variables ---- + * Local Variables: + * c-basic-offset: 8 + * indent-tabs-mode: nil + * End: + */