Diff for /embedaddon/arping/src/arping.c between versions 1.1.1.2 and 1.1.1.3

version 1.1.1.2, 2014/06/15 16:26:43 version 1.1.1.3, 2016/10/18 13:16:10
Line 15 Line 15
  *   *
  */   */
 /*  /*
 *  Copyright (C) 2000-2011 Thomas Habets <thomas@habets.se> *  Copyright (C) 2000-2014 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 85 Line 85
 #include <win32/libnet.h>  #include <win32/libnet.h>
 #endif  #endif
   
   #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
Line 110 Line 118
   
 /**  /**
  * 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(uint32_t srcip, uint32_t dstip, char *ebuf);  arping_lookupdev(uint32_t srcip, uint32_t dstip, char *ebuf);
Line 121  static const char *version = VERSION; /* from autoconf Line 131  static const char *version = VERSION; /* from autoconf
   
 static libnet_t *libnet = 0;  static libnet_t *libnet = 0;
   
   /* Timestamp of last packet sent.
    * Used for timing, and assumes that reply is due to most recent sent query.
    */
 static struct timespec lastpacketsent;  static struct timespec lastpacketsent;
   
 /* target string */  /* target string */
Line 146  static int reverse_beep = 0;         /* beep when expe Line 159  static int reverse_beep = 0;         /* beep when expe
 static int alsototal = 0;            /* print sent as well as received. -u */  static int alsototal = 0;            /* print sent as well as received. -u */
 static int addr_must_be_same = 0;    /* -A */  static int addr_must_be_same = 0;    /* -A */
 static int unsolicited = 0;          /* -U */  static int unsolicited = 0;          /* -U */
   static int send_reply = 0;           /* Send reply instead of request. -P */
   
 static int finddup = 0;              /* finddup mode. -d */  static int finddup = 0;              /* finddup mode. -d */
 static int dupfound = 0;             /* set to 1 if dup found */  static int dupfound = 0;             /* set to 1 if dup found */
 static char lastreplymac[ETH_ALEN];  /* if last different from this then dup */  static char lastreplymac[ETH_ALEN];  /* if last different from this then dup */
   
static unsigned int numsent = 0;     /* packets sent */static unsigned int numsent = 0;            /* packets sent */
static unsigned int numrecvd = 0;    /* packets received */static unsigned int numrecvd = 0;           /* packets received */
static unsigned int numdots = 0;     /* dots that should be printed */static unsigned int max_replies = UINT_MAX; /* exit after -C replies */
 static unsigned int numdots = 0;            /* dots that should be printed */
 static const char* timestamp_type = NULL;   /* Incoming packet measurement ts type (-m) */
   
 static double stats_min_time = -1;  static double stats_min_time = -1;
 static double stats_max_time = -1;  static double stats_max_time = -1;
