/*
* arping
*
* By Thomas Habets <thomas@habets.pp.se>
*
* ARP 'ping' utility
*
* Broadcasts a who-has ARP packet on the network and prints answers.
* *VERY* useful when you are trying to pick an unused IP for a net that
* 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.
*
* Also finds out IP of specified MAC
*
* $Id: arping.c 1893 2007-07-09 22:23:28Z marvin $
*/
/*
* Copyright (C) 2000-2002 Thomas Habets <thomas@habets.pp.se>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#ifndef WIN32
#include <unistd.h>
// NOTE: try un-commenting this
//#include <stdint.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <libnet.h>
#endif
#ifdef WIN32
#include <win32/libnet.h>
#endif
#include <pcap.h>
#if defined(WIN32)
#define HAVE_ESIZE_TYPES 1
#include "win32.h"
#include "win32/getopt.h"
#endif
#if !defined(linux)
#define HAVE_WEIRD_BSD 1
#endif
#if defined(linux)
#define HAVE_ESIZE_TYPES 1
#define FINDIF 1
#endif
#ifdef HAVE_NET_BPF_H
#include <net/bpf.h>
#endif
#ifndef HAVE_ESIZE_TYPES
/*
* let's hope we at least have these
* FIXME: bleh, this is not auto-detected, so fix it with os-dependent stuff
* like we have above for linux
* But this broken thing compiled on my solaris, openbsd and linux-boxes so
* it kinda works.
*/
#define u_int8_t uint8_t
#define u_int16_t uint16_t
#define u_int32_t uint32_t
#endif
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
#ifndef IP_ALEN
#define IP_ALEN 4
#endif
const float version = 2.06f;
static libnet_t *libnet = 0;
static struct timeval lastpacketsent;
static u_int32_t srcip,dstip;
static int beep = 0;
static int verbose = 0;
static int alsototal = 0;
/*static int pingmac = 0; */
static int finddup = 0;
static unsigned int numsent = 0;
static unsigned int numrecvd = 0;
static int addr_must_be_same = 0;
// RAWRAW is RAW|RRAW
static enum { NORMAL,QUIET,RAW,RRAW,RAWRAW } display = NORMAL;
static char *target = "huh? bug in arping?";
static u_int8_t ethnull[ETH_ALEN];
static u_int8_t ethxmas[ETH_ALEN];
static char srcmac[ETH_ALEN];
static char dstmac[ETH_ALEN];
volatile int time_to_die = 0;
/*
*
*/
static void do_libnet_init(const char *ifname)
{
char ebuf[LIBNET_ERRBUF_SIZE];
if (verbose > 1) {
printf("libnet_init(%s)\n", ifname);
}
if (libnet) {
/* prolly going to switch interface from temp to real */
libnet_destroy(libnet);
libnet = 0;
}
if (getuid() && geteuid()) {
fprintf(stderr, "arping: must run as root\n");
exit(1);
}
if (!(libnet = libnet_init(LIBNET_LINK,
(char*)ifname,
ebuf))) {
fprintf(stderr, "arping: libnet_init(): %s\n", ebuf);
exit(1);
}
}
/*
*
*/
static const char *arping_lookupdev_default(u_int32_t srcip, u_int32_t dstip,
char *ebuf)
{
#ifdef 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 defined(FINDIF) && defined(linux)
/*
*
*/
static const char *arping_lookupdev(u_int32_t srcip, u_int32_t dstip,
char *ebuf)
{
FILE *f;
static char buf[1024];
char buf1[1024];
char buf2[1024];
char *p,*p2;
int n;
do_libnet_init(NULL);
libnet_addr2name4_r(dstip,0,buf2);
libnet_addr2name4_r(srcip,0,buf1);
/*
* Construct and run command
*/
snprintf(buf, 1023, "/sbin/ip route get %s from %s 2>&1",
buf2,buf1);
if (!(f = popen(buf, "r"))) {
goto failed;
}
if (0>(n = fread(buf, 1, sizeof(buf)-1, f))) {
pclose(f);
goto failed;
}
buf[n] = 0;
if (-1 == pclose(f)) {
perror("arping: pclose()");
goto failed;
}
/*
* Parse out device
*/
p = strstr(buf, "dev ");
if (!p) {
goto failed;
}
p+=4;
p2 = strchr(p, ' ');
if (!p2) {
goto failed;
}
*p2 = 0;
return p;
failed:
return arping_lookupdev_default(srcip,dstip,ebuf);
}
#else
/*
*
*/
static const char *arping_lookupdev(u_int32_t srcip, u_int32_t dstip,
char *ebuf)
{
return arping_lookupdev_default(srcip,dstip,ebuf);
}
#endif
#ifdef 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;
#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
/*
*
*/
static void sigint(int i)
{
time_to_die = 1;
}
static void
extended_usage()
{
printf("\nOptions:\n");
printf("\n"
" -0 Use this option to ping with source IP address 0.0.0.0. Use this\n"
" when you haven't configured your interface yet. Note that this\n"
" may get the MAC-ping unanswered. This is an alias for -S\n"
" 0.0.0.0.\n"
" -a Audiable ping.\n"
" -A Only count addresses matching requested address (This *WILL*\n"
" break most things you do. Only useful if you are arpinging many\n"
" hosts at once. See arping-scan-net.sh for an example).\n"
" -b Like -0 but source broadcast source address (255.255.255.255).\n"
" Note that this may get the arping unanswered since it's not nor-\n"
" mal behavior for a host.\n"
" -B Use instead of host if you want to address 255.255.255.255.\n"
" -c count\n"
" Only send count requests.\n"
" -d Find duplicate replies.\n"
" -F Don't try to be smart about the interface name. (even if this\n"
" switch is not given, -i overrides smartness.\n"
" -h Displays a help message and exits.\n"
" -i interface\n"
" Use the specified interface.\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: Like -r but shows \"the other one\", can be combined\n"
" with -r.\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"
" 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"
" 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"
" ing an IP-address yourself.\n"
" -t MAC Set target MAC address to use when pinging IP address.\n"
" -T IP Use -T as target address when pinging MACs that won't respond to\n"
" a broadcast ping but perhaps to a directed broadcast.\n"
" Example:\n"
" To check the address of MAC-A, use knowledge of MAC-B and IP-B.\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"
" \"own\" the MAC address you are using.\n"
" -u Show index=received/sent instead of just index=received when\n"
" pinging MACs.\n"
" -v Verbose output. Use twice for more messages.\n"
" -w (arping 2.x only) Time to wait between pings, in microseconds.\n");
}
/*
*
*/
static void usage(int ret)
{
printf("ARPing %1.2f, by Thomas Habets <thomas@habets.pp.se>\n",
version);
printf("usage: arping [ -0aAbdFpqrRuv ] [ -w <us> ] [ -S <host/ip> ] "
"[ -T <host/ip ]\n"
" [ -s <MAC> ] [ -t <MAC> ] [ -c <count> ] "
"[ -i <interface> ]\n"
" <host/ip/MAC | -B>\n");
#ifdef WIN32
extended_usage();
#endif
exit(ret);
}
/*
* It was unclear from msdn.microsoft.com if their scanf() supported
* [0-9a-fA-F], so I'll stay away from it.
*/
static int is_mac_addr(const char *p)
{
/* cisco-style */
if (3*5-1 == strlen(p)) {
int c;
for (c = 0; c < strlen(p); c++) {
if ((c % 5) == 4) {
if ('.' != p[c]) {
goto checkcolon;
}
} else {
if (!isxdigit(p[c])) {
goto checkcolon;
}
}
}
return 1;
}
/* windows-style */
if (6*3-1 == strlen(p)) {
int c;
for (c = 0; c < strlen(p); c++) {
if ((c % 3) == 2) {
if ('-' != p[c]) {
goto checkcolon;
}
} else {
if (!isxdigit(p[c])) {
goto checkcolon;
}
}
}
return 1;
}
checkcolon:
/* unix */
return strchr(p, ':') ? 1 : 0;
}
/*
* lots of parms since C arrays suck
*/
static int get_mac_addr(const char *in,
unsigned int *n0,
unsigned int *n1,
unsigned int *n2,
unsigned int *n3,
unsigned int *n4,
unsigned int *n5)
{
if (6 == sscanf(in, "%x:%x:%x:%x:%x:%x",n0,n1,n2,n3,n4,n5)) {
return 1;
} else if(6 == sscanf(in, "%2x%x.%2x%x.%2x%x",n0,n1,n2,n3,n4,n5)) {
return 1;
} else if(6 == sscanf(in, "%x-%x-%x-%x-%x-%x",n0,n1,n2,n3,n4,n5)) {
return 1;
}
return 0;
}
/*
* as always, the answer is 42
*
* in this case the question is how many bytes buf needs to be.
* Assuming a 33 byte max %d
*
* Still, I'm using at least 128bytes below
*
* (because snprintf() sadly isn't as portable, that's why)
*/
static char *tv2str(const struct timeval *tv, const struct timeval *tv2,
char *buf)
{
double f,f2;
int exp = 0;
f = tv->tv_sec + (double)tv->tv_usec / 1000000;
f2 = tv2->tv_sec + (double)tv2->tv_usec / 1000000;
f = (f2 - f) * 1000000;
while (f > 1000) {
exp+= 3;
f /= 1000;
}
switch (exp) {
case 0:
sprintf(buf, "%.3f usec", f);
break;
case 3:
sprintf(buf, "%.3f msec", f);
break;
case 6:
sprintf(buf, "%.3f sec", f);
break;
case 9:
sprintf(buf, "%.3f sec", f*1000);
break;
default:
// huh, uh, huhuh
sprintf(buf, "%.3fe%d sec", f, exp-6);
}
return buf;
}
/*
*
*/
static void pingmac_send(u_int8_t *srcmac, u_int8_t *dstmac,
u_int32_t srcip, u_int32_t dstip,
u_int16_t id, u_int16_t seq)
{
static libnet_ptag_t icmp = 0, ipv4 = 0,eth=0;
int c;
if (-1 == (icmp = libnet_build_icmpv4_echo(ICMP_ECHO, // type
0, // code
0, // checksum
id, // id
seq, // seq
NULL, // payload
0, // payload len
libnet,
icmp))) {
fprintf(stderr, "libnet_build_icmpv4_echo(): %s\n",
libnet_geterror(libnet));
sigint(0);
}
if (-1==(ipv4 = libnet_build_ipv4(LIBNET_IPV4_H
+ LIBNET_ICMPV4_ECHO_H + 0,
0, // ToS
id, // id
0, // frag
64, // ttl
IPPROTO_ICMP,
0, // checksum
srcip,
dstip,
NULL, // payload
0,
libnet,
ipv4))) {
fprintf(stderr, "libnet_build_ipv4(): %s\n",
libnet_geterror(libnet));
sigint(0);
}
if (-1 == (eth = libnet_build_ethernet(dstmac,
srcmac,
ETHERTYPE_IP,
NULL,
0,
libnet,
eth))) {
fprintf(stderr, "libnet_build_ethernet(): %s\n",
libnet_geterror(libnet));
sigint(0);
}
if(verbose>1) {
printf("arping: sending packet\n");
}
if (-1 == (c = libnet_write(libnet))) {
fprintf(stderr, "arping: libnet_write(): %s\n",
libnet_geterror(libnet));
sigint(0);
}
if (-1 == gettimeofday(&lastpacketsent, NULL)) {
fprintf(stderr, "arping: gettimeofday(): %s\n",
strerror(errno));
sigint(0);
}
numsent++;
}
/*
*
*/
static void pingip_send(u_int8_t *srcmac, u_int8_t *dstmac,
u_int32_t srcip, u_int32_t dstip)
{
static libnet_ptag_t arp=0,eth=0;
if (-1 == (arp = libnet_build_arp(ARPHRD_ETHER,
ETHERTYPE_IP,
ETH_ALEN,
IP_ALEN,
ARPOP_REQUEST,
srcmac,
(u_int8_t*)&srcip,
ethnull,
(u_int8_t*)&dstip,
NULL,
0,
libnet,
arp))) {
fprintf(stderr, "arping: libnet_build_arp(): %s\n",
libnet_geterror(libnet));
sigint(0);
}
if (-1 == (eth = libnet_build_ethernet(dstmac,
srcmac,
ETHERTYPE_ARP,
NULL,
0,
libnet,
eth))) {
fprintf(stderr, "arping: libnet_build_ethernet(): %s\n",
libnet_geterror(libnet));
sigint(0);
}
if(verbose>1) {
printf("arping: sending packet\n");
}
if (-1 == libnet_write(libnet)) {
fprintf(stderr, "arping: libnet_write(): %s\n",
libnet_geterror(libnet));
sigint(0);
}
if (-1 == gettimeofday(&lastpacketsent, NULL)) {
fprintf(stderr, "arping: gettimeofday(): %s\n",
strerror(errno));
sigint(0);
}
numsent++;
}
/*
*
*/
static void pingip_recv(const char *unused, struct pcap_pkthdr *h,
u_int8_t *packet)
{
struct libnet_802_3_hdr *heth;
struct libnet_arp_hdr *harp;
struct timeval arrival;
int c;
if(verbose>2) {
printf("arping: received response for ip ping\n");
}
if (-1 == gettimeofday(&arrival, NULL)) {
fprintf(stderr, "arping: gettimeofday(): %s\n",
strerror(errno));
sigint(0);
}
heth = (void*)packet;
harp = (void*)((char*)heth + LIBNET_ETH_H);
if ((htons(harp->ar_op) == ARPOP_REPLY)
&& (htons(harp->ar_pro) == ETHERTYPE_IP)
&& (htons(harp->ar_hrd) == ARPHRD_ETHER)) {
u_int32_t ip;
memcpy(&ip, (char*)harp + harp->ar_hln
+ LIBNET_ARP_H,4);
if (addr_must_be_same
&& (memcmp((u_char*)harp+sizeof(struct libnet_arp_hdr),
dstmac, ETH_ALEN))) {
return;
}
if (dstip == ip) {
switch(display) {
case NORMAL: {
char buf[128];
printf("%d bytes from ", h->len);
for (c = 0; c < 6; c++) {
printf("%.2x%c", heth->_802_3_shost[c],
(c<5)?':':' ');
}
printf("(%s): index=%d",
libnet_addr2name4(ip,0),
numrecvd);
if (alsototal) {
printf("/%u", numsent-1);
}
printf(" time=%s",
tv2str(&lastpacketsent,
&arrival,buf));
break; }
case QUIET:
break;
case RAWRAW:
for (c = 0; c < 6; c++) {
printf("%.2x%c", heth->_802_3_shost[c],
(c<5)?':':' ');
}
printf("%s", libnet_addr2name4(ip,0));
break;
case RRAW:
printf("%s", libnet_addr2name4(ip,0));
break;
case RAW:
for (c = 0; c < 6; c++) {
printf("%.2x%s", heth->_802_3_shost[c],
(c<5)?":":"");
}
break;
default:
fprintf(stderr, "arping: can't happen!\n");
}
if (display != QUIET) {
printf(beep?"\a\n":"\n");
}
numrecvd++;
}
}
}
/*
*
*/
static void pingmac_recv(const char *unused, struct pcap_pkthdr *h,
u_int8_t *packet)
{
struct libnet_802_3_hdr *heth;
struct libnet_ipv4_hdr *hip;
struct libnet_icmpv4_hdr *hicmp;
struct timeval arrival;
int c;
if(verbose>2) {
printf("arping: received response for mac ping\n");
}
if (-1 == gettimeofday(&arrival, NULL)) {
fprintf(stderr, "arping: gettimeofday(): %s\n",
strerror(errno));
sigint(0);
}
heth = (void*)packet;
hip = (void*)((char*)heth + LIBNET_ETH_H);
hicmp = (void*)((char*)hip + LIBNET_IPV4_H);
if ((htons(hicmp->icmp_type) == ICMP_ECHOREPLY)
&& ((!memcmp(heth->_802_3_shost, dstmac,ETH_ALEN)
|| !memcmp(dstmac, ethxmas, ETH_ALEN)))
&& !memcmp(heth->_802_3_dhost, srcmac, ETH_ALEN)) {
/* u_int8_t *cp = heth->_802_3_shost; */
if (addr_must_be_same) {
u_int32_t tmp;
memcpy(&tmp, &hip->ip_src, 4);
if (dstip != tmp) {
return;
}
}
switch(display) {
case QUIET:
break;
case NORMAL: {
char buf[128];
printf("%d bytes from %s (",h->len,
libnet_addr2name4(*(int*)&hip->ip_src, 0));
for (c = 0; c < 6; c++) {
printf("%.2x%c", heth->_802_3_shost[c],
(c<5)?':':')');
}
printf(": icmp_seq=%d time=%s",
htons(hicmp->icmp_seq),tv2str(&lastpacketsent,
&arrival,buf));
break; }
case RAW:
printf("%s",
libnet_addr2name4(hip->ip_src.s_addr, 0));
break;
case RRAW:
for (c = 0; c < 6; c++) {
printf("%.2x%s", heth->_802_3_shost[c],
(c<5)?":":"");
}
break;
case RAWRAW:
for (c = 0; c < 6; c++) {
printf("%.2x%c", heth->_802_3_shost[c],
(c<5)?':':' ');
}
printf("%s",
libnet_addr2name4(hip->ip_src.s_addr, 0));
break;
default:
fprintf(stderr, "arping: can't-happen-bug\n");
sigint(0);
}
if (display != QUIET) {
printf(beep?"\a\n":"\n");
}
numrecvd++;
}
}
#ifdef WIN32
static void
ping_recv_win32(pcap_t *pcap,u_int32_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
static void
fixup_timeval(struct timeval *tv)
{
while (tv->tv_usec < 0) {
tv->tv_sec--;
tv->tv_usec += 1000000;
}
}
static void
gettv(struct timeval *tv)
{
if (-1 == gettimeofday(tv,NULL)) {
fprintf(stderr, "arping: "
"gettimeofday(): %s\n",
strerror(errno));
sigint(0);
}
}
/*
*
*/
static void
ping_recv_unix(pcap_t *pcap,u_int32_t packetwait, pcap_handler func)
{
struct timeval tv;
struct timeval endtime;
char done = 0;
fd_set fds;
gettv(&tv);
endtime.tv_sec = tv.tv_sec + (packetwait / 1000000);
endtime.tv_usec = tv.tv_usec + (packetwait % 1000000);
fixup_timeval(&endtime);
for (;!done;) {
int sr;
FD_ZERO(&fds);
FD_SET(pcap_fileno(pcap), &fds);
gettv(&tv);
tv.tv_sec = endtime.tv_sec - tv.tv_sec;
tv.tv_usec = endtime.tv_usec - tv.tv_usec;
fixup_timeval(&tv);
if (tv.tv_sec < 0) {
tv.tv_sec = 0;
tv.tv_usec = 1;
done = 1;
}
if (time_to_die) {
return;
}
#ifndef HAVE_WEIRD_BSD
switch((sr = select(pcap_fileno(pcap)+1,
&fds,
NULL,NULL,&tv))) {
case -1:
if (errno == EINTR) {
return;
}
fprintf(stderr, "arping: select(%lu.%lu): "
"%s\n",
tv.tv_sec,
tv.tv_usec,
strerror(errno));
sigint(0);
case 0:
done = 1;
break;
default: {
#else
usleep(10);
{{
#endif
int ret;
if (1 != (ret = pcap_dispatch(pcap, 1,
func,
NULL))) {
// rest, so we don't take 100% CPU... mostly
// hmm... does usleep() exist everywhere?
usleep(10);
#ifndef HAVE_WEIRD_BSD
// weird is normal on bsd :)
if (verbose) {
fprintf(stderr, "arping: select=%d "
"pcap_dispatch=%d!\n",
sr, ret);
}
}
break;
#else
}
#endif
}
}
}
}
/*
*
*/
static void
ping_recv(pcap_t *pcap,u_int32_t packetwait, pcap_handler func)
{
if(verbose>3) {
printf("arping: receiving packets...\n");
}
#ifdef WIN32
ping_recv_win32(pcap,packetwait,func);
#else
ping_recv_unix(pcap,packetwait,func);
#endif
}
/*
*
*/
int main(int argc, char **argv)
{
char ebuf[LIBNET_ERRBUF_SIZE + PCAP_ERRBUF_SIZE];
char *cp;
/* int nullip = 0;*/
int promisc = 0;
int srcip_given = 0;
int srcmac_given = 0;
int dstip_given = 0;
const char *ifname = NULL;
char *parm;
int c;
unsigned int maxcount = -1;
int dont_use_arping_lookupdev=0;
struct bpf_program bp;
pcap_t *pcap;
static enum { NONE, PINGMAC, PINGIP } mode = NONE;
unsigned int packetwait = 1000000;
memset(ethnull, 0, ETH_ALEN);
srcip = 0;
dstip = 0xffffffff;
memset(dstmac, 0xff, ETH_ALEN);
memset(ethxmas, 0xff, ETH_ALEN);
while (EOF!=(c=getopt(argc, argv, "0aAbBc:dFhi:I:pqrRs:S:t:T:uvw:"))) {
switch(c) {
case '0':
srcip = 0;
srcip_given = 1;
break;
case 'a':
beep = 1;
break;
case 'A':
addr_must_be_same = 1;
break;
case 'b':
srcip = 0xffffffff;
srcip_given = 1;
break;
case 'B':
dstip = 0xffffffff;
dstip_given = 1;
break;
case 'c':
maxcount = atoi(optarg);
break;
case 'd':
finddup = 1;
break;
case 'F':
dont_use_arping_lookupdev=1;
break;
case 'h':
usage(0);
case 'i':
if (strchr(optarg, ':')) {
fprintf(stderr, "arping: If you're trying to "
"feed me an interface alias then you "
"don't really\nknow what this programs"
" does, do you?\nUse -I if you really"
" mean it (undocumented on "
"purpose)\n");
exit(1);
}
case 'I': /* FALL THROUGH */
ifname = optarg;
break;
case 'p':
promisc = 1;
break;
case 'q':
display = QUIET;
break;
case 'r':
display = (display==RRAW)?RAWRAW:RAW;
break;
case 'R':
display = (display==RAW)?RAWRAW:RRAW;
break;
case 's': {// spoof source MAC
unsigned int n[6];
if (!get_mac_addr(optarg,
&n[0],&n[1],&n[2],
&n[3],&n[4],&n[5])){
fprintf(stderr, "arping: Weird MAC addr %s\n",
optarg);
exit(1);
}
for (c = 0; c < 6; c++) {
srcmac[c] = n[c] & 0xff;
}
srcmac_given = 1;
break;
}
case 'S': // set source IP, may be null for don't-know
do_libnet_init(NULL);
if (-1 == (srcip = libnet_name2addr4(libnet,
optarg,
LIBNET_RESOLVE))){
fprintf(stderr, "arping: Can't resolve %s, or "
"%s is broadcast. If it is, use -b"
" instead of -S\n", optarg,optarg);
exit(1);
}
srcip_given = 1;
break;
case 't': { // set taget mac
unsigned int n[6];
if (mode == PINGMAC) {
fprintf(stderr, "arping: -t can only be used "
"in IP ping mode\n");
exit(1);
}
if (!get_mac_addr(optarg,
&n[0],&n[1],&n[2],
&n[3],&n[4],&n[5])){
fprintf(stderr, "Illegal MAC addr %s\n",
optarg);
exit(1);
}
for (c = 0; c < 6; c++) {
dstmac[c] = n[c] & 0xff;
}
mode = PINGIP;
break;
}
case 'T': // set destination IP
if (mode == PINGIP) {
fprintf(stderr, "arping: -T can only be used "
"in MAC ping mode\n");
exit(1);
}
do_libnet_init(NULL);
if (-1 == (dstip = libnet_name2addr4(libnet,
optarg,
LIBNET_RESOLVE))){
fprintf(stderr,"arping: Can't resolve %s, or "
"%s is broadcast. If it is, use -B "
"instead of -T\n",optarg,optarg);
exit(1);
}
mode = PINGMAC;
break;
case 'u':
alsototal = 1;
break;
case 'v':
verbose++;
break;
case 'w':
packetwait = (unsigned)atoi(optarg);
break;
default:
usage(1);
}
}
parm = (optind < argc) ? argv[optind] : NULL;
/*
* Handle dstip_given instead of ip address after parms (-B really)
*/
if (mode == NONE) {
if (optind + 1 == argc) {
mode = is_mac_addr(parm)?PINGMAC:PINGIP;
} else if (dstip_given) {
mode = PINGIP;
do_libnet_init(NULL);
parm = strdup(libnet_addr2name4(dstip,0));
if (!parm) {
fprintf(stderr, "arping: out of mem\n");
exit(1);
}
}
}
if (!parm) {
usage(1);
}
/*
*
*/
if (mode == NONE) {
usage(1);
}
/*
* libnet init (may be done already for resolving)
*/
do_libnet_init(ifname);
/*
* Make sure dstip and parm like eachother
*/
if (mode == PINGIP && (!dstip_given)) {
if (is_mac_addr(parm)) {
fprintf(stderr, "arping: Options given only apply to "
"IP ping, but MAC address given as argument"
"\n");
exit(1);
}
if (-1 == (dstip = libnet_name2addr4(libnet,
parm,
LIBNET_RESOLVE))) {
fprintf(stderr, "arping: Can't resolve %s\n", parm);
exit(1);
}
parm = strdup(libnet_addr2name4(dstip,0));
}
/*
* parse parm into dstmac
*/
if (mode == PINGMAC) {
unsigned int n[6];
if (optind + 1 != argc) {
usage(1);
}
if (!is_mac_addr(parm)) {
fprintf(stderr, "arping: Options given only apply to "
"MAC ping, but no MAC address given as "
"argument\n");
exit(1);
}
if (!get_mac_addr(argv[optind],
&n[0],&n[1],&n[2],
&n[3],&n[4],&n[5])) {
fprintf(stderr, "arping: Illegal mac addr %s\n",
argv[optind]);
return 1;
}
for (c = 0; c < 6; c++) {
dstmac[c] = n[c] & 0xff;
}
}
target = parm;
/*
* Argument processing done, parameters considered sane below
*/
/*
* Get some good iface.
*/
if (!ifname) {
if (dont_use_arping_lookupdev) {
ifname = arping_lookupdev_default(srcip,dstip,ebuf);
} else {
ifname = arping_lookupdev(srcip,dstip,ebuf);
}
if (!ifname) {
fprintf(stderr, "arping: arping_lookupdev(): %s\n",
ebuf);
exit(1);
}
// FIXME: check for other probably-not interfaces
if (!strcmp(ifname, "ipsec")
|| !strcmp(ifname,"lo")) {
fprintf(stderr, "arping: Um.. %s looks like the wrong "
"interface to use. Is it? "
"(-i switch)\n", ifname);
fprintf(stderr, "arping: using it anyway this time\n");
}
}
/*
* Init libnet again, because we now know the interface name.
* We should know it by know at least
*/
do_libnet_init(ifname);
/*
* pcap init
*/
if (!(pcap = pcap_open_live((char*)ifname, 100, promisc, 10, ebuf))) {
fprintf(stderr, "arping: pcap_open_live(): %s\n",ebuf);
exit(1);
}
#ifdef HAVE_NET_BPF_H
{
u_int32_t on = 1;
if (0 < (ioctl(pcap_fileno(pcap), BIOCIMMEDIATE,
&on))) {
fprintf(stderr, "arping: ioctl(fd,BIOCIMMEDIATE, 1) "
"failed, continuing anyway, YMMV: %s\n",
strerror(errno));
}
}
#endif
if (mode == PINGIP) {
// FIXME: better filter with addresses?
if (-1 == pcap_compile(pcap, &bp, "arp", 0,-1)) {
fprintf(stderr, "arping: pcap_compile(): error\n");
exit(1);
}
} else { // ping mac
// FIXME: better filter with addresses?
if (-1 == pcap_compile(pcap, &bp, "icmp", 0,-1)) {
fprintf(stderr, "arping: pcap_compile(): error\n");
exit(1);
}
}
if (-1 == pcap_setfilter(pcap, &bp)) {
fprintf(stderr, "arping: pcap_setfilter(): error\n");
exit(1);
}
/*
* final init
*/
if (!srcmac_given) {
if (!(cp = (char*)libnet_get_hwaddr(libnet))) {
fprintf(stderr, "arping: libnet_get_hwaddr(): %s\n",
libnet_geterror(libnet));
exit(1);
}
memcpy(srcmac, cp, ETH_ALEN);
}
if (!srcip_given) {
if (-1 == (srcip = libnet_get_ipaddr4(libnet))) {
fprintf(stderr, "arping: libnet_get_ipaddr4(libnet): "
"%s\n", libnet_geterror(libnet));
exit(1);
}
}
#ifdef WIN32
//SetConsoleCtrlHandler(NULL, TRUE);
SetConsoleCtrlHandler(arping_console_ctrl_handler, TRUE);
#else
signal(SIGINT, sigint);
#endif
if (verbose) {
printf("This box: Interface: %s IP: %s MAC address: ",
ifname, libnet_addr2name4(libnet_get_ipaddr4(libnet),
0));
for (c = 0; c < ETH_ALEN - 1; c++) {
printf("%.2x:", (u_int8_t)srcmac[c]);
}
printf("%.2x\n", (u_int8_t)srcmac[ETH_ALEN - 1]);
}
if (display == NORMAL) {
printf("ARPING %s\n", parm);
}
/*
* let's roll
*/
if (mode == PINGIP) {
unsigned int c;
for (c = 0; c < maxcount && !time_to_die; c++) {
pingip_send(srcmac, dstmac, srcip, dstip);
ping_recv(pcap,packetwait,
(pcap_handler)pingip_recv);
}
} else { // PINGMAC
unsigned int c;
for (c = 0; c < maxcount && !time_to_die; c++) {
pingmac_send(srcmac, dstmac, srcip, dstip, rand(), c);
ping_recv(pcap,packetwait,
(pcap_handler)pingmac_recv);
}
}
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);
}
exit(!numrecvd);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1