//------------------------------------------------------------------- // vwnetdev.cpp // // This application shows the current contents of the kernel's // 'struct net_device' object for a specified interface if the // interface's name is entered as a command-line argument. It // demonstrates the feasibility of a programming technique for // extracting and displaying a data-structure in kernel space. // // compile using: $ g++ vwnetdev.cpp -o vwnetdev // execute using: $ ./vwnetdev // // NOTE: The files named 'dram.ko' and 'netdevs.ko' have to be // located in a user's current working directory. // // programmer: ALLAN CRUSE // written on: 25 JAN 2008 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), close() #include // for strstr(), strchr() char dramname[] = "/dev/dram"; // name of device-file char procname[] = "/proc/netdevs"; // name of pseudo-file char hostname[ 64 ]; // buffer for hostname char buffer[ 4096 ]; // multiple-use buffer int main( int argc, char **argv ) { // check for required command-line argument if ( argc == 1 ) { fprintf( stderr, "interface was unspecified\n" ); exit(1); } // get this station's hostname for use in output message gethostname( hostname, sizeof( hostname ) - 1 ); // install the kernel module that creates our pseudo-file system( "/sbin/insmod netdevs.ko" ); // open that pseudo-file for reading int proc = open( procname, O_RDONLY ); if ( proc < 0 ) { perror( procname ); exit(1); } // read the contents of the pseudo-file int nbytes = read( proc, buffer, sizeof( buffer ) ); if ( nbytes < 0 ) { perror( "read" ); exit(1); } // close the pseudo-file and remove the kernel-module close( proc ); system( "/sbin/rmmod netdevs" ); // exhibit the pseudo-file's contents printf( "%s", buffer ); // search file's contents for the specified interface-name char *ifp = strstr( buffer, argv[1] ); if ( !ifp ) { fprintf( stderr, "interface name not found\n" ); exit(1); } // search for the size of a 'task_struct' object char *szp = strstr( buffer, "sizeof" ); szp = strchr( szp, '=' ); unsigned long sbytes = strtoul( szp+1, NULL, 10 ); // printf( " size of \'net_device\' is %u bytes \n", sbytes ); // split the pseudo-file's contents into lines char *line = strtok( buffer, "\n" ); while ( !strstr( line, argv[1] ) ) line = strtok( NULL, "\n" ); // printf( " found: %s\n", line ); // extract the physical-address of the 'net_device' structure char *ifa = strstr( line, "0x" ); unsigned long ifaddr = strtoul( ifa+2, NULL, 16 ); // printf( "physical address of structure is %08lX \n", ifaddr ); // read the 'net_device' structure from physical memory system( "/sbin/insmod dram.ko" ); int dram = open( dramname, O_RDONLY ); if ( dram < 0 ) { perror( dramname ); exit(1); } lseek( dram, ifaddr, SEEK_SET ); nbytes = read( dram, buffer, sbytes ); if ( nbytes < 0 ) { perror( "read" ); exit(1); } close( dram ); system( "/sbin/rmmod dram" ); // display the 'net_device' object in hex and ascii formats printf( "\n Contents of the \'%s\' net_device object " ); printf( "on station \'%s\': \n", hostname ); unsigned int *ip = (unsigned int*)buffer; // <-- changed 1/29/2008 for (int i = 0; i < sbytes; i+=16) { printf( "\n 0x%08X (0x%03X): ", ifaddr + i, i ); for (int j = 0; j < 16; j+=4) { if ( i+j < sbytes ) printf( "%08X ", ip[ (i+j)/4 ] ); else printf( "9s", " " ); } for (int j = 0; j < 16; j++) { unsigned char ch; ch = ( i+j < sbytes ) ? buffer[ i+j ] : ' '; if (( ch < 0x20 )||( ch > 0x7E )) ch = '.'; printf( "%c", ch ); } } printf( "\n\n" ); }