Annotation of embedaddon/arping/src/arping.c, revision 1.1.1.3

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.3 ! misho      18:  *  Copyright (C) 2000-2014 Thomas Habets <thomas@habets.se>
1.1       misho      19:  *
1.1.1.3 ! misho      20:  *  This program is free software; you can redistribute it and/or modify
        !            21:  *  it under the terms of the GNU General Public License as published by
        !            22:  *  the Free Software Foundation; either version 2 of the License, or
        !            23:  *  (at your option) any later version.
1.1       misho      24:  *
1.1.1.3 ! misho      25:  *  This program is distributed in the hope that it will be useful,
1.1       misho      26:  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1.1.1.3 ! misho      27:  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            28:  *  GNU General Public License for more details.
1.1       misho      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: 
1.1.1.3 ! misho      88: #if HAVE_PWD_H
        !            89: #include <pwd.h>
        !            90: #endif
        !            91: 
        !            92: #if HAVE_SYS_CAPABILITY_H
        !            93: #include <sys/capability.h>
        !            94: #endif
        !            95: 
1.1       misho      96: #if HAVE_NET_BPF_H
                     97: #include <net/bpf.h>
                     98: #endif
1.1.1.2   misho      99: #include <pcap.h>
                    100: 
                    101: #include "arping.h"
1.1       misho     102: 
                    103: #ifndef ETH_ALEN
                    104: #define ETH_ALEN 6
                    105: #endif
                    106: 
                    107: #ifndef IP_ALEN
                    108: #define IP_ALEN 4
                    109: #endif
                    110: 
                    111: #ifndef WIN32
                    112: #define WIN32 0
                    113: #endif
                    114: 
1.1.1.2   misho     115: #ifndef CLOCK_MONOTONIC
                    116: #define CLOCK_MONOTONIC CLOCK_REALTIME
                    117: #endif
                    118: 
1.1       misho     119: /**
                    120:  * OS-specific interface finding using routing table. See findif_*.c
1.1.1.3 ! misho     121:  * ebuf must be called with a size of at least
        !           122:  * max(LIBNET_ERRBUF_SIZE, PCAP_ERRBUF_SIZE).
1.1       misho     123:  */
                    124: const char *
1.1.1.2   misho     125: arping_lookupdev(uint32_t srcip, uint32_t dstip, char *ebuf);
                    126: 
                    127: const char *
                    128: arping_lookupdev_default(uint32_t srcip, uint32_t dstip, char *ebuf);
1.1       misho     129: 
                    130: static const char *version = VERSION; /* from autoconf */
                    131: 
                    132: static libnet_t *libnet = 0;
                    133: 
1.1.1.3 ! misho     134: /* Timestamp of last packet sent.
        !           135:  * Used for timing, and assumes that reply is due to most recent sent query.
        !           136:  */
1.1.1.2   misho     137: static struct timespec lastpacketsent;
1.1       misho     138: 
1.1.1.2   misho     139: /* target string */
                    140: static char *target = "huh? bug in arping?";
                    141: 
                    142: /*
                    143:  * Ping IP mode:   cmdline target
                    144:  * Ping MAC mode:  255.255.255.255, override with -T
                    145:  */
                    146: static uint32_t dstip;
                    147: 
                    148: /*
                    149:  * Ping IP mode:   ethxmas, override with -t
                    150:  * Ping MAC mode:  cmdline target
                    151:  */
                    152: static uint8_t dstmac[ETH_ALEN];
                    153: 
                    154: static uint32_t srcip;            /* autodetected, override with -S/-b/-0 */
                    155: static uint8_t srcmac[ETH_ALEN];  /* autodetected, override with -s */
                    156: 
                    157: static int beep = 0;                 /* beep when reply is received. -a */
                    158: static int reverse_beep = 0;         /* beep when expected reply absent. -e */
                    159: static int alsototal = 0;            /* print sent as well as received. -u */
                    160: static int addr_must_be_same = 0;    /* -A */
                    161: static int unsolicited = 0;          /* -U */
1.1.1.3 ! misho     162: static int send_reply = 0;           /* Send reply instead of request. -P */
1.1.1.2   misho     163: 
                    164: static int finddup = 0;              /* finddup mode. -d */
                    165: static int dupfound = 0;             /* set to 1 if dup found */
                    166: static char lastreplymac[ETH_ALEN];  /* if last different from this then dup */
                    167: 
1.1.1.3 ! misho     168: static unsigned int numsent = 0;            /* packets sent */
        !           169: static unsigned int numrecvd = 0;           /* packets received */
        !           170: static unsigned int max_replies = UINT_MAX; /* exit after -C replies */
        !           171: static unsigned int numdots = 0;            /* dots that should be printed */
        !           172: static const char* timestamp_type = NULL;   /* Incoming packet measurement ts type (-m) */
1.1.1.2   misho     173: 
                    174: static double stats_min_time = -1;
                    175: static double stats_max_time = -1;
                    176: static double stats_total_time = 0;
                    177: static double stats_total_sq_time = 0;
1.1       misho     178: 
                    179: /* RAWRAW is RAW|RRAW */
