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 void | void |
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, " |