//------------------------------------------------------------------- // arpdemo.cpp // // This application will transmit an ARP Request message via // our character-mode Linux device-driver for Intel's 82573L // Ethernet network interface controller, modified to permit // writing and reading a 'raw' Ethernet packet ('nicraw.c'); // then afterward, it will try to read an ARP Reply message. // // compile using: $ g++ arpdemo.cpp -o arpdemo // execute using: $ ./arpdemo // // NOTE: In this revision of 'arpdemo.cpp' the device-driver // is expected to implement an 'ioctl()' method that returns // the hardware MAC-address of the network interface device. // // programmer: ALLAN CRUSE // written on: 10 MAY 2009 // revised on: 13 MAY 2009 -- remove reliance on 'ethers' file //------------------------------------------------------------------- #include // for gethostbyname() #include // for printf(), perror(), fopen(), fgets() #include // for open() #include // for strtol(), exit() #include // for write(), read() #include // for strlen(), strtok() #include // for inet_aton() #include // for ioctl() typedef struct { unsigned short hardware_type; unsigned short protocol_type; unsigned char hardware_size; unsigned char protocol_size; unsigned short arp_operation; unsigned char src_hw[ 6 ]; unsigned char src_ip[ 4 ]; unsigned char dst_hw[ 6 ]; unsigned char dst_ip[ 4 ]; } ARP_MESSAGE; char devname[] = "/dev/nic"; unsigned char dst[ 6 ] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; unsigned char src[ 6 ] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned char typ[ 2 ] = { 0x08, 0x06 }; char arp[ 60 ], buf[ 60 ]; int main( int argc, char **argv ) { // check for presence of the command-line argument if ( argc == 1 ) { fprintf( stderr, "nodename missing\n" ); exit(1); } // get the IP-address for the destination nodename struct hostent *pp = gethostbyname( argv[ 1 ] ); if ( !pp ) { herror( "gethostbyname" ); exit(1); } char peeraddr[ 16 ] = { 0 }; strcpy( peeraddr, inet_ntoa( *(in_addr*)pp->h_addr ) ); // get the IP-address for the source nodename char hostname[ 64 ] = { 0 }, hostaddr[ 16 ] = { 0 }; gethostname( hostname, 63 ); struct hostent *hp = gethostbyname( hostname ); if ( !hp ) { herror( "gethostbyname" ); exit(1); } strcpy( hostaddr, inet_ntoa( *(in_addr*)hp->h_addr ) ); // convert dotted-decimal strings to 32-bit integers unsigned int peer_ip = inet_addr( peeraddr ); unsigned int host_ip = inet_addr( hostaddr ); printf( "\nHost is \'%s\' (%s) \n", hostname, hostaddr ); // open the network interface device-file int fp = open( devname, O_RDWR ); if ( fp < 0 ) { perror( devname ); exit(1); } // get this station's hardware MAC-address if ( ioctl( fp, 0, src ) < 0 ) { perror( "ioctl"); exit(1); } // initialize the ARP protocol header ARP_MESSAGE arp_request = { 0 }; arp_request.hardware_type = htons( 0x0001 ); arp_request.protocol_type = htons( 0x0800 ); arp_request.hardware_size = 6; arp_request.protocol_size = 4; arp_request.arp_operation = htons( 1 ); memcpy( &arp_request.src_hw, src, 6 ); memcpy( &arp_request.src_ip, &host_ip, 4 ); memcpy( &arp_request.dst_ip, &peer_ip, 4 ); // initialize the 'raw' Ethernet packet memcpy( arp+0, dst, 6 ); memcpy( arp+6, src, 6 ); *(unsigned short*)( arp+12 ) = htons( 0x0806 ); memcpy( arp+14, &arp_request, 28 ); // Display the 'raw' ARP Request frame unsigned char *cp = (unsigned char*)arp; for (int i = 0; i < 42; i+=16) { printf( "\n %04X: ", i ); for (int j = 0; j < 16; j++) { if ( i+j < 42 ) printf( "%02X ", cp[ i+j ] ); else printf( " " ); } for (int j = 0; j < 16; j++) { unsigned char c = (i+j<42) ? cp[ i+j ] : 0x20; if (( c < 0x20 )||( c > 0x7E )) c = '.'; printf( "%c", c ); } } printf( "\n\n" ); // write our ARP REQUEST to the device-file int txbytes = write( fp, arp, sizeof( arp ) ); if ( txbytes < 0 ) { perror( "write" ); exit(1); } printf( "Wrote %d bytes to \'%s\' \n\n", txbytes, argv[1] ); // try to read an ARP REPLY do { int rxbytes = read( fp, buf, sizeof( buf ) ); if ( rxbytes < 0 ) { perror( "read" ); exit(1); } printf( "Read %d bytes from \'%s\' \n", rxbytes, argv[1] ); } while ( *(unsigned short*)(buf+12) != htons( 0x0806 ) ); // Display the 'raw' ARP Reply frame cp = (unsigned char*)buf; for (int i = 0; i < 42; i+=16) { printf( "\n %04X: ", i ); for (int j = 0; j < 16; j++) { if ( i+j < 42 ) printf( "%02X ", cp[ i+j ] ); else printf( " " ); } for (int j = 0; j < 16; j++) { unsigned char c = (i+j<42) ? cp[ i+j ] : 0x20; if (( c < 0x20 )||( c > 0x7E )) c = '.'; printf( "%c", c ); } } printf( "\n\n" ); // display the reported Hardware Address of the target station ARP_MESSAGE *ap = (ARP_MESSAGE*)( buf + 14 ); printf( "Station \'%s\' (%s) ", argv[ 1 ], peeraddr ); printf( "has hardware-address " ); for (int i = 0; i < 6; i++) printf( "%02X%c", ap->src_hw[i], (i<5)?':':' ' ); printf( "\n\n" ); }