1.1.1.2   misho     180: static enum { NORMAL,      /* normal output */
                    181:               QUIET,       /* No output. -q */
                    182:               RAW,         /* Print MAC when pinging IP. -r */
                    183:               RRAW,        /* Print IP when pinging IP. -R */
                    184:               RAWRAW,      /* Print both. -r and -R */
                    185:               DOT          /* Print '.' and '!', Cisco-style. -D */
                    186: } display = NORMAL;
                    187: 
                    188: static const uint8_t ethnull[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
                    189: static const uint8_t ethxmas[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
                    190: 
                    191: int verbose = 0;  /* Increase with -v */
1.1       misho     192: 
1.1.1.2   misho     193: /* Doesn't really need to be volatile, but doesn't hurt. */
                    194: static volatile sig_atomic_t time_to_die = 0;
                    195: 
                    196: /**
1.1.1.3 ! misho     197:  * If possible, chroot.
        !           198:  *
        !           199:  * The sshd user is used for privilege separation in OpenSSH.
        !           200:  * Let's assume it's installed and chroot() to there.
        !           201:  */
        !           202: static void
        !           203: drop_fs_root()
        !           204: {
        !           205:         const char* chroot_user = "sshd";
        !           206:         struct passwd *pw;
        !           207:         errno = 0;
        !           208:         if (!(pw = getpwnam(chroot_user))) {
        !           209:                 if (verbose) {
        !           210:                         printf("arping: getpwnam(%s): %s",
        !           211:                                chroot_user, strerror(errno));
        !           212:                 }
        !           213:                 return;
        !           214:         }
        !           215:         if (chdir(pw->pw_dir)) {
        !           216:                 if (verbose) {
        !           217:                         printf("arping: chdir(%s): %s",
        !           218:                                pw->pw_dir, strerror(errno));
        !           219:                 }
        !           220:                 return;
        !           221:         }
        !           222:         if (chroot(pw->pw_dir)) {
        !           223:                 if (verbose) {
        !           224:                         printf("arping: chroot(%s): %s",
        !           225:                                pw->pw_dir, strerror(errno));
        !           226:                 }
        !           227:                 return;
        !           228:         }
        !           229:         if (verbose > 1) {
        !           230:                 printf("arping: Successfully chrooted to %s\n", pw->pw_dir);
        !           231:         }
        !           232: }
        !           233: 
        !           234: /**
        !           235:  * If possible, drop uid to nobody.
        !           236:  *
        !           237:  * This code only successfully sets all [ug]ids if running as
        !           238:  * root. ARPing is most likely running as root unless using
        !           239:  * capabilities, and those are dropped elsewhere.
        !           240:  */
        !           241: static void
        !           242: drop_uid(uid_t uid, gid_t gid)
        !           243: {
        !           244:         int fail = 0;
        !           245:         if (setgroups(0, NULL)) {
        !           246:                 if (verbose) {
        !           247:                         printf("arping: setgroups(0, NULL): %s\n", strerror(errno));
        !           248:                 }
        !           249:                 fail++;
        !           250:         }
        !           251:         if (gid && setgid(gid)) {
        !           252:                 if (verbose) {
        !           253:                         printf("arping: setgid(): %s\n", strerror(errno));
        !           254:                 }
        !           255:                 fail++;
        !           256:         }
        !           257:         if (uid && setuid(uid)) {
        !           258:                 if (verbose) {
        !           259:                         printf("arping: setuid(): %s\n", strerror(errno));
        !           260:                 }
        !           261:                 fail++;
        !           262:         }
        !           263:         if (!fail && verbose > 1) {
        !           264:                 printf("arping: Successfully dropped uid/gid to %d/%d.\n",
        !           265:                        uid, gid);
        !           266:         }
        !           267: }
        !           268: 
        !           269: /**
        !           270:  * Drop any and all capabilities.
        !           271:  */
        !           272: static void
        !           273: drop_capabilities()
        !           274: {
        !           275: #if HAVE_CAP_INIT
        !           276:         cap_t no_cap;
        !           277:         if (!(no_cap = cap_init())) {
        !           278:                 if (verbose) {
        !           279:                         printf("arping: cap_init(): %s\n", strerror(errno));
        !           280:                 }
        !           281:                 return;
        !           282:         }
        !           283:         if (cap_set_proc(no_cap)) {
        !           284:                 if (verbose) {
        !           285:                         printf("arping: cap_set_proc(): %s\n", strerror(errno));
        !           286:                 }
        !           287:         }
        !           288:         if (verbose > 1) {
        !           289:                 printf("arping: Successfully dropped all capabilities.\n");
        !           290:         }
        !           291:         cap_free(no_cap);
        !           292: #endif
        !           293: }
        !           294: 
        !           295: /**
        !           296:  * drop all privileges.
        !           297:  */
        !           298: static void
        !           299: drop_privileges()
        !           300: {
        !           301:         // Need to get uid/gid of 'nobody' before chroot().
        !           302:         const char* drop_user = "nobody";
        !           303:         struct passwd *pw;
        !           304:         errno = 0;
        !           305:         uid_t uid = 0;
        !           306:         gid_t gid = 0;
        !           307:         if (!(pw = getpwnam(drop_user))) {
        !           308:                 if (verbose) {
        !           309:                         printf("arping: getpwnam(%s): %s\n",
        !           310:                                drop_user, strerror(errno));
        !           311:                 }
        !           312:                 return;
        !           313:         } else {
        !           314:                 uid = pw->pw_uid;
        !           315:                 gid = pw->pw_gid;
        !           316:         }
        !           317:         drop_fs_root();
        !           318:         drop_uid(uid, gid);
        !           319:         drop_capabilities();
        !           320: }
        !           321: 
        !           322: 
        !           323: /**
        !           324:  * Do pcap_open_live(), except by using the pcap_create() interface
        !           325:  * introduced in 2008 (libpcap 0.4) where available.
        !           326:  *
        !           327:  * FIXME: Use pcap_set_buffer_size()?
        !           328:  */
        !           329: static pcap_t*
        !           330: try_pcap_open_live(const char *device, int snaplen,
        !           331:                    int promisc, int to_ms, char *errbuf)
        !           332: {
        !           333: #ifdef HAVE_PCAP_CREATE
        !           334:         pcap_t* pcap;
        !           335:         int rc;
        !           336: 
        !           337:         if (!(pcap = pcap_create(device, errbuf))) {
        !           338:                 goto err;
        !           339:         }
        !           340:         if ((rc = pcap_set_snaplen(pcap, snaplen))) {
        !           341:                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_set_snaplen(): %s", pcap_statustostr(rc));
        !           342:                 goto err;
        !           343:         }
        !           344:         if ((rc = pcap_set_promisc(pcap, promisc))) {
        !           345:                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_set_promisc(): %s", pcap_statustostr(rc));
        !           346:                 goto err;
        !           347:         }
        !           348:         if ((rc = pcap_set_timeout(pcap, to_ms))) {
        !           349:                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_set_timeout(): %s", pcap_statustostr(rc));
        !           350:                 goto err;
        !           351:         }
        !           352: 
        !           353: #ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
        !           354:         // Without immediate mode some architectures (e.g. Linux with
        !           355:         // TPACKET_V3) will buffer replies and incorrectly upwards of
        !           356:         // hundreds of milliseconds of delay.
        !           357:         if ((rc = pcap_set_immediate_mode(pcap, 1))) {
        !           358:                 if (verbose) {
        !           359:                         fprintf(stderr, "arping: pcap_set_immediate_mode() failed: %s\n", pcap_statustostr(rc));
        !           360:                 }
        !           361:         }
        !           362: #endif
        !           363: #ifdef HAVE_PCAP_LIST_TSTAMP_TYPES
        !           364:         if (timestamp_type) {
        !           365:                 int err;
        !           366:                 int v = pcap_tstamp_type_name_to_val(timestamp_type);
        !           367:                 if (v == PCAP_ERROR) {
        !           368:                         fprintf(stderr, "arping: Unknown timestamp type \"%s\"\n", timestamp_type);
        !           369:                         exit(1);
        !           370:                 }
        !           371:                 if ((err = pcap_set_tstamp_type(pcap, v))) {
        !           372:                         fprintf(stderr,
        !           373:                                 "arping: Failed to set timestamp type \"%s\" (%d): %s\n",
        !           374:                                 timestamp_type, v, pcap_statustostr(err));
        !           375:                 }
        !           376:         }
        !           377: #endif
        !           378:         if ((rc = pcap_activate(pcap))) {
        !           379:                 if (timestamp_type) {
        !           380:                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_activate(tstype=\"%s\"): %s. Try without setting timestamp type.", timestamp_type, pcap_statustostr(rc));
        !           381:                 } else {
        !           382:                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_activate(): %s", pcap_statustostr(rc));
        !           383:                 }
        !           384:                 goto err;
        !           385:         }
        !           386: #ifdef HAVE_PCAP_LIST_TSTAMP_TYPES
        !           387:         // List timestamp types after activating, since we don't want to list
        !           388:         // them if activating failed.
        !           389:         if (verbose > 1) {
        !           390:                 int *ts;
        !           391:                 int count;
        !           392:                 count = pcap_list_tstamp_types(pcap, &ts);
        !           393:                 if (count == PCAP_ERROR) {
        !           394:                         fprintf(stderr, "arping: pcap_list_tstamp_types() failed\n");
        !           395:                 } else {
        !           396:                         int c;
        !           397:                         const char* fmt = "  %-18s %s\n";
        !           398:                         fprintf(stderr, "Timestamp types:\n");
        !           399:                         fprintf(stderr, fmt, "Name", "Description");
        !           400:                         for (c = 0; c < count; c++) {
        !           401:                                 fprintf(stderr, fmt, pcap_tstamp_type_val_to_name(ts[c]),
        !           402:                                         pcap_tstamp_type_val_to_description(ts[c]));
        !           403:                         }
        !           404:                         pcap_free_tstamp_types(ts);
        !           405:                 }
        !           406:         }
        !           407: #endif
        !           408:         return pcap;
        !           409: err:
        !           410:         if (pcap) {
        !           411:                 pcap_close(pcap);
        !           412:         }
        !           413:         return NULL;
        !           414: #else
        !           415:         return pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
        !           416: #endif
        !           417: }
        !           418: 
        !           419: /**
1.1.1.2   misho     420:  * Some stupid OSs (Solaris) think it's a good idea to put network
                    421:  * devices in /dev and then play musical chairs with them.
                    422:  *
                    423:  * Since libpcap doesn't seem to have a workaround for that, here's arpings
                    424:  * workaround.
                    425:  *
                    426:  * E.g. if the network interface is called net0, pcap will fail because it
                    427:  * fails to open /dev/net, because it's a directory.
                    428:  */
                    429: static pcap_t*
                    430: do_pcap_open_live(const char *device, int snaplen,
                    431:                   int promisc, int to_ms, char *errbuf)
                    432: {
                    433:         pcap_t* ret;
                    434:         char buf[PATH_MAX];
                    435: 
1.1.1.3 ! misho     436:         if ((ret = try_pcap_open_live(device, snaplen, promisc, to_ms, errbuf))) {
1.1.1.2   misho     437:                 return ret;
                    438:         }
                    439: 
                    440:         snprintf(buf, sizeof(buf), "/dev/%s", device);
1.1.1.3 ! misho     441:         if ((ret = try_pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
1.1.1.2   misho     442:                 return ret;
                    443:         }
                    444: 
                    445:         snprintf(buf, sizeof(buf), "/dev/net/%s", device);
1.1.1.3 ! misho     446:         if ((ret = try_pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
1.1.1.2   misho     447:                 return ret;
                    448:         }
                    449: 
                    450:         /* Call original again to reset the error message. */
1.1.1.3 ! misho     451:         return try_pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
1.1.1.2   misho     452: }
1.1       misho     453: 
                    454: /**
1.1.1.3 ! misho     455:  * Some Libnet error messages end with a newline. Strip that in place.
1.1       misho     456:  */
1.1.1.3 ! misho     457: void
        !           458: strip_newline(char* s) {
        !           459:         if (!*s) {
        !           460:                 return;
        !           461:         }
        !           462:         size_t n;
        !           463:         for (n = strlen(s); s[n - 1] == '\n'; --n) {
        !           464:                 s[n - 1] = 0;
1.1       misho     465:         }
                    466: }
                    467: 
                    468: /**
1.1.1.2   misho     469:  * Init libnet with specified ifname. Destroy if already inited.
1.1.1.3 ! misho     470:  * If this function retries with different parameter it will preserve
        !           471:  * the original error message and print that.
        !           472:  * Call with recursive=0.
1.1.1.2   misho     473:  */
1.1       misho     474: void
1.1.1.3 ! misho     475: do_libnet_init(const char *ifname, int recursive)
1.1       misho     476: {
                    477:        char ebuf[LIBNET_ERRBUF_SIZE];
1.1.1.3 ! misho     478:         ebuf[0] = 0;
1.1       misho     479:        if (verbose > 1) {
1.1.1.3 ! misho     480:                 printf("arping: libnet_init(%s)\n", ifname ? ifname : "<null>");
1.1       misho     481:        }
                    482:        if (libnet) {
1.1.1.2   misho     483:                /* Probably going to switch interface from temp to real. */
1.1       misho     484:                libnet_destroy(libnet);
                    485:                libnet = 0;
                    486:        }
                    487: 
1.1.1.2   misho     488:         /* Try libnet_init() even though we aren't root. We may have
                    489:          * a capability or something. */
1.1       misho     490:        if (!(libnet = libnet_init(LIBNET_LINK,
                    491:                                   (char*)ifname,
                    492:                                   ebuf))) {
1.1.1.3 ! misho     493:                 strip_newline(ebuf);
        !           494:                 if (!ifname) {
        !           495:                         /* Sometimes libnet guesses an interface that it then
        !           496:                          * can't use. Work around that by attempting to
        !           497:                          * use "lo". */
        !           498:                         return do_libnet_init("lo", 1);
        !           499:                 } else if (recursive) {
        !           500:                         /* Continue original execution. */
        !           501:                         return;
        !           502:                 }
        !           503:                 fprintf(stderr, "arping: libnet_init(LIBNET_LINK, %s): %s\n",
        !           504:                         ifname ? ifname : "<null>", ebuf);
1.1.1.2   misho     505:                 if (getuid() && geteuid()) {
                    506:                         fprintf(stderr,
                    507:                                 "arping: you may need to run as root\n");
                    508:                 }
1.1       misho     509:                exit(1);
                    510:        }
                    511: }
                    512: 
                    513: /**
                    514:  *
                    515:  */
1.1.1.2   misho     516: void
                    517: sigint(int i)
1.1       misho     518: {
                    519:        time_to_die = 1;
                    520: }
                    521: 
                    522: /**
1.1.1.2   misho     523:  * idiot-proof clock_gettime() wrapper
1.1       misho     524:  */
1.1.1.2   misho     525: static void
                    526: getclock(struct timespec *ts)
1.1       misho     527: {
1.1.1.2   misho     528: #if HAVE_CLOCK_MONOTONIC
                    529:         if (-1 == clock_gettime(CLOCK_MONOTONIC, ts)) {
                    530:                 fprintf(stderr,
                    531:                         "arping: clock_gettime(): %s\n",
                    532:                         strerror(errno));
                    533:                 sigint(0);
                    534:         }
                    535: #else
                    536:         struct timeval tv;
                    537:         if (-1 == gettimeofday(&tv, NULL)) {
                    538:                 fprintf(stderr, "arping: gettimeofday(): %s\n",
                    539:                         strerror(errno));
                    540:                 sigint(0);
                    541:         }
                    542:         ts->tv_sec = tv.tv_sec;
                    543:         ts->tv_nsec = tv.tv_usec * 1000;
                    544: #endif
1.1       misho     545: }
                    546: 
                    547: /**
                    548:  *
                    549:  */
1.1.1.3 ! misho     550: static char*
        !           551: format_mac(unsigned char* mac, char* buf, size_t bufsize) {
        !           552:         snprintf(buf, bufsize, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
        !           553:                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
        !           554:         return buf;
        !           555: }
        !           556: 
        !           557: /**
        !           558:  *
        !           559:  */
1.1       misho     560: static void
                    561: extended_usage()
                    562: {
                    563:        printf("\nOptions:\n");
                    564:        printf("\n"
                    565:               "    -0     Use this option to ping with source IP address 0.0.0.0. Use this\n"
                    566:               "           when you haven't configured your interface yet.  Note that  this\n"
                    567:               "           may  get  the  MAC-ping  unanswered.   This  is  an alias for -S\n"
                    568:               "           0.0.0.0.\n"
                    569:               "    -a     Audiable ping.\n"
                    570:               "    -A     Only count addresses matching  requested  address  (This  *WILL*\n"
                    571:               "           break  most things you do. Only useful if you are arpinging many\n"
                    572:               "           hosts at once. See arping-scan-net.sh for an example).\n"
                    573:               "    -b     Like -0 but source broadcast source  address  (255.255.255.255).\n"
                    574:               "           Note that this may get the arping unanswered since it's not nor-\n"
                    575:               "           mal behavior for a host.\n"
                    576:               "    -B     Use instead of host if you want to address 255.255.255.255.\n"
                    577:               "    -c count\n"
                    578:               "           Only send count requests.\n"
1.1.1.3 ! misho     579:                "    -C count\n"
        !           580:                "           Only wait for this many replies, regardless of -c and -w.\n"
1.1       misho     581:               "    -d     Find duplicate replies. Exit with 1 if there are "
                    582:                "answers from\n"
                    583:                "           two different MAC addresses.\n"
1.1.1.2   misho     584:               "    -D     Display answers as exclamation points and missing packets as dots.\n"
1.1       misho     585:                "    -e     Like -a but beep when there is no reply.\n"
                    586:               "    -F     Don't try to be smart about the interface name.  (even  if  this\n"
                    587:               "           switch is not given, -i overrides smartness)\n"
                    588:               "    -h     Displays a help message and exits.\n"
                    589:               "    -i interface\n"
                    590:               "           Use the specified interface.\n"
1.1.1.3 ! misho     591:                "    -m type"
        !           592: #ifndef HAVE_PCAP_LIST_TSTAMP_TYPES
        !           593:                " (Disabled on this system. Option ignored)"
        !           594: #endif
        !           595:                "\n           Type of timestamp to use for incoming packets. Use -vv when\n"
        !           596:                "           pinging to list available ones.\n"
1.1       misho     597:               "    -q     Does not display messages, except error messages.\n"
                    598:               "    -r     Raw output: only the MAC/IP address is displayed for each reply.\n"
                    599:               "    -R     Raw output: Like -r but shows \"the other one\", can  be  combined\n"
                    600:               "           with -r.\n"
                    601:               "    -s MAC Set source MAC address. You may need to use -p with this.\n"
                    602:               "    -S IP  Like  -b and -0 but with set source address.  Note that this may\n"
1.1.1.3 ! misho     603:               "           get the arping unanswered if the target does not have routing to\n"
1.1       misho     604:               "           the  IP.  If you don't own the IP you are using, you may need to\n"
                    605:               "           turn on promiscious mode on the interface (with -p).  With  this\n"
                    606:               "           switch  you can find out what IP-address a host has without tak-\n"
                    607:               "           ing an IP-address yourself.\n"
                    608:               "    -t MAC Set target MAC address to use when pinging IP address.\n"
                    609:               "    -T IP  Use -T as target address when pinging MACs that won't respond to\n"
                    610:               "           a broadcast ping but perhaps to a directed broadcast.\n"
                    611:               "           Example:\n"
                    612:               "           To check the address of MAC-A, use knowledge of MAC-B and  IP-B.\n"
                    613:               "           $ arping -S <IP-B> -s <MAC-B> -p <MAC-A>\n"
                    614:               "    -p     Turn  on  promiscious  mode  on interface, use this if you don't\n"
                    615:               "           \"own\" the MAC address you are using.\n"
1.1.1.3 ! misho     616:                "    -P     Send ARP replies instead of requests. Useful with -U.\n"
1.1       misho     617:               "    -u     Show index=received/sent instead  of  just  index=received  when\n"
                    618:               "           pinging MACs.\n"
1.1.1.2   misho     619:               "    -U     Send unsolicited ARP.\n"
1.1       misho     620:               "    -v     Verbose output. Use twice for more messages.\n"
1.1.1.3 ! misho     621:                "    -w     Time to wait between pings, in microseconds.\n"
        !           622:                "    -W     Same as -w, but in floating point seconds.\n");
1.1.1.2   misho     623:         printf("Report bugs to: thomas@habets.se\n"
1.1       misho     624:                "Arping home page: <http://www.habets.pp.se/synscan/>\n"
                    625:                "Development repo: http://github.com/ThomasHabets/arping\n");
                    626: }
                    627: 
                    628: /**
                    629:  *
                    630:  */
                    631: static void
                    632: standard_usage()
                    633: {
1.1.1.2   misho     634:        printf("ARPing %s, by Thomas Habets <thomas@habets.se>\n",
1.1       misho     635:               version);
1.1.1.3 ! misho     636:         printf("usage: arping [ -0aAbdDeFpPqrRuUv ] [ -w <us> ] "
        !           637:                "[ -W <sec> ] "
1.1       misho     638:                "[ -S <host/ip> ]\n"
                    639:                "              "
                    640:                "[ -T <host/ip ] "
                    641:                "[ -s <MAC> ] [ -t <MAC> ] [ -c <count> ]\n"
                    642:                "              "
1.1.1.3 ! misho     643:                "[ -C <count> ] [ -i <interface> ] [ -m <type> ] "
1.1       misho     644:                "<host/ip/MAC | -B>\n");
                    645: }
                    646: 
                    647: /**
                    648:  *
                    649:  */
                    650: static void
                    651: usage(int ret)
                    652: {
                    653:         standard_usage();
                    654:         if (WIN32) {
                    655:                 extended_usage();
                    656:         } else {
                    657:                 printf("For complete usage info, use --help"
                    658:                        " or check the manpage.\n");
                    659:         }
                    660:        exit(ret);
                    661: }
                    662: 
                    663: /**
                    664:  * It was unclear from msdn.microsoft.com if their scanf() supported
                    665:  * [0-9a-fA-F], so I'll stay away from it.
                    666:  */
                    667: static int is_mac_addr(const char *p)
                    668: {
                    669:        /* cisco-style */
                    670:        if (3*5-1 == strlen(p)) {
                    671:                unsigned int c;
                    672:                for (c = 0; c < strlen(p); c++) {
                    673:                        if ((c % 5) == 4) {
                    674:                                if ('.' != p[c]) {
                    675:                                        goto checkcolon;
                    676:                                }
                    677:                        } else {
                    678:                                if (!isxdigit(p[c])) {
                    679:                                        goto checkcolon;
                    680:                                }
                    681:                        }
                    682:                }
                    683:                return 1;
                    684:        }
                    685:        /* windows-style */
                    686:        if (6*3-1 == strlen(p)) {
                    687:                unsigned int c;
                    688:                for (c = 0; c < strlen(p); c++) {
                    689:                        if ((c % 3) == 2) {
                    690:                                if ('-' != p[c]) {
                    691:                                        goto checkcolon;
                    692:                                }
                    693:                        } else {
                    694:                                if (!isxdigit(p[c])) {
                    695:                                        goto checkcolon;
                    696:                                }
                    697:                        }
                    698:                }
                    699:                return 1;
                    700:        }
                    701: 
                    702:  checkcolon:
                    703:        /* unix */
                    704:        return strchr(p, ':') ? 1 : 0;
                    705: }
                    706: 
                    707: /**
                    708:  * lots of parms since C arrays suck
                    709:  */
                    710: static int get_mac_addr(const char *in,
                    711:                        unsigned int *n0,
                    712:                        unsigned int *n1,
                    713:                        unsigned int *n2,
                    714:                        unsigned int *n3,
                    715:                        unsigned int *n4,
                    716:                        unsigned int *n5)
                    717: {
                    718:        if (6 == sscanf(in, "%x:%x:%x:%x:%x:%x",n0,n1,n2,n3,n4,n5)) {
                    719:                return 1;
                    720:        } else if(6 == sscanf(in, "%2x%x.%2x%x.%2x%x",n0,n1,n2,n3,n4,n5)) {
                    721:                return 1;
                    722:        } else if(6 == sscanf(in, "%x-%x-%x-%x-%x-%x",n0,n1,n2,n3,n4,n5)) {
                    723:                return 1;
                    724:        }
                    725:        return 0;
                    726: }
                    727: 
                    728: /**
                    729:  *
1.1.1.2   misho     730:  */
                    731: static void
                    732: update_stats(double sample)
                    733: {
                    734:         if (stats_min_time < 0 || sample < stats_min_time) {
                    735:                 stats_min_time = sample;
                    736:         }
                    737:         if (sample > stats_max_time) {
                    738:                 stats_max_time = sample;
                    739:         }
                    740:         stats_total_time += sample;
                    741:         stats_total_sq_time += sample * sample;
                    742: }
                    743: 
                    744: /**
                    745:  *
                    746:  */
                    747: static double
                    748: timespec2dbl(const struct timespec *tv)
                    749: {
                    750:         return tv->tv_sec + (double)tv->tv_nsec / 1000000000;
                    751: }
                    752: 
                    753: /**
                    754:  * max size of buffer is intsize + 1 + intsize + 4 = 70 bytes or so
1.1       misho     755:  *
                    756:  * Still, I'm using at least 128bytes below
                    757:  */
1.1.1.2   misho     758: static char *ts2str(const struct timespec *tv, const struct timespec *tv2,
1.1.1.3 ! misho     759:                     char *buf, size_t bufsize)
1.1       misho     760: {
                    761:        double f,f2;
                    762:        int exp = 0;
                    763: 
1.1.1.2   misho     764:         f = timespec2dbl(tv);
                    765:         f2 = timespec2dbl(tv2);
                    766:        f = (f2 - f) * 1000000000;
1.1       misho     767:        while (f > 1000) {
1.1.1.2   misho     768:                exp += 3;
1.1       misho     769:                f /= 1000;
                    770:        }
                    771:        switch (exp) {
                    772:        case 0:
1.1.1.3 ! misho     773:                 snprintf(buf, bufsize, "%.3f nsec", f);
1.1       misho     774:                break;
                    775:        case 3:
1.1.1.3 ! misho     776:                 snprintf(buf, bufsize, "%.3f usec", f);
1.1       misho     777:                break;
                    778:        case 6:
1.1.1.3 ! misho     779:                 snprintf(buf, bufsize, "%.3f msec", f);
1.1       misho     780:                break;
                    781:        case 9:
1.1.1.3 ! misho     782:                 snprintf(buf, bufsize, "%.3f sec", f);
1.1.1.2   misho     783:                break;
                    784:        case 12:
1.1.1.3 ! misho     785:                 snprintf(buf, bufsize, "%.3f sec", f*1000);
1.1       misho     786:                break;
                    787:         default:
                    788:                /* huh, uh, huhuh */
1.1.1.3 ! misho     789:                 snprintf(buf, bufsize, "%.3fe%d sec", f, exp-9);
1.1       misho     790:        }
                    791:        return buf;
                    792: }
                    793: 
                    794: 
                    795: 
                    796: /** Send directed IPv4 ICMP echo request.
                    797:  *
                    798:  * \param id      IP id
                    799:  * \param seq     Ping seq
                    800:  */
                    801: static void
1.1.1.2   misho     802: pingmac_send(uint16_t id, uint16_t seq)
1.1       misho     803: {
                    804:        static libnet_ptag_t icmp = 0, ipv4 = 0,eth=0;
                    805:        int c;
                    806: 
                    807:        if (-1 == (icmp = libnet_build_icmpv4_echo(ICMP_ECHO, /* type */
                    808:                                                   0, /* code */
                    809:                                                   0, /* checksum */
                    810:                                                   id, /* id */
                    811:                                                   seq, /* seq */
                    812:                                                   NULL, /* payload */
                    813:                                                   0, /* payload len */
                    814:                                                   libnet,
                    815:                                                   icmp))) {
                    816:                fprintf(stderr, "libnet_build_icmpv4_echo(): %s\n",
                    817:                        libnet_geterror(libnet));
                    818:                sigint(0);
                    819:        }
                    820: 
                    821:        if (-1==(ipv4 = libnet_build_ipv4(LIBNET_IPV4_H
                    822:                                          + LIBNET_ICMPV4_ECHO_H + 0,
                    823:                                          0, /* ToS */
                    824:                                          id, /* id */
                    825:                                          0, /* frag */
                    826:                                          64, /* ttl */
                    827:                                          IPPROTO_ICMP,
                    828:                                          0, /* checksum */
                    829:                                          srcip,
                    830:                                          dstip,
                    831:                                          NULL, /* payload */
                    832:                                          0,
                    833:                                          libnet,
                    834:                                          ipv4))) {
                    835:                fprintf(stderr, "libnet_build_ipv4(): %s\n",
                    836:                        libnet_geterror(libnet));
                    837:                sigint(0);
                    838:        }
                    839:        if (-1 == (eth = libnet_build_ethernet(dstmac,
                    840:                                               srcmac,
                    841:                                               ETHERTYPE_IP,
                    842:                                               NULL,
                    843:                                               0,
                    844:                                               libnet,
                    845:                                               eth))) {
                    846:                fprintf(stderr, "libnet_build_ethernet(): %s\n",
                    847:                        libnet_geterror(libnet));
                    848:                sigint(0);
                    849:        }
1.1.1.2   misho     850:        if (verbose > 1) {
                    851:                 getclock(&lastpacketsent);
                    852:                 printf("arping: sending packet at time %ld.%09ld\n",
                    853:                        (long)lastpacketsent.tv_sec,
                    854:                        (long)lastpacketsent.tv_nsec);
1.1       misho     855:        }
                    856:        if (-1 == (c = libnet_write(libnet))) {
                    857:                fprintf(stderr, "arping: libnet_write(): %s\n",
                    858:                        libnet_geterror(libnet));
                    859:                sigint(0);
                    860:        }
1.1.1.2   misho     861:         getclock(&lastpacketsent);
1.1       misho     862:        numsent++;
                    863: }
                    864: 
                    865: /** Send ARP who-has.
                    866:  *
                    867:  */
                    868: static void
1.1.1.2   misho     869: pingip_send()
1.1       misho     870: {
                    871:        static libnet_ptag_t arp=0,eth=0;
                    872:        if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER,
                    873:                                          ETHERTYPE_IP,
                    874:                                          ETH_ALEN,
                    875:                                          IP_ALEN,
1.1.1.3 ! misho     876:                                           send_reply ? ARPOP_REPLY : ARPOP_REQUEST,
1.1       misho     877:                                          srcmac,
                    878:                                          (uint8_t*)&srcip,
1.1.1.2   misho     879:                                          unsolicited ? (uint8_t*)ethxmas : (uint8_t*)ethnull,
1.1       misho     880:                                          (uint8_t*)&dstip,
                    881:                                          NULL,
                    882:                                          0,
                    883:                                          libnet,
                    884:                                          arp))) {
                    885:                fprintf(stderr, "arping: libnet_build_arp(): %s\n",
                    886:                        libnet_geterror(libnet));
                    887:                sigint(0);
                    888:        }
                    889:        if (-1 == (eth = libnet_build_ethernet(dstmac,
                    890:                                               srcmac,
                    891:                                               ETHERTYPE_ARP,
                    892:                                               NULL,
                    893:                                               0,
                    894:                                               libnet,
                    895:                                               eth))) {
                    896:                fprintf(stderr, "arping: libnet_build_ethernet(): %s\n",
                    897:                        libnet_geterror(libnet));
                    898:                sigint(0);
                    899:        }
1.1.1.2   misho     900:        if (verbose > 1) {
                    901:                 getclock(&lastpacketsent);
                    902:                 printf("arping: sending packet at time %ld.%09ld\n",
                    903:                        (long)lastpacketsent.tv_sec,
                    904:                        (long)lastpacketsent.tv_nsec);
1.1       misho     905:        }
                    906:        if (-1 == libnet_write(libnet)) {
                    907:                fprintf(stderr, "arping: libnet_write(): %s\n", 
                    908:                        libnet_geterror(libnet));
                    909:                sigint(0);
                    910:        }
1.1.1.2   misho     911:         getclock(&lastpacketsent);
1.1       misho     912:        numsent++;
                    913: }
                    914: 
                    915: /** handle incoming packet when pinging an IP address.
                    916:  *
                    917:  * \param h       packet metadata
                    918:  * \param packet  packet data
                    919:  */
                    920: static void
1.1.1.2   misho     921: pingip_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet)
1.1       misho     922: {
                    923:        struct libnet_802_3_hdr *heth;
                    924:        struct libnet_arp_hdr *harp;
1.1.1.2   misho     925:         struct timespec arrival;
1.1       misho     926:        int c;
                    927: 
1.1.1.2   misho     928:         if (verbose > 2) {
1.1.1.3 ! misho     929:                printf("arping: received response for IP ping\n");
1.1       misho     930:        }
                    931: 
1.1.1.2   misho     932:         getclock(&arrival);
                    933: 
1.1       misho     934:        heth = (void*)packet;
                    935:        harp = (void*)((char*)heth + LIBNET_ETH_H);
                    936: 
1.1.1.3 ! misho     937:         // ARP reply.
        !           938:         if (htons(harp->ar_op) != ARPOP_REPLY) {
        !           939:                 return;
        !           940:         }
        !           941:         if (verbose > 3) {
        !           942:                 printf("arping: ... packet is ARP reply\n");
        !           943:         }
1.1       misho     944: 
1.1.1.3 ! misho     945:         // From IPv4 address reply.
        !           946:         if (htons(harp->ar_pro) != ETHERTYPE_IP) {
        !           947:                 return;
        !           948:         }
        !           949:         if (verbose > 3) {
        !           950:                 printf("arping: ... from IPv4 address\n");
        !           951:         }
1.1       misho     952: 
1.1.1.3 ! misho     953:         // To Ethernet address.
        !           954:         if (htons(harp->ar_hrd) != ARPHRD_ETHER) {
        !           955:                 return;
        !           956:         }
        !           957:         if (verbose > 3) {
        !           958:                 printf("arping: ... to Ethernet address\n");
        !           959:         }
        !           960: 
        !           961:         // Must be sent from target address.
        !           962:         // Should very likely only be used if using -T.
        !           963:         if (addr_must_be_same) {
        !           964:                 if (memcmp((u_char*)harp + sizeof(struct libnet_arp_hdr),
        !           965:                            dstmac, ETH_ALEN)) {
        !           966:                         return;
        !           967:                 }
        !           968:         }
        !           969:         if (verbose > 3) {
        !           970:                 printf("arping: ... sent by acceptable host\n");
        !           971:         }
        !           972: 
        !           973:         // Actually the IPv4 address we asked for.
        !           974:         uint32_t ip;
        !           975:         memcpy(&ip, (char*)harp + harp->ar_hln + LIBNET_ARP_H, 4);
        !           976:         if (dstip != ip) {
        !           977:                 return;
        !           978:         }
        !           979:         if (verbose > 3) {
        !           980:                 printf("arping: ... for the right IPv4 address!\n");
        !           981:         }
        !           982: 
        !           983:         update_stats(timespec2dbl(&arrival) - timespec2dbl(&lastpacketsent));
        !           984:         char buf[128];
        !           985:         if (beep) {
        !           986:                 printf("\a");
        !           987:         }
        !           988:         switch(display) {
        !           989:         case DOT:
        !           990:                 putchar('!');
        !           991:                 break;
        !           992:         case NORMAL:
        !           993:                 printf("%d bytes from %s (%s): index=%d",
        !           994:                        h->len, format_mac(heth->_802_3_shost,
        !           995:                                           buf, sizeof(buf)),
        !           996:                        libnet_addr2name4(ip, 0), numrecvd);
        !           997: 
        !           998:                 if (alsototal) {
        !           999:                         printf("/%u", numsent-1);
        !          1000:                 }
        !          1001:                 printf(" time=%s", ts2str(&lastpacketsent, &arrival, buf,
        !          1002:                                           sizeof(buf)));
        !          1003:                 break;
        !          1004:         case QUIET:
        !          1005:                 break;
        !          1006:         case RAWRAW:
        !          1007:                 printf("%s %s", format_mac(heth->_802_3_shost,
        !          1008:                                            buf, sizeof(buf)),
        !          1009:                        libnet_addr2name4(ip, 0));
        !          1010:                 break;
        !          1011:         case RRAW:
        !          1012:                 printf("%s", libnet_addr2name4(ip, 0));
        !          1013:                 break;
        !          1014:         case RAW:
        !          1015:                 printf("%s", format_mac(heth->_802_3_shost,
        !          1016:                                         buf, sizeof(buf)));
        !          1017:                 break;
        !          1018:         default:
        !          1019:                 fprintf(stderr, "arping: can't happen!\n");
        !          1020:         }
        !          1021:         fflush(stdout);
        !          1022: 
        !          1023:         switch (display) {
        !          1024:         case QUIET:
        !          1025:         case DOT:
        !          1026:                 break;
        !          1027:         default:
        !          1028:                 printf("\n");
        !          1029:         }
        !          1030:         if (numrecvd) {
        !          1031:                 if (memcmp(lastreplymac,
        !          1032:                            heth->_802_3_shost, ETH_ALEN)) {
        !          1033:                         dupfound = 1;
        !          1034:                 }
        !          1035:         }
        !          1036:         memcpy(lastreplymac, heth->_802_3_shost, ETH_ALEN);
        !          1037: 
        !          1038:         numrecvd++;
        !          1039:         if (numrecvd >= max_replies) {
        !          1040:                 sigint(0);
        !          1041:         }
1.1       misho    1042: }
                   1043: 
                   1044: /** handle incoming packet when pinging an MAC address.
                   1045:  *
                   1046:  * \param h       packet metadata
                   1047:  * \param packet  packet data
                   1048:  */
                   1049: static void
1.1.1.2   misho    1050: pingmac_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet)
1.1       misho    1051: {
                   1052:        struct libnet_802_3_hdr *heth;
                   1053:        struct libnet_ipv4_hdr *hip;
                   1054:        struct libnet_icmpv4_hdr *hicmp;
1.1.1.2   misho    1055:         struct timespec arrival;
1.1       misho    1056:        int c;
                   1057: 
                   1058:        if(verbose>2) {
                   1059:                printf("arping: received response for mac ping\n");
                   1060:        }
                   1061: 
1.1.1.2   misho    1062:         getclock(&arrival);
1.1       misho    1063: 
                   1064:        heth = (void*)packet;
                   1065:        hip = (void*)((char*)heth + LIBNET_ETH_H);
                   1066:        hicmp = (void*)((char*)hip + LIBNET_IPV4_H);
                   1067: 
1.1.1.3 ! misho    1068:         // Dest MAC must be me.
        !          1069:         if (memcmp(heth->_802_3_dhost, srcmac, ETH_ALEN)) {
        !          1070:                 return;
        !          1071:         }
        !          1072: 
        !          1073:         // Source MAC must match, if set.
        !          1074:         if (memcmp(dstmac, ethxmas, ETH_ALEN)) {
        !          1075:                 if (memcmp(heth->_802_3_shost, dstmac, ETH_ALEN)) {
        !          1076:                         return;
        !          1077:                 }
        !          1078:         }
        !          1079: 
        !          1080:         // IPv4 Address must be me (maybe).
        !          1081:         if (addr_must_be_same) {
        !          1082:                 uint32_t tmp;
        !          1083:                 memcpy(&tmp, &hip->ip_src, 4);
        !          1084:                 if (dstip != tmp) {
        !          1085:                         return;
        !          1086:                 }
        !          1087:         }
        !          1088: 
        !          1089:         // Must be ICMP echo reply.
        !          1090:         if (htons(hicmp->icmp_type) != ICMP_ECHOREPLY) {
        !          1091:                 return;
        !          1092:         }
        !          1093: 
        !          1094:         update_stats(timespec2dbl(&arrival) - timespec2dbl(&lastpacketsent));
        !          1095:         if (beep) {
        !          1096:                 printf("\a");
        !          1097:         }
        !          1098:         char buf[128];
        !          1099:         char buf2[128];
        !          1100:         switch(display) {
        !          1101:         case QUIET:
        !          1102:                 break;
        !          1103:         case DOT:
        !          1104:                 putchar('!');
        !          1105:                 break;
        !          1106:         case NORMAL:
        !          1107:                 printf("%d bytes from %s (%s): icmp_seq=%d time=%s", h->len,
        !          1108:                        libnet_addr2name4(*(int*)&hip->ip_src, 0),
        !          1109:                        format_mac(heth->_802_3_shost, buf, sizeof(buf)),
        !          1110:                        htons(hicmp->icmp_seq),
        !          1111:                        ts2str(&lastpacketsent, &arrival, buf2, sizeof(buf2)));
        !          1112:                 break;
        !          1113:         case RAW:
        !          1114:                 printf("%s", libnet_addr2name4(hip->ip_src.s_addr, 0));
        !          1115:                 break;
        !          1116:         case RRAW:
        !          1117:                 printf("%s", format_mac(heth->_802_3_shost, buf, sizeof(buf)));
        !          1118:                 break;
        !          1119:         case RAWRAW:
        !          1120:                 printf("%s %s",
        !          1121:                        format_mac(heth->_802_3_shost, buf, sizeof(buf)),
        !          1122:                        libnet_addr2name4(hip->ip_src.s_addr, 0));
        !          1123:                 break;
        !          1124:         default:
        !          1125:                 fprintf(stderr, "arping: can't-happen-bug\n");
        !          1126:                 sigint(0);
        !          1127:         }
        !          1128:         fflush(stdout);
        !          1129:         switch (display) {
        !          1130:         case QUIET:
        !          1131:         case DOT:
        !          1132:                 break;
        !          1133:         default:
        !          1134:                 printf("\n");
        !          1135:         }
        !          1136:         numrecvd++;
        !          1137:         if (numrecvd >= max_replies) {
        !          1138:                 sigint(0);
        !          1139:         }
1.1       misho    1140: }
                   1141: 
                   1142: /**
1.1.1.2   misho    1143:  * while negative nanoseconds, take from whole seconds.
1.1       misho    1144:  * help function for measuring deltas.
                   1145:  */
                   1146: static void
