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

version 1.1, 2012/02/21 22:16:27 version 1.1.1.2, 2014/06/15 16:26:43
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-2011 Thomas Habets <thomas@habets.se>
  *   *
  *  This library is free software; you can redistribute it and/or   *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public   *  modify it under the terms of the GNU General Public
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
Line 51 Line 53
 #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 78 Line 84
 #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_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 104
 #define WIN32 0  #define WIN32 0
 #endif  #endif
   
   #ifndef CLOCK_MONOTONIC
   #define CLOCK_MONOTONIC CLOCK_REALTIME
   #endif
   
 /**  /**
  * OS-specific interface finding using routing table. See findif_*.c   * OS-specific interface finding using routing table. See findif_*.c
  */   */
 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;  static libnet_t *libnet = 0;
   
static struct timeval lastpacketsent;static struct timespec lastpacketsent;
   
uint32_t srcip, dstip;/* target string */
 static 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; */static 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 uint32_t srcip;            /* autodetected, override with -S/-b/-0 */
 static uint8_t srcmac[ETH_ALEN];  /* autodetected, override with -s */
 
 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 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 */
 
 static unsigned int numsent = 0;     /* packets sent */
 static unsigned int numrecvd = 0;    /* packets received */
 static unsigned int numdots = 0;     /* dots that should be printed */
 
 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};
   
   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;
   
 /**  /**
    * 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 = pcap_open_live(device, snaplen, promisc, to_ms, errbuf))) {
                   return ret;
           }
   
           snprintf(buf, sizeof(buf), "/dev/%s", device);
           if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
                   return ret;
           }
   
           snprintf(buf, sizeof(buf), "/dev/net/%s", device);
           if ((ret = pcap_open_live(buf, snaplen, promisc, to_ms, errbuf))) {
                   return ret;
           }
   
           /* Call original again to reset the error message. */
           return pcap_open_live(device, snaplen, promisc, to_ms, errbuf);
   }
   
   /**
    *
    */
 static void  static void
 count_missing_dots()  count_missing_dots()
 {  {
Line 149  count_missing_dots() Line 225  count_missing_dots()
 }  }
   
 /**  /**
 * * Init libnet with specified ifname. Destroy if already inited.
 */      */
 void  void
 do_libnet_init(const char *ifname)  do_libnet_init(const char *ifname)
 {  {
         char ebuf[LIBNET_ERRBUF_SIZE];          char ebuf[LIBNET_ERRBUF_SIZE];
         if (verbose > 1) {          if (verbose > 1) {
                printf("libnet_init(%s)\n", ifname?ifname:"<null>");                printf("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);                fprintf(stderr, "arping: %s\n", ebuf);
                 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 257  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  
         WCHAR buf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE];  
         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)  
 {  
         if(verbose) {  
                 printf("arping_console_ctrl_handler( %d )\n", (int)dwCtrlType);  
         }  
         time_to_die = 1;          time_to_die = 1;
   
 #if 0  
         /* if SetConsoleCtrlHandler() does what I think, this isn't needed */  
         if (display == NORMAL) {  
                 printf("\n--- %s statistics ---\n"  
                        "%d packets transmitted, %d packets received, %3.0f%% "  
                        "unanswered\n",target,numsent,numrecvd,  
                        100.0 - 100.0 * (float)(numrecvd)/(float)numsent);  
         }  
 #endif  
         return TRUE;  
 }  }
 #endif  
   
   
 /**  /**
 * * idiot-proof clock_gettime() wrapper
  */   */
static void sigint(int i)static void
 getclock(struct timespec *ts)
 {  {
        time_to_die = 1;#if HAVE_CLOCK_MONOTONIC
         if (-1 == clock_gettime(CLOCK_MONOTONIC, ts)) {
                 fprintf(stderr,
                         "arping: clock_gettime(): %s\n",
                         strerror(errno));
                 sigint(0);
         }
 #else
         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
 }  }
   
 /**  /**
Line 252  extended_usage() Line 313  extended_usage()
                "    -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"
Line 280  extended_usage() Line 341  extended_usage()
                "           \"own\" the MAC address you are using.\n"                 "           \"own\" the MAC address you are using.\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");                 "    -w     Time to wait between pings, in microseconds.\n");
        printf("Report bugs to: thomas@habets.pp.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 293  extended_usage() Line 355  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 [ -0aAbdDeFpqrRuUv ] [ -w <us> ] "
                "[ -S <host/ip> ]\n"                 "[ -S <host/ip> ]\n"
                "              "                 "              "
                "[ -T <host/ip ] "                 "[ -T <host/ip ] "
Line 387  static int get_mac_addr(const char *in, Line 449  static int get_mac_addr(const char *in,
 }  }
   
 /**  /**
  * 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;
 }
 
 /**
  *   *
    */
   static double
   timespec2dbl(const struct timespec *tv)
   {
           return tv->tv_sec + (double)tv->tv_nsec / 1000000000;
   }
   
   /**
    * 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)   * (because snprintf() sadly isn't as portable, that's why)
  */   */
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)
 {  {
         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);                sprintf(buf, "%.3f nsec", f);
                 break;                  break;
         case 3:          case 3:
                sprintf(buf, "%.3f msec", f);                sprintf(buf, "%.3f usec", f);
                 break;                  break;
         case 6:          case 6:
                sprintf(buf, "%.3f sec", f);                sprintf(buf, "%.3f msec", f);
                 break;                  break;
         case 9:          case 9:
                   sprintf(buf, "%.3f sec", f);
                   break;
           case 12:
                 sprintf(buf, "%.3f sec", f*1000);                  sprintf(buf, "%.3f sec", f*1000);
                 break;                  break;
         default:          default:
                 /* huh, uh, huhuh */                  /* huh, uh, huhuh */
                sprintf(buf, "%.3fe%d sec", f, exp-6);                sprintf(buf, "%.3fe%d sec", f, exp-9);
         }          }
         return buf;          return buf;
 }  }
