Repository URL to install this package:
/*
* The ARP Scanner (arp-scan) is Copyright (C) 2005-2016 Roy Hills,
* NTA Monitor Ltd.
*
* This file is part of arp-scan.
*
* arp-scan 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 3 of the License, or
* (at your option) any later version.
*
* arp-scan 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 arp-scan. If not, see <http://www.gnu.org/licenses/>.
*
* arp-scan -- The ARP Scanner
*
* Author: Roy Hills
* Date: 13 October 2005
*
* Usage:
* arp-scan [options] [host...]
*
* Description:
*
* arp-scan sends the specified ARP packet to the specified hosts
* and displays any responses received.
*
* The ARP protocol is defined in RFC 826 Ethernet Address Resolution Protocol
*
*/
#include "arp-scan.h"
/* Global variables */
static host_entry *helist = NULL; /* Array of host entries */
static host_entry **helistptr; /* Array of pointers to host entries */
static host_entry **cursor; /* Pointer to current host entry ptr */
static unsigned num_hosts = 0; /* Number of entries in the list */
static unsigned responders = 0; /* Number of hosts which responded */
static unsigned live_count; /* Number of entries awaiting reply */
static int verbose=0; /* Verbose level */
static char filename[MAXLINE]; /* Target list file name */
static int filename_flag=0; /* Set if using target list file */
static int random_flag=0; /* Randomise the list */
static int numeric_flag=0; /* IP addresses only */
static unsigned interval=0; /* Desired interval between packets */
static unsigned bandwidth=DEFAULT_BANDWIDTH; /* Bandwidth in bits per sec */
static unsigned retry = DEFAULT_RETRY; /* Number of retries */
static unsigned timeout = DEFAULT_TIMEOUT; /* Per-host timeout */
static float backoff_factor = DEFAULT_BACKOFF_FACTOR; /* Backoff factor */
static int snaplen = SNAPLEN; /* Pcap snap length */
static char *if_name=NULL; /* Interface name, e.g. "eth0" */
static int quiet_flag=0; /* Don't decode the packet */
static int ignore_dups=0; /* Don't display duplicate packets */
static uint32_t arp_spa; /* Source IP address */
static int arp_spa_flag=0; /* Source IP address specified */
static int arp_spa_is_tpa=0; /* Source IP is dest IP */
static unsigned char arp_sha[ETH_ALEN]; /* Source Ethernet MAC Address */
static int arp_sha_flag=0; /* Source MAC address specified */
static char ouifilename[MAXLINE]; /* OUI filename */
static char iabfilename[MAXLINE]; /* IAB filename */
static char macfilename[MAXLINE]; /* MAC filename */
static char pcap_savefile[MAXLINE]; /* pcap savefile filename */
static int arp_op=DEFAULT_ARP_OP; /* ARP Operation code */
static int arp_hrd=DEFAULT_ARP_HRD; /* ARP hardware type */
static int arp_pro=DEFAULT_ARP_PRO; /* ARP protocol */
static int arp_hln=DEFAULT_ARP_HLN; /* Hardware address length */
static int arp_pln=DEFAULT_ARP_PLN; /* Protocol address length */
static int eth_pro=DEFAULT_ETH_PRO; /* Ethernet protocol type */
static unsigned char arp_tha[6] = {0, 0, 0, 0, 0, 0};
static unsigned char target_mac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static unsigned char source_mac[6];
static int source_mac_flag = 0;
static unsigned char *padding=NULL;
static size_t padding_len=0;
static int localnet_flag=0; /* Scan local network */
static int llc_flag=0; /* Use 802.2 LLC with SNAP */
static int ieee_8021q_vlan=-1; /* Use 802.1Q VLAN tagging if >= 0 */
static int pkt_write_file_flag=0; /* Write packet to file flag */
static int pkt_read_file_flag=0; /* Read packet from file flag */
static char pkt_filename[MAXLINE]; /* Read/Write packet to file filename */
static int write_pkt_to_file=0; /* Write packet to file for debugging */
static int rtt_flag=0; /* Display round-trip time */
static pcap_dumper_t *pcap_dump_handle = NULL; /* pcap savefile handle */
static int plain_flag=0; /* Only show host information */
unsigned int random_seed=0;
int
main(int argc, char *argv[]) {
struct timeval now;
struct timeval diff; /* Difference between two timevals */
int select_timeout; /* Select timeout */
ARP_UINT64 loop_timediff; /* Time since last packet sent in us */
ARP_UINT64 host_timediff; /* Time since last pkt sent to this host (us) */
struct timeval last_packet_time; /* Time last packet was sent */
int req_interval; /* Requested per-packet interval */
int cum_err=0; /* Cumulative timing error */
struct timeval start_time; /* Program start time */
struct timeval end_time; /* Program end time */
struct timeval elapsed_time; /* Elapsed time as timeval */
double elapsed_seconds; /* Elapsed time in seconds */
int reset_cum_err;
int pass_no = 0;
int first_timeout=1;
unsigned i;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program filter;
char *filter_string;
bpf_u_int32 netmask;
bpf_u_int32 localnet;
int datalink;
int get_addr_status = 0;
int pcap_fd; /* Pcap file descriptor */
unsigned char interface_mac[ETH_ALEN];
pcap_t *pcap_handle; /* pcap handle */
/*
* Initialise file names to the empty string.
*/
ouifilename[0] = '\0';
iabfilename[0] = '\0';
macfilename[0] = '\0';
pcap_savefile[0] = '\0';
/*
* Process options.
*/
process_options(argc, argv);
/*
* Get program start time for statistics displayed on completion.
*/
Gettimeofday(&start_time);
/*
* Obtain network interface details unless we're reading
* from a pcap file or writing to a binary file.
*/
if (!pkt_read_file_flag && !pkt_write_file_flag) {
/*
* Determine network interface to use. If the interface was specified
* with the --interface option then use that, otherwise use
* pcap_lookupdev() to pick a suitable interface.
*/
if (!if_name) {
if (!(if_name=pcap_lookupdev(errbuf))) {
err_msg("pcap_lookupdev: %s", errbuf);
}
}
/*
* Obtain the MAC address for the selected interface, and use this
* as default for the source hardware addresses in the frame header
* and ARP packet if the user has not specified their values.
*
* Die with an error if we can't get the MAC address, as this
* indicates that the interface doesn't have a MAC address, so is
* probably not a compatible interface type.
*/
get_hardware_address(if_name, interface_mac);
if (interface_mac[0]==0 && interface_mac[1]==0 &&
interface_mac[2]==0 && interface_mac[3]==0 &&
interface_mac[4]==0 && interface_mac[5]==0) {
err_msg("ERROR: Could not obtain MAC address for interface %s",
if_name);
}
if (source_mac_flag == 0)
memcpy(source_mac, interface_mac, ETH_ALEN);
if (arp_sha_flag == 0)
memcpy(arp_sha, interface_mac, ETH_ALEN);
/*
* If the user has not specified the ARP source address, obtain the
* interface IP address and use that as the default value.
*/
if (arp_spa_flag == 0) {
get_addr_status = get_source_ip(if_name, &arp_spa);
if (get_addr_status == -1) {
warn_msg("WARNING: Could not obtain IP address for interface %s. "
"Using 0.0.0.0 for", if_name);
warn_msg("the source address, which is probably not what you want.");
warn_msg("Either configure %s with an IP address, or manually specify"
" the address", if_name);
warn_msg("with the --arpspa option.");
memset(&arp_spa, '\0', sizeof(arp_spa));
}
}
}
/*
* Open the network device for reading with pcap, or the pcap file if we
* have specified --readpktfromfile. If we are writing packets to a binary
* file, then set pcap_handle to NULL as we don't need to read packets in
* this case.
*/
if (pkt_read_file_flag) {
if (!(pcap_handle = pcap_open_offline(pkt_filename, errbuf)))
err_msg("pcap_open_offline: %s", errbuf);
} else if (!pkt_write_file_flag) {
if (!(pcap_handle = pcap_create(if_name, errbuf)))
err_msg("pcap_create: %s", errbuf);
if ((pcap_set_snaplen(pcap_handle, snaplen)) < 0)
err_msg("pcap_set_snaplen: %s", pcap_geterr(pcap_handle));
if ((pcap_set_promisc(pcap_handle, PROMISC)) < 0)
err_msg("pcap_set_promisc: %s", pcap_geterr(pcap_handle));
if ((pcap_set_timeout(pcap_handle, TO_MS)) < 0)
err_msg("pcap_set_timeout: %s", pcap_geterr(pcap_handle));
if ((pcap_activate(pcap_handle)) < 0)
err_msg("pcap_activate: %s", pcap_geterr(pcap_handle));
} else {
pcap_handle = NULL;
}
/*
* If we are reading data with pcap, get and display the datalink details
*/
if (pcap_handle) {
if ((datalink=pcap_datalink(pcap_handle)) < 0)
err_msg("pcap_datalink: %s", pcap_geterr(pcap_handle));
if (!plain_flag) {
printf("Interface: %s, datalink type: %s (%s)\n",
pkt_read_file_flag ? "savefile" : if_name,
pcap_datalink_val_to_name(datalink),
pcap_datalink_val_to_description(datalink));
}
if (datalink != DLT_EN10MB) {
warn_msg("WARNING: Unsupported datalink type");
}
}
/*
* If we are reading from a network device, then get the associated file
* descriptor and configure it, determine the interface IP network and
* netmask, and install a pcap filter to receive only ARP responses.
* If we are reading from a pcap file, or writing to a binary file, just
* set the file descriptor to -1 to indicate that it is not associated
* with a network device.
*/
if (!pkt_read_file_flag && !pkt_write_file_flag) {
if ((pcap_fd=pcap_get_selectable_fd(pcap_handle)) < 0)
err_msg("pcap_fileno: %s", pcap_geterr(pcap_handle));
if ((pcap_setnonblock(pcap_handle, 1, errbuf)) < 0)
err_msg("pcap_setnonblock: %s", errbuf);
/*
* For the BPF pcap implementation, set the BPF device into immediate mode,
* otherwise it will buffer the responses.
*/
#ifdef ARP_PCAP_BPF
#ifdef BIOCIMMEDIATE
{
unsigned int one = 1;
if (ioctl(pcap_fd, BIOCIMMEDIATE, &one) < 0)
err_sys("ioctl BIOCIMMEDIATE");
}
#endif /* BIOCIMMEDIATE */
#endif /* ARP_PCAP_BPF */
/*
* For the DLPI pcap implementation on Solaris, set the bufmod timeout to
* zero. This has the side-effect of setting the chunk size to zero as
* well, so bufmod will pass all incoming messages on immediately.
*/
#ifdef ARP_PCAP_DLPI
{
struct timeval time_zero = {0, 0};
if (ioctl(pcap_fd, SBIOCSTIME, &time_zero) < 0)
err_sys("ioctl SBIOCSTIME");
}
#endif
if (pcap_lookupnet(if_name, &localnet, &netmask, errbuf) < 0) {
memset(&localnet, '\0', sizeof(localnet));
memset(&netmask, '\0', sizeof(netmask));
if (localnet_flag) {
warn_msg("ERROR: Could not obtain interface IP address and netmask");
err_msg("ERROR: pcap_lookupnet: %s", errbuf);
}
}
/*
* The filter string selects packets addressed to the ARP source address
* that are Ethernet-II ARP packets, 802.3 LLC/SNAP ARP packets,
* 802.1Q tagged ARP packets or 802.1Q tagged 802.3 LLC/SNAP ARP packets.
*/
filter_string=make_message("ether dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x and "
"(arp or (ether[14:4]=0xaaaa0300 and "
"ether[20:2]=0x0806) or (ether[12:2]=0x8100 "
"and ether[16:2]=0x0806) or "
"(ether[12:2]=0x8100 and "
"ether[18:4]=0xaaaa0300 and "
"ether[24:2]=0x0806))",
arp_sha[0], arp_sha[1],
arp_sha[2], arp_sha[3],
arp_sha[4], arp_sha[5]);
if (verbose > 1)
warn_msg("DEBUG: pcap filter string: \"%s\"", filter_string);
if ((pcap_compile(pcap_handle, &filter, filter_string, OPTIMISE,
netmask)) < 0)
err_msg("pcap_compile: %s", pcap_geterr(pcap_handle));
free(filter_string);
if ((pcap_setfilter(pcap_handle, &filter)) < 0)
err_msg("pcap_setfilter: %s", pcap_geterr(pcap_handle));
} else { /* Reading packets from file */
pcap_fd = -1;
}
/*
* Drop SUID privileges.
*/
if ((setuid(getuid())) < 0) {
err_sys("setuid");
}
/*
* Open pcap savefile is the --pcapsavefile (-W) option was specified
*/
if (*pcap_savefile != '\0') {
if (!(pcap_dump_handle=pcap_dump_open(pcap_handle, pcap_savefile))) {
err_msg("pcap_dump_open: %s", pcap_geterr(pcap_handle));
}
}
/*
* Check that the combination of specified options and arguments is
* valid.
*/
if (interval && bandwidth != DEFAULT_BANDWIDTH)
err_msg("ERROR: You cannot specify both --bandwidth and --interval.");
if (localnet_flag) {
if ((argc - optind) > 0)
err_msg("ERROR: You can not specify targets with the --localnet option");
if (filename_flag)
err_msg("ERROR: You can not specify both --file and --localnet options");
}
/*
* If we're not reading from a file, and --localnet was not specified, then
* we must have some hosts given as command line arguments.
*/
if (!filename_flag && !localnet_flag)
if ((argc - optind) < 1)
usage(EXIT_FAILURE, 0);
/*
* Create MAC/Vendor hash table if quiet if not in effect.
*/
if (!quiet_flag) {
char *fn;
int count;
if ((hcreate(HASH_TABLE_SIZE)) == 0)
err_sys("hcreate");
fn = get_mac_vendor_filename(ouifilename, DATADIR, OUIFILENAME);
count = add_mac_vendor(fn);
Loading ...