1.1.1.2   misho    1147: fixup_timespec(struct timespec *tv)
1.1       misho    1148: {
1.1.1.2   misho    1149:        while (tv->tv_nsec < 0) {
1.1       misho    1150:                tv->tv_sec--;
1.1.1.2   misho    1151:                tv->tv_nsec += 1000000000;
1.1       misho    1152:        }
                   1153: }
                   1154: 
                   1155: /**
1.1.1.2   misho    1156:  * try to receive a packet for 'packetwait' microseconds
1.1       misho    1157:  */
                   1158: static void
1.1.1.2   misho    1159: ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_handler func)
1.1       misho    1160: {
1.1.1.2   misho    1161:        struct timespec ts;
                   1162:        struct timespec endtime;
1.1       misho    1163:        char done = 0;
1.1.1.2   misho    1164:        int fd;
                   1165:        int old_received;
1.1       misho    1166: 
1.1.1.2   misho    1167:        if (verbose > 3) {
                   1168:                printf("arping: receiving packets...\n");
                   1169:        }
1.1       misho    1170: 
1.1.1.2   misho    1171:        getclock(&ts);
                   1172:        endtime.tv_sec = ts.tv_sec + (packetwait / 1000000);
                   1173:        endtime.tv_nsec = ts.tv_nsec + 1000 * (packetwait % 1000000);
                   1174:        fixup_timespec(&endtime);
1.1       misho    1175: 
                   1176:        fd = pcap_get_selectable_fd(pcap);
1.1.1.2   misho    1177:        old_received = numrecvd;
1.1       misho    1178: 
                   1179:        for (;!done;) {
                   1180:               int trydispatch = 0;
                   1181: 
1.1.1.2   misho    1182:               getclock(&ts);
                   1183:               ts.tv_sec = endtime.tv_sec - ts.tv_sec;
                   1184:               ts.tv_nsec = endtime.tv_nsec - ts.tv_nsec;
                   1185:               fixup_timespec(&ts);
                   1186:                if (verbose > 2) {
1.1.1.3 ! misho    1187:                        printf("arping: listen for replies for %ld.%09ld sec\n",
1.1.1.2   misho    1188:                               (long)ts.tv_sec, (long)ts.tv_nsec);
                   1189:                }
                   1190: 
                   1191:                /* if time has passed, do one last check and then we're done.
                   1192:                 * this also triggers if not using monotonic clock and time
                   1193:                 * is set forwards */
                   1194:               if (ts.tv_sec < 0) {
                   1195:                       ts.tv_sec = 0;
                   1196:                       ts.tv_nsec = 1;
1.1       misho    1197:                       done = 1;
                   1198:               }
1.1.1.2   misho    1199: 
                   1200:                /* if wait-for-packet time is longer than full period,
                   1201:                 * we're obviously not using a monotonic clock and the system
                   1202:                 * time has been changed.
                   1203:                 * we don't know how far we're into the waiting, so just end
                   1204:                 * it here */
                   1205:                if ((ts.tv_sec > packetwait / 1000000)
                   1206:                    || ((ts.tv_sec == packetwait / 1000000)
                   1207:                        && (ts.tv_nsec/1000 > packetwait % 1000000))) {
                   1208:                       ts.tv_sec = 0;
                   1209:                       ts.tv_nsec = 1;
                   1210:                        done = 1;
                   1211:                }
                   1212: 
                   1213:                /* check for sigint */
1.1       misho    1214:               if (time_to_die) {
                   1215:                       return;
                   1216:               }
                   1217: 
                   1218:               /* try to wait for data */
                   1219:               {
1.1.1.2   misho    1220:                        fd_set fds;
1.1       misho    1221:                       int r;
1.1.1.2   misho    1222:                        struct timeval tv;
                   1223:                        tv.tv_sec = ts.tv_sec;
                   1224:                        tv.tv_usec = ts.tv_nsec / 1000;
                   1225: 
                   1226:                        FD_ZERO(&fds);
                   1227:                        FD_SET(fd, &fds);
1.1       misho    1228: 
1.1.1.2   misho    1229:                        r = select(fd + 1, &fds, NULL, NULL, &tv);
1.1       misho    1230:                       switch (r) {
                   1231:                       case 0: /* timeout */
1.1.1.3 ! misho    1232:                                if (numrecvd == old_received) {
        !          1233:                                        if (reverse_beep) {
        !          1234:                                                printf("\a");
        !          1235:                                        }
        !          1236:                                        switch (display) {
        !          1237:                                        case NORMAL:
1.1.1.2   misho    1238:                                                printf("Timeout\n");
1.1.1.3 ! misho    1239:                                                break;
        !          1240:                                        case DOT:
        !          1241:                                                printf(".");
        !          1242:                                                break;
1.1.1.2   misho    1243:                                        }
1.1.1.3 ! misho    1244:                                        fflush(stdout);
1.1.1.2   misho    1245:                                }
1.1       misho    1246:                               done = 1;
                   1247:                               break;
                   1248:                       case -1: /* error */
                   1249:                               if (errno != EINTR) {
                   1250:                                       done = 1;
                   1251:                                       sigint(0);
                   1252:                                       fprintf(stderr,
1.1.1.2   misho    1253:                                               "arping: select() failed: %s\n",
1.1       misho    1254:                                               strerror(errno));
                   1255:                               }
                   1256:                               break;
                   1257:                       default: /* data returned */
                   1258:                               trydispatch = 1;
                   1259:                               break;
                   1260:                       }
                   1261:               }
                   1262: 
                   1263:               if (trydispatch) {
                   1264:                       int ret;
1.1.1.2   misho    1265:                        if (0 > (ret = pcap_dispatch(pcap, -1,
                   1266:                                                     func,
                   1267:                                                     NULL))) {
1.1       misho    1268:                               /* rest, so we don't take 100% CPU... mostly
                   1269:                                   hmm... does usleep() exist everywhere? */
                   1270:                               usleep(1);
                   1271: 
                   1272:                               /* weird is normal on bsd :) */
                   1273:                               if (verbose > 3) {
                   1274:                                       fprintf(stderr,
1.1.1.2   misho    1275:                                               "arping: select says ok, but "
1.1       misho    1276:                                               "pcap_dispatch=%d!\n",
                   1277:                                               ret);
                   1278:                               }
                   1279:                       }
                   1280:               }
                   1281:        }
                   1282: }
                   1283: 
                   1284: /**
                   1285:  *
                   1286:  */
                   1287: int main(int argc, char **argv)
                   1288: {
                   1289:        char ebuf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE];
                   1290:        char *cp;
                   1291:        int promisc = 0;
                   1292:        int srcip_given = 0;
                   1293:        int srcmac_given = 0;
                   1294:        int dstip_given = 0;
                   1295:        const char *ifname = NULL;
                   1296:        char *parm;
                   1297:        int c;
                   1298:        unsigned int maxcount = -1;
                   1299:        int dont_use_arping_lookupdev=0;
                   1300:        struct bpf_program bp;
                   1301:        pcap_t *pcap;