Line 178  int verbose = 0;  /* Increase with -v */ Line 194  int verbose = 0;  /* Increase with -v */
 static volatile sig_atomic_t time_to_die = 0;  static volatile sig_atomic_t time_to_die = 0;
   
 /**  /**
    * 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
   drop_fs_root()
   {
           const char* chroot_user = "sshd";
           struct passwd *pw;
           errno = 0;
           if (!(pw = getpwnam(chroot_user))) {
                   if (verbose) {
                           printf("arping: getpwnam(%s): %s",
                                  chroot_user, strerror(errno));
                   }
                   return;
           }
           if (chdir(pw->pw_dir)) {
                   if (verbose) {
                           printf("arping: chdir(%s): %s",
                                  pw->pw_dir, strerror(errno));
                   }
                   return;
           }
           if (chroot(pw->pw_dir)) {
                   if (verbose) {
                           printf("arping: chroot(%s): %s",
                                  pw->pw_dir, 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
   }
   
   /**
    * drop all privileges.
    */
   static void
   drop_privileges()
   {
           // 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) {
                           printf("arping: getpwnam(%s): %s\n",
                                  drop_user, strerror(errno));
                   }
                   return;
           } else {
                   uid = pw->pw_uid;
                   gid = pw->pw_gid;
           }
           drop_fs_root();
           drop_uid(uid, gid);
           drop_capabilities();
   }
   
   
   /**
    * Do pcap_open_live(), except by using the pcap_create() interface
    * introduced in 2008 (libpcap 0.4) where available.
    *
    * 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 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   * Some stupid OSs (Solaris) think it's a good idea to put network
  * devices in /dev and then play musical chairs with them.   * devices in /dev and then play musical chairs with them.
  *   *
Line 194  do_pcap_open_live(const char *device, int snaplen, Line 433  do_pcap_open_live(const char *device, int snaplen,
         pcap_t* ret;          pcap_t* ret;
         char buf[PATH_MAX];          char buf[PATH_MAX];
   
        if ((ret = pcap_open_live(device, snaplen, promisc, to_ms, errbuf))) {        if ((ret = try_pcap_open_live(device, snaplen, promisc, to_ms, errbuf))) {
                 return ret;                  return ret;
         }          }
   
         snprintf(buf, sizeof(buf), "/dev/%s", device);          snprintf(buf, sizeof(buf), "/dev/%s", device);
        if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {        if ((ret = try_pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
                 return ret;                  return ret;
         }          }
   
         snprintf(buf, sizeof(buf), "/dev/net/%s", device);          snprintf(buf, sizeof(buf), "/dev/net/%s", device);
        if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {        if ((ret = try_pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
                 return ret;                  return ret;
         }          }
   
         /* Call original again to reset the error message. */          /* Call original again to reset the error message. */
        return pcap_open_live(device, snaplen, promisc, to_ms, errbuf);        return try_pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
 }  }
   
 /**  /**
 * * Some Libnet error messages end with a newline. Strip that in place.
  */   */
static voidvoid
count_missing_dots()strip_newline(char* s) {
{        if (!*s) {
        while (numsent > numdots) {                return;
                putchar('.'); 
                numdots++; 
         }          }
           size_t n;
           for (n = strlen(s); s[n - 1] == '\n'; --n) {
                   s[n - 1] = 0;
           }
 }  }
   
 /**  /**
  * Init libnet with specified ifname. Destroy if already inited.   * 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  void
do_libnet_init(const char *ifname)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) {
                 /* Probably going to switch interface from temp to real. */                  /* Probably going to switch interface from temp to real. */
