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>