1.1.1.2   misho    1302:        enum { NONE, PINGMAC, PINGIP } mode = NONE;
1.1       misho    1303:        unsigned int packetwait = 1000000;
1.1.1.3 ! misho    1304:         ebuf[0] = 0;
1.1       misho    1305: 
                   1306:         for (c = 1; c < argc; c++) {
                   1307:                 if (!strcmp(argv[c], "--help")) {
                   1308:                         standard_usage();
                   1309:                         extended_usage();
                   1310:                         exit(0);
                   1311:                 }
                   1312:         }
                   1313: 
                   1314:        srcip = 0;
                   1315:        dstip = 0xffffffff;
1.1.1.2   misho    1316:        memcpy(dstmac, ethxmas, ETH_ALEN);
1.1       misho    1317: 
1.1.1.3 ! misho    1318:         while (EOF != (c = getopt(argc, argv,
        !          1319:                                   "0aAbBC:c:dDeFhi:I:m:pPqrRs:S:t:T:uUvw:W:"))) {
1.1       misho    1320:                switch(c) {
                   1321:                case '0':
                   1322:                        srcip = 0;
                   1323:                        srcip_given = 1;
                   1324:                        break;
                   1325:                case 'a':
                   1326:                        beep = 1;
                   1327:                        break;
                   1328:                case 'A':
                   1329:                        addr_must_be_same = 1;
                   1330:                        break;
                   1331:                case 'b':
                   1332:                        srcip = 0xffffffff;
                   1333:                        srcip_given = 1;
                   1334:                        break;
                   1335:                case 'B':
                   1336:                        dstip = 0xffffffff;
                   1337:                        dstip_given = 1;
                   1338:                        break;
                   1339:                case 'c':
                   1340:                        maxcount = atoi(optarg);
                   1341:                        break;
1.1.1.3 ! misho    1342:                 case 'C':
        !          1343:                         max_replies = atoi(optarg);
        !          1344:                         break;
1.1       misho    1345:                case 'd':
                   1346:                        finddup = 1;
                   1347:                        break;
                   1348:                case 'D':
                   1349:                        display = DOT;
                   1350:                        break;
                   1351:                 case 'e':
                   1352:                         reverse_beep = 1;
                   1353:                         break;
                   1354:                case 'F':
                   1355:                        dont_use_arping_lookupdev=1;
                   1356:                        break;
                   1357:                case 'h':
                   1358:                        usage(0);
                   1359:                case 'i':
                   1360:                        if (strchr(optarg, ':')) {
                   1361:                                fprintf(stderr, "arping: If you're trying to "
                   1362:                                        "feed me an interface alias then you "
                   1363:                                        "don't really\nknow what this programs"
                   1364:                                        " does, do you?\nUse -I if you really"
                   1365:                                        " mean it (undocumented on "
                   1366:                                        "purpose)\n");
                   1367:                                exit(1);
                   1368:                        }
                   1369:                case 'I': /* FALL THROUGH */
                   1370:                        ifname = optarg;
                   1371:                        break;
1.1.1.3 ! misho    1372:                 case 'm':
        !          1373:                         timestamp_type = optarg;
        !          1374:                         break;
1.1       misho    1375:                case 'p':
                   1376:                        promisc = 1;
                   1377:                        break;
1.1.1.3 ! misho    1378:                 case 'P':
        !          1379:                         send_reply = 1;
        !          1380:                         break;
1.1       misho    1381:                case 'q':
                   1382:                        display = QUIET;
                   1383:                        break;
                   1384:                case 'r':
                   1385:                        display = (display==RRAW)?RAWRAW:RAW;
                   1386:                        break;
                   1387:                case 'R':
                   1388:                        display = (display==RAW)?RAWRAW:RRAW;
                   1389:                        break;
                   1390:                case 's': { /* spoof source MAC */
                   1391:                        unsigned int n[6];
                   1392:                        if (!get_mac_addr(optarg,
                   1393:                                          &n[0],&n[1],&n[2],
                   1394:                                          &n[3],&n[4],&n[5])){
                   1395:                                fprintf(stderr, "arping: Weird MAC addr %s\n",
                   1396:                                        optarg);
                   1397:                                exit(1);
                   1398:                        }
                   1399:                        for (c = 0; c < 6; c++) {
                   1400:                                srcmac[c] = n[c] & 0xff;
                   1401:                        }
                   1402:                        srcmac_given = 1;
                   1403:                        break;
                   1404:                }
                   1405:                case 'S': /* set source IP, may be null for don't-know */
1.1.1.3 ! misho    1406:                         do_libnet_init(ifname, 0);
1.1       misho    1407:                        if (-1 == (srcip = libnet_name2addr4(libnet,
                   1408:                                                             optarg,
                   1409:                                                             LIBNET_RESOLVE))){
                   1410:                                fprintf(stderr, "arping: Can't resolve %s, or "
                   1411:                                        "%s is broadcast. If it is, use -b"
                   1412:                                        " instead of -S\n", optarg,optarg);
                   1413:                                exit(1);
                   1414:                        }
                   1415:                        srcip_given = 1;
                   1416:                        break;
                   1417:                case 't': { /* set taget mac */
                   1418:                        unsigned int n[6];
                   1419:                        if (mode == PINGMAC) {
                   1420:                                fprintf(stderr, "arping: -t can only be used "
                   1421:                                        "in IP ping mode\n");
                   1422:                                exit(1);
                   1423:                        }
                   1424:                        if (!get_mac_addr(optarg,
                   1425:                                          &n[0],&n[1],&n[2],
                   1426:                                          &n[3],&n[4],&n[5])){
                   1427:                                fprintf(stderr, "Illegal MAC addr %s\n",
                   1428:                                        optarg);
                   1429:                                exit(1);
                   1430:                        }
                   1431:                        for (c = 0; c < 6; c++) {
                   1432:                                dstmac[c] = n[c] & 0xff;
                   1433:                        }
                   1434:                        mode = PINGIP;
                   1435:                        break;
                   1436:                }
                   1437:                case 'T': /* set destination IP */
                   1438:                        if (mode == PINGIP) {
                   1439:                                fprintf(stderr, "arping: -T can only be used "
                   1440:                                        "in MAC ping mode\n");
                   1441:                                exit(1);
                   1442:                        }
1.1.1.3 ! misho    1443:                         do_libnet_init(ifname, 0);
1.1       misho    1444:                        if (-1 == (dstip = libnet_name2addr4(libnet,
                   1445:                                                             optarg,
                   1446:                                                             LIBNET_RESOLVE))){
                   1447:                                fprintf(stderr,"arping: Can't resolve %s, or "
                   1448:                                        "%s is broadcast. If it is, use -B "
                   1449:                                        "instead of -T\n",optarg,optarg);
                   1450:                                exit(1);
                   1451:                        }
                   1452:                        mode = PINGMAC;
                   1453:                        break;
                   1454:                case 'u':
                   1455:                        alsototal = 1;
                   1456:                        break;
1.1.1.2   misho    1457:                case 'U':
                   1458:                        if (mode == PINGMAC) {
                   1459:                                fprintf(stderr, "arping: -U can only be used "
                   1460:                                        "in IP ping mode\n");
                   1461:                                exit(1);
                   1462:                        }
                   1463:                        unsolicited = 1;
                   1464:                        break;
1.1       misho    1465:                case 'v':
                   1466:                        verbose++;
                   1467:                        break;
                   1468:                case 'w':
                   1469:                        packetwait = (unsigned)atoi(optarg);
                   1470:                        break;
1.1.1.3 ! misho    1471:                 case 'W':
        !          1472:                         packetwait = (unsigned)(1000000.0 * atof(optarg));
        !          1473:                         break;
1.1       misho    1474:                default:
                   1475:                        usage(1);
                   1476:                }
                   1477:        }
                   1478: 