Line 433  static char *tv2str(const struct timeval *tv, const st Line 520  static char *tv2str(const struct timeval *tv, const st
   
 /** 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;
         int c;          int c;
Line 491  pingmac_send(uint8_t *srcmac, uint8_t *dstmac, Line 572  pingmac_send(uint8_t *srcmac, uint8_t *dstmac,
                         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 == (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;
         if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER,          if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER,
Line 534  pingip_send(uint8_t *srcmac, uint8_t *dstmac, Line 601  pingip_send(uint8_t *srcmac, uint8_t *dstmac,
                                           ARPOP_REQUEST,                                            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,                                            NULL,
                                           0,                                            0,
Line 555  pingip_send(uint8_t *srcmac, uint8_t *dstmac, Line 622  pingip_send(uint8_t *srcmac, uint8_t *dstmac,
                         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 584  pingip_send(uint8_t *srcmac, uint8_t *dstmac, Line 643  pingip_send(uint8_t *srcmac, uint8_t *dstmac,
  * \param packet  packet data   * \param packet  packet data
  */   */
 static void  static void
pingip_recv(const char *unused, struct pcap_pkthdr *h,pingip_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet)
            uint8_t *packet) 
 {  {
         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;          int c;
   
        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)); 
                sigint(0); 
        } 
         heth = (void*)packet;          heth = (void*)packet;
         harp = (void*)((char*)heth + LIBNET_ETH_H);          harp = (void*)((char*)heth + LIBNET_ETH_H);
   
