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 %d | static 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: |
|
*/ |