1.1.1.2   misho    1479:         if (verbose > 1) {
                   1480: #if HAVE_CLOCK_MONOTONIC
                   1481:                 struct timespec ts;
                   1482:                 clock_getres(CLOCK_MONOTONIC, &ts);
1.1.1.3 ! misho    1483:                 printf("arping: clock_getres() = %ld %ld\n",
1.1.1.2   misho    1484:                        (long)ts.tv_sec, (long)ts.tv_nsec);
                   1485: #else
1.1.1.3 ! misho    1486:                 printf("arping: Using gettimeofday() for time measurements\n");
1.1.1.2   misho    1487: #endif
                   1488:         }
                   1489: 
1.1       misho    1490:         if (display == DOT) {
                   1491:                 setvbuf(stdout, NULL, _IONBF, 0);
                   1492:         }
                   1493: 
                   1494:         if (finddup && maxcount == -1) {
                   1495:                 maxcount = 3;
                   1496:         }
                   1497: 
                   1498:        parm = (optind < argc) ? argv[optind] : NULL;
                   1499: 
                   1500:         /* default to own IP address when doing -d */
                   1501:         if (finddup && !parm) {
                   1502:                 dstip_given = 1;
1.1.1.3 ! misho    1503:                 do_libnet_init(ifname, 0);
1.1       misho    1504:                 dstip = libnet_get_ipaddr4(libnet);
                   1505:                 if (verbose) {
                   1506:                         printf("defaulting to checking dup for %s\n",
                   1507:                                libnet_addr2name4(dstip, 0));
                   1508:                 }
                   1509:         }
                   1510: 
                   1511:        /*
                   1512:         * Handle dstip_given instead of ip address after parms (-B really)
                   1513:         */
                   1514:        if (mode == NONE) {
                   1515:                if (optind + 1 == argc) {
                   1516:                        mode = is_mac_addr(parm)?PINGMAC:PINGIP;
                   1517:                } else if (dstip_given) {
                   1518:                        mode = PINGIP;
1.1.1.3 ! misho    1519:                         do_libnet_init(ifname, 0);
1.1       misho    1520:                        parm = strdup(libnet_addr2name4(dstip,0));
                   1521:                        if (!parm) {
                   1522:                                fprintf(stderr, "arping: out of mem\n");
                   1523:                                exit(1);
                   1524:                        }
                   1525:                }
                   1526:        }
                   1527: 
                   1528:        if (!parm) {
                   1529:                usage(1);
                   1530:        }
                   1531: 
                   1532:        /*
                   1533:         *
                   1534:         */
                   1535:        if (mode == NONE) {
                   1536:                usage(1);
                   1537:        }
                   1538: 
                   1539:        /*
                   1540:         * libnet init (may be done already for resolving)
                   1541:         */
