Diff for /embedaddon/arping/src/arping.c between versions 1.1 and 1.1.1.4

version 1.1, 2012/02/21 22:16:27 version 1.1.1.4, 2021/03/16 23:40:57
Line 2 Line 2
  *   *
  * arping   * arping
  *   *
 * By Thomas Habets <thomas@habets.pp.se> * By Thomas Habets <thomas@habets.se>
  *   *
  * ARP 'ping' utility   * ARP 'ping' utility
  *   *
Line 11 Line 11
  * you don't yet have routing to. Then again, if you have no idea what I'm   * you don't yet have routing to. Then again, if you have no idea what I'm
  * talking about then you prolly don't need it.   * talking about then you prolly don't need it.
  *   *
 * Also finds out IP of specified MAC * Also finds out IP of specified MAC.
  *   *
  */   */
 /*  /*
 *  Copyright (C) 2000-2010 Thomas Habets <thomas@habets.pp.se> *  Copyright (C) 2000-2019 Thomas Habets <thomas@habets.se>
  *   *
 *  This library is free software; you can redistribute it and/or *  This program is free software; you can redistribute it and/or modify
 *  modify it under the terms of the GNU General Public *  it under the terms of the GNU General Public License as published by
 *  License as published by the Free Software Foundation; either *  the Free Software Foundation; either version 2 of the License, or
 *  version 2 of the License, or (at your option) any later version. *  (at your option) any later version.
  *   *
 *  This library is distributed in the hope that it will be useful, *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  General Public License for more details. *  GNU General Public License for more details.
  *   *
  *  You should have received a copy of the GNU General Public License along   *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,   *  with this program; if not, write to the Free Software Foundation, Inc.,
Line 37 Line 37
   
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
   #include <limits.h>
   #include <math.h>
 #include <poll.h>  #include <poll.h>
   
 #if HAVE_UNISTD_H  #if HAVE_UNISTD_H
 #include <unistd.h>  #include <unistd.h>
 #endif  #endif
   
   #if HAVE_GETOPT_H
   #include <getopt.h>
   #endif
   
 #if HAVE_STDINT_H  #if HAVE_STDINT_H
 #include <stdint.h>  #include <stdint.h>
 #endif  #endif
Line 51 Line 57
 #include <inttypes.h>  #include <inttypes.h>
 #endif  #endif
   
   #if HAVE_TIME_H
   #include <time.h>
   #endif
   
 #if HAVE_SYS_TIME_H  #if HAVE_SYS_TIME_H
 #include <sys/time.h>  #include <sys/time.h>
 #endif  #endif
Line 59 Line 69
 #include <sys/types.h>  #include <sys/types.h>
 #endif  #endif
   
   #if HAVE_SYS_PARAM_H
   #include <sys/param.h>
   #endif
   
   #if HAVE_SYS_RANDOM_H
   #include <sys/random.h>
   #endif
   
   #if HAVE_GRP_H
   #include <grp.h>
   #endif
   
 #if HAVE_SYS_SOCKET_H  #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>  #include <sys/socket.h>
 #endif  #endif
Line 78 Line 100
 #if HAVE_WIN32_LIBNET_H  #if HAVE_WIN32_LIBNET_H
 #include <win32/libnet.h>  #include <win32/libnet.h>
 #endif  #endif
 #include <pcap.h>  
   
   #if HAVE_PWD_H
   #include <pwd.h>
   #endif
   
   #if HAVE_SYS_CAPABILITY_H
   #include <sys/capability.h>
   #endif
   
 #if HAVE_NET_BPF_H  #if HAVE_NET_BPF_H
 #include <net/bpf.h>  #include <net/bpf.h>
 #endif  #endif
   #include <pcap.h>
   
   #include "arping.h"
   
 #ifndef ETH_ALEN  #ifndef ETH_ALEN
 #define ETH_ALEN 6  #define ETH_ALEN 6
 #endif  #endif
Line 96 Line 128
 #define WIN32 0  #define WIN32 0
 #endif  #endif
   
   #ifndef CLOCK_MONOTONIC
   #define CLOCK_MONOTONIC CLOCK_REALTIME
   #endif
   
   #define UNUSED(x) (void)(x)
   
 /**  /**
  * OS-specific interface finding using routing table. See findif_*.c   * OS-specific interface finding using routing table. See findif_*.c
    * ebuf must be called with a size of at least
    * max(LIBNET_ERRBUF_SIZE, PCAP_ERRBUF_SIZE).
  */   */
 const char *  const char *
arping_lookupdev(const char *ifname,arping_lookupdev(uint32_t srcip, uint32_t dstip, char *ebuf);
                 uint32_t srcip, 
                 uint32_t dstip, 
                 char *ebuf); 
   
   const char *
   arping_lookupdev_default(uint32_t srcip, uint32_t dstip, char *ebuf);
   
 static const char *version = VERSION; /* from autoconf */  static const char *version = VERSION; /* from autoconf */
   
static libnet_t *libnet = 0;libnet_t *libnet = 0;
   
static struct timeval lastpacketsent;/* Timestamp of last packet sent.
  * Used for timing, and assumes that reply is due to most recent sent query.
  */
 static struct timespec lastpacketsent;
   
uint32_t srcip, dstip;/* target string */
 static const char *target = "huh? bug in arping?";
   
static int beep = 0;/*
static int reverse_beep = 0; * Ping IP mode:   cmdline target
static int verbose = 0; * Ping MAC mode:  255.255.255.255, override with -T
static int alsototal = 0; */
/*static int pingmac = 0; */uint32_t dstip;
static int finddup = 0;
static int dupfound = 0;/*
static unsigned int numsent = 0; * Ping IP mode:   ethxmas, override with -t
static unsigned int numrecvd = 0; * Ping MAC mode:  cmdline target
static unsigned int numdots = 0; */
static int addr_must_be_same = 0;static uint8_t dstmac[ETH_ALEN];
 
 static char* payload_suffix = NULL;
 static ssize_t payload_suffix_size = -1;
 
 uint32_t srcip;                   /* autodetected, override with -S/-b/-0 */
 uint8_t srcmac[ETH_ALEN];         /* autodetected, override with -s */
 
 static int16_t vlan_tag = -1; /* 802.1Q tag to add to packets. -V */
 static int16_t vlan_prio = -1; /* 802.1p prio to use with 802.1Q. -Q */
 
 static int beep = 0;                 /* beep when reply is received. -a */
 static int reverse_beep = 0;         /* beep when expected reply absent. -e */
 static int alsototal = 0;            /* print sent as well as received. -u */
 static int addr_must_be_same = 0;    /* -A */
 static int unsolicited = 0;          /* -U */
 static int send_reply = 0;           /* Send reply instead of request. -P */
 static int promisc = 0;              /* Use promisc mode. -p */
 
 static int finddup = 0;              /* finddup mode. -d */
 static int dupfound = 0;             /* set to 1 if dup found */
 static char lastreplymac[ETH_ALEN];  /* if last different from this then dup */
 
 unsigned int numsent = 0;                   /* packets sent */
 unsigned int numrecvd = 0;                  /* packets received */
 static unsigned int max_replies = UINT_MAX; /* exit after -C replies */
 static const char* timestamp_type = NULL;   /* Incoming packet measurement ts type (-m) */
 
 static double stats_min_time = -1;
 static double stats_max_time = -1;
 static double stats_total_time = 0;
 static double stats_total_sq_time = 0;
 
 /* RAWRAW is RAW|RRAW */  /* RAWRAW is RAW|RRAW */
static enum { NORMAL, QUIET, RAW, RRAW, RAWRAW, DOT } display = NORMAL;static enum { NORMAL,      /* normal output */
static char *target = "huh? bug in arping?";              QUIET,       /* No output. -q */
static uint8_t ethnull[ETH_ALEN];              RAW,         /* Print MAC when pinging IP. -r */
static uint8_t ethxmas[ETH_ALEN];              RRAW,        /* Print IP when pinging IP. -R */
static char srcmac[ETH_ALEN];              RAWRAW,      /* Print both. -r and -R */
static char dstmac[ETH_ALEN];              DOT          /* Print '.' and '!', Cisco-style. -D */
static char lastreplymac[ETH_ALEN];} display = NORMAL;
   
