//--------------------------------------------------------------------- // netsniff.cpp // // This program demonstrates the promiscuous reception of raw // ethernet packets using the Linux PF_PACKET protocol family. // Its screen-output may be redirected to a file. A user hits // the key-combination to terminate its execution. // // NOTE: compile as 'root' and change mode using // root# gcc netsniff.cpp -o netsniff // root# chmod a+s netsniff // in order to permit execution by all users // // REFERENCE: Gianluca Insolvibile, "The Linux Socket Filter: // Sniffing Bytes over the Network," article in Linux Journal // (June 2001), pp. 26-31. // // programmer: ALLAN CRUSE // written on: 18 JAN 2008 // revised on: 21 JAN 2008 -- added bound on loop-iterations //--------------------------------------------------------------------- #include // for printf(), perror() #include // for strncpy() #include // for exit() #include // for signal() #include // for socket(), recvfrom() #include // for SIOCGIFFLAGS, SIOCSIFFLAGS #include // for htons() #include // for ETH_P_ALL #include // for struct ifreq, IFNAMSIZ #define MTU 1536 // Maximum Transfer Unit (bytes) #define MAX_NUM 1000 // Maximum allowed packet-number char ifname[] = "eth0"; // name for the network interface struct ifreq ethreq; // structure for 'ioctl' requests int sock, pkt_num; // socket-ID and packet-number void my_cleanup( void ) { // turn off the interface's 'promiscuous' mode ethreq.ifr_flags &= ~IFF_PROMISC; if ( ioctl( sock, SIOCSIFFLAGS, ðreq ) < 0 ) { perror( "ioctl: set ifflags" ); exit(1); } } void my_handler( int signo ) { // This function executes when the user hits . // It initiates program-termination, thus triggering // the 'cleanup' function we previously installed. exit(0); } void display_packet( char *buf, int n ) { unsigned char ch; printf( "\npacket #%d ", ++pkt_num ); for (int i = 0; i < n; i+=16) { printf( "\n%04X: ", i ); for (int j = 0; j < 16; j++) { ch = ( i + j < n ) ? buf[ i+j ] : 0; if ( i + j < n ) printf( "%02X ", ch ); else printf( " " ); } for (int j = 0; j < 16; j++) { ch = ( i + j < n ) ? buf[ i+j ] : ' '; if (( ch < 0x20 )||( ch > 0x7E )) ch = '.'; printf( "%c", ch ); } } printf( "\n%d bytes read\n-------\n", n ); } int main( void ) { // create an unnamed socket for reception of ethernet packets sock = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) ); if ( sock < 0 ) { perror( "socket" ); exit( 1 ); } // enable 'promiscuous mode' for the selected socket interface strncpy( ethreq.ifr_name, ifname, IFNAMSIZ ); if ( ioctl( sock, SIOCGIFFLAGS, ðreq ) < 0 ) { perror( "ioctl: get ifflags" ); exit(1); } ethreq.ifr_flags |= IFF_PROMISC; // enable 'promiscuous' mode if ( ioctl( sock, SIOCSIFFLAGS, ðreq ) < 0 ) { perror( "ioctl: set ifflags" ); exit(1); } // make sure 'promiscuous mode' will get disabled upon termination atexit( my_cleanup ); signal( SIGINT, my_handler ); // main loop to intercept and display the ethernet packets char buffer[ MTU ]; printf( "\nMonitoring all packets on interface \'%s\' \n", ifname ); do { int n = recvfrom( sock, buffer, MTU, 0, NULL, NULL ); display_packet( buffer, n ); } while ( pkt_num < MAX_NUM ); }