1.1.1.3 ! misho    1542:         do_libnet_init(ifname, 0);
        !          1543: 
1.1       misho    1544:        /*
                   1545:         * Make sure dstip and parm like eachother
                   1546:         */
                   1547:        if (mode == PINGIP && (!dstip_given)) {
                   1548:                if (is_mac_addr(parm)) {
                   1549:                        fprintf(stderr, "arping: Options given only apply to "
                   1550:                                "IP ping, but MAC address given as argument"
                   1551:                                "\n");
                   1552:                        exit(1);
                   1553:                }
                   1554:                if (-1 == (dstip = libnet_name2addr4(libnet,
                   1555:                                                     parm,
                   1556:                                                     LIBNET_RESOLVE))) {
                   1557:                        fprintf(stderr, "arping: Can't resolve %s\n", parm);
                   1558:                        exit(1);
                   1559:                }
                   1560:                parm = strdup(libnet_addr2name4(dstip,0));
                   1561:        }
                   1562: 
                   1563:        /*
                   1564:         * parse parm into dstmac
                   1565:         */
                   1566:        if (mode == PINGMAC) {
                   1567:                unsigned int n[6];
                   1568:                if (optind + 1 != argc) {
                   1569:                        usage(1);
                   1570:                }
                   1571:                if (!is_mac_addr(parm)) {
                   1572:                        fprintf(stderr, "arping: Options given only apply to "
                   1573:                                "MAC ping, but no MAC address given as "
                   1574:                                "argument\n");
                   1575:                        exit(1);
                   1576:                }
                   1577:                if (!get_mac_addr(argv[optind],
                   1578:                                  &n[0],&n[1],&n[2],
                   1579:                                  &n[3],&n[4],&n[5])) {
                   1580:                        fprintf(stderr, "arping: Illegal mac addr %s\n",
                   1581:                                argv[optind]);
                   1582:                        return 1;
                   1583:                }
                   1584:                for (c = 0; c < 6; c++) {
                   1585:                        dstmac[c] = n[c] & 0xff;
                   1586:                }
                   1587:        }       
                   1588: 
                   1589:        target = parm;
                   1590:        /*
                   1591:         * Argument processing done, parameters considered sane below
                   1592:         */
                   1593: 
                   1594:        /*
                   1595:         * Get some good iface.
                   1596:         */
                   1597:        if (!ifname) {
1.1.1.2   misho    1598:                 if (!dont_use_arping_lookupdev) {
                   1599:                         ifname = arping_lookupdev(srcip, dstip, ebuf);
1.1.1.3 ! misho    1600:                         strip_newline(ebuf);
        !          1601:                         if (!ifname) {
        !          1602:                                 fprintf(stderr, "arping: lookup dev: %s\n",
        !          1603:                                         ebuf);
        !          1604:                         }
1.1.1.2   misho    1605:                 }
                   1606:                 if (!ifname) {
                   1607:                         ifname = arping_lookupdev_default(srcip, dstip, ebuf);
1.1.1.3 ! misho    1608:                         strip_newline(ebuf);
        !          1609:                         if (ifname && !dont_use_arping_lookupdev) {
1.1.1.2   misho    1610:                                 fprintf(stderr,
                   1611:                                         "arping: Unable to automatically find "
                   1612:                                         "interface to use. Is it on the local "
                   1613:                                         "LAN?\n"
                   1614:                                         "arping: Use -i to manually "
                   1615:                                         "specify interface. "
                   1616:                                         "Guessing interface %s.\n", ifname);
                   1617:                         }
1.1       misho    1618:                }
                   1619:                if (!ifname) {
1.1.1.2   misho    1620:                         fprintf(stderr, "arping: Gave up looking for interface"
                   1621:                                 " to use: %s\n", ebuf);
1.1       misho    1622:                        exit(1);
                   1623:                }
                   1624:                /* FIXME: check for other probably-not interfaces */
                   1625:                if (!strcmp(ifname, "ipsec")
                   1626:                    || !strcmp(ifname,"lo")) {
                   1627:                        fprintf(stderr, "arping: Um.. %s looks like the wrong "
                   1628:                                "interface to use. Is it? "
                   1629:                                "(-i switch)\n", ifname);
                   1630:                        fprintf(stderr, "arping: using it anyway this time\n");
                   1631:                }
                   1632:        }
                   1633: 
                   1634:        /*
                   1635:         * Init libnet again, because we now know the interface name.
                   1636:         * We should know it by know at least
                   1637:         */
