// ------------------------------- //
// -------- Start of File -------- //
// ------------------------------- //
// ----------------------------------------------------------- //
// C++ Source Code File Name: arpscan.cpp
// C++ Compiler Used: MSVC, BCC32, GCC, HPUX aCC, SOLARIS CC
// Produced By: glNET Software
// File Creation Date: 09/20/1999
// Date Last Modified: 05/25/2001
// Copyright (c) 2001 glNET Software
// ----------------------------------------------------------- //
// ------------- Program Description and Details ------------- //
// ----------------------------------------------------------- //
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser 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
Test program used to get the Media Access Control (MAC) addresses
of all the hosts on a specified class C subnet.
*/
// ----------------------------------------------------------- //
#include <iostream.h>
#include <fstream.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include "gxsping.h"
#include "gxip32.h"
#include "gxmac48.h"
// Platform specific include files
#if defined (__UNIX__)
#include <net/if_arp.h>
#include <sys/ioctl.h>
#endif
#if defined (__WIN32__)
int WIN32GetMAC(const char *ip_address, char *mac_address);
#endif
int GetMacAddress(const char *ip_address, char *eth_dev, char *fname = 0,
fstream *outfile = 0)
{
// Construct a raw socket;
gxSocket raw_socket;
if(raw_socket.InitSocketLibrary() != 0) {
cout << raw_socket.SocketExceptionMessage() << endl << flush;
if(outfile)
*(outfile) << raw_socket.SocketExceptionMessage() << endl << flush;
return 0;
}
cout << ip_address << '\t' << flush;
if(outfile) *(outfile) << ip_address << '\t' << flush;
gxsHostNameInfo *hostnm = raw_socket.GetHostInformation((char *)ip_address);
if(hostnm) {
cout << hostnm->h_name << flush;
if(outfile) *(outfile) << hostnm->h_name << flush;
}
else {
cout << "no_DNS_entry" << flush;
if(outfile) *(outfile) << "no_DNS_entry" << flush;
}
if(raw_socket.InitSocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, 0,
(char *)ip_address) < 0) {
cout << raw_socket.SocketExceptionMessage() << endl << flush;
if(outfile)
*(outfile) << raw_socket.SocketExceptionMessage() << endl << flush;
return 0;
}
// Ping with a specified timeout value
gxsPing ping(&raw_socket);
if(ping.Ping(4) != gxSOCKET_NO_ERROR) {
if(raw_socket.GetSocketError() == gxSOCKET_REQUEST_TIMEOUT) {
}
else {
cout << endl << flush;
cout << raw_socket.SocketExceptionMessage() << endl << flush;
if(outfile) {
*(outfile) << endl << flush;
*(outfile) << raw_socket.SocketExceptionMessage() << endl << flush;
}
delete hostnm;
return 0;
}
}
#if defined (__WIN32__)
char mac_address[255];
if(!WIN32GetMAC(ip_address, mac_address)) {
cout << endl << flush;
if(outfile) *(outfile) << endl << flush;
delete hostnm;
return 0; // No entry in the arp cache
}
gxMAC48 mac(mac_address, '-', 2);
cout << '\t' << mac.c_str(mac_address) << flush;
if(outfile) *(outfile) << '\t' << mac.c_str(mac_address) << flush;
#elif defined (__UNIX__)
arpreq arp_data;
memset(&arp_data, 0, sizeof(arp_data));
memcpy(&arp_data.arp_pa, &raw_socket.sin, sizeof(arp_data.arp_pa));
#if defined (__LINUX__)
strcpy(arp_data.arp_dev, eth_dev);
#endif
#ifndef SIOCGARP
#error SIOCGARP is not available on this platform
#endif
if(ioctl(raw_socket.GetSocket(), SIOCGARP, &arp_data) == -1) {
cout << endl << flush;
if(outfile) *(outfile) << endl << flush;
delete hostnm;
return 0; // No entry in the arp cache
}
char mac_address[255];
unsigned char *ptr = (unsigned char *)&arp_data.arp_ha.sa_data[0];
sprintf(mac_address, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",*ptr,
*(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5));
gxMAC48 mac(mac_address, ':', 2);
cout << '\t' << mac.c_str(mac_address) << flush;
if(outfile) *(outfile) << '\t' << mac.c_str(mac_address) << flush;
#else
#error You must define a target platform: __WIN32__ or __UNIX__
#endif
if(fname) { // Find the vendor information
char name[255];
char comment[255];
if(FindVendor((const char *)fname, mac, name, comment)) {
cout << '\t' << name << flush;
if(outfile) *(outfile) << '\t' << name << flush;
}
}
cout << endl << flush;
if(outfile) *(outfile) << endl << flush;
delete hostnm;
return 1;
}
int main(int argc, char **argv)
{
#ifdef __UNIX__
// Raw sockets require root access on all UNIX platforms. Programs
// that use raw sockets can be excucuted by non-root users if the
// effective user ID of the executing process is set to the same as
// the file's owner. In the case root must own the excutable and
// the effective User-ID or Group-ID on execution bit must be set
// by root using the chmod command: "chmod u+s" or "chmod 4510"
// Now the effective user ID of the executing process will be set to
// the same user ID of the file's owner.
if(geteuid() != 0) {
cout << "You must be root to run this program" << endl;
return 0;
}
#endif
// Check the command line arguments
#if defined (__WIN32__)
if(argc < 2) {
cout << endl;
cout << "Usage: " << argv[0] << " subnet " << endl;
cout << "Example 1: " << argv[0] <<" 254.10.50 " << endl;
cout << "Example 2: " << argv[0] <<" 254.10.50 maccodes.txt" << endl;
cout << "Example 3: " << argv[0] <<" 254.10.50.1 " << endl;
cout << "Example 4: " << argv[0] <<" 254.10.50.1 maccodes.txt" << endl;
cout << "Example 5: " << argv[0] <<" 254.10.50.255 maccodes.txt \
outfile.txt" << endl;
return 1;
}
char *subnet = argv[1];
char *eth_dev = 0;
char *fname = 0;
char *ofname = 0;
if(argc >= 3) fname = argv[2];
if(argc == 4) ofname = argv[3];
#elif defined (__UNIX__)
if(argc < 3) {
cout << endl;
cout << "Usage: " << argv[0] << " subnet ethernet_device" << endl;
cout << "Example 1: " << argv[0] <<" 254.10.50 eth0" << endl;
cout << "Example 2: " << argv[0] <<" 254.10.50 eth0 maccodes.txt"
<< endl;
cout << "Example 3: " << argv[0] <<" 254.10.50.1 eth0" << endl;
cout << "Example 4: " << argv[0] <<" 254.10.50.1 eth0 maccodes.txt"
<< endl;
cout << "Example 5: " << argv[0] <<" 254.10.50.255 eth0 maccodes.txt \
outfile.txt" << endl;
return 1;
}
char *subnet = argv[1];
char *eth_dev = argv[2];
char *fname = 0;
char *ofname = 0;
if(argc >= 4) fname = argv[3];
if(argc == 5) fname = argv[4];
#else
#error You must define a target platform: __WIN32__ or __UNIX__
#endif
fstream outfile;
int out = 0;
if(ofname) {
// Open the output file and truncate if it already exists
out = 1;
outfile.open(ofname, ios::out|ios::trunc|ios::binary);
if(!outfile) {
cout << "Could not open the " << ofname << " output file" << endl;
return 1;
}
}
gxIP32 ip32(subnet);
char sbuf[255];
if((ip32.GetByte4() == 0) || (ip32.GetByte4() == 255)) {
// Find the mac address of all the nodes on a specified subnet
for(int i = 1; i < 255; i++) {
ip32.SetByte4(i);
if(out)
GetMacAddress(ip32.c_str(sbuf), eth_dev, fname, &outfile);
else
GetMacAddress(ip32.c_str(sbuf), eth_dev, fname);
}
}
else {
// Get the mac address of a single node
if(out)
GetMacAddress(ip32.c_str(sbuf), eth_dev, fname, &outfile);
else
GetMacAddress(ip32.c_str(sbuf), eth_dev, fname);
}
if(out) outfile.close();
return 0;
}
#if defined (__WIN32__)
int WIN32GetMAC(const char *ip_address, char *mac_address)
// Function used to get a mac address from the WIN32 arp cache.
// Returns true if an arp cache entry exists for the specified
// IP address string.
{
system("arp -a > arpcache.txt");
ifstream infile("arpcache.txt", ios::in);
if(!infile) return 0; // Cannot open the file
char sbuf[255];
char ip_in[255];
while(!infile.eof()) {
infile.getline(sbuf, 255);
int len, offset, i = 0;
int byte_count = strlen(sbuf);
ip_in[0] = 0;
mac_address[0] = 0;
// Trim leading tabs and spaces
while((sbuf[i] == ' ') || (sbuf[i] == '\t')) i++;
byte_count -= i;
if(byte_count <= 0) continue;
memmove(sbuf, sbuf+i, byte_count);
sbuf[byte_count] = 0;
// Parse the IP Address
for(i = 0; i < byte_count; i ++) {
if((sbuf[i] == ' ') || (sbuf[i] == '\t')) break;
ip_in[i] = sbuf[i];
}
ip_in[i] = 0; // Null terminate the string
if(strcmp(ip_in, ip_address) == 0) { // Parse the MAC Address
while((sbuf[i] == ' ') || (sbuf[i] == '\t')) i++;
byte_count -= i;
if(byte_count <= 0) continue;
memmove(sbuf, sbuf+i, byte_count);
for(i = 0; i < byte_count; i ++) {
if(sbuf[i] == ' ') break;
mac_address[i] = sbuf[i];
}
mac_address[i] = 0; // Null terminate the string
if(mac_address[0] != 0) { // Remove any trailing spaces
offset = len = strlen(mac_address);
while(offset--) if(mac_address[offset] != ' ') break;
if(offset < len) mac_address[offset+1] = 0;
return 1; // Found the arp cache entry
}
else {
return 0;
}
}
}
infile.close();
return 0;
}
#endif
// ----------------------------------------------------------- //
// ------------------------------- //
// --------- End of File --------- //
// ------------------------------- //