#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <linux/if_arp.h>
#include <sys/uio.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#define MAX_SEND 4
#define MAX_RECV 3
#define RESP_TIMEOUT 20
class CArpTest
{
public:
/////////////////////////////////////////////////////////////////////////////
//
//
///////////////////////////////////////////////////////////////////////////////
CArpTest::CArpTest( const char * const device = "eth0" ) : m_arp_socket( -1 ), m_dev( device )
{
initSocket();
};
/////////////////////////////////////////////////////////////////////////////
//
//
/////////////////////////////////////////////////////////////////////////////
CArpTest::~CArpTest()
{
close( m_arp_socket );
};
private:
int m_arp_socket;
const char * const m_dev;
struct sockaddr_ll m_slladdr;
struct sockaddr_ll m_dlladdr;
/////////////////////////////////////////////////////////////////////////////
//
// Set up socket
//
///////////////////////////////////////////////////////////////////////////////
void initSocket()
{
if ( ( m_arp_socket = socket( PF_PACKET, SOCK_DGRAM, 0 ) ) < 0 )
{
printf( "Error: the socket() call retured %d: %s\n", m_arp_socket, strerror(errno) );
exit( 1 );
}
int val = 1;
if ( ioctl( m_arp_socket, FIONBIO, &val ) < 0 )
{
printf( "Error: FIONBIO: %s\n", strerror(errno) );
close( m_arp_socket );
exit ( 1 );
}
struct ifreq ifr;
memset( &ifr, 0, sizeof(ifr) );
strncpy( ifr.ifr_name, m_dev, IFNAMSIZ-1 );
if ( ioctl( m_arp_socket, SIOCGIFINDEX, &ifr ) < 0 )
{
printf( "Error: SIOCGIFINDEX: %s\n", strerror(errno) );
close( m_arp_socket );
exit( 1 );
}
m_slladdr.sll_family = AF_PACKET;
m_slladdr.sll_ifindex = ifr.ifr_ifindex;
m_slladdr.sll_protocol = htons( ETH_P_ARP );
if ( bind( m_arp_socket, (struct sockaddr*) &m_slladdr, sizeof(m_slladdr) ) == -1 )
{
printf( "Error in bind() call: %s\n", strerror(errno) );
close( m_arp_socket );
exit( 1 );
}
unsigned int len = sizeof(m_slladdr);
if ( getsockname( m_arp_socket, (struct sockaddr*) &m_slladdr, &len ) < 0 )
{
printf( "Error in getsockname() call: %s\n", strerror(errno) );
close( m_arp_socket );
exit( 1 );
}
if ( m_slladdr.sll_halen == 0 )
{
close( m_arp_socket );
exit( 1 );
}
m_dlladdr = m_slladdr;
memset( m_dlladdr.sll_addr, -1, m_dlladdr.sll_halen);
}
/////////////////////////////////////////////////////////////////////////////
//
// Send out an arp packet
//
///////////////////////////////////////////////////////////////////////////////
int send_pack( int socket,
struct in_addr src,
struct in_addr dst,
struct sockaddr_ll *ME,
struct sockaddr_ll *HE,
int advert = 0 )
{
unsigned char buf[256] = {0};
struct arphdr *ah = (struct arphdr*)buf;
unsigned char *p = (unsigned char *)(ah+1);
ah->ar_hrd = htons(ME->sll_hatype);
if (ah->ar_hrd == htons(ARPHRD_FDDI))
{
ah->ar_hrd = htons(ARPHRD_ETHER);
}
ah->ar_pro = htons(ETH_P_IP);
ah->ar_hln = ME->sll_halen;
ah->ar_pln = 4;
ah->ar_op = ( advert ? htons(ARPOP_REPLY) : htons(ARPOP_REQUEST) );
memcpy( p, &ME->sll_addr, ah->ar_hln );
p += ME->sll_halen;
memcpy( p, &src, 4 );
p += 4;
if ( advert )
{
memcpy( p, &ME->sll_addr, ah->ar_hln );
}
else
{
memcpy( p, &HE->sll_addr, ah->ar_hln );
}
p+=ah->ar_hln;
memcpy( p, &dst, 4 );
p += 4;
return sendto( socket, buf, p - buf, 0, (struct sockaddr*)HE, sizeof(*HE) );
}
/////////////////////////////////////////////////////////////////////////////
//
// Receive arp packets
//
///////////////////////////////////////////////////////////////////////////////
int recv_pack( unsigned char *buf,
int len,
struct sockaddr_ll *FROM,
struct in_addr &src_ip,
struct in_addr &dst_ip,
unsigned char *mac )
{
struct timeval tv;
struct arphdr *ah = (struct arphdr*)buf;
unsigned char *p = (unsigned char *)(ah+1);
gettimeofday( &tv, NULL );
if ( FROM->sll_pkttype != PACKET_HOST &&
FROM->sll_pkttype != PACKET_BROADCAST &&
FROM->sll_pkttype != PACKET_MULTICAST )
return 0;
if ( ah->ar_op != htons(ARPOP_REPLY) ) return 0;
if ( ah->ar_hrd != htons(FROM->sll_hatype) &&
( (FROM->sll_hatype != ARPHRD_FDDI) || (ah->ar_hrd != htons(ARPHRD_ETHER)) ) )
{
return 0;
}
if ( ah->ar_pro != htons(ETH_P_IP) ) return 0;
if ( ah->ar_pln != 4 ) return 0;
if ( len < (int) (sizeof(*ah) + 2*(4 + ah->ar_hln) )) return 0;
memcpy( &src_ip, p+ah->ar_hln, 4 );
memcpy( &dst_ip, p+ah->ar_hln+4+ah->ar_hln, 4 );
memcpy( mac, p, ah->ar_hln );
return 1;
}
/////////////////////////////////////////////////////////////////////////////
//
// Send out an arp request
//
///////////////////////////////////////////////////////////////////////////////
bool sendDUPProbe(unsigned long addr)
{
struct in_addr diaddr,siaddr;
diaddr.s_addr = addr;
if ( send_pack( m_arp_socket, siaddr, diaddr, &m_slladdr, &m_dlladdr ) < 0 )
{
printf( "Error send packet: %s\n", strerror(errno) );
return false;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
//
// Try to get an response
// return value of 0 = timeout or non duplicate address -> did not find ip
// return value of 1 = found ip
// return value of -1 = error
//
///////////////////////////////////////////////////////////////////////////////
int RecvDUPResp( const unsigned long &addr, unsigned char *mac )
{
struct timeval tv;
fd_set rset;
struct in_addr siaddr,diaddr;
tv.tv_sec = 0;
tv.tv_usec = RESP_TIMEOUT;
FD_ZERO( &rset );
FD_SET( m_arp_socket, &rset );
int ret = select( m_arp_socket + 1, &rset, NULL, NULL, &tv );
if ( -1 == ret ) return -1;
else if ( 0 == ret ) return 0;
if ( FD_ISSET( m_arp_socket, &rset ) )
{
unsigned char buff[1024];
struct sockaddr_ll from;
unsigned int alen = sizeof(from);
int len = recvfrom( m_arp_socket, buff, sizeof(buff), 0,(struct sockaddr *)&from, &alen );
if ( len < 0 )
{
printf( "RecvDUPResp returned an error: %s.\n", strerror(errno) );
return -1;
}
if ( recv_pack( buff, len, &from, siaddr, diaddr, mac ) == 1 )
{
if ( addr == siaddr.s_addr )
{
return 1;
}
}
}
return 0;
}
public:
///////////////////////////////////////////////////////////////////////////////
//
// Test if ip already exists on the network
//
///////////////////////////////////////////////////////////////////////////////
bool testIP( const unsigned long & ip, unsigned char mac[6] )
{
memset( mac, 0x0, sizeof(mac) );
for ( int k = 0; k < MAX_SEND; ++k )
{
printf( "send probe #%d\n", k+1 );
if ( !sendDUPProbe( ip ) )
{
printf("testIP: Error in sendDUPProbe()\n" );
exit( 1 );
}
for ( int j = 0; j < MAX_RECV; ++j )
{
int ret = RecvDUPResp( ip, mac );
if ( 1 == ret )
{
return true;
}
else if ( -1 == ret )
{
printf("testIP: Error in RecvDUPResp()\n" );
exit( 1 );
}
}
}
return false;
}
};
int main( int argc, char * argv[] )
{
char * device = "eth0";
char * progname = argv[0];
if ( argc < 2 )
{
printf("1. Usage: %s ip-address [device] ( default: eth0 )\n", progname );
exit( 1 );
}
else if ( 3 == argc )
{
device = argv[2];
printf( "device = %s\n", device );
}
else if ( argc > 3 )
{
printf("2. Usage: %s ip-address [device] ( default: eth0 )\n", progname );
exit( 1 );
}
CArpTest arp( device );
unsigned char mac[6];
unsigned long ip = inet_addr( argv[1] );
if ( arp.testIP( ip, mac ) )
{
printf( "The ip address %s already exists on a card with the mac %02X:%02X:%02X:%02X:%02X:%02X.\n",
argv[1], mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
else
{
printf( "Ip address %s is not in use.\n", argv[1] );
}
return 0;
}