1.1.1.3 ! misho    1638:         do_libnet_init(ifname, 0);
1.1       misho    1639: 
                   1640:        /*
                   1641:         * pcap init
                   1642:         */
1.1.1.2   misho    1643:         if (!(pcap = do_pcap_open_live(ifname, 100, promisc, 10, ebuf))) {
1.1.1.3 ! misho    1644:                 strip_newline(ebuf);
        !          1645:                 fprintf(stderr, "arping: pcap_open_live(): %s\n", ebuf);
1.1       misho    1646:                exit(1);
                   1647:        }
1.1.1.3 ! misho    1648:         drop_privileges();
1.1       misho    1649:        if (pcap_setnonblock(pcap, 1, ebuf)) {
1.1.1.3 ! misho    1650:                 strip_newline(ebuf);
1.1       misho    1651:                fprintf(stderr, "arping: pcap_set_nonblock(): %s\n", ebuf);
                   1652:                exit(1);
                   1653:        }
1.1.1.2   misho    1654:        if (verbose > 1) {
1.1.1.3 ! misho    1655:                printf("arping: pcap_get_selectable_fd(): %d\n",
1.1       misho    1656:                       pcap_get_selectable_fd(pcap));
                   1657:        }
                   1658: 
1.1.1.2   misho    1659: #ifdef BIOCIMMEDIATE
1.1       misho    1660:        {
1.1.1.3 ! misho    1661:                 // This may be redundant if pcap_set_immediate_mode() is present.
1.1       misho    1662:                uint32_t on = 1;
                   1663:                if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE,
                   1664:                               &on))) {
                   1665:                        fprintf(stderr, "arping: ioctl(fd,BIOCIMMEDIATE, 1) "
                   1666:                                "failed, continuing anyway, YMMV: %s\n",
                   1667:                                strerror(errno));
                   1668:                }
                   1669:        }
                   1670: #endif
                   1671: 
                   1672:        if (mode == PINGIP) {
                   1673:                /* FIXME: better filter with addresses? */
                   1674:                if (-1 == pcap_compile(pcap, &bp, "arp", 0,-1)) {
                   1675:                        fprintf(stderr, "arping: pcap_compile(): error\n");
                   1676:                        exit(1);
                   1677:                }
                   1678:        } else { /* ping mac */
                   1679:                /* FIXME: better filter with addresses? */
                   1680:                if (-1 == pcap_compile(pcap, &bp, "icmp", 0,-1)) {
                   1681:                        fprintf(stderr, "arping: pcap_compile(): error\n");
                   1682:                        exit(1);
                   1683:                }
                   1684:        }
                   1685:        if (-1 == pcap_setfilter(pcap, &bp)) {
                   1686:                fprintf(stderr, "arping: pcap_setfilter(): error\n");
                   1687:                exit(1);
                   1688:        }
                   1689: 
                   1690:        /*
                   1691:         * final init
                   1692:         */
                   1693:        if (!srcmac_given) {
                   1694:                if (!(cp = (char*)libnet_get_hwaddr(libnet))) {
                   1695:                        fprintf(stderr, "arping: libnet_get_hwaddr(): %s\n",
                   1696:                                libnet_geterror(libnet));
                   1697:                        exit(1);
                   1698:                }
                   1699:                memcpy(srcmac, cp, ETH_ALEN);
                   1700:        }
                   1701:        if (!srcip_given) {
                   1702:                if (-1 == (srcip = libnet_get_ipaddr4(libnet))) {
1.1.1.2   misho    1703:                        fprintf(stderr,
                   1704:                                 "arping: Unable to get the IPv4 address of "
                   1705:                                 "interface %s:\narping: %s"
                   1706:                                 "arping: "
                   1707:                                 "Use -S to specify address manually.\n",
                   1708:                                 ifname, libnet_geterror(libnet));
1.1       misho    1709:                        exit(1);
                   1710:                }
                   1711:        }