/* doesn't need to be volatile */static const uint8_t ethnull[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
volatile int time_to_die = 0;static const uint8_t ethxmas[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 static const char* ip_broadcast = "255.255.255.255";
 static const uint32_t ip_broadcast_num = (uint32_t)-1;
   
   int verbose = 0;  /* Increase with -v */
   
   /* Doesn't really need to be volatile, but doesn't hurt. */
   static volatile sig_atomic_t time_to_die = 0;
   
   static ssize_t
   xgetrandom(void *buf, const size_t buflen, const unsigned int flags)
   {
   #ifdef HAVE_GETRANDOM
           return getrandom(buf, buflen, flags);
   #else
           char* p = buf;
           for (int n = 0; n < buflen; n++) {
                   p[n] = random() & 0xff;
           }
           return buflen;
   #endif
   }
   
   static long int
   xrandom() {
           const int maxtry = 10;
           for (int c = 0; c < maxtry; c++) {
                   long int ret;
                   const ssize_t rc = xgetrandom(&ret, sizeof(ret), 0);
                   if (rc == -1) {
                           fprintf(stderr, "arping: failed to get random bytes: %s\n", strerror(errno));
                           continue;
                   }
                   if (sizeof(ret) != rc) {
                           fprintf(stderr, "arping: got too few random bytes %zd, want %zd\n", rc, sizeof(ret));
                           continue;
                   }
                   return ret;
           }
           fprintf(stderr, "arping: failed to get random bytes after %d tries\n", maxtry);
           exit(1);
   }
   
 /**  /**
    * If possible, chroot.
  *   *
    * The sshd user is used for privilege separation in OpenSSH.
    * Let's assume it's installed and chroot() to there.
  */   */
 static void  static void
count_missing_dots()drop_fs_root()
 {  {
        while (numsent > numdots) {        const char* chroot_user = "sshd";
                putchar('.');        struct passwd *pw;
                numdots++;        errno = 0;
         if (!(pw = getpwnam(chroot_user))) {
                 if (verbose) {
                         printf("arping: getpwnam(%s): %s\n",
                                chroot_user, strerror(errno));
                 }
                 return;
         }          }
           if (chdir(pw->pw_dir)) {
                   if (verbose) {
                           printf("arping: chdir(%s): %s\n",
                                  pw->pw_dir, strerror(errno));
                   }
                   return;
           }
           if (chroot(pw->pw_dir)) {
                   if (verbose) {
                           printf("arping: chroot(%s): %s\n",
                                  pw->pw_dir, strerror(errno));
                   }
                   return;
           }
           if (chdir("/")) {
                   if (verbose) {
                           printf("arping: chdir(/): %s\n", strerror(errno));
                   }
                   return;
           }
           if (verbose > 1) {
                   printf("arping: Successfully chrooted to %s\n", pw->pw_dir);
           }
 }  }
   
 /**  /**
    * If possible, drop uid to nobody.
  *   *
 */      * This code only successfully sets all [ug]ids if running as
  * root. ARPing is most likely running as root unless using
  * capabilities, and those are dropped elsewhere.
  */
 static void
 drop_uid(uid_t uid, gid_t gid)
 {
         int fail = 0;
         if (setgroups(0, NULL)) {
                 if (verbose) {
                         printf("arping: setgroups(0, NULL): %s\n", strerror(errno));
                 }
                 fail++;
         }
         if (gid && setgid(gid)) {
                 if (verbose) {
                         printf("arping: setgid(): %s\n", strerror(errno));
                 }
                 fail++;
         }
         if (uid && setuid(uid)) {
                 if (verbose) {
                         printf("arping: setuid(): %s\n", strerror(errno));
                 }
                 fail++;
         }
         if (!fail && verbose > 1) {
                 printf("arping: Successfully dropped uid/gid to %d/%d.\n",
                        uid, gid);
         }
 }
 
 /**
  * Drop any and all capabilities.
  */
 static void
 drop_capabilities()
 {
 #if HAVE_CAP_INIT
         cap_t no_cap;
         if (!(no_cap = cap_init())) {
                 if (verbose) {
                         printf("arping: cap_init(): %s\n", strerror(errno));
                 }
                 return;
         }
         if (cap_set_proc(no_cap)) {
                 if (verbose) {
                         printf("arping: cap_set_proc(): %s\n", strerror(errno));
                 }
         }
         if (verbose > 1) {
                 printf("arping: Successfully dropped all capabilities.\n");
         }
         cap_free(no_cap);
 #endif
 }
 
 /**
  * Get GID of input (handle both name and number) or die.
  */
 static gid_t
 must_get_group(const char* ident)
 {
         // Special case empty string, because strtol.
         int saved_errno = 0;
         if (*ident) {
                 // First try it as a name.
                 {
                         struct group* gr;
                         errno = 0;
                         if ((gr = getgrnam(ident))) {
                                 return gr->gr_gid;
                         }
                         saved_errno = errno;
                 }
 
                 // Not a name. Try it as an integer.
                 {
                         char* endp = NULL;
                         gid_t r = strtol(ident, &endp, 0);
                         if (!*endp) {
                                 return r;
                         }
                 }
         }
 
         if (saved_errno != 0) {
                 fprintf(stderr,
                         "arping: %s not a number and getgrnam(%s): %s\n",
                         ident, ident, strerror(saved_errno));
         } else {
                 // If group was supplied, then not
                 // existing is fatal error too.
                 fprintf(stderr,
                         "arping: %s is not a number or group\n",
                         ident);
         }
         exit(1);
 }
 
 /**
  * drop all privileges.
  *
  * To be called as early as possible. IOW: immediately after opening
  * raw socket.
  */
 static void
 drop_privileges(const char* drop_group)
 {
         // Need to get uid/gid of 'nobody' before chroot().
         const char* drop_user = "nobody";
         struct passwd *pw;
         errno = 0;
         uid_t uid = 0;
         gid_t gid = 0;
         if (!(pw = getpwnam(drop_user))) {
                 if (verbose) {
                         if (errno != 0) {
                                 printf("arping: getpwnam(%s): %s\n",
                                        drop_user, strerror(errno));
                         } else {
                                 printf("arping: getpwnam(%s): unknown user\n",
                                        drop_user);
                         }
                 }
         } else {
                 uid = pw->pw_uid;
                 gid = pw->pw_gid;
         }
 
         // If group is supplied, use that gid instead.
         if (drop_group != NULL) {
                 gid = must_get_group(drop_group);
         }
         drop_fs_root();
         drop_uid(uid, gid);
         drop_capabilities();
 #ifdef HAVE_UNVEIL
         if (unveil("/", "")) {
                 fprintf(stderr,
                         "arping: failed to unveil(/, <>): %s\n",
                         strerror(errno));
                 exit(1);
         }
         if (unveil(NULL, NULL)) {
                 fprintf(stderr, "arping: failed to unveil(NULL, NULL): %s\n",
                        strerror(errno));
                 exit(1);
         }
         if (verbose > 1) {
                 printf("arping: Successfully unveiled\n");
         }
 #endif
 }
 
 /**
  * drop even more privileges, where possible.
  *
  * After all setup is done and main loop is about to start.
  */
 static void
 drop_more_privileges()
 {
 #ifdef HAVE_PLEDGE
         if (pledge("stdio tty", "")) {
                 fprintf(stderr, "arping: failed to pledge(stdio, <empty>): %s\n",
                        strerror(errno));
                 exit(1);
         } else if (verbose > 1) {
                 printf("arping: Successfully pledged\n");
         }
 #endif
 }
 
 
 /**
  * Do pcap_open_live(), except by using the pcap_create() interface
  * introduced in 2008 (libpcap 0.4) where available.
  * This is so that we can set some options, which can't be set with
  * pcap_open_live:
  * 1) Immediate mode -- this prevents pcap from buffering.
  * 2) Set timestamp type -- specify what type of timer to use.
  *
  * FIXME: Use pcap_set_buffer_size()?
  */
 static pcap_t*
 try_pcap_open_live(const char *device, int snaplen,
                    int promisc, int to_ms, char *errbuf)
 {
 #ifdef HAVE_PCAP_CREATE
         pcap_t* pcap;
         int rc;
 
         if (!(pcap = pcap_create(device, errbuf))) {
                 goto err;
         }
         if ((rc = pcap_set_snaplen(pcap, snaplen))) {
                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_set_snaplen(): %s", pcap_statustostr(rc));
                 goto err;
         }
         if ((rc = pcap_set_promisc(pcap, promisc))) {
                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_set_promisc(): %s", pcap_statustostr(rc));
                 goto err;
         }
         if ((rc = pcap_set_timeout(pcap, to_ms))) {
                 snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_set_timeout(): %s", pcap_statustostr(rc));
                 goto err;
         }
 
 #ifdef HAVE_PCAP_SET_IMMEDIATE_MODE
         // Without immediate mode some architectures (e.g. Linux with
         // TPACKET_V3) will buffer replies and incorrectly report upwards of
         // hundreds of milliseconds of delay.
         if ((rc = pcap_set_immediate_mode(pcap, 1))) {
                 if (verbose) {
                         fprintf(stderr, "arping: pcap_set_immediate_mode() failed: %s\n", pcap_statustostr(rc));
                 }
         }
 #endif
 #ifdef HAVE_PCAP_LIST_TSTAMP_TYPES
         if (timestamp_type) {
                 int err;
                 int v = pcap_tstamp_type_name_to_val(timestamp_type);
                 if (v == PCAP_ERROR) {
                         fprintf(stderr, "arping: Unknown timestamp type \"%s\"\n", timestamp_type);
                         exit(1);
                 }
                 if ((err = pcap_set_tstamp_type(pcap, v))) {
                         fprintf(stderr,
                                 "arping: Failed to set timestamp type \"%s\" (%d): %s\n",
                                 timestamp_type, v, pcap_statustostr(err));
                 }
         }
 #endif
         if ((rc = pcap_activate(pcap))) {
                 if (timestamp_type) {
                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_activate(tstype=\"%s\"): %s. Try without setting timestamp type.", timestamp_type, pcap_statustostr(rc));
                 } else {
                         snprintf(errbuf, PCAP_ERRBUF_SIZE, "pcap_activate(): %s", pcap_statustostr(rc));
                 }
                 goto err;
         }
 #ifdef HAVE_PCAP_LIST_TSTAMP_TYPES
         // List timestamp types after activating, since we don't want to list
         // them if activating failed.
         if (verbose > 1) {
                 int *ts;
                 int count;
                 count = pcap_list_tstamp_types(pcap, &ts);
                 if (count == PCAP_ERROR) {
                         fprintf(stderr, "arping: pcap_list_tstamp_types() failed\n");
                 } else {
                         int c;
                         const char* fmt = "  %-18s %s\n";
                         fprintf(stderr, "Timestamp types:\n");
                         fprintf(stderr, fmt, "Name", "Description");
                         for (c = 0; c < count; c++) {
                                 fprintf(stderr, fmt, pcap_tstamp_type_val_to_name(ts[c]),
                                         pcap_tstamp_type_val_to_description(ts[c]));
                         }
                         pcap_free_tstamp_types(ts);
                 }
         }
 #endif
         return pcap;
 err:
         if (pcap) {
                 pcap_close(pcap);
         }
         return NULL;
 #else
         return pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
 #endif
 }
 
 /**
  * Some stupid OSs (Solaris) think it's a good idea to put network
  * devices in /dev and then play musical chairs with them.
  *
  * Since libpcap doesn't seem to have a workaround for that, here's arpings
  * workaround.
  *
  * E.g. if the network interface is called net0, pcap will fail because it
  * fails to open /dev/net, because it's a directory.
  */
 static pcap_t*
 do_pcap_open_live(const char *device, int snaplen,
                   int promisc, int to_ms, char *errbuf)
 {
         pcap_t* ret;
         char buf[PATH_MAX];
 
         if ((ret = try_pcap_open_live(device, snaplen, promisc, to_ms, errbuf))) {
                 return ret;
         }
 
         snprintf(buf, sizeof(buf), "/dev/%s", device);
         if ((ret = try_pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
                 return ret;
         }
 
         snprintf(buf, sizeof(buf), "/dev/net/%s", device);
         if ((ret = try_pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
                 return ret;
         }
 
         /* Call original again to reset the error message. */
         return try_pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
 }
 
 /**
  * Some Libnet error messages end with a newline. Strip that in place.
  */
 void  void
do_libnet_init(const char *ifname)strip_newline(char* s) {
         size_t n;
         for (n = strlen(s); n && (s[n - 1] == '\n'); --n) {
                 s[n - 1] = 0;
         }
 }
 
 /**
  * Init libnet with specified ifname. Destroy if already inited.
  * If this function retries with different parameter it will preserve
  * the original error message and print that.
  * Call with recursive=0.
  */
 void
 do_libnet_init(const char *ifname, int recursive)
 {  {
         char ebuf[LIBNET_ERRBUF_SIZE];          char ebuf[LIBNET_ERRBUF_SIZE];
           ebuf[0] = 0;
         if (verbose > 1) {          if (verbose > 1) {
                printf("libnet_init(%s)\n", ifname?ifname:"<null>");                printf("arping: libnet_init(%s)\n", ifname ? ifname : "<null>");
         }          }
         if (libnet) {          if (libnet) {
                /* prolly going to switch interface from temp to real */                /* Probably going to switch interface from temp to real. */
                 libnet_destroy(libnet);                  libnet_destroy(libnet);
                 libnet = 0;                  libnet = 0;
         }          }
         if (getuid() && geteuid()) {  
                 fprintf(stderr, "arping: must run as root\n");  
                 exit(1);  
         }  
   
           /* Try libnet_init() even though we aren't root. We may have
            * a capability or something. */
         if (!(libnet = libnet_init(LIBNET_LINK,          if (!(libnet = libnet_init(LIBNET_LINK,
                                    (char*)ifname,                                     (char*)ifname,
                                    ebuf))) {                                     ebuf))) {
                fprintf(stderr, "arping: libnet_init(): %s\n", ebuf);                strip_newline(ebuf);
                 if (!ifname) {
                         /* Sometimes libnet guesses an interface that it then
                          * can't use. Work around that by attempting to
                          * use "lo". */
                         do_libnet_init("lo", 1);
                         if (libnet != NULL) {
                                 return;
                         }
                 } else if (recursive) {
                         /* Continue original execution to get that
                          * error message. */
                         return;
                 }
                 fprintf(stderr, "arping: libnet_init(LIBNET_LINK, %s): %s\n",
                         ifname ? ifname : "<null>",
                         *ebuf ? ebuf : "<no error message>");
                 if (getuid() && geteuid()) {
                         fprintf(stderr,
                                 "arping: you may need to run as root\n");
                 }
                 exit(1);                  exit(1);
         }          }
 }  }
Line 179  do_libnet_init(const char *ifname) Line 675  do_libnet_init(const char *ifname)
 /**  /**
  *   *
  */   */
const char *void
arping_lookupdev_default(const char *ifname,sigint(int i)
                         uint32_t srcip, uint32_t dstip, 
                         char *ebuf) 
 {  {
#if WIN32        UNUSED(i);
        WCHAR buf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE];        time_to_die = 1;
        WCHAR* ret = (WCHAR*)pcap_lookupdev((char*)buf); 
        if (ret != NULL) { 
                wcstombs(ebuf, ret, LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE); 
                return ebuf; 
        } 
        return NULL; 
#else 
        return pcap_lookupdev(ebuf); 
#endif 
 }  }
   
#if WIN32/**
static BOOL WINAPI arping_console_ctrl_handler(DWORD dwCtrlType) * idiot-proof clock_gettime() wrapper
  */
 static void
 getclock(struct timespec *ts)
 {  {
        if(verbose) {#if HAVE_CLOCK_MONOTONIC
                printf("arping_console_ctrl_handler( %d )\n", (int)dwCtrlType);        static int clock_gettime_failed = 0;
        }        if (!clock_gettime_failed) {
        time_to_die = 1;                if (0 == clock_gettime(CLOCK_MONOTONIC, ts)) {
                        return;
#if 0                }
        /* if SetConsoleCtrlHandler() does what I think, this isn't needed */                fprintf(stderr, "arping: clock_gettime(): %s\n",
        if (display == NORMAL) {                        strerror(errno));
                printf("\n--- %s statistics ---\n"                clock_gettime_failed = 1; // Prevent duplicate error messages.
                       "%d packets transmitted, %d packets received, %3.0f%% " 
                       "unanswered\n",target,numsent,numrecvd, 
                       100.0 - 100.0 * (float)(numrecvd)/(float)numsent); 
         }          }
 #endif  #endif
        return TRUE;        struct timeval tv;
         if (-1 == gettimeofday(&tv, NULL)) {
                 fprintf(stderr, "arping: gettimeofday(): %s\n",
                         strerror(errno));
                 sigint(0);
         }
         ts->tv_sec = tv.tv_sec;
         ts->tv_nsec = tv.tv_usec * 1000;
 }  }
 #endif  
   
   
 /**  /**
  *   *
  */   */
static void sigint(int i)static char*
{format_mac(const unsigned char* mac, char* buf, size_t bufsize) {
        time_to_die = 1;        snprintf(buf, bufsize, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
         return buf;
 }  }
   
 /**  /**
Line 249  extended_usage() Line 741  extended_usage()
                "    -B     Use instead of host if you want to address 255.255.255.255.\n"                 "    -B     Use instead of host if you want to address 255.255.255.255.\n"
                "    -c count\n"                 "    -c count\n"
                "           Only send count requests.\n"                 "           Only send count requests.\n"
                  "    -C count\n"
                  "           Only wait for this many replies, regardless of -c and -w.\n"
                "    -d     Find duplicate replies. Exit with 1 if there are "                 "    -d     Find duplicate replies. Exit with 1 if there are "
                "answers from\n"                 "answers from\n"
                "           two different MAC addresses.\n"                 "           two different MAC addresses.\n"
               "    -D     Display answers as dots and missing packets as exclamation points.\n"               "    -D     Display answers as exclamation points and missing packets as dots.\n"
                "    -e     Like -a but beep when there is no reply.\n"                 "    -e     Like -a but beep when there is no reply.\n"
                "    -F     Don't try to be smart about the interface name.  (even  if  this\n"                 "    -F     Don't try to be smart about the interface name.  (even  if  this\n"
                "           switch is not given, -i overrides smartness)\n"                 "           switch is not given, -i overrides smartness)\n"
                  "    -g group\n"
                  "           setgid() to this group instead of the nobody group.\n"
                "    -h     Displays a help message and exits.\n"                 "    -h     Displays a help message and exits.\n"
                "    -i interface\n"                 "    -i interface\n"
                "           Use the specified interface.\n"                 "           Use the specified interface.\n"
                  "    -m type"
   #ifndef HAVE_PCAP_LIST_TSTAMP_TYPES
                  " (Disabled on this system. Option ignored)"
   #endif
                  "\n           Type of timestamp to use for incoming packets. Use -vv when\n"
                  "           pinging to list available ones.\n"
                "    -q     Does not display messages, except error messages.\n"                 "    -q     Does not display messages, except error messages.\n"
                  "    -Q pri 802.1p priority to set. Should be used with 802.1Q (-V).\n"
                  "           Defaults to 0.\n"
                "    -r     Raw output: only the MAC/IP address is displayed for each reply.\n"                 "    -r     Raw output: only the MAC/IP address is displayed for each reply.\n"
                "    -R     Raw output: Like -r but shows \"the other one\", can  be  combined\n"                 "    -R     Raw output: Like -r but shows \"the other one\", can  be  combined\n"
                "           with -r.\n"                 "           with -r.\n"
                "    -s MAC Set source MAC address. You may need to use -p with this.\n"                 "    -s MAC Set source MAC address. You may need to use -p with this.\n"
                "    -S IP  Like  -b and -0 but with set source address.  Note that this may\n"                 "    -S IP  Like  -b and -0 but with set source address.  Note that this may\n"
               "           get the arping unanswered if the target does not have routing to\n"               "           get the arping unanswered if the target does not have routing to\n"
                "           the  IP.  If you don't own the IP you are using, you may need to\n"                 "           the  IP.  If you don't own the IP you are using, you may need to\n"
                "           turn on promiscious mode on the interface (with -p).  With  this\n"                 "           turn on promiscious mode on the interface (with -p).  With  this\n"
                "           switch  you can find out what IP-address a host has without tak-\n"                 "           switch  you can find out what IP-address a host has without tak-\n"
Line 278  extended_usage() Line 782  extended_usage()
                "           $ arping -S <IP-B> -s <MAC-B> -p <MAC-A>\n"                 "           $ arping -S <IP-B> -s <MAC-B> -p <MAC-A>\n"
                "    -p     Turn  on  promiscious  mode  on interface, use this if you don't\n"                 "    -p     Turn  on  promiscious  mode  on interface, use this if you don't\n"
                "           \"own\" the MAC address you are using.\n"                 "           \"own\" the MAC address you are using.\n"
                  "    -P     Send ARP replies instead of requests. Useful with -U.\n"
                "    -u     Show index=received/sent instead  of  just  index=received  when\n"                 "    -u     Show index=received/sent instead  of  just  index=received  when\n"
                "           pinging MACs.\n"                 "           pinging MACs.\n"
                  "    -U     Send unsolicited ARP.\n"
                "    -v     Verbose output. Use twice for more messages.\n"                 "    -v     Verbose output. Use twice for more messages.\n"
               "    -w     Time to wait between pings, in microseconds.\n");               "    -V num 802.1Q tag to add. Defaults to no VLAN tag.\n"
        printf("Report bugs to: thomas@habets.pp.se\n"               "    -w sec Specify a timeout before ping exits regardless of how"
                " many\npackets have been sent or received.\n"
                "    -W sec Time to wait between pings.\n");
         printf("Report bugs to: thomas@habets.se\n"
                "Arping home page: <http://www.habets.pp.se/synscan/>\n"                 "Arping home page: <http://www.habets.pp.se/synscan/>\n"
                "Development repo: http://github.com/ThomasHabets/arping\n");                 "Development repo: http://github.com/ThomasHabets/arping\n");
 }  }
Line 293  extended_usage() Line 802  extended_usage()
 static void  static void
 standard_usage()  standard_usage()
 {  {
        printf("ARPing %s, by Thomas Habets <thomas@habets.pp.se>\n",        printf("ARPing %s, by Thomas Habets <thomas@habets.se>\n",
                version);                 version);
        printf("usage: arping [ -0aAbdDeFpqrRuv ] [ -w <us> ] "        printf("usage: arping [ -0aAbdDeFpPqrRuUv ] [ -w <sec> ] "
                "[ -W <sec> ] "
                "[ -S <host/ip> ]\n"                 "[ -S <host/ip> ]\n"
                "              "                 "              "
                "[ -T <host/ip ] "                 "[ -T <host/ip ] "
                "[ -s <MAC> ] [ -t <MAC> ] [ -c <count> ]\n"                 "[ -s <MAC> ] [ -t <MAC> ] [ -c <count> ]\n"
                "              "                 "              "
               "[ -i <interface> ] "               "[ -C <count> ] [ -i <interface> ] [ -m <type> ]"
                " [ -g <group> ]\n"
                "              "
                "[ -V <vlan> ] [ -Q <priority> ] "
                "<host/ip/MAC | -B>\n");                 "<host/ip/MAC | -B>\n");
 }  }
   
Line 322  usage(int ret) Line 835  usage(int ret)
 }  }
   
 /**  /**
    * Check to see if it looks somewhat like a MAC address.
    *
  * It was unclear from msdn.microsoft.com if their scanf() supported   * It was unclear from msdn.microsoft.com if their scanf() supported
  * [0-9a-fA-F], so I'll stay away from it.   * [0-9a-fA-F], so I'll stay away from it.
    *
  */   */
 static int is_mac_addr(const char *p)  static int is_mac_addr(const char *p)
 {  {
Line 366  static int is_mac_addr(const char *p) Line 882  static int is_mac_addr(const char *p)
 }  }
   
 /**  /**
 * lots of parms since C arrays suck * parse mac address.
  *
  * return 1 on success.
  */   */
static int get_mac_addr(const char *in,int
                        unsigned int *n0,get_mac_addr(const char *in, uint8_t *out)
                        unsigned int *n1, 
                        unsigned int *n2, 
                        unsigned int *n3, 
                        unsigned int *n4, 
                        unsigned int *n5) 
 {  {
        if (6 == sscanf(in, "%x:%x:%x:%x:%x:%x",n0,n1,n2,n3,n4,n5)) {        const char *formats[] = {
                return 1;                "%x:%x:%x:%x:%x:%x",
        } else if(6 == sscanf(in, "%2x%x.%2x%x.%2x%x",n0,n1,n2,n3,n4,n5)) {                "%2x%x.%2x%x.%2x%x",
                return 1;                "%x-%x-%x-%x-%x-%x",
        } else if(6 == sscanf(in, "%x-%x-%x-%x-%x-%x",n0,n1,n2,n3,n4,n5)) {                NULL,
                return 1;        };
        }        int c;
        return 0;        for (c = 0; formats[c]; c++) {
                 unsigned int n[6];
                 if (6 == sscanf(in, formats[c],
                                 &n[0], &n[1], &n[2], &n[3], &n[4], &n[5])) {
                         for (c = 0; c < 6; c++) {
                                 out[c] = n[c] & 0xff;
                         }
                         return 1;
                 }
         }
         return 0;
 }  }
   
 /**  /**
  * as always, the answer is 42  
  *   *
 * in this case the question is how many bytes buf needs to be. */
 * Assuming a 33 byte max %dstatic void
 update_stats(double sample)
 {
         if (stats_min_time < 0 || sample < stats_min_time) {
                 stats_min_time = sample;
         }
         if (sample > stats_max_time) {
                 stats_max_time = sample;
         }
         stats_total_time += sample;
         stats_total_sq_time += sample * sample;
 }
 
 /**
  *   *
 * Still, I'm using at least 128bytes below */
 static double
 timespec2dbl(const struct timespec *tv)
 {
         return tv->tv_sec + (double)tv->tv_nsec / 1000000000;
 }
 
 /**
  * return number of microseconds to wait for packets.
  */
 static uint32_t
 wait_time(double deadline, uint32_t packetwait)
 {
         struct timespec ts;
 
         // If deadline not specified, then don't use it.
         if (deadline < 0) {
                 return packetwait;
         }
 
         getclock(&ts);
         const double max_wait = deadline - timespec2dbl(&ts);
         if (max_wait < 0) {
                 return 0;
         }
         if (max_wait > packetwait / 1000000.0) {
                 return packetwait;
         }
         return max_wait * 1000000;
 }
 
 /**
  * max size of buffer is intsize + 1 + intsize + 4 = 70 bytes or so
  *   *
 * (because snprintf() sadly isn't as portable, that's why) * Still, I'm using at least 128bytes below
  */   */
static char *tv2str(const struct timeval *tv, const struct timeval *tv2,static char *ts2str(const struct timespec *tv, const struct timespec *tv2,
                    char *buf)                    char *buf, size_t bufsize)
 {  {
         double f,f2;          double f,f2;
         int exp = 0;          int exp = 0;
   
        f = tv->tv_sec + (double)tv->tv_usec / 1000000;        f = timespec2dbl(tv);
        f2 = tv2->tv_sec + (double)tv2->tv_usec / 1000000;        f2 = timespec2dbl(tv2);
        f = (f2 - f) * 1000000;        f = (f2 - f) * 1000000000;
         while (f > 1000) {          while (f > 1000) {
                exp+= 3;                exp += 3;
                 f /= 1000;                  f /= 1000;
         }          }
         switch (exp) {          switch (exp) {
         case 0:          case 0:
                sprintf(buf, "%.3f usec", f);                snprintf(buf, bufsize, "%.3f nsec", f);
                 break;                  break;
         case 3:          case 3:
                sprintf(buf, "%.3f msec", f);                snprintf(buf, bufsize, "%.3f usec", f);
                 break;                  break;
         case 6:          case 6:
                sprintf(buf, "%.3f sec", f);                snprintf(buf, bufsize, "%.3f msec", f);
                 break;                  break;
         case 9:          case 9:
                sprintf(buf, "%.3f sec", f*1000);                snprintf(buf, bufsize, "%.3f sec", f);
                 break;                  break;
           case 12:
                   snprintf(buf, bufsize, "%.3f sec", f*1000);
                   break;
         default:          default:
                 /* huh, uh, huhuh */                  /* huh, uh, huhuh */
                sprintf(buf, "%.3fe%d sec", f, exp-6);                snprintf(buf, bufsize, "%.3fe%d sec", f, exp-9);
         }          }
         return buf;          return buf;
 }  }
   
   
   
 /** Send directed IPv4 ICMP echo request.  /** Send directed IPv4 ICMP echo request.
  *   *
  * \param srcmac  Source MAC. From -s switch or autodetected  
  * \param dstmac  Destination/target MAC. Target command line.  
  * \param srcip   From -S switch or autodetected  
  * \param dstip   From -D switch, or 255.255.255.255  
  * \param id      IP id   * \param id      IP id
  * \param seq     Ping seq   * \param seq     Ping seq
  */   */
 static void  static void
pingmac_send(uint8_t *srcmac, uint8_t *dstmac,pingmac_send(uint16_t id, uint16_t seq)
             uint32_t srcip, uint32_t dstip, 
             uint16_t id, uint16_t seq) 
 {  {
         static libnet_ptag_t icmp = 0, ipv4 = 0,eth=0;          static libnet_ptag_t icmp = 0, ipv4 = 0,eth=0;
   
           // Padding size chosen fairly arbitrarily.
           // Without this padding some systems (e.g. Raspberry Pi 3
           // wireless interface) failed. dmesg said:
           //   arping: packet size is too short (42 <= 50)
           const size_t padding_size = sizeof(struct timespec) + payload_suffix_size;
           uint8_t padding[padding_size];
           memset(padding, 0, padding_size);
           {
                   struct timespec ts;
                   getclock(&ts);
                   memcpy(padding, &ts, sizeof(struct timespec));
                   memcpy(&padding[sizeof(struct timespec)],
                          payload_suffix, payload_suffix_size);
           }
   
         int c;          int c;
   
         if (-1 == (icmp = libnet_build_icmpv4_echo(ICMP_ECHO, /* type */          if (-1 == (icmp = libnet_build_icmpv4_echo(ICMP_ECHO, /* type */
Line 453  pingmac_send(uint8_t *srcmac, uint8_t *dstmac, Line 1031  pingmac_send(uint8_t *srcmac, uint8_t *dstmac,
                                                    0, /* checksum */                                                     0, /* checksum */
                                                    id, /* id */                                                     id, /* id */
                                                    seq, /* seq */                                                     seq, /* seq */
                                                   NULL, /* payload */                                                   (uint8_t*)padding, /* payload */
                                                   0, /* payload len */                                                   sizeof padding, /* payload len */
                                                    libnet,                                                     libnet,
                                                    icmp))) {                                                     icmp))) {
                 fprintf(stderr, "libnet_build_icmpv4_echo(): %s\n",                  fprintf(stderr, "libnet_build_icmpv4_echo(): %s\n",
Line 463  pingmac_send(uint8_t *srcmac, uint8_t *dstmac, Line 1041  pingmac_send(uint8_t *srcmac, uint8_t *dstmac,
         }          }
   
         if (-1==(ipv4 = libnet_build_ipv4(LIBNET_IPV4_H          if (-1==(ipv4 = libnet_build_ipv4(LIBNET_IPV4_H
                                          + LIBNET_ICMPV4_ECHO_H + 0,                                          + LIBNET_ICMPV4_ECHO_H
                                           + sizeof padding,
                                           0, /* ToS */                                            0, /* ToS */
                                           id, /* id */                                            id, /* id */
                                           0, /* frag */                                            0, /* frag */
Line 480  pingmac_send(uint8_t *srcmac, uint8_t *dstmac, Line 1059  pingmac_send(uint8_t *srcmac, uint8_t *dstmac,
                         libnet_geterror(libnet));                          libnet_geterror(libnet));
                 sigint(0);                  sigint(0);
         }          }
        if (-1 == (eth = libnet_build_ethernet(dstmac,        if (vlan_tag >= 0) {
                                               srcmac,                eth = libnet_build_802_1q(dstmac,
                                               ETHERTYPE_IP,                                          srcmac,
                                               NULL,                                          ETHERTYPE_VLAN,
                                               0,                                          vlan_prio,
                                               libnet,                                          0, // cfi
                                               eth))) {                                          vlan_tag,
                fprintf(stderr, "libnet_build_ethernet(): %s\n",                                          ETHERTYPE_IP,
                        libnet_geterror(libnet));                                          NULL, // payload
                sigint(0);                                          0, // payload length
                                           libnet,
                                           eth);
         } else {
                 eth = libnet_build_ethernet(dstmac,
                                             srcmac,
                                             ETHERTYPE_IP,
                                             NULL, // payload
                                             0, // payload length
                                             libnet,
                                             eth);
         }
         if (-1 == eth) {
                 fprintf(stderr, "arping: %s: %s\n",
                         (vlan_tag >= 0) ? "libnet_build_802_1q()" :
                         "libnet_build_ethernet()",
                         libnet_geterror(libnet));
                 sigint(0);
         }
         if (verbose > 1) {
                 getclock(&lastpacketsent);
                 printf("arping: sending packet at time %ld.%09ld\n",
                        (long)lastpacketsent.tv_sec,
                        (long)lastpacketsent.tv_nsec);
         }          }
         if(verbose>1) {  
                 if (-1 == gettimeofday(&lastpacketsent, NULL)) {  
                         fprintf(stderr, "arping: gettimeofday(): %s\n",  
                                 strerror(errno));  
                         sigint(0);  
                 }  
                 printf("arping: sending packet at time %d %d\n",  
                        lastpacketsent.tv_sec,  
                        lastpacketsent.tv_usec);  
         }  
         if (-1 == (c = libnet_write(libnet))) {          if (-1 == (c = libnet_write(libnet))) {
                 fprintf(stderr, "arping: libnet_write(): %s\n",                  fprintf(stderr, "arping: libnet_write(): %s\n",
                         libnet_geterror(libnet));                          libnet_geterror(libnet));
                 sigint(0);                  sigint(0);
         }          }
        if (-1 == gettimeofday(&lastpacketsent, NULL)) {        getclock(&lastpacketsent);
                fprintf(stderr, "arping: gettimeofday(): %s\n", 
                        strerror(errno)); 
                sigint(0); 
        } 
         numsent++;          numsent++;
 }  }
   
 /** Send ARP who-has.  /** Send ARP who-has.
  *   *
  * \param srcmac   -s or autodetected  
  * \param dstmac   -t or ff:ff:ff:ff:ff:ff  
  * \param srcip    -S or autodetected  
  * \param dstip    -T or or cmdline  
  *  
  */   */
 static void  static void
pingip_send(uint8_t *srcmac, uint8_t *dstmac,pingip_send()
            uint32_t srcip, uint32_t dstip) 
 {  {
         static libnet_ptag_t arp=0,eth=0;          static libnet_ptag_t arp=0,eth=0;
   
           // Padding size chosen fairly arbitrarily.
           // Without this padding some systems (e.g. Raspberry Pi 3
           // wireless interface) failed. dmesg said:
           //   arping: packet size is too short (42 <= 50)
           const uint8_t padding[16] = {0};
   
         if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER,          if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER,
                                           ETHERTYPE_IP,                                            ETHERTYPE_IP,
                                           ETH_ALEN,                                            ETH_ALEN,
                                           IP_ALEN,                                            IP_ALEN,
                                          ARPOP_REQUEST,                                          send_reply ? ARPOP_REPLY : ARPOP_REQUEST,
                                           srcmac,                                            srcmac,
                                           (uint8_t*)&srcip,                                            (uint8_t*)&srcip,
                                          ethnull,                                          unsolicited ? (uint8_t*)ethxmas : (uint8_t*)ethnull,
                                           (uint8_t*)&dstip,                                            (uint8_t*)&dstip,
                                          NULL,                                          (uint8_t*)padding,
                                          0,                                          sizeof padding,
                                           libnet,                                            libnet,
                                           arp))) {                                            arp))) {
                 fprintf(stderr, "arping: libnet_build_arp(): %s\n",                  fprintf(stderr, "arping: libnet_build_arp(): %s\n",
                         libnet_geterror(libnet));                          libnet_geterror(libnet));
                 sigint(0);                  sigint(0);
         }          }
        if (-1 == (eth = libnet_build_ethernet(dstmac,
                                               srcmac,        if (vlan_tag >= 0) {
                                               ETHERTYPE_ARP,                eth = libnet_build_802_1q(dstmac,
                                               NULL,                                          srcmac,
                                               0,                                          ETHERTYPE_VLAN,
                                               libnet,                                          vlan_prio,
                                               eth))) {                                          0, // cfi
                fprintf(stderr, "arping: libnet_build_ethernet(): %s\n",                                          vlan_tag,
                                           ETHERTYPE_ARP,
                                           NULL, // payload
                                           0, // payload size
                                           libnet,
                                           eth);
         } else {
                 eth = libnet_build_ethernet(dstmac,
                                             srcmac,
                                             ETHERTYPE_ARP,
                                             NULL, // payload
                                             0, // payload size
                                             libnet,
                                             eth);
         }
         if (-1 == eth) {
                 fprintf(stderr, "arping: %s: %s\n",
                         (vlan_tag >= 0) ? "libnet_build_802_1q()" :
                         "libnet_build_ethernet()",
                         libnet_geterror(libnet));                          libnet_geterror(libnet));
                 sigint(0);                  sigint(0);
         }          }
        if(verbose>1) {        if (verbose > 1) {
                if (-1 == gettimeofday(&lastpacketsent, NULL)) {                getclock(&lastpacketsent);
                        fprintf(stderr, "arping: gettimeofday(): %s\n",                printf("arping: sending packet at time %ld.%09ld\n",
                                strerror(errno));                       (long)lastpacketsent.tv_sec,
                        sigint(0);                       (long)lastpacketsent.tv_nsec);
                } 
                printf("arping: sending packet at time %d %d\n", 
                       lastpacketsent.tv_sec, 
                       lastpacketsent.tv_usec); 
         }          }
         if (-1 == libnet_write(libnet)) {          if (-1 == libnet_write(libnet)) {
                fprintf(stderr, "arping: libnet_write(): %s\n",                 fprintf(stderr, "arping: libnet_write(): %s\n",
                         libnet_geterror(libnet));                          libnet_geterror(libnet));
                 sigint(0);                  sigint(0);
         }          }
        if (-1 == gettimeofday(&lastpacketsent, NULL)) {        getclock(&lastpacketsent);
                fprintf(stderr, "arping: gettimeofday(): %s\n", 
                        strerror(errno)); 
                sigint(0); 
        } 
         numsent++;          numsent++;
 }  }
   
Line 583  pingip_send(uint8_t *srcmac, uint8_t *dstmac, Line 1182  pingip_send(uint8_t *srcmac, uint8_t *dstmac,
  * \param h       packet metadata   * \param h       packet metadata
  * \param packet  packet data   * \param packet  packet data
  */   */
static voidvoid
pingip_recv(const char *unused, struct pcap_pkthdr *h,pingip_recv(const char *unused, struct pcap_pkthdr *h, const char * const packet)
            uint8_t *packet) 
 {  {
           const unsigned char *pkt_srcmac;
           const struct libnet_802_1q_hdr *veth;
         struct libnet_802_3_hdr *heth;          struct libnet_802_3_hdr *heth;
         struct libnet_arp_hdr *harp;          struct libnet_arp_hdr *harp;
        struct timeval arrival;        struct timespec arrival;
        int c;        UNUSED(unused);
   
        if(verbose>2) {        if (verbose > 2) {
                printf("arping: received response for ip ping\n");                printf("arping: received response for IP ping\n");
         }          }
   
        if (-1 == gettimeofday(&arrival, NULL)) {        getclock(&arrival);
                fprintf(stderr, "arping: gettimeofday(): %s\n",
                        strerror(errno));        if (vlan_tag >= 0) {
                sigint(0);                veth = (void*)packet;
                 harp = (void*)((char*)veth + LIBNET_802_1Q_H);
                 pkt_srcmac = veth->vlan_shost;
         } else {
                 // Short packet.
                 if (h->caplen < LIBNET_ETH_H + LIBNET_ARP_H + 2*(ETH_ALEN + 4)) {
                         return;
                 }
 
                 heth = (void*)packet;
                 harp = (void*)((char*)heth + LIBNET_ETH_H);
                 pkt_srcmac = heth->_802_3_shost;
                 // Wrong length of hardware address.
                 if (harp->ar_hln != ETH_ALEN) {
                         return;
                 }
 
                 // Wrong length of protocol address.
                 if (harp->ar_pln != 4) {
                         return;
                 }
         }          }
         heth = (void*)packet;  
         harp = (void*)((char*)heth + LIBNET_ETH_H);  
   
        if ((htons(harp->ar_op) == ARPOP_REPLY)        // ARP reply.
            && (htons(harp->ar_pro) == ETHERTYPE_IP)        if (htons(harp->ar_op) != ARPOP_REPLY) {
            && (htons(harp->ar_hrd) == ARPHRD_ETHER)) {                return;
                uint32_t ip;        }
                memcpy(&ip, (char*)harp + harp->ar_hln        if (verbose > 3) {
                       + LIBNET_ARP_H,4);                printf("arping: ... packet is ARP reply\n");
                if (addr_must_be_same        }
                    && (memcmp((u_char*)harp+sizeof(struct libnet_arp_hdr), 
                               dstmac, ETH_ALEN))) { 
                        return; 
                } 
                if (dstip == ip) { 
                        switch(display) { 
                        case DOT: 
                                numdots++; 
                                count_missing_dots(); 
                                putchar('!'); 
                                break; 
                        case NORMAL: { 
                                char buf[128]; 
                                printf("%d bytes from ", h->len); 
                                for (c = 0; c < 6; c++) { 
                                        printf("%.2x%c", heth->_802_3_shost[c], 
                                               (c<5)?':':' '); 
                                } 
                                 
                                printf("(%s): index=%d", 
                                       libnet_addr2name4(ip,0), 
                                       numrecvd); 
                                if (alsototal) { 
                                        printf("/%u", numsent-1); 
                                } 
                                printf(" time=%s", 
                                       tv2str(&lastpacketsent, 
                                              &arrival,buf)); 
                                break; } 
                        case QUIET: 
                                break; 
                        case RAWRAW: 
                                for (c = 0; c < 6; c++) { 
                                        printf("%.2x%c", heth->_802_3_shost[c], 
                                               (c<5)?':':' '); 
                                } 
                                printf("%s", libnet_addr2name4(ip,0)); 
                                break; 
                        case RRAW: 
                                printf("%s", libnet_addr2name4(ip,0)); 
                                break; 
                        case RAW: 
                                for (c = 0; c < 6; c++) { 
                                        printf("%.2x%s", heth->_802_3_shost[c], 
                                               (c<5)?":":""); 
                                } 
                                break; 
                        default: 
                                fprintf(stderr, "arping: can't happen!\n"); 
                        } 
   
                        switch (display) {        // From IPv4 address reply.
                        case QUIET:        if (htons(harp->ar_pro) != ETHERTYPE_IP) {
                        case DOT:                return;
                                break;        }
                        default:        if (verbose > 3) {
                                if (beep) {                printf("arping: ... from IPv4 address\n");
                                        printf("\a");        }
                                }
                                printf("\n");        // To Ethernet address.
         if (htons(harp->ar_hrd) != ARPHRD_ETHER) {
                 return;
         }
         if (verbose > 3) {
                 printf("arping: ... to Ethernet address\n");
         }
 
         // Must be sent from target address.
         // Should very likely only be used if using -T.
         if (addr_must_be_same) {
                 if (memcmp((u_char*)harp + sizeof(struct libnet_arp_hdr),
                            dstmac, ETH_ALEN)) {
                         return;
                 }
         }
         if (verbose > 3) {
                 printf("arping: ... sent by acceptable host\n");
         }
 
         // Special case: If we're not in promisc mode we could still
         // get packets where DST mac is not us, if they're *sent* from
         // the local host. This is an edge case but in general falls under "is promisc?".
         //
         // It may cause confusion because `-p` now means not just
         // enable promisc mode (disable filter on card / in kernel),
         // but also allow packets to any destination (disable filter
         // in `arping`).
         {
                 const uint8_t* p = (u_char*)harp
                         + sizeof(struct libnet_arp_hdr)
                         + ETH_ALEN
                         + IP_ALEN;
                 char buf[128];
                 if (!promisc && memcmp(p, srcmac, ETH_ALEN)) {
                         format_mac(p, buf, sizeof buf);
                         if (verbose > 3) {
                                 printf("arping: ... but sent from %s\n", buf);
                         }                          }
                        if (numrecvd) {                        return;
                                if (memcmp(lastreplymac,                }
                                           heth->_802_3_shost, ETH_ALEN)) {        }
                                        dupfound = 1;        if (verbose > 3) {
                                }                printf("arping: ... destination is the source we used\n");
                        }        }
                        memcpy(lastreplymac, heth->_802_3_shost, ETH_ALEN); 
   
                        numrecvd++;
                }        // Actually the IPv4 address we asked for.
        }        uint32_t ip;
         memcpy(&ip, (char*)harp + harp->ar_hln + LIBNET_ARP_H, 4);
         if (dstip != ip) {
                 return;
         }
         if (verbose > 3) {
                 printf("arping: ... for the right IPv4 address!\n");
         }
 
         update_stats(timespec2dbl(&arrival) - timespec2dbl(&lastpacketsent));
         char buf[128];
         if (beep) {
                 printf("\a");
         }
         switch(display) {
         case DOT:
                 putchar('!');
                 break;
         case NORMAL:
                 printf("%d bytes from %s (%s): index=%d",
                        h->len, format_mac(pkt_srcmac, buf, sizeof(buf)),
                        libnet_addr2name4(ip, 0), numrecvd);
 
                 if (alsototal) {
                         printf("/%u", numsent-1);
                 }
                 printf(" time=%s", ts2str(&lastpacketsent, &arrival, buf,
                                           sizeof(buf)));
                 break;
         case QUIET:
                 break;
         case RAWRAW:
                 printf("%s %s", format_mac(pkt_srcmac, buf, sizeof(buf)),
                        libnet_addr2name4(ip, 0));
                 break;
         case RRAW:
                 printf("%s", libnet_addr2name4(ip, 0));
                 break;
         case RAW:
                 printf("%s", format_mac(pkt_srcmac, buf, sizeof(buf)));
                 break;
         default:
                 fprintf(stderr, "arping: can't happen!\n");
         }
         fflush(stdout);
 
         switch (display) {
         case QUIET:
         case DOT:
                 break;
         default:
                 printf("\n");
         }
         if (numrecvd) {
                 if (memcmp(lastreplymac,
                            pkt_srcmac, ETH_ALEN)) {
                         dupfound = 1;
                 }
         }
         memcpy(lastreplymac, pkt_srcmac, ETH_ALEN);
 
         numrecvd++;
         if (numrecvd >= max_replies) {
                 sigint(0);
         }
 }  }
   
 /** handle incoming packet when pinging an MAC address.  /** handle incoming packet when pinging an MAC address.
Line 690  pingip_recv(const char *unused, struct pcap_pkthdr *h, Line 1358  pingip_recv(const char *unused, struct pcap_pkthdr *h,
  * \param h       packet metadata   * \param h       packet metadata
  * \param packet  packet data   * \param packet  packet data
  */   */
static voidvoid
pingmac_recv(const char *unused, struct pcap_pkthdr *h,pingmac_recv(const char* unused, struct pcap_pkthdr *h, uint8_t *packet)
             uint8_t *packet) 
 {  {
           const unsigned char *pkt_dstmac;
           const unsigned char *pkt_srcmac;
           const struct libnet_802_1q_hdr *veth;
         struct libnet_802_3_hdr *heth;          struct libnet_802_3_hdr *heth;
         struct libnet_ipv4_hdr *hip;          struct libnet_ipv4_hdr *hip;
         struct libnet_icmpv4_hdr *hicmp;          struct libnet_icmpv4_hdr *hicmp;
        struct timeval arrival;        struct timespec arrival;
        int c;        UNUSED(unused);
   
         if(verbose>2) {          if(verbose>2) {
                 printf("arping: received response for mac ping\n");                  printf("arping: received response for mac ping\n");
         }          }
   
        if (-1 == gettimeofday(&arrival, NULL)) {        getclock(&arrival);
                fprintf(stderr, "arping: gettimeofday(): %s\n", 
                        strerror(errno)); 
                sigint(0); 
        } 
   
        heth = (void*)packet;        if (vlan_tag >= 0) {
        hip = (void*)((char*)heth + LIBNET_ETH_H);                veth = (void*)packet;
        hicmp = (void*)((char*)hip + LIBNET_IPV4_H);                hip = (void*)((char*)veth + LIBNET_802_1Q_H);
                 hicmp = (void*)((char*)hip + LIBNET_IPV4_H);
                 pkt_srcmac = veth->vlan_shost;
                 pkt_dstmac = veth->vlan_dhost;
         } else {
                 heth = (void*)packet;
                 hip = (void*)((char*)heth + LIBNET_ETH_H);
                 hicmp = (void*)((char*)hip + LIBNET_IPV4_H);
                 pkt_srcmac = heth->_802_3_shost;
                 pkt_dstmac = heth->_802_3_dhost;
         }
   
        if ((htons(hicmp->icmp_type) == ICMP_ECHOREPLY)        // Dest MAC must be me.
            && ((!memcmp(heth->_802_3_shost, dstmac,ETH_ALEN)        if (memcmp(pkt_dstmac, srcmac, ETH_ALEN)) {
                 || !memcmp(dstmac, ethxmas, ETH_ALEN)))                return;
            && !memcmp(heth->_802_3_dhost, srcmac, ETH_ALEN)) {        }
                if (addr_must_be_same) { 
                        uint32_t tmp; 
                        memcpy(&tmp, &hip->ip_src, 4); 
                        if (dstip != tmp) { 
                                return; 
                        } 
                } 
                switch(display) { 
                case QUIET: 
                        break; 
                case NORMAL: { 
                        char buf[128]; 
                        printf("%d bytes from %s (",h->len, 
                               libnet_addr2name4(*(int*)&hip->ip_src, 0)); 
                        for (c = 0; c < 6; c++) { 
                                printf("%.2x%c", heth->_802_3_shost[c], 
                                       (c<5)?':':')'); 
                        } 
                        printf(": icmp_seq=%d time=%s", 
                               htons(hicmp->icmp_seq),tv2str(&lastpacketsent, 
                                                      &arrival,buf)); 
                        break; } 
                case RAW: 
                        printf("%s", 
                               libnet_addr2name4(hip->ip_src.s_addr, 0)); 
                        break; 
                case RRAW: 
                        for (c = 0; c < 6; c++) { 
                                printf("%.2x%s", heth->_802_3_shost[c], 
                                       (c<5)?":":""); 
                        } 
                        break; 
                case RAWRAW: 
                        for (c = 0; c < 6; c++) { 
                                printf("%.2x%c", heth->_802_3_shost[c], 
                                       (c<5)?':':' '); 
                        } 
                        printf("%s", 
                               libnet_addr2name4(hip->ip_src.s_addr, 0)); 
                        break; 
                default: 
                        fprintf(stderr, "arping: can't-happen-bug\n"); 
                        sigint(0); 
                } 
                if (display != QUIET) { 
                        printf(beep?"\a\n":"\n"); 
                } 
                numrecvd++; 
        } 
} 
   
           if (verbose > 3) {
                   printf("arping: ... right dst mac\n");
           }
   
#if WIN32        // Source MAC must match, if set.
/**        if (memcmp(dstmac, ethxmas, ETH_ALEN)) {
 * untested for a long time. Maybe since arping 2.05 or so.                if (memcmp(pkt_srcmac, dstmac, ETH_ALEN)) {
 */                        return;
static void                }
ping_recv_win32(pcap_t *pcap,uint32_t packetwait, pcap_handler func)        }
{
       struct timeval tv,tv2;        if (verbose > 3) {
       char done = 0;                printf("arping: ... right src mac\n");
       /* windows won't let us do select() */        }
       if (-1 == gettimeofday(&tv2,NULL)) {
               fprintf(stderr, "arping: gettimeofday(): %s\n",        // IPv4 Address must be me (maybe).
                       strerror(errno));        if (addr_must_be_same) {
               sigint(0);                uint32_t tmp;
       }                memcpy(&tmp, &hip->ip_src, 4);
       while (!done && !time_to_die) {                if (dstip != tmp) {
               struct pcap_pkthdr *pkt_header;                        return;
               u_char *pkt_data;                }
               if (pcap_next_ex(pcap, &pkt_header, &pkt_data) == 1) {        }
                       func(pcap, pkt_header, pkt_data);
               }        if (verbose > 3) {
               if (-1 == gettimeofday(&tv,NULL)) {                printf("arping: ... src IP acceptable\n");
                       fprintf(stderr, "arping: "        }
                               "gettimeofday(): %s\n",
                               strerror(errno));        // Must be ICMP echo reply type.
                       sigint(0);        if (htons(hicmp->icmp_type) != ICMP_ECHOREPLY) {
               }                return;
               /*        }
                * setup next timeval, not very exact
                */        if (verbose > 3) {
               tv.tv_sec  = (packetwait / 1000000)                printf("arping: ... is echo reply type\n");
                       - (tv.tv_sec - tv2.tv_sec);        }
               tv.tv_usec = (packetwait % 1000000)
                       - (tv.tv_usec - tv2.tv_usec);        // Must be ICMP echo reply code 0.
               while (tv.tv_usec < 0) {        if (htons(hicmp->icmp_code) != 0) {
                       tv.tv_sec--;                return;
                       tv.tv_usec += 1000000;        }
               }
               usleep(10);        if (verbose > 3) {
               if (tv.tv_sec < 0) {                printf("arping: ... is echo reply code\n");
                       done=1;        }
               }
       }        const char* payload = (char*)hicmp + LIBNET_ICMPV4_ECHO_H;
         const ssize_t payload_size = h->len - (payload - (char*)packet);
         if (payload_size < 0) {
                 return;
         }
         if (payload_size < sizeof(struct timespec) + payload_suffix_size) {
                 return;
         }
         if (verbose > 3) {
                 printf("arping: ... correct payload size (%zd)\n",
                        payload_size);
         }
         if (memcmp(&payload[sizeof(struct timespec)],
                     payload_suffix, payload_suffix_size)) {
                     return;
         }
         if (verbose > 3) {
                 printf("arping: ... correct payload suffix\n");
         }
 
         update_stats(timespec2dbl(&arrival) - timespec2dbl(&lastpacketsent));
         if (beep) {
                 printf("\a");
         }
         char buf[128];
         char buf2[128];
         switch(display) {
         case QUIET:
                 break;
         case DOT:
                 putchar('!');
                 break;
         case NORMAL:
                 printf("%d bytes from %s (%s): icmp_seq=%d time=%s", h->len,
                        libnet_addr2name4(*(int*)&hip->ip_src, 0),
                        format_mac(pkt_srcmac, buf, sizeof(buf)),
                        htons(hicmp->icmp_seq),
                        ts2str(&lastpacketsent, &arrival, buf2, sizeof(buf2)));
                 break;
         case RAW:
                 printf("%s", libnet_addr2name4(hip->ip_src.s_addr, 0));
                 break;
         case RRAW:
                 printf("%s", format_mac(pkt_srcmac, buf, sizeof(buf)));
                 break;
         case RAWRAW:
                 printf("%s %s",
                        format_mac(pkt_srcmac, buf, sizeof(buf)),
                        libnet_addr2name4(hip->ip_src.s_addr, 0));
                 break;
         default:
                 fprintf(stderr, "arping: can't-happen-bug\n");
                 sigint(0);
         }
         fflush(stdout);
         switch (display) {
         case QUIET:
         case DOT:
                 break;
         default:
                 printf("\n");
         }
         numrecvd++;
         if (numrecvd >= max_replies) {
                 sigint(0);
         }
 }  }
 #endif  
   
 /**  /**
 * while negative microseconds, take from whole seconds. * while negative nanoseconds, take from whole seconds.
  * help function for measuring deltas.   * help function for measuring deltas.
  */   */
 static void  static void
fixup_timeval(struct timeval *tv)fixup_timespec(struct timespec *tv)
 {  {
        while (tv->tv_usec < 0) {        while (tv->tv_nsec < 0) {
                 tv->tv_sec--;                  tv->tv_sec--;
                tv->tv_usec += 1000000;                tv->tv_nsec += 1000000000;
         }          }
 }  }
   
 /**  /**
 * idiot-proof gettimeofday() wrapper * try to receive a packet for 'packetwait' microseconds
  */   */
 static void  static void
gettv(struct timeval *tv)ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_handler func)
 {  {
        if (-1 == gettimeofday(tv,NULL)) {       struct timespec ts;
                fprintf(stderr, "arping: "       struct timespec endtime;
                        "gettimeofday(): %s\n", 
                        strerror(errno)); 
                sigint(0); 
        } 
} 
 
 
/** 
 *  
 */ 
static void 
ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_handler func) 
{ 
       struct timeval tv; 
       struct timeval endtime; 
        char done = 0;         char done = 0;
          int fd;
          unsigned int old_received;
   
       gettv(&tv);       if (verbose > 3) {
       endtime.tv_sec = tv.tv_sec + (packetwait / 1000000);               printf("arping: receiving packets...\n");
       endtime.tv_usec = tv.tv_usec + (packetwait % 1000000);       }
       fixup_timeval(&endtime); 
   
       int fd;       getclock(&ts);
        endtime.tv_sec = ts.tv_sec + (packetwait / 1000000);
        endtime.tv_nsec = ts.tv_nsec + 1000 * (packetwait % 1000000);
        fixup_timespec(&endtime);
   
        fd = pcap_get_selectable_fd(pcap);         fd = pcap_get_selectable_fd(pcap);
          if (fd == -1) {
                  fprintf(stderr, "arping: pcap_get_selectable_fd()=-1: %s\n",
                          pcap_geterr(pcap));
                  exit(1);
          }
          old_received = numrecvd;
   
        for (;!done;) {         for (;!done;) {
                int trydispatch = 0;                 int trydispatch = 0;
   
               gettv(&tv);               getclock(&ts);
               tv.tv_sec = endtime.tv_sec - tv.tv_sec;               ts.tv_sec = endtime.tv_sec - ts.tv_sec;
               tv.tv_usec = endtime.tv_usec - tv.tv_usec;               ts.tv_nsec = endtime.tv_nsec - ts.tv_nsec;
               fixup_timeval(&tv);               fixup_timespec(&ts);
               if (tv.tv_sec < 0) {               if (verbose > 2) {
                       tv.tv_sec = 0;                       printf("arping: listen for replies for %ld.%09ld sec\n",
                       tv.tv_usec = 1;                              (long)ts.tv_sec, (long)ts.tv_nsec);
                }
 
                /* if time has passed, do one last check and then we're done.
                 * this also triggers if not using monotonic clock and time
                 * is set forwards */
                if (ts.tv_sec < 0) {
                        ts.tv_sec = 0;
                        ts.tv_nsec = 1;
                        done = 1;                         done = 1;
                }                 }
   
                  /* if wait-for-packet time is longer than full period,
                   * we're obviously not using a monotonic clock and the system
                   * time has been changed.
                   * we don't know how far we're into the waiting, so just end
                   * it here */
                  if ((ts.tv_sec > packetwait / 1000000)
                      || ((ts.tv_sec == packetwait / 1000000)
                          && (ts.tv_nsec/1000 > packetwait % 1000000))) {
                          ts.tv_sec = 0;
                          ts.tv_nsec = 1;
                          done = 1;
                  }
   
                  /* check for sigint */
                if (time_to_die) {                 if (time_to_die) {
                        return;                         return;
                }                 }
   
                /* try to wait for data */                 /* try to wait for data */
                {                 {
                       struct pollfd p;                       fd_set fds;
                        int r;                         int r;
                       p.fd = fd;                       struct timeval tv;
                       p.events = POLLIN | POLLPRI;                       tv.tv_sec = ts.tv_sec;
                        tv.tv_usec = ts.tv_nsec / 1000;
   
                       r = poll(&p, 1, tv.tv_sec * 1000 + tv.tv_usec / 1000);                       FD_ZERO(&fds);
                        FD_SET(fd, &fds);
 
                        r = select(fd + 1, &fds, NULL, NULL, &tv);
                        switch (r) {                         switch (r) {
                        case 0: /* timeout */                         case 0: /* timeout */
                                  if (numrecvd == old_received) {
                                          if (reverse_beep) {
                                                  printf("\a");
                                          }
                                          switch (display) {
                                          case NORMAL:
                                                  printf("Timeout\n");
                                                  break;
                                          case DOT:
                                                  printf(".");
                                                  break;
                                          case RAW:
                                          case RAWRAW:
                                          case RRAW:
                                          case QUIET:
                                                  break;
                                          }
                                          fflush(stdout);
                                  }
                                done = 1;                                 done = 1;
                                break;                                 break;
                        case -1: /* error */                         case -1: /* error */
Line 896  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ Line 1630  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_
                                        done = 1;                                         done = 1;
                                        sigint(0);                                         sigint(0);
                                        fprintf(stderr,                                         fprintf(stderr,
                                               "arping: poll() failed: %s\n",                                               "arping: select() failed: %s\n",
                                                strerror(errno));                                                 strerror(errno));
                                }                                 }
                                break;                                 break;
Line 908  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ Line 1642  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_
   
                if (trydispatch) {                 if (trydispatch) {
                        int ret;                         int ret;
                       if (1 != (ret = pcap_dispatch(pcap, 1,                       if (0 > (ret = pcap_dispatch(pcap, -1,
                                                     func,                                                    func,
                                                     NULL))) {                                                    NULL))) {
                                /* rest, so we don't take 100% CPU... mostly                                 /* rest, so we don't take 100% CPU... mostly
                                   hmm... does usleep() exist everywhere? */                                    hmm... does usleep() exist everywhere? */
                                usleep(1);                                 usleep(1);
Line 918  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ Line 1652  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_
                                /* weird is normal on bsd :) */                                 /* weird is normal on bsd :) */
                                if (verbose > 3) {                                 if (verbose > 3) {
                                        fprintf(stderr,                                         fprintf(stderr,
                                               "arping: poll says ok, "                                               "arping: select says ok, but "
                                                "pcap_dispatch=%d!\n",                                                 "pcap_dispatch=%d!\n",
                                                ret);                                                 ret);
                                }                                 }
Line 927  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ Line 1661  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_
        }         }
 }  }
   
/**// return 1 on success.
 * static int
 */xresolve(libnet_t* l, const char *name, int r, uint32_t *addr)
static void 
ping_recv(pcap_t *pcap,uint32_t packetwait, pcap_handler func) 
 {  {
       if(verbose>3) {        if (!strcmp(ip_broadcast, name)) {
               printf("arping: receiving packets...\n");                *addr = 0xffffffff;
       }                return 1;
        }
#if WIN32        *addr = libnet_name2addr4(l, (char*)name, r);
       ping_recv_win32(pcap,packetwait,func);        return *addr != 0xffffffff;
#else 
       ping_recv_unix(pcap,packetwait,func); 
#endif 
 }  }
   
 /**  /**
  *   *
  */   */
int main(int argc, char **argv)int
 arping_main(int argc, char **argv)
 {  {
         char ebuf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE];          char ebuf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE];
         char *cp;          char *cp;
        int promisc = 0;        const char *srcip_opt = NULL;
        int srcip_given = 0;        const char *dstip_opt = NULL;
        int srcmac_given = 0;        // `dstip_given` can be set even when there's no arg past flags on the
         // cmdline and -B not set. E.g. -d defaults to self, so requires no
         // extra arg.
         int dstip_given = 0;          int dstip_given = 0;
        const char *ifname = NULL;        const char *srcmac_opt = NULL;
        char *parm;        const char *dstmac_opt = NULL;
         const char *ifname = NULL;      // -i/-I
         int opt_B = 0;
         int opt_T = 0;
         int opt_U = 0;
         const char* drop_group = NULL;  // -g
         const char *parm; // First argument, meaning the target IP.
         int c;          int c;
        unsigned int maxcount = -1;        int maxcount = -1;
         int dont_use_arping_lookupdev=0;          int dont_use_arping_lookupdev=0;
         struct bpf_program bp;          struct bpf_program bp;
         pcap_t *pcap;          pcap_t *pcap;
        static enum { NONE, PINGMAC, PINGIP } mode = NONE;        enum { NONE, PINGMAC, PINGIP } mode = NONE;
        unsigned int packetwait = 1000000;        unsigned int packetwait = 1000000; // Default one second.
         double deadline = -1;
         char bpf_filter[64];
         ebuf[0] = 0;
         srandom(time(NULL));
   
         for (c = 1; c < argc; c++) {          for (c = 1; c < argc; c++) {
                 if (!strcmp(argv[c], "--help")) {                  if (!strcmp(argv[c], "--help")) {
Line 973  int main(int argc, char **argv) Line 1715  int main(int argc, char **argv)
                 }                  }
         }          }
   
         memset(ethnull, 0, ETH_ALEN);  
   
         srcip = 0;          srcip = 0;
         dstip = 0xffffffff;          dstip = 0xffffffff;
        memset(dstmac, 0xff, ETH_ALEN);        memcpy(dstmac, ethxmas, ETH_ALEN);
        memset(ethxmas, 0xff, ETH_ALEN); 
   
        while (EOF!=(c=getopt(argc,argv,"0aAbBc:dDeFhi:I:pqrRs:S:t:T:uvw:"))) {        while (EOF != (c = getopt(argc, argv,
                                   "0aAbBC:c:dDeFg:hi:I:m:pPqQ:rRs:S:t:T:uUvV:w:W:"))) {
                 switch(c) {                  switch(c) {
                 case '0':                  case '0':
                        srcip = 0;                        srcip_opt = "0.0.0.0";
                        srcip_given = 1; 
                         break;                          break;
                 case 'a':                  case 'a':
                         beep = 1;                          beep = 1;
Line 993  int main(int argc, char **argv) Line 1732  int main(int argc, char **argv)
                         addr_must_be_same = 1;                          addr_must_be_same = 1;
                         break;                          break;
                 case 'b':                  case 'b':
                        srcip = 0xffffffff;                        srcip_opt = ip_broadcast;
                        srcip_given = 1; 
                         break;                          break;
                 case 'B':                  case 'B':
                        dstip = 0xffffffff;                        dstip_opt = ip_broadcast;
                        dstip_given = 1;                        dstip_given = 1;
                         opt_B = 1;
                         break;                          break;
                 case 'c':                  case 'c':
                         maxcount = atoi(optarg);                          maxcount = atoi(optarg);
                         break;                          break;
                   case 'C':
                           max_replies = atoi(optarg);
                           break;
                 case 'd':                  case 'd':
                         finddup = 1;                          finddup = 1;
                         break;                          break;
Line 1017  int main(int argc, char **argv) Line 1759  int main(int argc, char **argv)
                         break;                          break;
                 case 'h':                  case 'h':
                         usage(0);                          usage(0);
                           exit(0); // Needless but shuts up compiler warnings.
                   case 'g':
                           drop_group = optarg;
                           break;
                 case 'i':                  case 'i':
                         if (strchr(optarg, ':')) {                          if (strchr(optarg, ':')) {
                                 fprintf(stderr, "arping: If you're trying to "                                  fprintf(stderr, "arping: If you're trying to "
Line 1027  int main(int argc, char **argv) Line 1773  int main(int argc, char **argv)
                                         "purpose)\n");                                          "purpose)\n");
                                 exit(1);                                  exit(1);
                         }                          }
                 case 'I': /* FALL THROUGH */  
                         ifname = optarg;                          ifname = optarg;
                           break;
                   case 'I':
                           ifname = optarg;
                         break;                          break;
                   case 'm':
                           timestamp_type = optarg;
                           break;
                 case 'p':                  case 'p':
                         promisc = 1;                          promisc = 1;
                         break;                          break;
                   case 'P':
                           send_reply = 1;
                           break;
                 case 'q':                  case 'q':
                         display = QUIET;                          display = QUIET;
                         break;                          break;
                   case 'Q':
                           vlan_prio = atoi(optarg);
                           if (vlan_prio < 0 || vlan_prio > 7) {
                                   fprintf(stderr,
                                           "arping: 802.1p priority must be 0-7. It's %d\n",
                                           vlan_prio);
                                   exit(1);
                           }
                           break;
                 case 'r':                  case 'r':
                         display = (display==RRAW)?RAWRAW:RAW;                          display = (display==RRAW)?RAWRAW:RAW;
                         break;                          break;
Line 1043  int main(int argc, char **argv) Line 1806  int main(int argc, char **argv)
                         display = (display==RAW)?RAWRAW:RRAW;                          display = (display==RAW)?RAWRAW:RRAW;
                         break;                          break;
                 case 's': { /* spoof source MAC */                  case 's': { /* spoof source MAC */
                        unsigned int n[6];                        srcmac_opt = optarg;
                        if (!get_mac_addr(optarg, 
                                          &n[0],&n[1],&n[2], 
                                          &n[3],&n[4],&n[5])){ 
                                fprintf(stderr, "arping: Weird MAC addr %s\n", 
                                        optarg); 
                                exit(1); 
                        } 
                        for (c = 0; c < 6; c++) { 
                                srcmac[c] = n[c] & 0xff; 
                        } 
                        srcmac_given = 1; 
                         break;                          break;
                 }                  }
                 case 'S': /* set source IP, may be null for don't-know */                  case 'S': /* set source IP, may be null for don't-know */
                        do_libnet_init(ifname);                        srcip_opt = optarg;
                        if (-1 == (srcip = libnet_name2addr4(libnet, 
                                                             optarg, 
                                                             LIBNET_RESOLVE))){ 
                                fprintf(stderr, "arping: Can't resolve %s, or " 
                                        "%s is broadcast. If it is, use -b" 
                                        " instead of -S\n", optarg,optarg); 
                                exit(1); 
                        } 
                        srcip_given = 1; 
                         break;                          break;
                 case 't': { /* set taget mac */                  case 't': { /* set taget mac */
                        unsigned int n[6];                        dstmac_opt = optarg;
                        if (mode == PINGMAC) { 
                                fprintf(stderr, "arping: -t can only be used " 
                                        "in IP ping mode\n"); 
                                exit(1); 
                        } 
                        if (!get_mac_addr(optarg, 
                                          &n[0],&n[1],&n[2], 
                                          &n[3],&n[4],&n[5])){ 
                                fprintf(stderr, "Illegal MAC addr %s\n", 
                                        optarg); 
                                exit(1); 
                        } 
                        for (c = 0; c < 6; c++) { 
                                dstmac[c] = n[c] & 0xff; 
                        } 
                         mode = PINGIP;                          mode = PINGIP;
                         break;                          break;
                 }                  }
                 case 'T': /* set destination IP */                  case 'T': /* set destination IP */
                        if (mode == PINGIP) {                        opt_T = 1;
                                fprintf(stderr, "arping: -T can only be used "                        dstip_opt = optarg;
                                        "in MAC ping mode\n"); 
                                exit(1); 
                        } 
                        do_libnet_init(ifname); 
                        if (-1 == (dstip = libnet_name2addr4(libnet, 
                                                             optarg, 
                                                             LIBNET_RESOLVE))){ 
                                fprintf(stderr,"arping: Can't resolve %s, or " 
                                        "%s is broadcast. If it is, use -B " 
                                        "instead of -T\n",optarg,optarg); 
                                exit(1); 
                        } 
                         mode = PINGMAC;                          mode = PINGMAC;
                         break;                          break;
                 case 'u':                  case 'u':
                         alsototal = 1;                          alsototal = 1;
                         break;                          break;
                   case 'U':
                           opt_U = 1;
                           unsolicited = 1;
                           mode = PINGIP;
                           break;
                 case 'v':                  case 'v':
                         verbose++;                          verbose++;
                         break;                          break;
                   case 'V':
                           vlan_tag = atoi(optarg);
                           if (vlan_tag < 0 || vlan_tag > 4095) {
                                   fprintf(stderr,
                                           "arping: vlan tag must 0-4095. Is %d\n",
                                           vlan_tag);
                                   exit(1);
                           }
                           break;
                 case 'w':                  case 'w':
                        packetwait = (unsigned)atoi(optarg);                        deadline = atof(optarg);
                         break;                          break;
                   case 'W':
                           packetwait = (unsigned)(1000000.0 * atof(optarg));
                           break;
                 default:                  default:
                         usage(1);                          usage(1);
                 }                  }
         }          }
   
           if (argc - optind > 1) {
                   // Can be zero if using -d or -B.
                   fprintf(stderr, "arping: Too many args on command line."
                           " Expected at most one.\n");
                   exit(1);
           }
   
           // Generate random payload suffix for MAC pings, to be able to
           // differentiate from unrelated ping replies.
           if (payload_suffix_size < 0) {
                   payload_suffix_size = 4;
                   payload_suffix = malloc(payload_suffix_size);
                   if (payload_suffix) {
                           const ssize_t rc = xgetrandom(payload_suffix, payload_suffix_size, 0);
                           if (rc == -1) {
                                   fprintf(stderr,
                                           "arping: failed to get %zd random bytes: %s\n",
                                           payload_suffix_size,
                                           strerror(errno));
                                   free(payload_suffix);
                                   payload_suffix = NULL;
                           } else if (payload_suffix_size != rc) {
                                   fprintf(stderr,
                                           "arping: only got %zd out of %zd bytes for random suffix\n",
                                           rc, payload_suffix_size);
                           }
                   } else {
                           fprintf(stderr, "arping: failed to allocate %zd bytes for payload suffix.\n",
                                   payload_suffix_size);
                   }
   
                   if (!payload_suffix) {
                           fprintf(stderr, "arping:  Using constant suffix.\n");
                           payload_suffix = "arping";
                           payload_suffix_size = strlen(payload_suffix);
                   }
           }
   
           if (((mode == PINGIP) && opt_T)
               || ((mode == PINGMAC) && (opt_B || dstmac_opt || opt_U))) {
                   fprintf(stderr, "arping: -T can only be used to ping MAC"
                           " and -BtU only to ping IPs");
                   exit(1);
           }
           if (opt_T && opt_B) {
                   fprintf(stderr,
                           "arping: -B can't be used with -T,"
                           " since they set the same thing\n");
                   exit(1);
           }
   
           if (srcmac_opt != NULL) {
                   if (!get_mac_addr(srcmac_opt, srcmac)) {
                           fprintf(stderr, "arping: Weird MAC addr %s\n",
                                   srcmac_opt);
                           exit(1);
                   }
           }
   
           if (dstmac_opt != NULL) {
                   if (!get_mac_addr(dstmac_opt, dstmac)) {
                           fprintf(stderr, "Illegal MAC addr %s\n", dstmac_opt);
                           exit(1);
                   }
           }
   
           if (srcip_opt != NULL) {
                   do_libnet_init(ifname, 0);
                   if (!xresolve(libnet, srcip_opt, LIBNET_RESOLVE, &srcip)) {
                           fprintf(stderr, "arping: Can't resolve %s, or "
                                   "%s is broadcast. If it is, use -b"
                                   " instead of -S\n", srcip_opt,srcip_opt);
                           exit(1);
                   }
           }
   
           if (dstip_opt) {
                   do_libnet_init(ifname, 0);
                   if (!xresolve(libnet, dstip_opt, LIBNET_RESOLVE, &dstip)) {
                           fprintf(stderr,"arping: Can't resolve %s, or "
                                   "%s is broadcast. If it is, use -B "
                                   "instead of -T\n",dstip_opt,dstip_opt);
                           exit(1);
                   }
           }
   
           if (vlan_prio >= 0 && vlan_tag == -1) {
                   fprintf(stderr, "arping: -Q requires the use of 802.1Q (-V)\n");
                   exit(1);
           }
           if (vlan_prio == -1) {
                   vlan_prio = 0;
           }
   
           if (verbose > 1) {
   #if HAVE_CLOCK_MONOTONIC
                   struct timespec ts;
                   if (clock_getres(CLOCK_MONOTONIC, &ts)) {
                           fprintf(stderr,
                                   "arping: clock_getres(CLOCK_MONOTONIC, ...): %s\n",
                                   strerror(errno));
                   } else {
                           printf("arping: clock_getres() = %lds %ldns\n",
                                  (long)ts.tv_sec, (long)ts.tv_nsec);
                   }
   #else
                   printf("arping: Using gettimeofday() for time measurements\n");
   #endif
           }
   
         if (display == DOT) {          if (display == DOT) {
                setvbuf(stdout, NULL, _IONBF, 0);                if (0 != setvbuf(stdout, NULL, _IONBF, 0)) {
                         fprintf(stderr,
                                 "arping: setvbuf(stdout, NULL, IONBF, 0): %s\n",
                                 strerror(errno));
                 }
         }          }
   
         if (finddup && maxcount == -1) {          if (finddup && maxcount == -1) {
Line 1133  int main(int argc, char **argv) Line 1980  int main(int argc, char **argv)
         /* default to own IP address when doing -d */          /* default to own IP address when doing -d */
         if (finddup && !parm) {          if (finddup && !parm) {
                 dstip_given = 1;                  dstip_given = 1;
                do_libnet_init(ifname);                do_libnet_init(ifname, 0);
                 dstip = libnet_get_ipaddr4(libnet);                  dstip = libnet_get_ipaddr4(libnet);
                 if (verbose) {                  if (verbose) {
                         printf("defaulting to checking dup for %s\n",                          printf("defaulting to checking dup for %s\n",
Line 1145  int main(int argc, char **argv) Line 1992  int main(int argc, char **argv)
          * Handle dstip_given instead of ip address after parms (-B really)           * Handle dstip_given instead of ip address after parms (-B really)
          */           */
         if (mode == NONE) {          if (mode == NONE) {
                if (optind + 1 == argc) {                if (parm) {
                         mode = is_mac_addr(parm)?PINGMAC:PINGIP;                          mode = is_mac_addr(parm)?PINGMAC:PINGIP;
                 } else if (dstip_given) {                  } else if (dstip_given) {
                         mode = PINGIP;                          mode = PINGIP;
                        do_libnet_init(ifname);                        do_libnet_init(ifname, 0);
                         parm = strdup(libnet_addr2name4(dstip,0));                          parm = strdup(libnet_addr2name4(dstip,0));
                         if (!parm) {                          if (!parm) {
                                fprintf(stderr, "arping: out of mem\n");                                fprintf(stderr, "arping: out of memory\n");
                                 exit(1);                                  exit(1);
                         }                          }
                 }                  }
Line 1172  int main(int argc, char **argv) Line 2019  int main(int argc, char **argv)
         /*          /*
          * libnet init (may be done already for resolving)           * libnet init (may be done already for resolving)
          */           */
        do_libnet_init(ifname);        do_libnet_init(ifname, 0);
        
         /*          /*
          * Make sure dstip and parm like eachother           * Make sure dstip and parm like eachother
          */           */
Line 1184  int main(int argc, char **argv) Line 2031  int main(int argc, char **argv)
                                 "\n");                                  "\n");
                         exit(1);                          exit(1);
                 }                  }
                if (-1 == (dstip = libnet_name2addr4(libnet,                if (!xresolve(libnet, parm, LIBNET_RESOLVE, &dstip)) {
                                                     parm, 
                                                     LIBNET_RESOLVE))) { 
                         fprintf(stderr, "arping: Can't resolve %s\n", parm);                          fprintf(stderr, "arping: Can't resolve %s\n", parm);
                         exit(1);                          exit(1);
                 }                  }
Line 1197  int main(int argc, char **argv) Line 2042  int main(int argc, char **argv)
          * parse parm into dstmac           * parse parm into dstmac
          */           */
         if (mode == PINGMAC) {          if (mode == PINGMAC) {
                 unsigned int n[6];  
                 if (optind + 1 != argc) {                  if (optind + 1 != argc) {
                         usage(1);                          usage(1);
                 }                  }
Line 1207  int main(int argc, char **argv) Line 2051  int main(int argc, char **argv)
                                 "argument\n");                                  "argument\n");
                         exit(1);                          exit(1);
                 }                  }
                if (!get_mac_addr(argv[optind],                if (!get_mac_addr(argv[optind], dstmac)) {
                                  &n[0],&n[1],&n[2], 
                                  &n[3],&n[4],&n[5])) { 
                         fprintf(stderr, "arping: Illegal mac addr %s\n",                          fprintf(stderr, "arping: Illegal mac addr %s\n",
                                 argv[optind]);                                  argv[optind]);
                         return 1;                          return 1;
                 }                  }
                for (c = 0; c < 6; c++) {        }
                        dstmac[c] = n[c] & 0xff; 
                } 
        }        
   
         target = parm;          target = parm;
         /*          /*
Line 1228  int main(int argc, char **argv) Line 2067  int main(int argc, char **argv)
          * Get some good iface.           * Get some good iface.
          */           */
         if (!ifname) {          if (!ifname) {
                if (dont_use_arping_lookupdev) {                if (!dont_use_arping_lookupdev) {
                        ifname = arping_lookupdev_default(ifname,                        ifname = arping_lookupdev(srcip, dstip, ebuf);
                                                          srcip,dstip,ebuf);                        strip_newline(ebuf);
                } else {                        if (!ifname) {
                        ifname = arping_lookupdev(ifname,srcip,dstip,ebuf);                                fprintf(stderr, "arping: lookup dev: %s\n",
                                         ebuf);
                         }
                 }
                 if (!ifname) {
                         ifname = arping_lookupdev_default(srcip, dstip, ebuf);
                         strip_newline(ebuf);
                         if (ifname && !dont_use_arping_lookupdev) {
                                 fprintf(stderr,
                                         "arping: Unable to automatically find "
                                         "interface to use. Is it on the local "
                                         "LAN?\n"
                                         "arping: Use -i to manually "
                                         "specify interface. "
                                         "Guessing interface %s.\n", ifname);
                         }
                 }                  }
                 if (!ifname) {                  if (!ifname) {
                        fprintf(stderr, "arping: arping_lookupdev(): %s\n",                        fprintf(stderr, "arping: Gave up looking for interface"
                                ebuf);                                " to use: %s\n", ebuf);
                         exit(1);                          exit(1);
                 }                  }
                 /* FIXME: check for other probably-not interfaces */                  /* FIXME: check for other probably-not interfaces */
Line 1253  int main(int argc, char **argv) Line 2107  int main(int argc, char **argv)
          * Init libnet again, because we now know the interface name.           * Init libnet again, because we now know the interface name.
          * We should know it by know at least           * We should know it by know at least
          */           */
        do_libnet_init(ifname);        do_libnet_init(ifname, 0);
   
         /*          /*
          * pcap init           * pcap init
          */           */
        if (!(pcap = pcap_open_live((char*)ifname, 100, promisc, 10, ebuf))) {        if (!(pcap = do_pcap_open_live(ifname, 100, promisc, 10, ebuf))) {
                fprintf(stderr, "arping: pcap_open_live(): %s\n",ebuf);                strip_newline(ebuf);
                 fprintf(stderr, "arping: pcap_open_live(): %s\n", ebuf);
                 exit(1);                  exit(1);
         }          }
           drop_privileges(drop_group);
         if (pcap_setnonblock(pcap, 1, ebuf)) {          if (pcap_setnonblock(pcap, 1, ebuf)) {
                   strip_newline(ebuf);
                 fprintf(stderr, "arping: pcap_set_nonblock(): %s\n", ebuf);                  fprintf(stderr, "arping: pcap_set_nonblock(): %s\n", ebuf);
                 exit(1);                  exit(1);
         }          }
        if (verbose) {        if (verbose > 1) {
                printf("pcap_get_selectable(): %d\n",                printf("arping: pcap_get_selectable_fd(): %d\n",
                        pcap_get_selectable_fd(pcap));                         pcap_get_selectable_fd(pcap));
         }          }
   
#if HAVE_NET_BPF_H#ifdef BIOCIMMEDIATE
         {          {
                   // This may be redundant if pcap_set_immediate_mode() is present.
                 uint32_t on = 1;                  uint32_t on = 1;
                 if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE,                  if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE,
                                &on))) {                                 &on))) {
Line 1285  int main(int argc, char **argv) Line 2143  int main(int argc, char **argv)
   
         if (mode == PINGIP) {          if (mode == PINGIP) {
                 /* FIXME: better filter with addresses? */                  /* FIXME: better filter with addresses? */
                if (-1 == pcap_compile(pcap, &bp, "arp", 0,-1)) {                if (vlan_tag >= 0) {
                        fprintf(stderr, "arping: pcap_compile(): error\n");                        snprintf(bpf_filter, sizeof(bpf_filter),
                                  "vlan %u and arp", vlan_tag);
                 } else {
                         snprintf(bpf_filter, sizeof(bpf_filter), "arp");
                 }
                 if (-1 == pcap_compile(pcap, &bp, bpf_filter, 0, -1)) {
                         fprintf(stderr, "arping: pcap_compile(%s): %s\n",
                                 bpf_filter, pcap_geterr(pcap));
                         exit(1);                          exit(1);
                 }                  }
         } else { /* ping mac */          } else { /* ping mac */
                 /* FIXME: better filter with addresses? */                  /* FIXME: better filter with addresses? */
                if (-1 == pcap_compile(pcap, &bp, "icmp", 0,-1)) {                if (vlan_tag >= 0) {
                        fprintf(stderr, "arping: pcap_compile(): error\n");                        snprintf(bpf_filter, sizeof(bpf_filter),
                                  "vlan %u and icmp", vlan_tag);
                 } else {
                         snprintf(bpf_filter, sizeof(bpf_filter), "icmp");
                 }
                 if (-1 == pcap_compile(pcap, &bp, bpf_filter, 0,-1)) {
                         fprintf(stderr, "arping: pcap_compile(%s): %s\n",
                                 bpf_filter, pcap_geterr(pcap));
                         exit(1);                          exit(1);
                 }                  }
         }          }
         if (-1 == pcap_setfilter(pcap, &bp)) {          if (-1 == pcap_setfilter(pcap, &bp)) {
                fprintf(stderr, "arping: pcap_setfilter(): error\n");                fprintf(stderr, "arping: pcap_setfilter(): %s\n",
                         pcap_geterr(pcap));
                 exit(1);                  exit(1);
         }          }
   
         /*          /*
          * final init           * final init
          */           */
        if (!srcmac_given) {        if (srcmac_opt == NULL) {
                 if (!(cp = (char*)libnet_get_hwaddr(libnet))) {                  if (!(cp = (char*)libnet_get_hwaddr(libnet))) {
                         fprintf(stderr, "arping: libnet_get_hwaddr(): %s\n",                          fprintf(stderr, "arping: libnet_get_hwaddr(): %s\n",
                                 libnet_geterror(libnet));                                  libnet_geterror(libnet));
Line 1312  int main(int argc, char **argv) Line 2185  int main(int argc, char **argv)
                 }                  }
                 memcpy(srcmac, cp, ETH_ALEN);                  memcpy(srcmac, cp, ETH_ALEN);
         }          }
        if (!srcip_given) {        if (srcip_opt == NULL) {
                if (-1 == (srcip = libnet_get_ipaddr4(libnet))) {                if (ip_broadcast_num == (srcip = libnet_get_ipaddr4(libnet))) {
                        fprintf(stderr, "arping: libnet_get_ipaddr4(libnet): "                        fprintf(stderr,
                                "%s\n", libnet_geterror(libnet));                                "arping: Unable to get the IPv4 address of "
                                 "interface %s:\narping: %s"
                                 "arping: "
                                 "Use -S to specify address manually.\n",
                                 ifname, libnet_geterror(libnet));
                         exit(1);                          exit(1);
                 }                  }
         }          }
#if WIN32        do_signal_init();
        /* SetConsoleCtrlHandler(NULL, TRUE); */ 
        SetConsoleCtrlHandler(arping_console_ctrl_handler, TRUE); 
#else 
        signal(SIGINT, sigint); 
#endif 
   
         if (verbose) {          if (verbose) {
                printf("This box:   Interface: %s  IP: %s   MAC address: ",                char buf[128];
                       ifname, libnet_addr2name4(libnet_get_ipaddr4(libnet),                printf("This box:   Interface: %s  IP: %s   MAC address: %s\n",
                                                 0));                       ifname,
                for (c = 0; c < ETH_ALEN - 1; c++) {                       libnet_addr2name4(libnet_get_ipaddr4(libnet), 0),
                        printf("%.2x:", (uint8_t)srcmac[c]);                       format_mac(srcmac, buf, sizeof(buf)));
                } 
                printf("%.2x\n", (uint8_t)srcmac[ETH_ALEN - 1]); 
         }          }
   
           drop_more_privileges();
   
         if (display == NORMAL) {          if (display == NORMAL) {
                 printf("ARPING %s\n", parm);                  printf("ARPING %s\n", parm);
Line 1344  int main(int argc, char **argv) Line 2215  int main(int argc, char **argv)
         /*          /*
          * let's roll           * let's roll
          */           */
           if (deadline > 0) {
                   struct timespec ts;
                   getclock(&ts);
                   deadline += timespec2dbl(&ts);
           }
         if (mode == PINGIP) {          if (mode == PINGIP) {
                unsigned int c;                int c;
                unsigned int r;                for (c = 0; (maxcount < 0 || c < maxcount) && !time_to_die; c++) {
                for (c = 0; c < maxcount && !time_to_die; c++) {                        pingip_send();
                        pingip_send(srcmac, dstmac, srcip, dstip);                        const uint32_t w = wait_time(deadline, packetwait);
                        r = numrecvd;                        if (w == 0) {
                        ping_recv(pcap,packetwait,                                break;
                                  (pcap_handler)pingip_recv); 
                        if (reverse_beep && !time_to_die && (r == numrecvd)) { 
                                printf("\a"); 
                                fflush(stdout); 
                         }                          }
                           ping_recv(pcap, w, (pcap_handler)pingip_recv);
                 }                  }
         } else { /* PINGMAC */          } else { /* PINGMAC */
                unsigned int c;                int c;
                unsigned int r;                for (c = 0; (maxcount < 0 || c < maxcount) && !time_to_die; c++) {
                for (c = 0; c < maxcount && !time_to_die; c++) {                        pingmac_send(xrandom(), c);
                        pingmac_send(srcmac, dstmac, srcip, dstip, rand(), c);                        const uint32_t w = wait_time(deadline, packetwait);
                        r = numrecvd;                        if (w == 0) {
                        ping_recv(pcap,packetwait,                                break;
                                  (pcap_handler)pingmac_recv); 
                        if (reverse_beep && !time_to_die && (r == numrecvd)) { 
                                printf("\a"); 
                                fflush(stdout); 
                         }                          }
                           ping_recv(pcap, w,  (pcap_handler)pingmac_recv);
                 }                  }
         }          }
         if (display == DOT) {          if (display == DOT) {
                count_missing_dots();                const float succ = 100.0 - 100.0 * (float)(numrecvd)/(float)numsent;
                printf("\t%3.0f%% packet loss\n",                printf("\t%3.0f%% packet loss (%d extra)\n",
                       100.0 - 100.0 * (float)(numrecvd)/(float)numsent);                       (succ < 0.0) ? 0.0 : succ,
                        (succ < 0.0) ? (numrecvd - numsent) : 0);
         } else if (display == NORMAL) {          } else if (display == NORMAL) {
                float succ;                const float succ = 100.0 - 100.0 * (float)(numrecvd)/(float)numsent;
                succ = 100.0 - 100.0 * (float)(numrecvd)/(float)numsent; 
                 printf("\n--- %s statistics ---\n"                  printf("\n--- %s statistics ---\n"
                        "%d packets transmitted, "                         "%d packets transmitted, "
                        "%d packets received, "                         "%d packets received, "
Line 1385  int main(int argc, char **argv) Line 2255  int main(int argc, char **argv)
                        "unanswered (%d extra)\n",                         "unanswered (%d extra)\n",
                        target,numsent,numrecvd,                         target,numsent,numrecvd,
                        (succ < 0.0) ? 0.0 : succ,                         (succ < 0.0) ? 0.0 : succ,
                       (succ < 0.0) ? (numrecvd - numsent): 0);                        (succ < 0.0) ? (numrecvd - numsent): 0);
                 if (numrecvd) {
                         double avg = stats_total_time / numrecvd;
                         printf("rtt min/avg/max/std-dev = "
                                "%.3f/%.3f/%.3f/%.3f ms",
                                1000*stats_min_time,
                                1000*avg,
                                1000*stats_max_time,
                                1000*sqrt(stats_total_sq_time/numrecvd
                                          -avg*avg));
                 }
                 printf("\n");
         }          }
   
         if (finddup) {          if (finddup) {
Line 1394  int main(int argc, char **argv) Line 2275  int main(int argc, char **argv)
                 return !numrecvd;                  return !numrecvd;
         }          }
 }  }
   /* ---- Emacs Variables ----
    * Local Variables:
    * c-basic-offset: 8
    * indent-tabs-mode: nil
    * End:
    *
    * vim: ts=8 sw=8
    */

Removed from v.1.1  
changed lines
  Added in v.1.1.1.4


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