Line 616  pingip_recv(const char *unused, struct pcap_pkthdr *h, Line 671  pingip_recv(const char *unused, struct pcap_pkthdr *h,
                         return;                          return;
                 }                  }
                 if (dstip == ip) {                  if (dstip == ip) {
                           update_stats(timespec2dbl(&arrival)
                                        - timespec2dbl(&lastpacketsent));
                         switch(display) {                          switch(display) {
                         case DOT:                          case DOT:
                                 numdots++;                                  numdots++;
Line 637  pingip_recv(const char *unused, struct pcap_pkthdr *h, Line 694  pingip_recv(const char *unused, struct pcap_pkthdr *h,
                                         printf("/%u", numsent-1);                                          printf("/%u", numsent-1);
                                 }                                  }
                                 printf(" time=%s",                                  printf(" time=%s",
                                       tv2str(&lastpacketsent,                                       ts2str(&lastpacketsent,
                                              &arrival,buf));                                              &arrival,buf));
                                break; }                                break;
                         }
                         case QUIET:                          case QUIET:
                                 break;                                  break;
                         case RAWRAW:                          case RAWRAW:
Line 691  pingip_recv(const char *unused, struct pcap_pkthdr *h, Line 749  pingip_recv(const char *unused, struct pcap_pkthdr *h,
  * \param packet  packet data   * \param packet  packet data
  */   */
 static void  static void
pingmac_recv(const char *unused, struct pcap_pkthdr *h,pingmac_recv(const char *unused, struct pcap_pkthdr *h, uint8_t *packet)
             uint8_t *packet) 
 {  {
         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;          int c;
   
         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;          heth = (void*)packet;
         hip = (void*)((char*)heth + LIBNET_ETH_H);          hip = (void*)((char*)heth + LIBNET_ETH_H);
Line 725  pingmac_recv(const char *unused, struct pcap_pkthdr *h Line 778  pingmac_recv(const char *unused, struct pcap_pkthdr *h
                                 return;                                  return;
                         }                          }
                 }                  }
                   update_stats(timespec2dbl(&arrival)
                                - timespec2dbl(&lastpacketsent));
                 switch(display) {                  switch(display) {
                 case QUIET:                  case QUIET:
                         break;                          break;
Line 737  pingmac_recv(const char *unused, struct pcap_pkthdr *h Line 792  pingmac_recv(const char *unused, struct pcap_pkthdr *h
                                        (c<5)?':':')');                                         (c<5)?':':')');
                         }                          }
                         printf(": icmp_seq=%d time=%s",                          printf(": icmp_seq=%d time=%s",
                               htons(hicmp->icmp_seq),tv2str(&lastpacketsent,                               htons(hicmp->icmp_seq),ts2str(&lastpacketsent,
                                                      &arrival,buf));                                                             &arrival,buf));
                         break; }                          break; }
                 case RAW:                  case RAW:
                         printf("%s",                          printf("%s",
Line 769  pingmac_recv(const char *unused, struct pcap_pkthdr *h Line 824  pingmac_recv(const char *unused, struct pcap_pkthdr *h
         }          }
 }  }
   
   
 #if WIN32  
 /**  /**
 * untested for a long time. Maybe since arping 2.05 or so. * while negative nanoseconds, take from whole seconds.
 */ 
static void 
ping_recv_win32(pcap_t *pcap,uint32_t packetwait, pcap_handler func) 
{ 
       struct timeval tv,tv2; 
       char done = 0; 
       /* windows won't let us do select() */ 
       if (-1 == gettimeofday(&tv2,NULL)) { 
               fprintf(stderr, "arping: gettimeofday(): %s\n", 
                       strerror(errno)); 
               sigint(0); 
       } 
       while (!done && !time_to_die) { 
               struct pcap_pkthdr *pkt_header; 
               u_char *pkt_data; 
               if (pcap_next_ex(pcap, &pkt_header, &pkt_data) == 1) { 
                       func(pcap, pkt_header, pkt_data); 
               } 
               if (-1 == gettimeofday(&tv,NULL)) { 
                       fprintf(stderr, "arping: " 
                               "gettimeofday(): %s\n", 
                               strerror(errno)); 
                       sigint(0); 
               } 
               /* 
                * setup next timeval, not very exact 
                */ 
               tv.tv_sec  = (packetwait / 1000000) 
                       - (tv.tv_sec - tv2.tv_sec); 
               tv.tv_usec = (packetwait % 1000000) 
                       - (tv.tv_usec - tv2.tv_usec); 
               while (tv.tv_usec < 0) { 
                       tv.tv_sec--; 
                       tv.tv_usec += 1000000; 
               } 
               usleep(10); 
               if (tv.tv_sec < 0) { 
                       done=1; 
               } 
       } 
} 
#endif 
 
/** 
 * while negative microseconds, 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;
          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);
          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("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 (display == NORMAL) {
                                          if (numrecvd == old_received) {
                                                  printf("Timeout\n");
                                          }
                                  }
                                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 926  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 938  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 948  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 928  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_ Line 958  ping_recv_unix(pcap_t *pcap,uint32_t packetwait, pcap_
 }  }
   
 /**  /**
  *   
  */  
 static void  
 ping_recv(pcap_t *pcap,uint32_t packetwait, pcap_handler func)  
 {  
        if(verbose>3) {  
                printf("arping: receiving packets...\n");  
        }  
   
 #if WIN32  
        ping_recv_win32(pcap,packetwait,func);  
 #else  
        ping_recv_unix(pcap,packetwait,func);  
 #endif  
 }  
   
 /**  
  *   *
  */   */
 int main(int argc, char **argv)  int main(int argc, char **argv)
Line 962  int main(int argc, char **argv) Line 975  int main(int argc, char **argv)
         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;
   
         for (c = 1; c < argc; c++) {          for (c = 1; c < argc; c++) {
Line 973  int main(int argc, char **argv) Line 986  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:dDeFhi:I:pqrRs:S:t:T:uUvw:"))) {
                 switch(c) {                  switch(c) {
                 case '0':                  case '0':
                         srcip = 0;                          srcip = 0;
Line 1109  int main(int argc, char **argv) Line 1119  int main(int argc, char **argv)
                 case 'u':                  case 'u':
                         alsototal = 1;                          alsototal = 1;
                         break;                          break;
                   case 'U':
                           if (mode == PINGMAC) {
                                   fprintf(stderr, "arping: -U can only be used "
                                           "in IP ping mode\n");
                                   exit(1);
                           }
                           unsolicited = 1;
                           break;
                 case 'v':                  case 'v':
                         verbose++;                          verbose++;
                         break;                          break;
Line 1120  int main(int argc, char **argv) Line 1138  int main(int argc, char **argv)
                 }                  }
         }          }
   
           if (verbose > 1) {
   #if HAVE_CLOCK_MONOTONIC
                   struct timespec ts;
                   clock_getres(CLOCK_MONOTONIC, &ts);
                   printf("clock_getres() = %ld %ld\n",
                          (long)ts.tv_sec, (long)ts.tv_nsec);
   #else
                   printf("Using gettimeofday() for time measurements\n");
   #endif
           }
   
         if (display == DOT) {          if (display == DOT) {
                 setvbuf(stdout, NULL, _IONBF, 0);                  setvbuf(stdout, NULL, _IONBF, 0);
         }          }
Line 1228  int main(int argc, char **argv) Line 1257  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);                }
                } else {                if (!ifname) {
                        ifname = arping_lookupdev(ifname,srcip,dstip,ebuf);                        ifname = arping_lookupdev_default(srcip, dstip, ebuf);
                         if (!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 1258  int main(int argc, char **argv) Line 1296  int main(int argc, char **argv)
         /*          /*
          * 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);                  fprintf(stderr, "arping: pcap_open_live(): %s\n",ebuf);
                 exit(1);                  exit(1);
         }          }
Line 1266  int main(int argc, char **argv) Line 1304  int main(int argc, char **argv)
                 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("pcap_get_selectable_fd(): %d\n",
                        pcap_get_selectable_fd(pcap));                         pcap_get_selectable_fd(pcap));
         }          }
   
#if HAVE_NET_BPF_H#ifdef BIOCIMMEDIATE
         {          {
                 uint32_t on = 1;                  uint32_t on = 1;
                 if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE,                  if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE,
Line 1314  int main(int argc, char **argv) Line 1352  int main(int argc, char **argv)
         }          }
         if (!srcip_given) {          if (!srcip_given) {
                 if (-1 == (srcip = libnet_get_ipaddr4(libnet))) {                  if (-1 == (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: ",                  printf("This box:   Interface: %s  IP: %s   MAC address: ",
Line 1348  int main(int argc, char **argv) Line 1385  int main(int argc, char **argv)
                 unsigned int c;                  unsigned int c;
                 unsigned int r;                  unsigned int r;
                 for (c = 0; c < maxcount && !time_to_die; c++) {                  for (c = 0; c < maxcount && !time_to_die; c++) {
                        pingip_send(srcmac, dstmac, srcip, dstip);                        pingip_send();
                         r = numrecvd;                          r = numrecvd;
                         ping_recv(pcap,packetwait,                          ping_recv(pcap,packetwait,
                                   (pcap_handler)pingip_recv);                                    (pcap_handler)pingip_recv);
Line 1361  int main(int argc, char **argv) Line 1398  int main(int argc, char **argv)
                 unsigned int c;                  unsigned int c;
                 unsigned int r;                  unsigned int r;
                 for (c = 0; c < maxcount && !time_to_die; c++) {                  for (c = 0; c < maxcount && !time_to_die; c++) {
                        pingmac_send(srcmac, dstmac, srcip, dstip, rand(), c);                        pingmac_send(rand(), c);
                         r = numrecvd;                          r = numrecvd;
                         ping_recv(pcap,packetwait,                          ping_recv(pcap,packetwait,
                                   (pcap_handler)pingmac_recv);                                    (pcap_handler)pingmac_recv);
Line 1385  int main(int argc, char **argv) Line 1422  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 1442  int main(int argc, char **argv)
                 return !numrecvd;                  return !numrecvd;
         }          }
 }  }
   /* ---- Emacs Variables ----
    * Local Variables:
    * c-basic-offset: 8
    * indent-tabs-mode: nil
    * End:
    */

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


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