1.1.1.2   misho    1712:         do_signal_init();
1.1       misho    1713: 
                   1714:        if (verbose) {
1.1.1.3 ! misho    1715:                 char buf[128];
        !          1716:                printf("This box:   Interface: %s  IP: %s   MAC address: %s\n",
        !          1717:                       ifname,
        !          1718:                        libnet_addr2name4(libnet_get_ipaddr4(libnet), 0),
        !          1719:                        format_mac(srcmac, buf, sizeof(buf)));
1.1       misho    1720:        }
                   1721: 
                   1722: 
                   1723:        if (display == NORMAL) {
                   1724:                printf("ARPING %s\n", parm);
                   1725:        }
                   1726: 
                   1727:        /*
                   1728:         * let's roll
                   1729:         */
                   1730:        if (mode == PINGIP) {
                   1731:                unsigned int c;
                   1732:                 unsigned int r;
                   1733:                for (c = 0; c < maxcount && !time_to_die; c++) {
1.1.1.2   misho    1734:                        pingip_send();
1.1       misho    1735:                         r = numrecvd;
                   1736:                        ping_recv(pcap,packetwait,
                   1737:                                  (pcap_handler)pingip_recv);
                   1738:                }
                   1739:        } else { /* PINGMAC */
                   1740:                unsigned int c;
                   1741:                 unsigned int r;
                   1742:                for (c = 0; c < maxcount && !time_to_die; c++) {
1.1.1.2   misho    1743:                        pingmac_send(rand(), c);
1.1       misho    1744:                         r = numrecvd;
                   1745:                        ping_recv(pcap,packetwait,
                   1746:                                  (pcap_handler)pingmac_recv);
                   1747:                }
                   1748:        }
                   1749:         if (display == DOT) {
1.1.1.3 ! misho    1750:                 const float succ = 100.0 - 100.0 * (float)(numrecvd)/(float)numsent;
        !          1751:                 printf("\t%3.0f%% packet loss (%d extra)\n",
        !          1752:                        (succ < 0.0) ? 0.0 : succ,
        !          1753:                        (succ < 0.0) ? (numrecvd - numsent) : 0);
1.1       misho    1754:         } else if (display == NORMAL) {
1.1.1.3 ! misho    1755:                 const float succ = 100.0 - 100.0 * (float)(numrecvd)/(float)numsent;
1.1       misho    1756:                 printf("\n--- %s statistics ---\n"
                   1757:                        "%d packets transmitted, "
                   1758:                        "%d packets received, "
                   1759:                        "%3.0f%% "
                   1760:                        "unanswered (%d extra)\n",
                   1761:                        target,numsent,numrecvd,
                   1762:                        (succ < 0.0) ? 0.0 : succ,
1.1.1.2   misho    1763:                        (succ < 0.0) ? (numrecvd - numsent): 0);
                   1764:                 if (numrecvd) {
                   1765:                         double avg = stats_total_time / numrecvd;
                   1766:                         printf("rtt min/avg/max/std-dev = "
                   1767:                                "%.3f/%.3f/%.3f/%.3f ms",
                   1768:                                1000*stats_min_time,
                   1769:                                1000*avg,
                   1770:                                1000*stats_max_time,
                   1771:                                1000*sqrt(stats_total_sq_time/numrecvd
                   1772:                                          -avg*avg));
                   1773:                 }
                   1774:                 printf("\n");
1.1       misho    1775:        }
                   1776: 
                   1777:         if (finddup) {
                   1778:                 return dupfound;
                   1779:         } else {
                   1780:                 return !numrecvd;
                   1781:         }
                   1782: }
1.1.1.2   misho    1783: /* ---- Emacs Variables ----
                   1784:  * Local Variables:
                   1785:  * c-basic-offset: 8
                   1786:  * indent-tabs-mode: nil
                   1787:  * End:
                   1788:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>