Line 245  do_libnet_init(const char *ifname) Line 490  do_libnet_init(const char *ifname)
         if (!(libnet = libnet_init(LIBNET_LINK,          if (!(libnet = libnet_init(LIBNET_LINK,
                                    (char*)ifname,                                     (char*)ifname,
                                    ebuf))) {                                     ebuf))) {
                fprintf(stderr, "arping: %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". */
                         return do_libnet_init("lo", 1);
                 } else if (recursive) {
                         /* Continue original execution. */
                         return;
                 }
                 fprintf(stderr, "arping: libnet_init(LIBNET_LINK, %s): %s\n",
                         ifname ? ifname : "<null>", ebuf);
                 if (getuid() && geteuid()) {                  if (getuid() && geteuid()) {
                         fprintf(stderr,                          fprintf(stderr,
                                 "arping: you may need to run as root\n");                                  "arping: you may need to run as root\n");
Line 291  getclock(struct timespec *ts) Line 547  getclock(struct timespec *ts)
 /**  /**
  *   *
  */   */
   static char*
   format_mac(unsigned char* mac, char* buf, size_t bufsize) {
           snprintf(buf, bufsize, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",
                   mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
           return buf;
   }
   
   /**
    *
    */
 static void  static void
 extended_usage()  extended_usage()
 {  {
Line 310  extended_usage() Line 576  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"
Line 320  extended_usage() Line 588  extended_usage()
                "    -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"
                "    -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 339  extended_usage() Line 613  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"                 "    -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");               "    -w     Time to wait between pings, in microseconds.\n"
                "    -W     Same as -w, but in floating point seconds.\n");
         printf("Report bugs to: thomas@habets.se\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 357  standard_usage() Line 633  standard_usage()
 {  {
         printf("ARPing %s, by Thomas Habets <thomas@habets.se>\n",          printf("ARPing %s, by Thomas Habets <thomas@habets.se>\n",
                version);                 version);
        printf("usage: arping [ -0aAbdDeFpqrRuUv ] [ -w <us> ] "        printf("usage: arping [ -0aAbdDeFpPqrRuUv ] [ -w <us> ] "
                "[ -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> ] "
                "<host/ip/MAC | -B>\n");                 "<host/ip/MAC | -B>\n");
 }  }
   
Line 477  timespec2dbl(const struct timespec *tv) Line 754  timespec2dbl(const struct timespec *tv)
  * max size of buffer is intsize + 1 + intsize + 4 = 70 bytes or so   * max size of buffer is intsize + 1 + intsize + 4 = 70 bytes or so
  *   *
  * Still, I'm using at least 128bytes below   * Still, I'm using at least 128bytes below
  *  
  * (because snprintf() sadly isn't as portable, that's why)  
  */   */
 static char *ts2str(const struct timespec *tv, const struct timespec *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;
Line 495  static char *ts2str(const struct timespec *tv, const s Line 770  static char *ts2str(const struct timespec *tv, const s
         }          }
         switch (exp) {          switch (exp) {
         case 0:          case 0:
                sprintf(buf, "%.3f nsec", f);                snprintf(buf, bufsize, "%.3f nsec", f);
                 break;                  break;
         case 3:          case 3:
                sprintf(buf, "%.3f usec", f);                snprintf(buf, bufsize, "%.3f usec", f);
                 break;                  break;
         case 6:          case 6:
                sprintf(buf, "%.3f msec", f);                snprintf(buf, bufsize, "%.3f msec", f);
                 break;                  break;
         case 9:          case 9:
                sprintf(buf, "%.3f sec", f);                snprintf(buf, bufsize, "%.3f sec", f);
                 break;                  break;
         case 12:          case 12:
                sprintf(buf, "%.3f sec", f*1000);                snprintf(buf, bufsize, "%.3f sec", f*1000);
                 break;                  break;
         default:          default:
                 /* huh, uh, huhuh */                  /* huh, uh, huhuh */
                sprintf(buf, "%.3fe%d sec", f, exp-9);                snprintf(buf, bufsize, "%.3fe%d sec", f, exp-9);
         }          }
         return buf;          return buf;
 }  }
Line 598  pingip_send() Line 873  pingip_send()
                                           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,
                                           unsolicited ? (uint8_t*)ethxmas : (uint8_t*)ethnull,                                            unsolicited ? (uint8_t*)ethxmas : (uint8_t*)ethnull,
Line 651  pingip_recv(const char *unused, struct pcap_pkthdr *h, Line 926  pingip_recv(const char *unused, struct pcap_pkthdr *h,
         int c;          int c;
   
         if (verbose > 2) {          if (verbose > 2) {
                printf("arping: received response for ip ping\n");                printf("arping: received response for IP ping\n");
         }          }
   
         getclock(&arrival);          getclock(&arrival);
Line 659  pingip_recv(const char *unused, struct pcap_pkthdr *h, Line 934  pingip_recv(const char *unused, struct pcap_pkthdr *h,
         heth = (void*)packet;          heth = (void*)packet;
         harp = (void*)((char*)heth + LIBNET_ETH_H);          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) { 
                        update_stats(timespec2dbl(&arrival) 
                                     - timespec2dbl(&lastpacketsent)); 
                        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", 
                                       ts2str(&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"); 
                        } 
                        if (numrecvd) { 
                                if (memcmp(lastreplymac, 
                                           heth->_802_3_shost, ETH_ALEN)) { 
                                        dupfound = 1; 
                                } 
                        } 
                        memcpy(lastreplymac, heth->_802_3_shost, ETH_ALEN); 
   
                        numrecvd++;        // 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");
         }
 
         // 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(heth->_802_3_shost,
                                           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(heth->_802_3_shost,
                                            buf, sizeof(buf)),
                        libnet_addr2name4(ip, 0));
                 break;
         case RRAW:
                 printf("%s", libnet_addr2name4(ip, 0));
                 break;
         case RAW:
                 printf("%s", format_mac(heth->_802_3_shost,
                                         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,
                            heth->_802_3_shost, ETH_ALEN)) {
                         dupfound = 1;
                 }
         }
         memcpy(lastreplymac, heth->_802_3_shost, 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 767  pingmac_recv(const char *unused, struct pcap_pkthdr *h Line 1065  pingmac_recv(const char *unused, struct pcap_pkthdr *h
         hip = (void*)((char*)heth + LIBNET_ETH_H);          hip = (void*)((char*)heth + LIBNET_ETH_H);
         hicmp = (void*)((char*)hip + LIBNET_IPV4_H);          hicmp = (void*)((char*)hip + LIBNET_IPV4_H);
   
        if ((htons(hicmp->icmp_type) == ICMP_ECHOREPLY)        // Dest MAC must be me.
            && ((!memcmp(heth->_802_3_shost, dstmac,ETH_ALEN)        if (memcmp(heth->_802_3_dhost, 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;        // Source MAC must match, if set.
                        memcpy(&tmp, &hip->ip_src, 4);        if (memcmp(dstmac, ethxmas, ETH_ALEN)) {
                        if (dstip != tmp) {                if (memcmp(heth->_802_3_shost, dstmac, ETH_ALEN)) {
                                return;                        return;
                        }                }
                }        }
                update_stats(timespec2dbl(&arrival)
                             - timespec2dbl(&lastpacketsent));        // IPv4 Address must be me (maybe).
                switch(display) {        if (addr_must_be_same) {
                case QUIET:                uint32_t tmp;
                        break;                memcpy(&tmp, &hip->ip_src, 4);
                case NORMAL: {                if (dstip != tmp) {
                        char buf[128];                        return;
                        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],        // Must be ICMP echo reply.
                                       (c<5)?':':')');        if (htons(hicmp->icmp_type) != ICMP_ECHOREPLY) {
                        }                return;
                        printf(": icmp_seq=%d time=%s",        }
                               htons(hicmp->icmp_seq),ts2str(&lastpacketsent,
                                                             &arrival,buf));        update_stats(timespec2dbl(&arrival) - timespec2dbl(&lastpacketsent));
                        break; }        if (beep) {
                case RAW:                printf("\a");
                        printf("%s",        }
                               libnet_addr2name4(hip->ip_src.s_addr, 0));        char buf[128];
                        break;        char buf2[128];
                case RRAW:        switch(display) {
                        for (c = 0; c < 6; c++) {        case QUIET:
                                printf("%.2x%s", heth->_802_3_shost[c],                break;
                                       (c<5)?":":"");        case DOT:
                        }                putchar('!');
                        break;                break;
                case RAWRAW:        case NORMAL:
                        for (c = 0; c < 6; c++) {                printf("%d bytes from %s (%s): icmp_seq=%d time=%s", h->len,
                                printf("%.2x%c", heth->_802_3_shost[c],                       libnet_addr2name4(*(int*)&hip->ip_src, 0),
                                       (c<5)?':':' ');                       format_mac(heth->_802_3_shost, buf, sizeof(buf)),
                        }                       htons(hicmp->icmp_seq),
                        printf("%s",                       ts2str(&lastpacketsent, &arrival, buf2, sizeof(buf2)));
                               libnet_addr2name4(hip->ip_src.s_addr, 0));                break;
                        break;        case RAW:
                default:                printf("%s", libnet_addr2name4(hip->ip_src.s_addr, 0));
                        fprintf(stderr, "arping: can't-happen-bug\n");                break;
                        sigint(0);        case RRAW:
                }                printf("%s", format_mac(heth->_802_3_shost, buf, sizeof(buf)));
                if (display != QUIET) {                break;
                        printf(beep?"\a\n":"\n");        case RAWRAW:
                }                printf("%s %s",
                numrecvd++;                       format_mac(heth->_802_3_shost, 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);
         }
 }  }
   
 /**  /**
Line 869  ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_hand Line 1184  ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_hand
                ts.tv_nsec = endtime.tv_nsec - ts.tv_nsec;                 ts.tv_nsec = endtime.tv_nsec - ts.tv_nsec;
                fixup_timespec(&ts);                 fixup_timespec(&ts);
                if (verbose > 2) {                 if (verbose > 2) {
                       printf("listen for replies for %ld.%09ld sec\n",                       printf("arping: listen for replies for %ld.%09ld sec\n",
                               (long)ts.tv_sec, (long)ts.tv_nsec);                                (long)ts.tv_sec, (long)ts.tv_nsec);
                }                 }
   
Line 914  ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_hand Line 1229  ping_recv(pcap_t *pcap, uint32_t packetwait, pcap_hand
                        r = select(fd + 1, &fds, NULL, NULL, &tv);                         r = select(fd + 1, &fds, NULL, NULL, &tv);
                        switch (r) {                         switch (r) {
                        case 0: /* timeout */                         case 0: /* timeout */
                               if (display == NORMAL) {                               if (numrecvd == old_received) {
                                       if (numrecvd == old_received) {                                       if (reverse_beep) {
                                                printf("\a");
                                        }
                                        switch (display) {
                                        case NORMAL:
                                                printf("Timeout\n");                                                 printf("Timeout\n");
                                                  break;
                                          case DOT:
                                                  printf(".");
                                                  break;
                                        }                                         }
                                          fflush(stdout);
                                }                                 }
                                done = 1;                                 done = 1;
                                break;                                 break;
Line 977  int main(int argc, char **argv) Line 1301  int main(int argc, char **argv)
         pcap_t *pcap;          pcap_t *pcap;
         enum { NONE, PINGMAC, PINGIP } mode = NONE;          enum { NONE, PINGMAC, PINGIP } mode = NONE;
         unsigned int packetwait = 1000000;          unsigned int packetwait = 1000000;
           ebuf[0] = 0;
   
         for (c = 1; c < argc; c++) {          for (c = 1; c < argc; c++) {
                 if (!strcmp(argv[c], "--help")) {                  if (!strcmp(argv[c], "--help")) {
Line 990  int main(int argc, char **argv) Line 1315  int main(int argc, char **argv)
         dstip = 0xffffffff;          dstip = 0xffffffff;
         memcpy(dstmac, ethxmas, ETH_ALEN);          memcpy(dstmac, ethxmas, ETH_ALEN);
   
        while (EOF!=(c=getopt(argc,argv,"0aAbBc:dDeFhi:I:pqrRs:S:t:T:uUvw:"))) {        while (EOF != (c = getopt(argc, argv,
                                   "0aAbBC:c:dDeFhi:I:m:pPqrRs:S:t:T:uUvw:W:"))) {
                 switch(c) {                  switch(c) {
                 case '0':                  case '0':
                         srcip = 0;                          srcip = 0;
Line 1013  int main(int argc, char **argv) Line 1339  int main(int argc, char **argv)
                 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 1040  int main(int argc, char **argv) Line 1369  int main(int argc, char **argv)
                 case 'I': /* FALL THROUGH */                  case 'I': /* FALL THROUGH */
                         ifname = optarg;                          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;
Line 1068  int main(int argc, char **argv) Line 1403  int main(int argc, char **argv)
                         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);                        do_libnet_init(ifname, 0);
                         if (-1 == (srcip = libnet_name2addr4(libnet,                          if (-1 == (srcip = libnet_name2addr4(libnet,
                                                              optarg,                                                               optarg,
                                                              LIBNET_RESOLVE))){                                                               LIBNET_RESOLVE))){
Line 1105  int main(int argc, char **argv) Line 1440  int main(int argc, char **argv)
                                         "in MAC ping mode\n");                                          "in MAC ping mode\n");
                                 exit(1);                                  exit(1);
                         }                          }
                        do_libnet_init(ifname);                        do_libnet_init(ifname, 0);
                         if (-1 == (dstip = libnet_name2addr4(libnet,                          if (-1 == (dstip = libnet_name2addr4(libnet,
                                                              optarg,                                                               optarg,
                                                              LIBNET_RESOLVE))){                                                               LIBNET_RESOLVE))){
Line 1133  int main(int argc, char **argv) Line 1468  int main(int argc, char **argv)
                 case 'w':                  case 'w':
                         packetwait = (unsigned)atoi(optarg);                          packetwait = (unsigned)atoi(optarg);
                         break;                          break;
                   case 'W':
                           packetwait = (unsigned)(1000000.0 * atof(optarg));
                           break;
                 default:                  default:
                         usage(1);                          usage(1);
                 }                  }
Line 1142  int main(int argc, char **argv) Line 1480  int main(int argc, char **argv)
 #if HAVE_CLOCK_MONOTONIC  #if HAVE_CLOCK_MONOTONIC
                 struct timespec ts;                  struct timespec ts;
                 clock_getres(CLOCK_MONOTONIC, &ts);                  clock_getres(CLOCK_MONOTONIC, &ts);
                printf("clock_getres() = %ld %ld\n",                printf("arping: clock_getres() = %ld %ld\n",
                        (long)ts.tv_sec, (long)ts.tv_nsec);                         (long)ts.tv_sec, (long)ts.tv_nsec);
 #else  #else
                printf("Using gettimeofday() for time measurements\n");                printf("arping: Using gettimeofday() for time measurements\n");
 #endif  #endif
         }          }
   
Line 1162  int main(int argc, char **argv) Line 1500  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 1178  int main(int argc, char **argv) Line 1516  int main(int argc, char **argv)
                         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 mem\n");
Line 1201  int main(int argc, char **argv) Line 1539  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 1259  int main(int argc, char **argv) Line 1597  int main(int argc, char **argv)
         if (!ifname) {          if (!ifname) {
                 if (!dont_use_arping_lookupdev) {                  if (!dont_use_arping_lookupdev) {
                         ifname = arping_lookupdev(srcip, dstip, ebuf);                          ifname = arping_lookupdev(srcip, dstip, ebuf);
                           strip_newline(ebuf);
                           if (!ifname) {
                                   fprintf(stderr, "arping: lookup dev: %s\n",
                                           ebuf);
                           }
                 }                  }
                 if (!ifname) {                  if (!ifname) {
                         ifname = arping_lookupdev_default(srcip, dstip, ebuf);                          ifname = arping_lookupdev_default(srcip, dstip, ebuf);
                        if (!dont_use_arping_lookupdev) {                        strip_newline(ebuf);
                         if (ifname && !dont_use_arping_lookupdev) {
                                 fprintf(stderr,                                  fprintf(stderr,
                                         "arping: Unable to automatically find "                                          "arping: Unable to automatically find "
                                         "interface to use. Is it on the local "                                          "interface to use. Is it on the local "
Line 1291  int main(int argc, char **argv) Line 1635  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 = do_pcap_open_live(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();
         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 > 1) {          if (verbose > 1) {
                printf("pcap_get_selectable_fd(): %d\n",                printf("arping: pcap_get_selectable_fd(): %d\n",
                        pcap_get_selectable_fd(pcap));                         pcap_get_selectable_fd(pcap));
         }          }
   
 #ifdef BIOCIMMEDIATE  #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 1364  int main(int argc, char **argv) Line 1712  int main(int argc, char **argv)
         do_signal_init();          do_signal_init();
   
         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]); 
         }          }
   
   
Line 1389  int main(int argc, char **argv) Line 1735  int main(int argc, char **argv)
                         r = numrecvd;                          r = numrecvd;
                         ping_recv(pcap,packetwait,                          ping_recv(pcap,packetwait,
                                   (pcap_handler)pingip_recv);                                    (pcap_handler)pingip_recv);
                         if (reverse_beep && !time_to_die && (r == numrecvd)) {  
                                 printf("\a");  
                                 fflush(stdout);  
                         }  
                 }                  }
         } else { /* PINGMAC */          } else { /* PINGMAC */
                 unsigned int c;                  unsigned int c;
Line 1402  int main(int argc, char **argv) Line 1744  int main(int argc, char **argv)
                         r = numrecvd;                          r = numrecvd;
                         ping_recv(pcap,packetwait,                          ping_recv(pcap,packetwait,
                                   (pcap_handler)pingmac_recv);                                    (pcap_handler)pingmac_recv);
                         if (reverse_beep && !time_to_die && (r == numrecvd)) {  
                                 printf("\a");  
                                 fflush(stdout);  
                         }  
                 }                  }
         }          }
         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, "

Removed from v.1.1.1.2  
changed lines
  Added in v.1.1.1.3


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