Annotation of embedaddon/arping/src/arping.c, revision 1.1.1.2
1.1 misho 1: /** arping/src/arping.c
2: *
3: * arping
4: *
1.1.1.2 ! misho 5: * By Thomas Habets <thomas@habets.se>
1.1 misho 6: *
7: * ARP 'ping' utility
8: *
9: * Broadcasts a who-has ARP packet on the network and prints answers.
10: * *VERY* useful when you are trying to pick an unused IP for a net that
11: * you don't yet have routing to. Then again, if you have no idea what I'm
12: * talking about then you prolly don't need it.
13: *
1.1.1.2 ! misho 14: * Also finds out IP of specified MAC.
1.1 misho 15: *
16: */
17: /*
1.1.1.2 ! misho 18: * Copyright (C) 2000-2011 Thomas Habets <thomas@habets.se>
1.1 misho 19: *
20: * This library is free software; you can redistribute it and/or
21: * modify it under the terms of the GNU General Public
22: * License as published by the Free Software Foundation; either
23: * version 2 of the License, or (at your option) any later version.
24: *
25: * This library is distributed in the hope that it will be useful,
26: * but WITHOUT ANY WARRANTY; without even the implied warranty of
27: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28: * General Public License for more details.
29: *
30: * You should have received a copy of the GNU General Public License along
31: * with this program; if not, write to the Free Software Foundation, Inc.,
32: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
33: */
34: #if HAVE_CONFIG_H
35: #include "config.h"
36: #endif
37:
38: #include <stdio.h>
39: #include <stdlib.h>
1.1.1.2 ! misho 40: #include <limits.h>
! 41: #include <math.h>
1.1 misho 42: #include <poll.h>
43:
44: #if HAVE_UNISTD_H
45: #include <unistd.h>
46: #endif
47:
48: #if HAVE_STDINT_H
49: #include <stdint.h>
50: #endif
51:
52: #if HAVE_INTTYPES_H
53: #include <inttypes.h>
54: #endif
55:
1.1.1.2 ! misho 56: #if HAVE_TIME_H
! 57: #include <time.h>
! 58: #endif
! 59:
1.1 misho 60: #if HAVE_SYS_TIME_H
61: #include <sys/time.h>
62: #endif
63:
64: #if HAVE_SYS_TYPES_H
65: #include <sys/types.h>
66: #endif
67:
68: #if HAVE_SYS_SOCKET_H
69: #include <sys/socket.h>
70: #endif
71:
72: #if HAVE_NETINET_IN_H
73: #include <netinet/in.h>
74: #endif
75:
76: #if HAVE_ARPA_INET_H
77: #include <arpa/inet.h>
78: #endif
79:
80: #if HAVE_LIBNET_H
81: #include <libnet.h>
82: #endif
83:
84: #if HAVE_WIN32_LIBNET_H
85: #include <win32/libnet.h>
86: #endif
87:
88: #if HAVE_NET_BPF_H
89: #include <net/bpf.h>
90: #endif
1.1.1.2 ! misho 91: #include <pcap.h>
! 92:
! 93: #include "arping.h"
1.1 misho 94:
95: #ifndef ETH_ALEN
96: #define ETH_ALEN 6
97: #endif
98:
99: #ifndef IP_ALEN
100: #define IP_ALEN 4
101: #endif
102:
103: #ifndef WIN32
104: #define WIN32 0
105: #endif
106:
1.1.1.2 ! misho 107: #ifndef CLOCK_MONOTONIC
! 108: #define CLOCK_MONOTONIC CLOCK_REALTIME
! 109: #endif
! 110:
1.1 misho 111: /**
112: * OS-specific interface finding using routing table. See findif_*.c
113: */
114: const char *
1.1.1.2 ! misho 115: arping_lookupdev(uint32_t srcip, uint32_t dstip, char *ebuf);
! 116:
! 117: const char *
! 118: arping_lookupdev_default(uint32_t srcip, uint32_t dstip, char *ebuf);
1.1 misho 119:
120: static const char *version = VERSION; /* from autoconf */
121:
122: static libnet_t *libnet = 0;
123:
1.1.1.2 ! misho 124: static struct timespec lastpacketsent;
1.1 misho 125:
1.1.1.2 ! misho 126: /* target string */
! 127: static char *target = "huh? bug in arping?";
! 128:
! 129: /*
! 130: * Ping IP mode: cmdline target
! 131: * Ping MAC mode: 255.255.255.255, override with -T
! 132: */
! 133: static uint32_t dstip;
! 134:
! 135: /*
! 136: * Ping IP mode: ethxmas, override with -t
! 137: * Ping MAC mode: cmdline target
! 138: */
! 139: static uint8_t dstmac[ETH_ALEN];
! 140:
! 141: static uint32_t srcip; /* autodetected, override with -S/-b/-0 */
! 142: static uint8_t srcmac[ETH_ALEN]; /* autodetected, override with -s */
! 143:
! 144: static int beep = 0; /* beep when reply is received. -a */
! 145: static int reverse_beep = 0; /* beep when expected reply absent. -e */
! 146: static int alsototal = 0; /* print sent as well as received. -u */
! 147: static int addr_must_be_same = 0; /* -A */
! 148: static int unsolicited = 0; /* -U */
! 149:
! 150: static int finddup = 0; /* finddup mode. -d */
! 151: static int dupfound = 0; /* set to 1 if dup found */
! 152: static char lastreplymac[ETH_ALEN]; /* if last different from this then dup */
! 153:
! 154: static unsigned int numsent = 0; /* packets sent */
! 155: static unsigned int numrecvd = 0; /* packets received */
! 156: static unsigned int numdots = 0; /* dots that should be printed */
! 157:
! 158: static double stats_min_time = -1;
! 159: static double stats_max_time = -1;
! 160: static double stats_total_time = 0;
! 161: static double stats_total_sq_time = 0;
1.1 misho 162:
163: /* RAWRAW is RAW|RRAW */
1.1.1.2 ! misho 164: static enum { NORMAL, /* normal output */
! 165: QUIET, /* No output. -q */
! 166: RAW, /* Print MAC when pinging IP. -r */
! 167: RRAW, /* Print IP when pinging IP. -R */
! 168: RAWRAW, /* Print both. -r and -R */
! 169: DOT /* Print '.' and '!', Cisco-style. -D */
! 170: } display = NORMAL;
! 171:
! 172: static const uint8_t ethnull[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
! 173: static const uint8_t ethxmas[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
! 174:
! 175: int verbose = 0; /* Increase with -v */
1.1 misho 176:
1.1.1.2 ! misho 177: /* Doesn't really need to be volatile, but doesn't hurt. */
! 178: static volatile sig_atomic_t time_to_die = 0;
! 179:
! 180: /**
! 181: * Some stupid OSs (Solaris) think it's a good idea to put network
! 182: * devices in /dev and then play musical chairs with them.
! 183: *
! 184: * Since libpcap doesn't seem to have a workaround for that, here's arpings
! 185: * workaround.
! 186: *
! 187: * E.g. if the network interface is called net0, pcap will fail because it
! 188: * fails to open /dev/net, because it's a directory.
! 189: */
! 190: static pcap_t*
! 191: do_pcap_open_live(const char *device, int snaplen,
! 192: int promisc, int to_ms, char *errbuf)
! 193: {
! 194: pcap_t* ret;
! 195: char buf[PATH_MAX];
! 196:
! 197: if ((ret = pcap_open_live(device, snaplen, promisc, to_ms, errbuf))) {
! 198: return ret;
! 199: }
! 200:
! 201: snprintf(buf, sizeof(buf), "/dev/%s", device);
! 202: if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
! 203: return ret;
! 204: }
! 205:
! 206: snprintf(buf, sizeof(buf), "/dev/net/%s", device);
! 207: if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
! 208: return ret;
! 209: }
! 210:
! 211: /* Call original again to reset the error message. */
! 212: return pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
! 213: }
1.1 misho 214:
215: /**
216: *
217: */
218: static void
219: count_missing_dots()
220: {
221: while (numsent > numdots) {
222: putchar('.');
223: numdots++;
224: }
225: }
226:
227: /**
1.1.1.2 ! misho 228: * Init libnet with specified ifname. Destroy if already inited.
! 229: */
1.1 misho 230: void
231: do_libnet_init(const char *ifname)
232: {
233: char ebuf[LIBNET_ERRBUF_SIZE];
234: if (verbose > 1) {
1.1.1.2 ! misho 235: printf("libnet_init(%s)\n", ifname ? ifname : "<null>");
1.1 misho 236: }
237: if (libnet) {
1.1.1.2 ! misho 238: /* Probably going to switch interface from temp to real. */
1.1 misho 239: libnet_destroy(libnet);
240: libnet = 0;
241: }
242:
1.1.1.2 ! misho 243: /* Try libnet_init() even though we aren't root. We may have
! 244: * a capability or something. */
1.1 misho 245: if (!(libnet = libnet_init(LIBNET_LINK,
246: (char*)ifname,
247: ebuf))) {
1.1.1.2 ! misho 248: fprintf(stderr, "arping: %s\n", ebuf);
! 249: if (getuid() && geteuid()) {
! 250: fprintf(stderr,
! 251: "arping: you may need to run as root\n");
! 252: }
1.1 misho 253: exit(1);
254: }
255: }
256:
257: /**
258: *
259: */
1.1.1.2 ! misho 260: void
! 261: sigint(int i)
1.1 misho 262: {
263: time_to_die = 1;
264: }
265:
266: /**
1.1.1.2 ! misho 267: * idiot-proof clock_gettime() wrapper
1.1 misho 268: */
1.1.1.2 ! misho 269: static void
! 270: getclock(struct timespec *ts)
1.1 misho 271: {
1.1.1.2 ! misho 272: #if HAVE_CLOCK_MONOTONIC
! 273: if (-1 == clock_gettime(CLOCK_MONOTONIC, ts)) {
! 274: fprintf(stderr,
! 275: "arping: clock_gettime(): %s\n",
! 276: strerror(errno));
! 277: sigint(0);
! 278: }
! 279: #else
! 280: struct timeval tv;
! 281: if (-1 == gettimeofday(&tv, NULL)) {
! 282: fprintf(stderr, "arping: gettimeofday(): %s\n",
! 283: strerror(errno));
! 284: sigint(0);
! 285: }
! 286: ts->tv_sec = tv.tv_sec;
! 287: ts->tv_nsec = tv.tv_usec * 1000;
! 288: #endif
1.1 misho 289: }
290:
291: /**
292: *
293: */
294: static void
295: extended_usage()
296: {
297: printf("\nOptions:\n");
298: printf("\n"
299: " -0 Use this option to ping with source IP address 0.0.0.0. Use this\n"
300: " when you haven't configured your interface yet. Note that this\n"
301: " may get the MAC-ping unanswered. This is an alias for -S\n"
302: " 0.0.0.0.\n"
303: " -a Audiable ping.\n"
304: " -A Only count addresses matching requested address (This *WILL*\n"
305: " break most things you do. Only useful if you are arpinging many\n"
306: " hosts at once. See arping-scan-net.sh for an example).\n"
307: " -b Like -0 but source broadcast source address (255.255.255.255).\n"
308: " Note that this may get the arping unanswered since it's not nor-\n"
309: " mal behavior for a host.\n"
310: " -B Use instead of host if you want to address 255.255.255.255.\n"
311: " -c count\n"
312: " Only send count requests.\n"
313: " -d Find duplicate replies. Exit with 1 if there are "
314: "answers from\n"
315: " two different MAC addresses.\n"
1.1.1.2 ! misho 316: " -D Display answers as exclamation points and missing packets as dots.\n"
1.1 misho 317: " -e Like -a but beep when there is no reply.\n"
318: " -F Don't try to be smart about the interface name. (even if this\n"
319: " switch is not given, -i overrides smartness)\n"
320: " -h Displays a help message and exits.\n"
321: " -i interface\n"
322: " Use the specified interface.\n"
323: " -q Does not display messages, except error messages.\n"
324: " -r Raw output: only the MAC/IP address is displayed for each reply.\n"
325: " -R Raw output: Like -r but shows \"the other one\", can be combined\n"
326: " with -r.\n"
327: " -s MAC Set source MAC address. You may need to use -p with this.\n"
328: " -S IP Like -b and -0 but with set source address. Note that this may\n"
329: " get the arping unanswered if the target does not have routing to\n"
330: " the IP. If you don't own the IP you are using, you may need to\n"
331: " turn on promiscious mode on the interface (with -p). With this\n"
332: " switch you can find out what IP-address a host has without tak-\n"
333: " ing an IP-address yourself.\n"
334: " -t MAC Set target MAC address to use when pinging IP address.\n"
335: " -T IP Use -T as target address when pinging MACs that won't respond to\n"
336: " a broadcast ping but perhaps to a directed broadcast.\n"
337: " Example:\n"
338: " To check the address of MAC-A, use knowledge of MAC-B and IP-B.\n"
339: " $ arping -S <IP-B> -s <MAC-B> -p <MAC-A>\n"
340: " -p Turn on promiscious mode on interface, use this if you don't\n"
341: " \"own\" the MAC address you are using.\n"
342: " -u Show index=received/sent instead of just index=received when\n"
343: " pinging MACs.\n"
1.1.1.2 ! misho 344: " -U Send unsolicited ARP.\n"
1.1 misho 345: " -v Verbose output. Use twice for more messages.\n"
346: " -w Time to wait between pings, in microseconds.\n");
1.1.1.2 ! misho 347: printf("Report bugs to: thomas@habets.se\n"
1.1 misho 348: "Arping home page: <http://www.habets.pp.se/synscan/>\n"
349: "Development repo: http://github.com/ThomasHabets/arping\n");
350: }
351:
352: /**
353: *
354: */
355: static void
356: standard_usage()
357: {
1.1.1.2 ! misho 358: printf("ARPing %s, by Thomas Habets <thomas@habets.se>\n",
1.1 misho 359: version);
1.1.1.2 ! misho 360: printf("usage: arping [ -0aAbdDeFpqrRuUv ] [ -w <us> ] "
1.1 misho 361: "[ -S <host/ip> ]\n"
362: " "
363: "[ -T <host/ip ] "
364: "[ -s <MAC> ] [ -t <MAC> ] [ -c <count> ]\n"
365: " "
366: "[ -i <interface> ] "
367: "<host/ip/MAC | -B>\n");
368: }
369:
370: /**
371: *
372: */
373: static void
374: usage(int ret)
375: {
376: standard_usage();
377: if (WIN32) {
378: extended_usage();
379: } else {
380: printf("For complete usage info, use --help"
381: " or check the manpage.\n");
382: }
383: exit(ret);
384: }
385:
386: /**
387: * It was unclear from msdn.microsoft.com if their scanf() supported
388: * [0-9a-fA-F], so I'll stay away from it.
389: */
390: static int is_mac_addr(const char *p)
391: {
392: /* cisco-style */
393: if (3*5-1 == strlen(p)) {
394: unsigned int c;
395: for (c = 0; c < strlen(p); c++) {
396: if ((c % 5) == 4) {
397: if ('.' != p[c]) {
398: goto checkcolon;
399: }
400: } else {
401: if (!isxdigit(p[c])) {
402: goto checkcolon;
403: }
404: }
405: }
406: return 1;
407: }
408: /* windows-style */
409: if (6*3-1 == strlen(p)) {
410: unsigned int c;
411: for (c = 0; c < strlen(p); c++) {
412: if ((c % 3) == 2) {
413: if ('-' != p[c]) {
414: goto checkcolon;
415: }
416: } else {
417: if (!isxdigit(p[c])) {
418: goto checkcolon;
419: }
420: }
421: }
422: return 1;
423: }
424:
425: checkcolon:
426: /* unix */
427: return strchr(p, ':') ? 1 : 0;
428: }
429:
430: /**
431: * lots of parms since C arrays suck
432: */
433: static int get_mac_addr(const char *in,
434: unsigned int *n0,
435: unsigned int *n1,
436: unsigned int *n2,
437: unsigned int *n3,
438: unsigned int *n4,
439: unsigned int *n5)
440: {
441: if (6 == sscanf(in, "%x:%x:%x:%x:%x:%x",n0,n1,n2,n3,n4,n5)) {
442: return 1;
443: } else if(6 == sscanf(in, "%2x%x.%2x%x.%2x%x",n0,n1,n2,n3,n4,n5)) {
444: return 1;
445: } else if(6 == sscanf(in, "%x-%x-%x-%x-%x-%x",n0,n1,n2,n3,n4,n5)) {
446: return 1;
447: }
448: return 0;
449: }
450:
451: /**
452: *
1.1.1.2 ! misho 453: */
! 454: static void
! 455: update_stats(double sample)
! 456: {
! 457: if (stats_min_time < 0 || sample < stats_min_time) {
! 458: stats_min_time = sample;
! 459: }
! 460: if (sample > stats_max_time) {
! 461: stats_max_time = sample;
! 462: }
! 463: stats_total_time += sample;
! 464: stats_total_sq_time += sample * sample;
! 465: }
! 466:
! 467: /**
! 468: *
! 469: */
! 470: static double
! 471: timespec2dbl(const struct timespec *tv)
! 472: {
! 473: return tv->tv_sec + (double)tv->tv_nsec / 1000000000;
! 474: }
! 475:
! 476: /**
! 477: * max size of buffer is intsize + 1 + intsize + 4 = 70 bytes or so
1.1 misho 478: *
479: * Still, I'm using at least 128bytes below
480: *
481: * (because snprintf() sadly isn't as portable, that's why)
482: */
1.1.1.2 ! misho 483: static char *ts2str(const struct timespec *tv, const struct timespec *tv2,
1.1 misho 484: char *buf)
485: {
486: double f,f2;
487: int exp = 0;
488:
1.1.1.2 ! misho 489: f = timespec2dbl(tv);
! 490: f2 = timespec2dbl(tv2);
! 491: f = (f2 - f) * 1000000000;
1.1 misho 492: while (f > 1000) {
1.1.1.2 ! misho 493: exp += 3;
1.1 misho 494: f /= 1000;
495: }
496: switch (exp) {
497: case 0:
1.1.1.2 ! misho 498: sprintf(buf, "%.3f nsec", f);
1.1 misho 499: break;
500: case 3:
1.1.1.2 ! misho 501: sprintf(buf, "%.3f usec", f);
1.1 misho 502: break;
503: case 6:
1.1.1.2 ! misho 504: sprintf(buf, "%.3f msec", f);
1.1 misho 505: break;
506: case 9:
1.1.1.2 ! misho 507: sprintf(buf, "%.3f sec", f);
! 508: break;
! 509: case 12:
1.1 misho 510: sprintf(buf, "%.3f sec", f*1000);
511: break;
512: default:
513: /* huh, uh, huhuh */
1.1.1.2 ! misho 514: sprintf(buf, "%.3fe%d sec", f, exp-9);
1.1 misho 515: }
516: return buf;
517: }
518:
519:
520:
521: /** Send directed IPv4 ICMP echo request.
522: *
523: * \param id IP id
524: * \param seq Ping seq
525: */
526: static void
1.1.1.2 ! misho 527: pingmac_send(uint16_t id, uint16_t seq)
1.1 misho 528: {
529: static libnet_ptag_t icmp = 0, ipv4 = 0,eth=0;
530: int c;
531:
532: if (-1 == (icmp = libnet_build_icmpv4_echo(ICMP_ECHO, /* type */
533: 0, /* code */
534: 0, /* checksum */
535: id, /* id */
536: seq, /* seq */
537: NULL, /* payload */
538: 0, /* payload len */
539: libnet,
540: icmp))) {
541: fprintf(stderr, "libnet_build_icmpv4_echo(): %s\n",
542: libnet_geterror(libnet));
543: sigint(0);
544: }
545:
546: if (-1==(ipv4 = libnet_build_ipv4(LIBNET_IPV4_H
547: + LIBNET_ICMPV4_ECHO_H + 0,
548: 0, /* ToS */
549: id, /* id */
550: 0, /* frag */
551: 64, /* ttl */
552: IPPROTO_ICMP,
553: 0, /* checksum */
554: srcip,
555: dstip,
556: NULL, /* payload */
557: 0,
558: libnet,
559: ipv4))) {
560: fprintf(stderr, "libnet_build_ipv4(): %s\n",
561: libnet_geterror(libnet));
562: sigint(0);
563: }
564: if (-1 == (eth = libnet_build_ethernet(dstmac,
565: srcmac,
566: ETHERTYPE_IP,
567: NULL,
568: 0,
569: libnet,
570: eth))) {
571: fprintf(stderr, "libnet_build_ethernet(): %s\n",
572: libnet_geterror(libnet));
573: sigint(0);
574: }
1.1.1.2 ! misho 575: if (verbose > 1) {
! 576: getclock(&lastpacketsent);
! 577: printf("arping: sending packet at time %ld.%09ld\n",
! 578: (long)lastpacketsent.tv_sec,
! 579: (long)lastpacketsent.tv_nsec);
1.1 misho 580: }
581: if (-1 == (c = libnet_write(libnet))) {
582: fprintf(stderr, "arping: libnet_write(): %s\n",
583: libnet_geterror(libnet));
584: sigint(0);
585: }
1.1.1.2 ! misho 586: getclock(&lastpacketsent);
1.1 misho 587: numsent++;
588: }
589:
590: /** Send ARP who-has.
591: *
592: */
593: static void
1.1.1.2 ! misho 594: pingip_send()
1.1 misho 595: {
596: static libnet_ptag_t arp=0,eth=0;
597: if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER,
598: ETHERTYPE_IP,
599: ETH_ALEN,
600: IP_ALEN,
601: ARPOP_REQUEST,
602: srcmac,
603: (uint8_t*)&srcip,
1.1.1.2 ! misho 604: unsolicited ? (uint8_t*)ethxmas : (uint8_t*)ethnull,
1.1 misho 605: (uint8_t*)&dstip,
606: NULL,
607: 0,
608: libnet,
609: arp))) {
610: fprintf(stderr, "arping: libnet_build_arp(): %s\n",
611: libnet_geterror(libnet));
612: sigint(0);
613: }
614: if (-1 == (eth = libnet_build_ethernet(dstmac,
615: srcmac,
616: ETHERTYPE_ARP,
617: NULL,
618: 0,
619: libnet,
620: eth))) {
621: fprintf(stderr, "arping: libnet_build_ethernet(): %s\n",
622: libnet_geterror(libnet));
623: sigint(0);
624: }
1.1.1.2 ! misho 625: if (verbose > 1) {
! 626: getclock(&lastpacketsent);
! 627: printf("arping: sending packet at time %ld.%09ld\n",
! 628: (long)lastpacketsent.tv_sec,
! 629: (long)lastpacketsent.tv_nsec);
1.1 misho 630: }
631: if (-1 == libnet_write(libnet)) {
632: fprintf(stderr, "arping: libnet_write(): %s\n",
633: libnet_geterror(libnet));
634: sigint(0);
635: }
1.1.1.2 ! misho 636: getclock(&lastpacketsent);
1.1 misho 637: numsent++;
638: }
639:
640: /** handle incoming packet when pinging an IP address.
641: *
642: * \param h packet metadata
643: * \param packet packet data
644: */
645: static void
1.1.1.2 ! misho 646: pingip_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet)
1.1 misho 647: {
648: struct libnet_802_3_hdr *heth;
649: struct libnet_arp_hdr *harp;
1.1.1.2 ! misho 650: struct timespec arrival;
1.1 misho 651: int c;
652:
1.1.1.2 ! misho 653: if (verbose > 2) {
1.1 misho 654: printf("arping: received response for ip ping\n");
655: }
656:
1.1.1.2 ! misho 657: getclock(&arrival);
! 658:
1.1 misho 659: heth = (void*)packet;
660: harp = (void*)((char*)heth + LIBNET_ETH_H);
661:
662: if ((htons(harp->ar_op) == ARPOP_REPLY)
663: && (htons(harp->ar_pro) == ETHERTYPE_IP)
664: && (htons(harp->ar_hrd) == ARPHRD_ETHER)) {
665: uint32_t ip;
666: memcpy(&ip, (char*)harp + harp->ar_hln
667: + LIBNET_ARP_H,4);
668: if (addr_must_be_same
669: && (memcmp((u_char*)harp+sizeof(struct libnet_arp_hdr),
670: dstmac, ETH_ALEN))) {
671: return;
672: }
673: if (dstip == ip) {
1.1.1.2 ! misho 674: update_stats(timespec2dbl(&arrival)
! 675: - timespec2dbl(&lastpacketsent));
1.1 misho 676: switch(display) {
677: case DOT:
678: numdots++;
679: count_missing_dots();
680: putchar('!');
681: break;
682: case NORMAL: {
683: char buf[128];
684: printf("%d bytes from ", h->len);
685: for (c = 0; c < 6; c++) {
686: printf("%.2x%c", heth->_802_3_shost[c],
687: (c<5)?':':' ');
688: }
689:
690: printf("(%s): index=%d",
691: libnet_addr2name4(ip,0),
692: numrecvd);
693: if (alsototal) {
694: printf("/%u", numsent-1);
695: }
696: printf(" time=%s",
1.1.1.2 ! misho 697: ts2str(&lastpacketsent,
! 698: &arrival,buf));
! 699: break;
! 700: }
1.1 misho 701: case QUIET:
702: break;
703: case RAWRAW:
704: for (c = 0; c < 6; c++) {
705: printf("%.2x%c", heth->_802_3_shost[c],
706: (c<5)?':':' ');
707: }
708: printf("%s", libnet_addr2name4(ip,0));
709: break;
710: case RRAW:
711: printf("%s", libnet_addr2name4(ip,0));
712: break;
713: case RAW:
714: for (c = 0; c < 6; c++) {
715: printf("%.2x%s", heth->_802_3_shost[c],
716: (c<5)?":":"");
717: }
718: break;
719: default:
720: fprintf(stderr, "arping: can't happen!\n");
721: }
722:
723: switch (display) {
724: case QUIET:
725: case DOT:
726: break;
727: default:
728: if (beep) {
729: printf("\a");
730: }
731: printf("\n");
732: }
733: if (numrecvd) {
734: if (memcmp(lastreplymac,
735: heth->_802_3_shost, ETH_ALEN)) {
736: dupfound = 1;
737: }
738: }
739: memcpy(lastreplymac, heth->_802_3_shost, ETH_ALEN);
740:
741: numrecvd++;
742: }
743: }
744: }
745:
746: /** handle incoming packet when pinging an MAC address.
747: *
748: * \param h packet metadata
749: * \param packet packet data
750: */
751: static void
1.1.1.2 ! misho 752: pingmac_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet)
1.1 misho 753: {
754: struct libnet_802_3_hdr *heth;
755: struct libnet_ipv4_hdr *hip;
756: struct libnet_icmpv4_hdr *hicmp;
1.1.1.2 ! misho 757: struct timespec arrival;
1.1 misho 758: int c;
759:
760: if(verbose>2) {
761: printf("arping: received response for mac ping\n");
762: }
763:
1.1.1.2 ! misho 764: getclock(&arrival);
1.1 misho 765:
766: heth = (void*)packet;
767: hip = (void*)((char*)heth + LIBNET_ETH_H);
768: hicmp = (void*)((char*)hip + LIBNET_IPV4_H);
769:
770: if ((htons(hicmp->icmp_type) == ICMP_ECHOREPLY)
771: && ((!memcmp(heth->_802_3_shost, dstmac,ETH_ALEN)
772: || !memcmp(dstmac, ethxmas, ETH_ALEN)))
773: && !memcmp(heth->_802_3_dhost, srcmac, ETH_ALEN)) {
774: if (addr_must_be_same) {
775: uint32_t tmp;
776: memcpy(&tmp, &hip->ip_src, 4);
777: if (dstip != tmp) {
778: return;
779: }
780: }
1.1.1.2 ! misho 781: update_stats(timespec2dbl(&arrival)
! 782: - timespec2dbl(&lastpacketsent));
1.1 misho 783: switch(display) {
784: case QUIET:
785: break;
786: case NORMAL: {
787: char buf[128];
788: printf("%d bytes from %s (",h->len,
789: libnet_addr2name4(*(int*)&hip->ip_src, 0));
790: for (c = 0; c < 6; c++) {
791: printf("%.2x%c", heth->_802_3_shost[c],
792: (c<5)?':':')');
793: }
794: printf(": icmp_seq=%d time=%s",
1.1.1.2 ! misho 795: htons(hicmp->icmp_seq),ts2str(&lastpacketsent,
! 796: &arrival,buf));
1.1 misho 797: break; }
798: case RAW:
799: printf("%s",
800: libnet_addr2name4(hip->ip_src.s_addr, 0));
801: break;
802: case RRAW:
803: for (c = 0; c < 6; c++) {
804: printf("%.2x%s", heth->_802_3_shost[c],
805: (c<5)?":":"");
806: }
807: break;
808: case RAWRAW:
809: for (c = 0; c < 6; c++) {
810: printf("%.2x%c", heth->_802_3_shost[c],
811: (c<5)?':':' ');
812: }
813: printf("%s",
814: libnet_addr2name4(hip->ip_src.s_addr, 0));
815: break;
816: default:
817: fprintf(stderr, "arping: can't-happen-bug\n");
818: sigint(0);
819: }
820: if (display != QUIET) {
821: printf(beep?"\a\n":"\n");
822: }
823: numrecvd++;
824: }
825: }
826:
827: /**
1.1.1.2 ! misho 828: * while negative nanoseconds, take from whole seconds.
1.1 misho 829: * help function for measuring deltas.
830: */
831: static void
1.1.1.2 ! misho 832: fixup_timespec(struct timespec *tv)
1.1 misho 833: {
1.1.1.2 ! misho 834: while (tv->tv_nsec < 0) {
1.1 misho 835: tv->tv_sec--;
1.1.1.2 ! misho 836: tv->tv_nsec += 1000000000;
1.1 misho 837: }
838: }
839:
840: /**
1.1.1.2 ! misho 841: * try to receive a packet for 'packetwait' microseconds
1.1 misho 842: */
843: static void
1.1.1.2 ! misho 844: ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_handler func)
1.1 misho 845: {
1.1.1.2 ! misho 846: struct timespec ts;
! 847: struct timespec endtime;
1.1 misho 848: char done = 0;
1.1.1.2 ! misho 849: int fd;
! 850: int old_received;
1.1 misho 851:
1.1.1.2 ! misho 852: if (verbose > 3) {
! 853: printf("arping: receiving packets...\n");
! 854: }
1.1 misho 855:
1.1.1.2 ! misho 856: getclock(&ts);
! 857: endtime.tv_sec = ts.tv_sec + (packetwait / 1000000);
! 858: endtime.tv_nsec = ts.tv_nsec + 1000 * (packetwait % 1000000);
! 859: fixup_timespec(&endtime);
1.1 misho 860:
861: fd = pcap_get_selectable_fd(pcap);
1.1.1.2 ! misho 862: old_received = numrecvd;
1.1 misho 863:
864: for (;!done;) {
865: int trydispatch = 0;
866:
1.1.1.2 ! misho 867: getclock(&ts);
! 868: ts.tv_sec = endtime.tv_sec - ts.tv_sec;
! 869: ts.tv_nsec = endtime.tv_nsec - ts.tv_nsec;
! 870: fixup_timespec(&ts);
! 871: if (verbose > 2) {
! 872: printf("listen for replies for %ld.%09ld sec\n",
! 873: (long)ts.tv_sec, (long)ts.tv_nsec);
! 874: }
! 875:
! 876: /* if time has passed, do one last check and then we're done.
! 877: * this also triggers if not using monotonic clock and time
! 878: * is set forwards */
! 879: if (ts.tv_sec < 0) {
! 880: ts.tv_sec = 0;
! 881: ts.tv_nsec = 1;
1.1 misho 882: done = 1;
883: }
1.1.1.2 ! misho 884:
! 885: /* if wait-for-packet time is longer than full period,
! 886: * we're obviously not using a monotonic clock and the system
! 887: * time has been changed.
! 888: * we don't know how far we're into the waiting, so just end
! 889: * it here */
! 890: if ((ts.tv_sec > packetwait / 1000000)
! 891: || ((ts.tv_sec == packetwait / 1000000)
! 892: && (ts.tv_nsec/1000 > packetwait % 1000000))) {
! 893: ts.tv_sec = 0;
! 894: ts.tv_nsec = 1;
! 895: done = 1;
! 896: }
! 897:
! 898: /* check for sigint */
1.1 misho 899: if (time_to_die) {
900: return;
901: }
902:
903: /* try to wait for data */
904: {
1.1.1.2 ! misho 905: fd_set fds;
1.1 misho 906: int r;
1.1.1.2 ! misho 907: struct timeval tv;
! 908: tv.tv_sec = ts.tv_sec;
! 909: tv.tv_usec = ts.tv_nsec / 1000;
! 910:
! 911: FD_ZERO(&fds);
! 912: FD_SET(fd, &fds);
1.1 misho 913:
1.1.1.2 ! misho 914: r = select(fd + 1, &fds, NULL, NULL, &tv);
1.1 misho 915: switch (r) {
916: case 0: /* timeout */
1.1.1.2 ! misho 917: if (display == NORMAL) {
! 918: if (numrecvd == old_received) {
! 919: printf("Timeout\n");
! 920: }
! 921: }
1.1 misho 922: done = 1;
923: break;
924: case -1: /* error */
925: if (errno != EINTR) {
926: done = 1;
927: sigint(0);
928: fprintf(stderr,
1.1.1.2 ! misho 929: "arping: select() failed: %s\n",
1.1 misho 930: strerror(errno));
931: }
932: break;
933: default: /* data returned */
934: trydispatch = 1;
935: break;
936: }
937: }
938:
939: if (trydispatch) {
940: int ret;
1.1.1.2 ! misho 941: if (0 > (ret = pcap_dispatch(pcap, -1,
! 942: func,
! 943: NULL))) {
1.1 misho 944: /* rest, so we don't take 100% CPU... mostly
945: hmm... does usleep() exist everywhere? */
946: usleep(1);
947:
948: /* weird is normal on bsd :) */
949: if (verbose > 3) {
950: fprintf(stderr,
1.1.1.2 ! misho 951: "arping: select says ok, but "
1.1 misho 952: "pcap_dispatch=%d!\n",
953: ret);
954: }
955: }
956: }
957: }
958: }
959:
960: /**
961: *
962: */
963: int main(int argc, char **argv)
964: {
965: char ebuf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE];
966: char *cp;
967: int promisc = 0;
968: int srcip_given = 0;
969: int srcmac_given = 0;
970: int dstip_given = 0;
971: const char *ifname = NULL;
972: char *parm;
973: int c;
974: unsigned int maxcount = -1;
975: int dont_use_arping_lookupdev=0;
976: struct bpf_program bp;
977: pcap_t *pcap;
1.1.1.2 ! misho 978: enum { NONE, PINGMAC, PINGIP } mode = NONE;
1.1 misho 979: unsigned int packetwait = 1000000;
980:
981: for (c = 1; c < argc; c++) {
982: if (!strcmp(argv[c], "--help")) {
983: standard_usage();
984: extended_usage();
985: exit(0);
986: }
987: }
988:
989: srcip = 0;
990: dstip = 0xffffffff;
1.1.1.2 ! misho 991: memcpy(dstmac, ethxmas, ETH_ALEN);
1.1 misho 992:
1.1.1.2 ! misho 993: while (EOF!=(c=getopt(argc,argv,"0aAbBc:dDeFhi:I:pqrRs:S:t:T:uUvw:"))) {
1.1 misho 994: switch(c) {
995: case '0':
996: srcip = 0;
997: srcip_given = 1;
998: break;
999: case 'a':
1000: beep = 1;
1001: break;
1002: case 'A':
1003: addr_must_be_same = 1;
1004: break;
1005: case 'b':
1006: srcip = 0xffffffff;
1007: srcip_given = 1;
1008: break;
1009: case 'B':
1010: dstip = 0xffffffff;
1011: dstip_given = 1;
1012: break;
1013: case 'c':
1014: maxcount = atoi(optarg);
1015: break;
1016: case 'd':
1017: finddup = 1;
1018: break;
1019: case 'D':
1020: display = DOT;
1021: break;
1022: case 'e':
1023: reverse_beep = 1;
1024: break;
1025: case 'F':
1026: dont_use_arping_lookupdev=1;
1027: break;
1028: case 'h':
1029: usage(0);
1030: case 'i':
1031: if (strchr(optarg, ':')) {
1032: fprintf(stderr, "arping: If you're trying to "
1033: "feed me an interface alias then you "
1034: "don't really\nknow what this programs"
1035: " does, do you?\nUse -I if you really"
1036: " mean it (undocumented on "
1037: "purpose)\n");
1038: exit(1);
1039: }
1040: case 'I': /* FALL THROUGH */
1041: ifname = optarg;
1042: break;
1043: case 'p':
1044: promisc = 1;
1045: break;
1046: case 'q':
1047: display = QUIET;
1048: break;
1049: case 'r':
1050: display = (display==RRAW)?RAWRAW:RAW;
1051: break;
1052: case 'R':
1053: display = (display==RAW)?RAWRAW:RRAW;
1054: break;
1055: case 's': { /* spoof source MAC */
1056: unsigned int n[6];
1057: if (!get_mac_addr(optarg,
1058: &n[0],&n[1],&n[2],
1059: &n[3],&n[4],&n[5])){
1060: fprintf(stderr, "arping: Weird MAC addr %s\n",
1061: optarg);
1062: exit(1);
1063: }
1064: for (c = 0; c < 6; c++) {
1065: srcmac[c] = n[c] & 0xff;
1066: }
1067: srcmac_given = 1;
1068: break;
1069: }
1070: case 'S': /* set source IP, may be null for don't-know */
1071: do_libnet_init(ifname);
1072: if (-1 == (srcip = libnet_name2addr4(libnet,
1073: optarg,
1074: LIBNET_RESOLVE))){
1075: fprintf(stderr, "arping: Can't resolve %s, or "
1076: "%s is broadcast. If it is, use -b"
1077: " instead of -S\n", optarg,optarg);
1078: exit(1);
1079: }
1080: srcip_given = 1;
1081: break;
1082: case 't': { /* set taget mac */
1083: unsigned int n[6];
1084: if (mode == PINGMAC) {
1085: fprintf(stderr, "arping: -t can only be used "
1086: "in IP ping mode\n");
1087: exit(1);
1088: }
1089: if (!get_mac_addr(optarg,
1090: &n[0],&n[1],&n[2],
1091: &n[3],&n[4],&n[5])){
1092: fprintf(stderr, "Illegal MAC addr %s\n",
1093: optarg);
1094: exit(1);
1095: }
1096: for (c = 0; c < 6; c++) {
1097: dstmac[c] = n[c] & 0xff;
1098: }
1099: mode = PINGIP;
1100: break;
1101: }
1102: case 'T': /* set destination IP */
1103: if (mode == PINGIP) {
1104: fprintf(stderr, "arping: -T can only be used "
1105: "in MAC ping mode\n");
1106: exit(1);
1107: }
1108: do_libnet_init(ifname);
1109: if (-1 == (dstip = libnet_name2addr4(libnet,
1110: optarg,
1111: LIBNET_RESOLVE))){
1112: fprintf(stderr,"arping: Can't resolve %s, or "
1113: "%s is broadcast. If it is, use -B "
1114: "instead of -T\n",optarg,optarg);
1115: exit(1);
1116: }
1117: mode = PINGMAC;
1118: break;
1119: case 'u':
1120: alsototal = 1;
1121: break;
1.1.1.2 ! misho 1122: case 'U':
! 1123: if (mode == PINGMAC) {
! 1124: fprintf(stderr, "arping: -U can only be used "
! 1125: "in IP ping mode\n");
! 1126: exit(1);
! 1127: }
! 1128: unsolicited = 1;
! 1129: break;
1.1 misho 1130: case 'v':
1131: verbose++;
1132: break;
1133: case 'w':
1134: packetwait = (unsigned)atoi(optarg);
1135: break;
1136: default:
1137: usage(1);
1138: }
1139: }
1140:
1.1.1.2 ! misho 1141: if (verbose > 1) {
! 1142: #if HAVE_CLOCK_MONOTONIC
! 1143: struct timespec ts;
! 1144: clock_getres(CLOCK_MONOTONIC, &ts);
! 1145: printf("clock_getres() = %ld %ld\n",
! 1146: (long)ts.tv_sec, (long)ts.tv_nsec);
! 1147: #else
! 1148: printf("Using gettimeofday() for time measurements\n");
! 1149: #endif
! 1150: }
! 1151:
1.1 misho 1152: if (display == DOT) {
1153: setvbuf(stdout, NULL, _IONBF, 0);
1154: }
1155:
1156: if (finddup && maxcount == -1) {
1157: maxcount = 3;
1158: }
1159:
1160: parm = (optind < argc) ? argv[optind] : NULL;
1161:
1162: /* default to own IP address when doing -d */
1163: if (finddup && !parm) {
1164: dstip_given = 1;
1165: do_libnet_init(ifname);
1166: dstip = libnet_get_ipaddr4(libnet);
1167: if (verbose) {
1168: printf("defaulting to checking dup for %s\n",
1169: libnet_addr2name4(dstip, 0));
1170: }
1171: }
1172:
1173: /*
1174: * Handle dstip_given instead of ip address after parms (-B really)
1175: */
1176: if (mode == NONE) {
1177: if (optind + 1 == argc) {
1178: mode = is_mac_addr(parm)?PINGMAC:PINGIP;
1179: } else if (dstip_given) {
1180: mode = PINGIP;
1181: do_libnet_init(ifname);
1182: parm = strdup(libnet_addr2name4(dstip,0));
1183: if (!parm) {
1184: fprintf(stderr, "arping: out of mem\n");
1185: exit(1);
1186: }
1187: }
1188: }
1189:
1190: if (!parm) {
1191: usage(1);
1192: }
1193:
1194: /*
1195: *
1196: */
1197: if (mode == NONE) {
1198: usage(1);
1199: }
1200:
1201: /*
1202: * libnet init (may be done already for resolving)
1203: */
1204: do_libnet_init(ifname);
1205:
1206: /*
1207: * Make sure dstip and parm like eachother
1208: */
1209: if (mode == PINGIP && (!dstip_given)) {
1210: if (is_mac_addr(parm)) {
1211: fprintf(stderr, "arping: Options given only apply to "
1212: "IP ping, but MAC address given as argument"
1213: "\n");
1214: exit(1);
1215: }
1216: if (-1 == (dstip = libnet_name2addr4(libnet,
1217: parm,
1218: LIBNET_RESOLVE))) {
1219: fprintf(stderr, "arping: Can't resolve %s\n", parm);
1220: exit(1);
1221: }
1222: parm = strdup(libnet_addr2name4(dstip,0));
1223: }
1224:
1225: /*
1226: * parse parm into dstmac
1227: */
1228: if (mode == PINGMAC) {
1229: unsigned int n[6];
1230: if (optind + 1 != argc) {
1231: usage(1);
1232: }
1233: if (!is_mac_addr(parm)) {
1234: fprintf(stderr, "arping: Options given only apply to "
1235: "MAC ping, but no MAC address given as "
1236: "argument\n");
1237: exit(1);
1238: }
1239: if (!get_mac_addr(argv[optind],
1240: &n[0],&n[1],&n[2],
1241: &n[3],&n[4],&n[5])) {
1242: fprintf(stderr, "arping: Illegal mac addr %s\n",
1243: argv[optind]);
1244: return 1;
1245: }
1246: for (c = 0; c < 6; c++) {
1247: dstmac[c] = n[c] & 0xff;
1248: }
1249: }
1250:
1251: target = parm;
1252: /*
1253: * Argument processing done, parameters considered sane below
1254: */
1255:
1256: /*
1257: * Get some good iface.
1258: */
1259: if (!ifname) {
1.1.1.2 ! misho 1260: if (!dont_use_arping_lookupdev) {
! 1261: ifname = arping_lookupdev(srcip, dstip, ebuf);
! 1262: }
! 1263: if (!ifname) {
! 1264: ifname = arping_lookupdev_default(srcip, dstip, ebuf);
! 1265: if (!dont_use_arping_lookupdev) {
! 1266: fprintf(stderr,
! 1267: "arping: Unable to automatically find "
! 1268: "interface to use. Is it on the local "
! 1269: "LAN?\n"
! 1270: "arping: Use -i to manually "
! 1271: "specify interface. "
! 1272: "Guessing interface %s.\n", ifname);
! 1273: }
1.1 misho 1274: }
1275: if (!ifname) {
1.1.1.2 ! misho 1276: fprintf(stderr, "arping: Gave up looking for interface"
! 1277: " to use: %s\n", ebuf);
1.1 misho 1278: exit(1);
1279: }
1280: /* FIXME: check for other probably-not interfaces */
1281: if (!strcmp(ifname, "ipsec")
1282: || !strcmp(ifname,"lo")) {
1283: fprintf(stderr, "arping: Um.. %s looks like the wrong "
1284: "interface to use. Is it? "
1285: "(-i switch)\n", ifname);
1286: fprintf(stderr, "arping: using it anyway this time\n");
1287: }
1288: }
1289:
1290: /*
1291: * Init libnet again, because we now know the interface name.
1292: * We should know it by know at least
1293: */
1294: do_libnet_init(ifname);
1295:
1296: /*
1297: * pcap init
1298: */
1.1.1.2 ! misho 1299: if (!(pcap = do_pcap_open_live(ifname, 100, promisc, 10, ebuf))) {
1.1 misho 1300: fprintf(stderr, "arping: pcap_open_live(): %s\n",ebuf);
1301: exit(1);
1302: }
1303: if (pcap_setnonblock(pcap, 1, ebuf)) {
1304: fprintf(stderr, "arping: pcap_set_nonblock(): %s\n", ebuf);
1305: exit(1);
1306: }
1.1.1.2 ! misho 1307: if (verbose > 1) {
! 1308: printf("pcap_get_selectable_fd(): %d\n",
1.1 misho 1309: pcap_get_selectable_fd(pcap));
1310: }
1311:
1.1.1.2 ! misho 1312: #ifdef BIOCIMMEDIATE
1.1 misho 1313: {
1314: uint32_t on = 1;
1315: if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE,
1316: &on))) {
1317: fprintf(stderr, "arping: ioctl(fd,BIOCIMMEDIATE, 1) "
1318: "failed, continuing anyway, YMMV: %s\n",
1319: strerror(errno));
1320: }
1321: }
1322: #endif
1323:
1324: if (mode == PINGIP) {
1325: /* FIXME: better filter with addresses? */
1326: if (-1 == pcap_compile(pcap, &bp, "arp", 0,-1)) {
1327: fprintf(stderr, "arping: pcap_compile(): error\n");
1328: exit(1);
1329: }
1330: } else { /* ping mac */
1331: /* FIXME: better filter with addresses? */
1332: if (-1 == pcap_compile(pcap, &bp, "icmp", 0,-1)) {
1333: fprintf(stderr, "arping: pcap_compile(): error\n");
1334: exit(1);
1335: }
1336: }
1337: if (-1 == pcap_setfilter(pcap, &bp)) {
1338: fprintf(stderr, "arping: pcap_setfilter(): error\n");
1339: exit(1);
1340: }
1341:
1342: /*
1343: * final init
1344: */
1345: if (!srcmac_given) {
1346: if (!(cp = (char*)libnet_get_hwaddr(libnet))) {
1347: fprintf(stderr, "arping: libnet_get_hwaddr(): %s\n",
1348: libnet_geterror(libnet));
1349: exit(1);
1350: }
1351: memcpy(srcmac, cp, ETH_ALEN);
1352: }
1353: if (!srcip_given) {
1354: if (-1 == (srcip = libnet_get_ipaddr4(libnet))) {
1.1.1.2 ! misho 1355: fprintf(stderr,
! 1356: "arping: Unable to get the IPv4 address of "
! 1357: "interface %s:\narping: %s"
! 1358: "arping: "
! 1359: "Use -S to specify address manually.\n",
! 1360: ifname, libnet_geterror(libnet));
1.1 misho 1361: exit(1);
1362: }
1363: }
1.1.1.2 ! misho 1364: do_signal_init();
1.1 misho 1365:
1366: if (verbose) {
1367: printf("This box: Interface: %s IP: %s MAC address: ",
1368: ifname, libnet_addr2name4(libnet_get_ipaddr4(libnet),
1369: 0));
1370: for (c = 0; c < ETH_ALEN - 1; c++) {
1371: printf("%.2x:", (uint8_t)srcmac[c]);
1372: }
1373: printf("%.2x\n", (uint8_t)srcmac[ETH_ALEN - 1]);
1374: }
1375:
1376:
1377: if (display == NORMAL) {
1378: printf("ARPING %s\n", parm);
1379: }
1380:
1381: /*
1382: * let's roll
1383: */
1384: if (mode == PINGIP) {
1385: unsigned int c;
1386: unsigned int r;
1387: for (c = 0; c < maxcount && !time_to_die; c++) {
1.1.1.2 ! misho 1388: pingip_send();
1.1 misho 1389: r = numrecvd;
1390: ping_recv(pcap,packetwait,
1391: (pcap_handler)pingip_recv);
1392: if (reverse_beep && !time_to_die && (r == numrecvd)) {
1393: printf("\a");
1394: fflush(stdout);
1395: }
1396: }
1397: } else { /* PINGMAC */
1398: unsigned int c;
1399: unsigned int r;
1400: for (c = 0; c < maxcount && !time_to_die; c++) {
1.1.1.2 ! misho 1401: pingmac_send(rand(), c);
1.1 misho 1402: r = numrecvd;
1403: ping_recv(pcap,packetwait,
1404: (pcap_handler)pingmac_recv);
1405: if (reverse_beep && !time_to_die && (r == numrecvd)) {
1406: printf("\a");
1407: fflush(stdout);
1408: }
1409: }
1410: }
1411: if (display == DOT) {
1412: count_missing_dots();
1413: printf("\t%3.0f%% packet loss\n",
1414: 100.0 - 100.0 * (float)(numrecvd)/(float)numsent);
1415: } else if (display == NORMAL) {
1416: float succ;
1417: succ = 100.0 - 100.0 * (float)(numrecvd)/(float)numsent;
1418: printf("\n--- %s statistics ---\n"
1419: "%d packets transmitted, "
1420: "%d packets received, "
1421: "%3.0f%% "
1422: "unanswered (%d extra)\n",
1423: target,numsent,numrecvd,
1424: (succ < 0.0) ? 0.0 : succ,
1.1.1.2 ! misho 1425: (succ < 0.0) ? (numrecvd - numsent): 0);
! 1426: if (numrecvd) {
! 1427: double avg = stats_total_time / numrecvd;
! 1428: printf("rtt min/avg/max/std-dev = "
! 1429: "%.3f/%.3f/%.3f/%.3f ms",
! 1430: 1000*stats_min_time,
! 1431: 1000*avg,
! 1432: 1000*stats_max_time,
! 1433: 1000*sqrt(stats_total_sq_time/numrecvd
! 1434: -avg*avg));
! 1435: }
! 1436: printf("\n");
1.1 misho 1437: }
1438:
1439: if (finddup) {
1440: return dupfound;
1441: } else {
1442: return !numrecvd;
1443: }
1444: }
1.1.1.2 ! misho 1445: /* ---- Emacs Variables ----
! 1446: * Local Variables:
! 1447: * c-basic-offset: 8
! 1448: * indent-tabs-mode: nil
! 1449: * End:
! 1450: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>