/* Serial 2005092003 */ /* Source code available for download at http://zaichik.org/msc/ipman.c */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*** Global variables */ char *target_mac[ 5 ]; // This has to be global, since pcap_callback_fct can't be sent params and has no return char *temp_mac; // Ditto char *myName; /* The name under which the program is running. Used in most functions */ char *username; /* The username from login function; used in many functions for logging */ enum e_query { INSERT, DELETE }; typedef enum e_query query; enum e_boolean { FALSE, TRUE }; typedef enum e_boolean boolean; /*** Functions */ int add_iphostserver_mac( char *ip ); /* updates ipman_db.ips_and_macs.mac_addr with the IP host server's MAC address on a binding operation, called from bindips(). */ int add_new_addr_block( int octet1, int octet2, int octet3 ); /* adds a new C-class to the local IPs database */ int add_new_base( int oct1, int oct2, int oct3 ); /* adds a new base record for a new C-class to ipmanage_ipplan */ void add_report( char *msg ); /* Adds item to /var/log/ipman/ipman.report */ int bindips( const char *ip, char *netmask ); void delete_unboundip( char *ip ); unsigned int dotted_to_int( char *addr ); /* returns the integer value of a IPv4 dotted decimal notation */ int get_base( const char *ip );/* returns the baseindex from ipmanage_ipplan.base for inserting a record into ipmanage_ipplan.ipaddr. Returns -1 on error, baseindex otherwise */ void get_mac( char *ip_addr ); /* arpings the IP address, puts the MAC address in target_mac[ ] or packs it full of 0.0.0.0 if a non-responder */ int get_user_id( void ); /* gets ipman_db.staff_members.staff_id based on login name */ char* int_to_dotted( unsigned int ipv4 ); int ip_is_bound( const char *addr ); /* Checks /etc/ips to see if IP alread bound to IP host server */ int is_numeric( char *str ); /* Checks to see if a string is all numeric */ int logEntry( const char *message, const char *file ); /* Passed the message and the log file, does the logging. */ int login( void ); /* compares username-password combo; returns 1 on failure */ int open_report( void ); // Creates the report file /var/log/ipman/ipman.report and adds the date. Returns -1 if unable to. int pass_one( void ); // Runs the scan on ipman_db.ips_and_macs int pass_two_three( void ); // Runs the scan on ipman_db.no_response void pcap_callback_fct( u_char *what, struct pcap_pkthdr *pkt_header, u_char *packet ); void print_usage( void ); int query_ipmanage( char *ip, query action ); /* ip is the IP to add/delete, and int (enum queryType instead?) to indicate INSERT or DELETE Will ask for the server label in the event of INSERT, lookup label and verify action in event of DELETE. Of course, bindips() entails DELETE (reclaiming an IP from a customer) and unbindip() entails INSERT (assigning them to a customer). */ int reload_ipaliases( void ); /* Calls WHM ipaliases reload, returns 0 on failure */ int report_non_responders( void ); int report_old_unbound( void ); int report_unbound_response( void ); int scan( int report ); /* Scans IPs in local database, returns 0 on any error */ int send_report( char *sendMsg ); /* Emails report digest */ int set_scannable( char *ip, boolean scan ); /* Updates ipman_db.ips_and_macs.scan to 0 on bind, 1 on unbind */ void to_upper( char *the_string ); /* changes a string to all uppercase, used for MACs */ int unbindip( const char *addr ); /* Unbinds a single IP address */ int update_unbound( char *ip, query queryType ); /* INSERT from unbindip(), DELETE from scan when response received */ int validate_addr( const char *addr, int *lower, int *upper ); /* Indicates if input is invalid, range, or single IP. If a range, the function sets lower and upper bounds */ #define MAX_SIZE_IPADDR 20 /* xxx.xxx.xxx.xxx-xxx\0 */ #define MAX_SIZE_NETMASK 16 /* xxx.xxx.xxx.xxx\0 */ #define MAX_SIZE_MSG 2048 /* Maximum characters in message sent to logEntry() function. */ #ifndef ETH_ALEN #define ETH_ALEN 6 #endif #ifndef IP_ALEN #define IP_ALEN 4 #endif #define MAX_SIZE_IPADDR 20 #define MAX_SIZE_ETHADDR 20 // xx:xx:xx:xx:xx:xx\0 int main( int argc, char **argv) { char o; /* return from getopt_long() */ char *ip; char *netmask; char *mac; int charsRead; /* for the bind operation */ char *tempch; int success; int MAX_IPADDR_SIZE = MAX_SIZE_IPADDR; int MAX_NETMASK_SIZE = MAX_SIZE_NETMASK; // Define the flags below. int bind = 0, checkip = 0, lookupMAC = 0, noalert = 0, runscan = 0, unbind = 0; struct option longopts[] = { { "bind", no_argument, NULL, 'b' }, { "check", required_argument, NULL, 'c' }, { "help", no_argument, NULL, 'h' }, { "lookup", required_argument, NULL, 'l' }, { "noalert", no_argument, NULL, 'n' }, { "scan", no_argument, NULL, 's' }, { "unbind", no_argument, NULL, 'u' }, { 0, 0, 0, 0 } }; myName = argv[ 0 ]; if( argc == 1 ) { print_usage(); return( 1 ); } while(( o = getopt_long( argc, argv, "bc:hl:nsuW;", longopts, NULL )) != -1 ) { switch( o ) { case 'b': // bind if( bind || checkip || lookupMAC || noalert || runscan || unbind ) { print_usage(); exit( 0 ); } bind = 1; break; case 'c': if( bind || checkip || lookupMAC || noalert || runscan || unbind ) { print_usage(); exit( 0 ); } checkip = 1; ip = optarg; break; case 'h': print_usage(); exit( 0 ); break; case 'l': if( bind || checkip || lookupMAC || noalert || runscan || unbind ) { print_usage(); exit( 0 ); } lookupMAC = 1; mac = optarg; break; case 'n': if( bind || checkip || lookupMAC || noalert || unbind ) { print_usage(); exit( 0 ); } noalert = 1; break; case 's': if( bind || checkip || lookupMAC || runscan || unbind ) { print_usage(); exit( 0 ); } runscan = 1; break; case 'u': if( bind || checkip || lookupMAC || noalert || runscan || unbind ) { print_usage(); exit( 0 ); } unbind = 1; break; case '?': default: printf( "%s: option `-%c' is invalid.\n", myName, optopt ); print_usage(); return( 1 ); } /* switch */ } /* while */ /************************************************************************* * Once we are here, only one--possibly two--flags have been set (two in * the case of -n, which can double with -s). Otherwise, we can assume * if a flag has been set, we run the associated action. We do need to * check when we get to if( noalert ) that the flag for runscan has been * set, because the above will not catch ONLY -n being set. First we need * to get logged in, or quit with error. *************************************************************************/ if( !login() ) { return( 1 ); } if( bind ) { ip = ( char * ) malloc ( MAX_SIZE_IPADDR + 1 ); if( ip == NULL ) { printf( "%s: Out of memory in main() ln 40.", argv[ 0 ] ); return( -1 ); } netmask = ( char * ) malloc( MAX_SIZE_NETMASK + 1 ); if( netmask == NULL ) { fprintf( stderr, "%s: Out of memory in main() ln 45.", argv[ 0 ] ); return( -1 ); } printf( "Enter the IP address: " ); charsRead = getline( &ip, &MAX_IPADDR_SIZE + 1, stdin ); printf( "Enter the subnet mask: " ); charsRead = getline( &netmask, &MAX_NETMASK_SIZE + 1, stdin ); bindips( ip, netmask ); free( ip ); free( netmask ); } // The arg below was assigned in the switch. if( checkip ) { printf( "IP = %s\n", ip ); } // The arg below was assigned in the switch. if( lookupMAC ) { printf( "MAC = %s\n", mac ); } if( noalert ) { if( ! runscan ) { fprintf( stderr, "--noalert ( -n ) option only allowed with the --scan ( -s ) option.\n" ); print_usage(); exit( 1 ); } } if( runscan ) { int x = 0; // just a counter for( x = 0; x < 5; x++ ) { target_mac[ x ] = ( char * ) malloc( MAX_SIZE_ETHADDR + 1 ); if( target_mac[ x ] == NULL ) { printf( "%s: Out of memory in main().\n", myName ); exit( -1 ); } } scan( 1 ); // means report for( x = 0; x < 5; x++ ){ free( target_mac[ x ] ); } return( 0 ); } if( unbind ) { ip = ( char * ) malloc ( MAX_SIZE_IPADDR + 1 ); if( ip == NULL ) { fprintf( stderr, "%s: Out of memory in main() ln 96.\n", argv[ 0 ] ); return( -1 ); } printf( "Enter the IP address: " ); // as in bind(): charsRead = getline( &ip, &MAX_IPADDR_SIZE + 1, stdin ); charsRead = getline( &ip, &MAX_IPADDR_SIZE + 1, stdin ); if ((tempch = strchr( ip ,'\n')) != NULL) { *tempch = '\0'; } if( unbindip( ip ) ) { fprintf( stderr, "%s: Error in unbindip().\n", myName); return( 1 ); } free( ip ); } return( 0 ); } /* main() */ int add_iphostserver_mac( char *ip ) { MYSQL conn; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "UPDATE ips_and_macs SET mac_addr = '00:10:DC:37:D1:74' WHERE ip_addr = 1234567890" ); char *mysqlQuery; unsigned int ipv4 = dotted_to_int( ip ); int return_code = 0; mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in add_iphostserver_mac().\n", myName ); exit( -1 ); } mysql_init( &conn ); sprintf( mysqlQuery, "UPDATE ips_and_macs SET mac_addr = '00:10:DC:37:D1:74' WHERE ip_addr = %u", ipv4 ); mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( mysql_errno( &conn )) { printf( "Error updating ipman_db.ips_and_macs.mac_addr for IP address %s\n", ip ); printf( "MySQL error is %s\n", mysql_error( &conn )); printf( "Contact an administrator.\n" ); return_code = -1; } mysql_close( &conn ); free( mysqlQuery ); return( return_code ); } // add_iphostserver_mac int add_new_addr_block( int octet1, int octet2, int octet3 ) { /* Takes first three octets of a class C address and adds to local database. Returns 1 if all is good, 0 otherwise. */ MYSQL conn; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "INSERT INTO ips_and_macs VALUES('xxx.xxx.xxx.xxx', '255.255.255.0', '', x)" ); int x = 0; // just a counter char *mysqlQuery; char *logMsg; unsigned int baseaddr = 0; char *ipString; add_new_base( octet1, octet2, octet3 ); ipString = ( char * ) malloc( MAX_SIZE_IPADDR ); if( ipString == NULL ) { printf( "%s: Out of memory in add_new_base().\n" ); exit( -1 ); } sprintf( ipString, "%d.%d.%d.0", octet1, octet2, octet3 ); baseaddr = dotted_to_int( ipString ) + 2; // baseaddr starts at integer equiv of x.x.x.2 mysqlQuery = ( char * ) malloc ( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { fprintf( stderr, "%s: Out of memory in add_new_addr_block() ln 181.\n", myName ); exit( -1 ); } logMsg = ( char * ) malloc( MAX_SIZE_MSG + 1 ); if( logMsg == NULL ) { fprintf( stderr, "%s: Out of memory in add_new_addr_block() ln 181.\n", myName ); free( mysqlQuery ); } mysql_init( &conn ); mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); for( x = 2; x <= 254; x++ ) { // adding x.x.x.2 - x.x.x.254, 253 addresses sprintf( mysqlQuery, "INSERT INTO ips_and_macs VALUES(%u, '255.255.255.0', '', 0)", baseaddr ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery ) ); if( mysql_errno( &conn ) ) { fprintf( stderr, "%s: Error on INSERT: %s.\n", myName, mysql_error( &conn ) ); free( mysqlQuery ); if( x == 2 ) { sprintf( logMsg, "IP address %d.%d.%d.2 added to list of local IPs by user %s when an error occurred. The IP may not have been added successfully to the database.\n", octet1, octet2, octet3, username ); } else { sprintf( logMsg, "IP addresses %d.%d.%d.2-%d added to list of local IPs by user %s when an error occurred. The last IP may not have been added successfully to the database.\n", octet1, octet2, octet3, x ); } printf( "%s: %s", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); free( logMsg ); return( -1 ); } baseaddr++; } free( mysqlQuery ); free( logMsg ); return( 0 ); } /* add_new_addr_block() */ int add_new_base( const int oct1, const int oct2, const int oct3 ) { MYSQL conn; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipmanage_ipplan"; int MAX_SIZE_QUERY = strlen( "INSERT INTO base (baseaddr, subnetsize, admingrp, customer, lastmod, userid, swipmod) VALUES (1234567890, 256, 'NET-XXX-XXX-XXX-0', 'IPADMINs', 2, NOW(), 'XXXXXXXXXXXXXXXX', '0000-00-00 00:00:00')" ); int x = 0; // just a counter char *mysqlQuery; char *logMsg; // database variables char *ipString; unsigned int baseaddr; // will be dotted_to_int( "oct1.oct2.oct3.0" ); char *descrip; // 'NET-OCT1-OCT2-OCT3-0' int subnetsize = 256; char *admingrp = "IPADMINs"; int customer = 2; // lastmod will be NOW() // userid will be username char *swipmod = "0000-00-00 00:00:00"; int returnValue; // for mysql_affected_rows() return value // assign field values ipString = ( char * ) malloc( MAX_SIZE_IPADDR ); if( ipString == NULL ) { printf( "%s: Out of memory in add_new_base().\n" ); exit( -1 ); } sprintf( ipString, "%d.%d.%d.0", oct1, oct2, oct3 ); baseaddr = dotted_to_int( ipString ); descrip = ( char * ) malloc( strlen( "NET-XXX-XXX-XXX-0" ) + 1 ); if( descrip == NULL ) { printf( "%s: Out of memory in add_new_base().\n" ); exit( -1 ); } sprintf( descrip, "NET-%d-%d-%d-0", oct1, oct2, oct3 ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( ipString ); free( descrip ); } mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in add_new_base().\n" ); free( ipString ); free( descrip ); } sprintf( mysqlQuery, "INSERT INTO base ( baseaddr, subnetsize, descrip, admingrp, customer, lastmod, userid, swipmod ) VALUES (%u, %d, '%s', '%s', %d, NOW(), '%s', '%s')", baseaddr, subnetsize, descrip, admingrp, customer, username, swipmod ); free( descrip ); // Still need ipString for logging. mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); returnValue = mysql_affected_rows( &conn ); if( returnValue == 1 ) { logMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { printf( "%s: Out of memory in add_new_base().\n", myName ); free( ipString ); exit (-1 ); } sprintf( logMsg, "New base added to ipmanage_ipplan.base by user %s. New base address is %s.\n", username, ipString ); logEntry( logMsg, "/var/log/ipman/ipman.bind" ); // ipman.bind because this is part of adding a new C-class // and therefore involves binding new IPs to the server. printf( "%s: %s", myName, logMsg ); } else { logMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { printf( "%s: Out of memory in add_new_base().\n", myName ); free( ipString ); exit (-1 ); } sprintf( logMsg, "New C-class bound to IP host server and added to ipman_db.ips_and_macs, but adding new base to ipmanage_ipplan.base by user %s failed. Base address that needs to be added is %s.\n", username, ipString ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); printf( "%s: %s", myName, logMsg ); } free( ipString ); free( logMsg ); return( 0 ); } void add_report( char *msg ) { FILE *out; if(( out = fopen( "/var/log/ipman/ipman.report", "a" )) == NULL ) { printf( "%s: Could not open /var/log/ipman/ipman.report for append.\n", myName ); printf( "%s: Scan aborting. Contact an administrator.\n", myName ); exit( -1 ); } fprintf( out, "%s", msg ); fclose( out ); } int bindips( const char *addr, char *mask ) { char *octet1, *octet2, *octet3, *octet4; /* Octets as strings */ int oct1, oct2, oct3, oct4; /* Octets as ints */ FILE *fd; /* /etc/ips */ int i; /* all-purpose counter */ char *output; /* for output to file /etc/ips */ char *tempch; /* temp char for removing \n from strings */ char *tempAddr; /* holds value of addr */ int lower = 0; /* lower bound of range of IPs to bind */ int upper = 0; /* upper bound of IP range */ enum e_input { INVALID, SINGLE_IP, IP_RANGE, C_BLOCK }; typedef enum e_input input; input inputType; char *logMsg; int MAX_SIZE_OCTET = 4; query queryType = DELETE; char bind_anyway; int returnValue = 0; // for return values boolean scan = TRUE; // value to set on ipman_db.ips_and_macs.scan /* Tokenize the string */ /* Replace \n with \0 */ if(( tempch = strchr( addr, '\n' )) != NULL ) *tempch = '\0'; if(( tempch = strchr( mask, '\n' )) != NULL ) *tempch = '\0'; tempAddr = ( char * ) malloc( MAX_SIZE_IPADDR + 1 ); if( tempAddr == NULL ) { fprintf( stderr, "%s: Out of memory in bindips() on ln 172.\n", myName ); free( tempAddr ); return( -1 ); } strcpy( tempAddr, addr ); inputType = validate_addr( tempAddr, &lower, &upper ); logMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { fprintf( stderr, "%s: Out of memory in bindips() ln 299.\n", myName ); exit( -1 ); } output = (char * ) malloc( MAX_SIZE_IPADDR + 1 + MAX_SIZE_NETMASK + 1 ); if( output == NULL ) { fprintf( stderr, "%s: Out of memory in bindips() on ln 172.\n", myName ); return( -1 ); } switch( inputType ) { case INVALID: printf( "%s: The address or range %s is invalid.\n", myName, addr ); free( tempAddr ); free( logMsg ); free( output ); return( 1 ); break; case SINGLE_IP: if(( fd = fopen( "/etc/ips", "a" )) == NULL ) { printf( "%s: Could not open /etc/ips for append in bindip() ln 177.\n", myName ); free( tempAddr ); free( logMsg ); free( output ); return ( -1 ); } strcpy( output, addr ); if (( tempch = strchr( output,'\n' )) != NULL ) { *tempch = '\0'; } if( ip_is_bound( output )) { printf( "%s: IP %s is already bound.\n", myName, output ); free( tempAddr ); free( logMsg ); free( output ); return( 1 ); } returnValue = query_ipmanage( tempAddr, queryType ); if( returnValue != 0 ) { printf( "%s: Record was not deleted from ipmanage_ipplan\n", myName ); printf( "Continue with bind operation for IP address %s [y/n]: ", output ); bind_anyway = getchar(); getchar(); if( bind_anyway == 'n' ) { printf( "%s: Bind operation for IP %s cancelled.\n", myName, output ); return( 1 ); } } add_iphostserver_mac( tempAddr ); set_scannable( tempAddr, scan ); strcat( output, ":" ); strcat( output, mask ); printf( "%s\n", output ); fprintf( fd, "%s\n", output ); sprintf( logMsg, "IP address %s bound to IP host server by user %s.\n", tempAddr, username ); logEntry( logMsg, "/var/log/ipman/ipman.bind" ); printf( "%s: %s", myName, logMsg ); delete_unboundip( tempAddr ); break; case C_BLOCK: // This entails adding individual IPs to ips_and_macs and /etc/ips, adding baseindex to // ipmanage_ipplan.base octet1 = ( char * ) malloc( MAX_SIZE_OCTET ); if( octet1 = NULL ) { printf( "Out of memory in bindips().\n" ); free( tempAddr ); free( logMsg ); free( output ); return( -1 ); } octet2 = ( char * ) malloc( MAX_SIZE_OCTET ); if( octet2 = NULL ) { printf( "Out of memory in bindips().\n" ); free( tempAddr ); free( logMsg ); free( output ); free( octet1 ); return( -1 ); } octet3 = ( char * ) malloc( MAX_SIZE_OCTET ); if( octet3 = NULL ) { printf( "Out of memory in bindips().\n" ); free( tempAddr ); free( logMsg ); free( output ); free( octet1 ); free( octet2 ); return( -1 ); } octet4 = ( char * ) malloc( MAX_SIZE_OCTET ); if( octet4 = NULL ) { printf( "Out of memory in bindips().\n" ); free( tempAddr ); free( logMsg ); free( output ); free( octet1 ); free( octet2 ); free( octet3 ); return( -1 ); } strcpy( tempAddr, addr ); sscanf( tempAddr, "%d.%d.%d.%d", &oct1, &oct2, &oct3, &oct4 ); add_new_addr_block( oct1, oct2, oct3 ); /* No break as we also do the stuff below. When setting logMsg we will have to test value of inputType to differentiate between adding a range or a C block. */ case IP_RANGE: if(( fd = fopen( "/etc/ips", "a" )) == NULL ) { printf( "%s: Could not open /etc/ips for append in bindip() ln 177.\n", myName ); return ( -1 ); } strcpy( output, addr ); if (( tempch = strchr( output,'\n' )) != NULL ) { *tempch = '\0'; } strcpy( tempAddr, addr ); /* Tokenize string to get octets 1 through 3. */ octet1 = strtok( tempAddr, "." ); octet2 = strtok( NULL, "." ); octet3 = strtok( NULL, "." ); for( i = lower; i <= upper; ++i ) { /* lower and upper set by call to validate_addr() */ sprintf( output, "%s.%s.%s.%d", octet1, octet2, octet3, i ); if( ip_is_bound( output ) ) printf( "%s: %s is already bound.\n", myName, output ); else { // If we are adding a new C-block, we don't want to query // ipmanage_ipplan; there will be no recoid there if( inputType != C_BLOCK ) { returnValue = query_ipmanage( output, queryType ); } if( returnValue == 0 ) { strcat( output, ":" ); strcat( output, mask ); strcat( output, "\n" ); fprintf( fd, "%s", output ); add_iphostserver_mac( tempAddr ); set_scannable( tempAddr, scan ); } else { // it didn't go well, the record was not deleted from ipmanage sprintf( logMsg, "The record for IP address %s could not be deleted from ipmanage_ipplan.ipaddr. query_ipmanage() returned %d. The address has not been bound to the IP host server.\n", output, returnValue ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); printf( "%s: %sContact an admin.\n", myName, logMsg ); } } } if( inputType == C_BLOCK ) sprintf( logMsg, "Class C address block %s added to database and bound to IP host server by user %s.\n", addr, username ); else sprintf( logMsg, "IP address range %s bound to IP host \ server by user %s.\n", addr, username ); logEntry( logMsg, "/var/log/ipman/ipman.bind" ); printf( "%s: %s", myName, logMsg ); break; default: printf( "%s: Something horrible has happened in bindips() ln 288", myName ); free( output ); return( -1 ); }/* switch( inputType ) */ fclose( fd ); free( logMsg ); free( output ); if( reload_ipaliases()) { // returns 0 if no error, so if reload_ipaliases() != 0 (false) something bad... printf( "Error reloading WHM ipaliases; contact an administrator.\n" ); return( -1 ); } return( 0 ); } unsigned int dotted_to_int( char *addr ) { unsigned int answer; unsigned int oct1 = 0, oct2 = 0, oct3 = 0, oct4 = 0; unsigned int FIRST_OCT_MULTIPLIER = 16777216; unsigned int SECOND_OCT_MULTIPLIER = 65536; unsigned int THIRD_OCT_MULTIPLIER = 256; sscanf( addr, "%d.%d.%d.%d", &oct1, &oct2, &oct3, &oct4 ); answer = oct1 * FIRST_OCT_MULTIPLIER + oct2 * SECOND_OCT_MULTIPLIER + oct3 * THIRD_OCT_MULTIPLIER + oct4; return( answer ); } void delete_unboundip( char *ip ){ MYSQL conn; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; char *mysqlQuery; int MAX_SIZE_QUERY = strlen( "DELETE FROM unbound_ips WHERE ip_addr = 1234567890" ) + 1; unsigned int ipv4 = dotted_to_int( ip ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); printf( "%s: Unable to delete potential record for %s from ipman_db.unbound_ips.\n", myName ); printf( "Contact an administrator.\n" ); free( mysqlQuery ); mysql_close( &conn ); return; } mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in delete_unboundip().\n" ); exit( -1 ); } sprintf( mysqlQuery, "DELETE FROM unbound_ips WHERE ip_addr = %u", ipv4 ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery ) ); free( mysqlQuery ); mysql_close( &conn ); return; } int get_base( const char *ip ) { MYSQL conn; MYSQL_RES *res; MYSQL_ROW row; char *server = "localhost"; char *mysqlUser = "root"; char *mysqlPass = "kimBall0508"; char *mysqlDB = "ipmanage_ipplan"; int MAX_SIZE_QUERY = strlen( "SELECT baseindex FROM base WHERE descrip LIKE 'NET-XXX-XXX-XXX%'" ); char *mysqlQuery; unsigned int answer; unsigned int oct1 = 0, oct2 = 0, oct3 = 0, oct4 = 0; int returnValue; // mysqlAffected_rows() return sscanf( ip, "%d.%d.%d.%d.", &oct1, &oct2, &oct3, &oct4 ); mysqlQuery = ( char * ) malloc ( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in get_base().\n", myName ); exit( -1 ); } sprintf( mysqlQuery, "SELECT baseindex FROM base WHERE descrip LIKE 'NET-%d-%d-%d%%'", oct1, oct2, oct3 ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( mysqlQuery ); mysql_close( &conn ); return( -1 ); } mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery ) ); free( mysqlQuery ); if( !( res = mysql_store_result( &conn ))) { printf( "%s\n", mysql_error( &conn )); mysql_close( &conn ); return( -1 ); } returnValue = mysql_affected_rows( &conn ); if( returnValue < 1 ) { printf( "%s: No base index for IP address %s in ipmanage_ipplan.base. Bind operation cancelled.\n", myName, ip ); return( -1 ); } row = mysql_fetch_row( res ); sscanf( row[ 0 ], "%d", &answer ); mysql_close( &conn ); return( answer ); } // get_base() void get_mac( char *ip_addr ) { pcap_t *pkt_descriptor; // like a file descriptor for packets struct bpf_program prog_buff; // space for compiled filter char error_buf[ PCAP_ERRBUF_SIZE ]; char libnet_error_buf[ LIBNET_ERRBUF_SIZE ]; const u_char *packet; char *interface = "eth0"; int x; // all-purpose counter int MAX_SIZE_FILTER = strlen( "arp src host " ) + MAX_SIZE_IPADDR + 1; int t; // test for libnet errors //stuff for forking the process and IPC pid_t child_pid; char *shared_mem; // This will be shared for getting the MAC into target_mac[] int shmseg_id; //stuff for building the packet libnet_t *context; u_int32_t temp_ip = 0; struct libnet_ether_addr *ptr_hwaddr; char src_ip[ IP_ALEN ], dest_ip[ IP_ALEN ]; char dest_mac[ ETH_ALEN ] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; // We don't know this, need to broadcast. char src_mac[ ETH_ALEN ]; // Will get assigned later int c = 0, p = 0; // just counters char *filter; // the pcap filter so that we only pick up packets of interest //build the ARP request packet // create the libnet session handle if((context = libnet_init( LIBNET_LINK, "eth0", libnet_error_buf )) == NULL ) { printf( "libnet_init failed: %s", libnet_error_buf ); } // pack the source and destination IPs temp_ip = libnet_name2addr4( context, "147.202.49.28", LIBNET_DONT_RESOLVE ); memcpy( src_ip, ( char * ) &temp_ip, IP_ALEN ); temp_ip = libnet_name2addr4( context, ip_addr, LIBNET_DONT_RESOLVE ); memcpy( dest_ip, ( char * ) &temp_ip, IP_ALEN ); // get the source MAC address ptr_hwaddr = libnet_get_hwaddr( context ); memcpy(src_mac, ptr_hwaddr, ETH_ALEN); // create the header structures static libnet_ptag_t arp = 0, eth = 0; // start at the top of the stack--create the ARP headers arp = libnet_build_arp( ARPHRD_ETHER, ETHERTYPE_IP, ETH_ALEN, IP_ALEN, ARPOP_REQUEST, src_mac, (u_int8_t *)src_ip, dest_mac, (u_int8_t *)dest_ip, NULL, 0, context, 0); if( arp == -1 ) { printf( "Error in libnet_build_arp: %s", libnet_geterror( context )); } // now add the Ethernet headers eth = libnet_build_ethernet( dest_mac, src_mac, ETHERTYPE_ARP, NULL, 0, context, 0); if( eth == -1 ) { printf( "Error in libnet_build_ethernet: %s", libnet_geterror( context )); } // packet is built, let's get stuff read to capture the packets we request // open for packet capture pkt_descriptor = pcap_open_live( interface, BUFSIZ, 0, 2000, error_buf ); if( pkt_descriptor == NULL ) { printf( "pcap function pcap_open_live(): %s", error_buf ); exit( 1 ); } filter = ( char * ) malloc( MAX_SIZE_FILTER ); if( filter == NULL ) { printf( "%s: Out of memory in get_mac().\n", myName ); exit( -1 ); } sprintf( filter, "arp src host %s", ip_addr ); if( pcap_compile( pkt_descriptor, &prog_buff, filter, 1, 0 ) < 0 ) { printf( "pcap function pcap_compile(): %s", error_buf ); exit( 1 ); } if( pcap_setfilter( pkt_descriptor, &prog_buff ) < 0 ) { printf( "pcap function pcap_setfilter(): %s", error_buf ); exit( 1 ); } temp_mac = ( char * ) malloc( MAX_SIZE_ETHADDR + 1 ); if( temp_mac == NULL ) { printf( "%s: Out of memory in get_mac().\n", myName ); free( filter ); exit( -1 ); } // Start sending and receiving packets // First allocate the shared memory shmseg_id = shmget( IPC_PRIVATE, MAX_SIZE_ETHADDR, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR ); for( x = 0; x < 5; x++ ) { t = libnet_write( context ); if( t == -1 ) { printf( "libnet_write error: %s\n", libnet_geterror( context )); } child_pid = fork(); if( child_pid == 0 ) { // this is the child process // attach to shared memory shared_mem = ( char * ) shmat( shmseg_id, 0, 0 ); pcap_dispatch( pkt_descriptor, 1, ( void * )pcap_callback_fct, NULL ); //convert to upper case to_upper( temp_mac ); memcpy( shared_mem, temp_mac, MAX_SIZE_ETHADDR ); exit( 0 ); } else { sleep( .1 ); shared_mem = ( char * ) shmat( shmseg_id, 0, 0 ); if( strlen( shared_mem ) == 0 ) { // the child has blocked, kill it kill( child_pid, SIGTERM ); } } memcpy( target_mac[ x ], shared_mem, MAX_SIZE_ETHADDR ); }// for( x = 0; x < 5; x++ ) // detach shared memory and deallocate shmdt( shared_mem ); shmctl( shmseg_id, IPC_RMID, 0 ); pcap_close( pkt_descriptor ); libnet_destroy( context ); free( filter ); free( temp_mac ); } int get_user_id( void ) { MYSQL conn; MYSQL_RES *res; MYSQL_ROW row; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "SELECT MAX(staff_id) FROM staff_members WHERE staff_name ='XXXXXXXXXXXXXXXX'" ); int user_id = 0; char *mysqlQuery; mysqlQuery = ( char * ) malloc ( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { fprintf( stderr, "%s: Out of memory in get_user_id().\n", myName ); exit( -1 ); } // If there are duplicates for staff_members.staff_name, the assumption is that the one with the // highest (most recent) staff_id is currently running the program as the previous one is no longer // with the company sprintf( mysqlQuery, "SELECT MAX(staff_id) FROM staff_members WHERE staff_name ='%s'", username ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s: Error on connect: %s\n", myName, mysql_error( &conn )); printf( "%s: Returning user_id = -1 from get_user_id(). Fix in ipman_db.unbound_ips.staff_id.\n" ); printf( "%s: Continuing execution normally.\n" ); free( mysqlQuery ); return( -1 ); } mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); free( mysqlQuery ); if( mysql_errno( &conn ) ) { printf( "%s: Error on SELECT: %s.\n", myName, mysql_error( &conn ) ); printf( "%s: Returning user_id = -1 from get_user_id(). Fix in ipman_db.unbound_ips.staff_id.\n" ); printf( "%s: Continuing execution normally.\n" ); return( -1 ); } if( !( res = mysql_use_result( &conn ))) { printf( "%s: Error on mysql_use_result(): %s.\n", myName, mysql_error( &conn ) ); printf( "%s: Returning user_id = -1 from get_user_id(). Fix in ipman_db.unbound_ips.staff_id.\n" ); printf( "%s: Continuing execution normally.\n" ); return( -1 ); } row = mysql_fetch_row( res ); sscanf( row[ 0 ], "%d", &user_id ); if( user_id < 1 ) { printf( "%s: Error getting user_id.\n", myName ); printf( "%s: Returning user_id = -1 from get_user_id(). Fix in ipman_db.unbound_ips.staff_id.\n" ); printf( "%s: Continuing execution normally.\n" ); return( -1 ); } return( user_id ); } // get_user_id() char* int_to_dotted( unsigned int ipv4 ) { int remainder = 0; int octet1 = 0, octet2 = 0, octet3 = 0; unsigned int FIRST_OCT_MULTIPLIER = 16777216; unsigned int SECOND_OCT_MULTIPLIER = 65536; unsigned int THIRD_OCT_MULTIPLIER = 256; char *answer; answer = ( char * ) malloc( MAX_SIZE_IPADDR + 1 ); if( answer == NULL ) { printf( "%s: Out of memory in int_to_dotted().\n", myName ); exit( -1 ); } octet1 = ipv4 / FIRST_OCT_MULTIPLIER; ipv4 %= FIRST_OCT_MULTIPLIER; octet2 = ipv4 / SECOND_OCT_MULTIPLIER; ipv4 %= SECOND_OCT_MULTIPLIER; octet3 = ipv4 / THIRD_OCT_MULTIPLIER; ipv4 %= THIRD_OCT_MULTIPLIER; sprintf( answer, "%d.%d.%d.%d", octet1, octet2, octet3, ipv4 ); return( answer ); } int is_numeric( char *str ) { while( *str ) { if( !isdigit( *str ) ) return( 0 ); str++; } return( 1 ); } int ip_is_bound( const char *addr ) { /* Check /etc/ips to see if the ip is already bound to the IP host host server. Here we are going to return false ( 0 ) or true ( 1 ) */ FILE *fd; /* /etc/ips */ int MAX_LINE_LENGTH = 32; // xxx.xxx.xxx.xxx:xxx.xxx.xxx.xxx\0 char line[ MAX_LINE_LENGTH ]; char tempAddr[ MAX_SIZE_IPADDR ]; char *token; if(( fd = fopen( "/etc/ips", "r" )) == NULL ) { printf( "%s: Could not open /etc/ips for read in ip_is_bound() ln 177.\n", myName ); return ( -1 ); } while( fgets( line, MAX_LINE_LENGTH, fd )) { token = strtok( line, ":" ); strcpy( tempAddr, token ); if( strcmp( addr, tempAddr) == 0 ) { fclose( fd ); return( 1 ); } } //while fgets fclose( fd ); return( 0 ); } int logEntry( const char *message, const char *file ) { FILE *out; char *time_buffer; time_t current_time; struct tm *local_time; int length; int MAX_TIME_BUFFER = 29; /* Get time/date and create string */ time_buffer = ( char * ) malloc( MAX_TIME_BUFFER ); if( time_buffer == NULL ) { fprintf( stderr, "%s: Out of memory in logEntry() ln 368.\n", myName ); exit( -1 ); } current_time = time( NULL ); local_time = localtime( ¤t_time ); strcpy( time_buffer, asctime( local_time )); length = strlen( time_buffer ); if( time_buffer[ length - 1 ] == '\n' ) time_buffer[ length - 1 ] = ' '; if(( out = fopen( file, "a" )) == NULL ) { fprintf( stderr, "Could not open %s for append.\n", file ); return( -1 ); } fprintf( out, "%s", time_buffer ); free( time_buffer ); fprintf( out, "%s", message ); fclose( out ); return( 0 ); } int login( void ) { /* Verifies login, returns 1 if OK and 0 on error. MD5 usage from http://www.openssl.org/docs/crypto/md5.html# */ MYSQL conn; MYSQL_RES *res; MYSQL_ROW row; int MAX_PASSWORD = 16; int MAX_USERNAME = 16; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; char *mysqlQuery; int MAX_SIZE_QUERY = strlen( "SELECT password FROM staff_members WHERE staff_name = 'xxxxxxxxxxxxxxxx'" ); char *password; char *tempChar; int charsRead; unsigned char hash[ MD5_DIGEST_LENGTH ]; char *hashStr; int i; username = ( char * ) malloc( MAX_USERNAME + 1 ); if( username == NULL ) { fprintf( stderr, "%s: Out of memory in login() ln 202.\n", myName ); free( username); exit( -1 ); } printf( "Login as: " ); charsRead = getline( &username, &MAX_USERNAME + 1, stdin ); if( charsRead == 1 ) { fprintf( stderr, "%s: Username cannot be blank.\n", myName ); free( username ); return( 0 ); } /* Replace \n with \0 */ if( (tempChar = strchr( username, '\n' )) != NULL ) *tempChar = '\0'; password = (char * ) malloc( MAX_PASSWORD + 1 ); if( password == NULL ) { fprintf( stderr, "%s: Out of memory in login() ln 216.\n", myName ); free( username ); free( password ); exit( -1 ); } printf( "Password for %s: ", username ); strcpy( password, getpass( "" )); if( (tempChar = strchr( password, '\n' )) != NULL ) *tempChar = '\0'; if( strlen( password ) < 1 ) { fprintf( stderr, "%s: Password cannot be blank.\n", myName ); free( username ); free( password ); return( 0 ); } MD5( password, strlen( password ), hash ); free( password ); hashStr = ( char * ) malloc ( MD5_DIGEST_LENGTH * 2 + 1 ); if( hashStr == NULL ) { printf( "%s: Out of memory in login() ln 246.\n", myName ); free( username ); free( hashStr ); exit( -1 ); } for( i = 0; i < MD5_DIGEST_LENGTH; ++i ) { sprintf( hashStr + 2 * i, "%.2x", hash[ i ] ); } mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in login() ln 257.\n", myName ); free( username ); free( hashStr ); exit( -1 ); } sprintf( mysqlQuery, "SELECT staff_password FROM staff_members WHERE staff_name = '%s'", username ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( username ); free( hashStr ); free( mysqlQuery ); exit( -1 ); } mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery ) ); free( mysqlQuery ); if( !( res = mysql_store_result( &conn ))) { printf( "%s\n", mysql_error( &conn )); free( username ); free( hashStr ); exit( -1 ); } if( mysql_affected_rows( &conn ) < 1 ) { printf( "%s: Invalid login for user %s.\n", myName, username ); free( username ); free( hashStr ); mysql_close( &conn ); return( 0 ); } row = mysql_fetch_row( res ); if( strcmp( hashStr, row[ 0 ] ) != 0 ) { printf( "%s: Invalid login for user %s.\n", myName, username ); free( hashStr ); free( username ); mysql_close( &conn ); return( 0 ); } printf( "user %s logged in.\n", username ); free( hashStr ); mysql_close( &conn ); return( 1 ); } int open_report( void ) { FILE *out; char *time_buffer; time_t current_time; struct tm *local_time; int length; int MAX_TIME_BUFFER = 29; /* Get time/date and create string */ if(( out = fopen( "/var/log/ipman/ipman.report", "w" )) == NULL ) { printf( "%s: Could not create report file /var/log/ipman/ipman.report.\n", myName ); return( -1 ); } /* Get time/date and create string */ time_buffer = ( char * ) malloc( MAX_TIME_BUFFER ); if( time_buffer == NULL ) { fprintf( stderr, "%s: Out of memory in logEntry() ln 368.\n", myName ); exit( -1 ); } current_time = time( NULL ); local_time = localtime( ¤t_time ); strcpy( time_buffer, asctime( local_time )); length = strlen( time_buffer ); if( time_buffer[ length - 1 ] == '\n' ) time_buffer[ length - 1 ] = ' '; fprintf( out, "%s: ipman scan begun.\n\n", time_buffer ); fprintf( out, "*****************************************\n\n" ); fclose( out ); return( 0 ); } int pass_one( void ) { // Scan ipman_db.ips_and_macs, move non-responders to ipman_db.no_response, // report mismatches. // Return 0 for no mismatch, 1 on mismatch MYSQL conn; MYSQL conn_temp; // the xxx_temp vars here may be reset immediately after use MYSQL_RES *res; MYSQL_RES *res_temp; MYSQL_ROW row; MYSQL_ROW row_temp; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "SELECT ip_addr, released_to FROM unbound_ips WHERE ip_addr = 1234567890" ); char *mysqlQuery; char *ip; char *mac; unsigned int ipv4; // IP as unsigned int int x = 0; // counter int pass = 1; // this will keep track of which pass we are on, mostly important for passes 2 and 3 // For the report: The booleans are for the mailed digest on error types boolean mismatch = FALSE; boolean no_response = FALSE; boolean old_unbound = FALSE; boolean unbound_response = FALSE; // This one is reset at the bottom of the loop through unbound_ips FILE *out; char *reportMsg; /* Scan IPs in pman_db.ips_and_macs. Return 0 if no mismatch, 1 if a mismatch. */ if( open_report() == -1 ) { printf( "%s: Report file could not be opened, scan aborted.\n", myName ); return( -1 ); } // Mismatch report header reportMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( reportMsg == NULL ) { printf( "%s: Out of memory in pass_one(). Scan aborting, contact an adminstrator.\n", myName ); exit( -1 ); } sprintf( reportMsg, "IP - MAC Address mismatches\n***************************\n" ); add_report( reportMsg ); // Get list of IPs to scan. ip = ( char * ) malloc( MAX_SIZE_MSG ); if( ip == NULL ) { printf( "%s: Out of memory in pass_one(). Scan aborting, contact an adminstrator.\n", myName ); free( reportMsg ); exit( -1 ); } mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in pass_one().\n", myName ); free( ip ); free( reportMsg ); exit( -1 ); } mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( mysqlQuery ); free( ip ); free( reportMsg ); mysql_close( &conn ); return( -1 ); } sprintf( mysqlQuery, "SELECT ip_addr, mac_addr FROM ips_and_macs WHERE scan = 1" ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( !( res = mysql_store_result( &conn ))) { printf( "%s\n", mysql_error( &conn )); free( mysqlQuery ); free( ip ); free( reportMsg ); mysql_close( &conn ); return( -1 ); } mac = ( char * ) malloc( MAX_SIZE_ETHADDR + 1 ); if( mac == NULL ) { printf( "%s: Out of memory in pass_one().\n", myName ); free( mysqlQuery ); free( ip ); free( reportMsg ); exit( -1 ); } while( row = mysql_fetch_row( res )) { ipv4 = strtoul( row[ 0 ], NULL, 10 ); ip = int_to_dotted( ipv4 ); sprintf( mac, "%s", row[ 1 ] ); for( x = 0; x < 5; x++ ) sprintf( target_mac[ x ], "" ); get_mac( ip ); // first, deal with a non-responder. if( strlen( target_mac[ 0 ] ) == 0 && strlen( target_mac[ 1 ] ) == 0 && strlen( target_mac[ 2 ] ) == 0 && strlen( target_mac[ 3 ] ) == 0 && strlen( target_mac[ 4 ] ) == 0 ) { if( !ip_is_bound( ip )) { // add the IP address to non-responders mysql_init( &conn_temp ); sprintf( mysqlQuery, "INSERT INTO no_response VALUES(%u, 1, NOW())", ipv4 ); if( !mysql_real_connect( &conn_temp, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn_temp )); printf( "%s: IP address %s did not respond, but there was an error adding it to the table no_response.\n", myName, row[ 0 ] ); } else { mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery )); } mysql_close( &conn_temp ); } } // otherwise, compare the stuff in target_mac with mac...they should be the same. Or, if the // packet got dropped, the array member for that packet should be a zero-length string. else { if(( strcmp( mac, target_mac[ 0 ] ) == 0 || strlen( target_mac[ 0 ] ) == 0 ) && ( strcmp( mac, target_mac[ 1 ] ) == 0 || strlen( target_mac[ 1 ] ) == 0 ) && ( strcmp( mac, target_mac[ 2 ] ) == 0 || strlen( target_mac[ 2 ] ) == 0 ) && ( strcmp( mac, target_mac[ 3 ] ) == 0 || strlen( target_mac[ 3 ] ) == 0 ) && ( strcmp( mac, target_mac[ 4 ] ) == 0 || strlen( target_mac[ 4 ] ) == 0 )) { // All is good /* We don't really need this stuff here, unless the decision is made later to leave non-responders in the no_response table between scans. sprintf( mysqlQuery, "DELETE FROM no_response WHERE ip_addr = %u", ipv4 ); mysql_init( &conn_temp ); if( !mysql_real_connect( &conn_temp, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn_temp )); printf( "%s: Please remove ip_addr %u manually from no_response.\n", myName, ipv4 ); } else { mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery ) ); } mysql_close( &conn_temp ); */ } else { // A stolen IP address! Report it! printf( "%s: The IP address %s does not report its assigned MAC address of %s. This will be reported shortly.\n", myName, ip, row[ 1 ] ); mismatch = TRUE; reportMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( reportMsg == NULL ) { printf( "%s: Out of memory pass_one(). Scan aborted, contact adminstrator.\n", myName ); exit( -1 ); } sprintf( reportMsg, "IP address %s should have MAC %s, but reported:\n%s\n%s\n%s\n%s\n%s\n.", ip, row[ 1 ], target_mac[ 0 ], target_mac[ 1 ], target_mac[ 2 ], target_mac[ 3 ], target_mac[ 4 ] ); add_report( reportMsg ); free( reportMsg ); } } } // while free( reportMsg ); free( ip ); free( mac ); free( mysqlQuery ); mysql_free_result( res ); mysql_close( &conn ); if( mismatch == FALSE ) return( 0 ); else return( 1 ); } int pass_two_three( void ) { // Scan ipman_db.no_response, report mismatches // Return 0 if no mismatches, 1 if there is a mismatch MYSQL conn; MYSQL conn_temp; // the xxx_temp vars here may be reset immediately after use MYSQL_RES *res; MYSQL_RES *res_temp; MYSQL_ROW row; MYSQL_ROW row_temp; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "SELECT no_response.ip_addr, mac_addr FROM no_response, ips_and_macs WHERE no_response.ip_addr = ips_and_macs.ip_addr" ); char *mysqlQuery; char *ip; char *mac; unsigned int ipv4; // IP as unsigned int int x = 0; // counter int pass = 1; // this will keep track of which pass we are on, mostly important for passes 2 and 3 // For the report: The booleans are for the mailed digest on error types boolean mismatch = FALSE; boolean no_response = FALSE; boolean old_unbound = FALSE; boolean unbound_response = FALSE; // This one is reset at the bottom of the loop through unbound_ips FILE *out; char *reportMsg; /* Scan IPs in pman_db.ips_and_macs. Return 0 if no mismatch, 1 if a mismatch. */ if( open_report() == -1 ) { printf( "%s: Report file could not be opened, scan aborted.\n", myName ); return( -1 ); } // Mismatch report header reportMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( reportMsg == NULL ) { printf( "%s: Out of memory in pass_one(). Scan aborting, contact an adminstrator.\n", myName ); exit( -1 ); } sprintf( reportMsg, "IP - MAC Address mismatches\n***************************\n" ); add_report( reportMsg ); // Get list of IPs to scan. ip = ( char * ) malloc( MAX_SIZE_MSG ); if( ip == NULL ) { printf( "%s: Out of memory in pass_one(). Scan aborting, contact an adminstrator.\n", myName ); free( reportMsg ); exit( -1 ); } mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in pass_one().\n", myName ); free( ip ); free( reportMsg ); exit( -1 ); } mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( mysqlQuery ); free( ip ); free( reportMsg ); mysql_close( &conn ); return( -1 ); } sprintf( mysqlQuery, "SELECT no_response.ip_addr, mac_addr FROM no_response, ips_and_macs WHERE no_response.ip_addr = ips_and_macs.ip_addr" ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( mysql_errno( &conn )) { printf( "%s\n", mysql_error( &conn )); free( mysqlQuery ); free( ip ); free( mac ); free( reportMsg ); mysql_close( &conn ); return( -1 ); } if( !( res = mysql_store_result( &conn ))) { printf( "%s\n", mysql_error( &conn )); free( mysqlQuery ); free( ip ); free( reportMsg ); mysql_close( &conn ); return( -1 ); } mac = ( char * ) malloc( MAX_SIZE_ETHADDR + 1 ); if( mac == NULL ) { printf( "%s: Out of memory in pass_one().\n", myName ); free( mysqlQuery ); free( ip ); free( reportMsg ); exit( -1 ); } while( row = mysql_fetch_row( res )) { ipv4 = strtoul( row[ 0 ], NULL, 10 ); ip = int_to_dotted( ipv4 ); sprintf( mac, "%s", row[ 1 ] ); for( x = 0; x < 5; x++ ) sprintf( target_mac[ x ], "" ); get_mac( ip ); // first, deal with a non-responder. if( strlen( target_mac[ 0 ] ) == 0 && strlen( target_mac[ 1 ] ) == 0 && strlen( target_mac[ 2 ] ) == 0 && strlen( target_mac[ 3 ] ) == 0 && strlen( target_mac[ 4 ] ) == 0 ) { if( !ip_is_bound( ip )) { // add the IP address to non-responders mysql_init( &conn_temp ); sprintf( mysqlQuery, "INSERT INTO no_response VALUES(%u, 1, NOW())", ipv4 ); if( !mysql_real_connect( &conn_temp, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn_temp )); printf( "%s: IP address %s did not respond, but there was an error adding it to the table no_response.\n", myName, row[ 0 ] ); } else { mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery )); } mysql_close( &conn_temp ); } } // otherwise, compare the stuff in target_mac with ip...they should be the same. Or, if the // packet got dropped, the array member for that packet should be a zero-length string. else { if(( strcmp( mac, target_mac[ 0 ] ) == 0 || strlen( target_mac[ 0 ] ) == 0 ) && ( strcmp( mac, target_mac[ 1 ] ) == 0 || strlen( target_mac[ 1 ] ) == 0 ) && ( strcmp( mac, target_mac[ 2 ] ) == 0 || strlen( target_mac[ 2 ] ) == 0 ) && ( strcmp( mac, target_mac[ 3 ] ) == 0 || strlen( target_mac[ 3 ] ) == 0 ) && ( strcmp( mac, target_mac[ 4 ] ) == 0 || strlen( target_mac[ 4 ] ) == 0 )) { // All is good /* We don't really need this stuff here, unless the decision is made later to leave non-responders in the no_response table between scans. sprintf( mysqlQuery, "DELETE FROM no_response WHERE ip_addr = %u", ipv4 ); mysql_init( &conn_temp ); if( !mysql_real_connect( &conn_temp, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn_temp )); printf( "%s: Please remove ip_addr %u manually from no_response.\n", myName, ipv4 ); } else { mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery ) ); } mysql_close( &conn_temp ); */ } else { // A stolen IP address! Report it! printf( "%s: The IP address %s does not report its assigned MAC address of %s. This will be reported shortly.\n", myName, ip, row[ 1 ] ); mismatch = TRUE; reportMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( reportMsg == NULL ) { printf( "%s: Out of memory pass_one(). Scan aborted, contact adminstrator.\n", myName ); exit( -1 ); } sprintf( reportMsg, "IP address %s should have MAC %s, but reported:\n%s\n%s\n%s\n%s\n%s\n.", ip, row[ 1 ], target_mac[ 0 ], target_mac[ 1 ], target_mac[ 2 ], target_mac[ 3 ], target_mac[ 4 ] ); add_report( reportMsg ); free( reportMsg ); } } } // while free( reportMsg ); free( ip ); free( mac ); free( mysqlQuery ); mysql_free_result( res ); mysql_close( &conn ); if( mismatch == FALSE ) return( 0 ); else return( 1 ); } void pcap_callback_fct( u_char *what, struct pcap_pkthdr *pkt_header, u_char *packet ) { struct ether_header *eth_header; // net/ethernet.h struct ether_arp *arp_header; // linux/if_arp.h u_char src_ha[ 19 ]; //source hardware address u_char src_pa[ 17 ]; //source protocol address eth_header = ( struct ether_header * ) packet; // If it's an ARP packet, get some ARP info from it: if( ntohs( eth_header->ether_type ) == ETHERTYPE_ARP ) { arp_header = ( struct ether_arp * ) ( packet + sizeof( struct ether_header ) ); if( arp_header->ea_hdr.ar_op == ntohs( ARPOP_REPLY ) ) { snprintf( src_ha, sizeof( src_ha ) - 1, "%02x:%02x:%02x:%02x:%02x:%02x:", arp_header->arp_sha[ 0 ], arp_header->arp_sha[ 1 ], arp_header->arp_sha[ 2 ], arp_header->arp_sha[ 3 ], arp_header->arp_sha[ 4 ], arp_header->arp_sha[ 5 ] ); snprintf( src_pa, sizeof( src_pa ) - 1, "%d.%d.%d.%d", arp_header->arp_spa[ 0 ], arp_header->arp_spa[ 1 ], arp_header->arp_spa[ 2 ], arp_header->arp_spa[ 3 ] ); memcpy( temp_mac, src_ha, 19 ); } } } void print_usage( void ) { printf( "Usage: ipman [OPTIONS]\n" ); printf( "Manage IP addresses by comparing IP address to authorized Ethernet address.\n\n" ); printf( "--bind,\t\t-b\tBind an IP address or an entire class C to the local interface.\n" ); printf( "--check=IP,\t-c\tCheck a single IP address (but don't log a mismatch).\n" ); printf( "--help,\t\t-h\tPrint this help and exit.\n" ); printf( "--lookup=MAC,\t-l\tLook up authorized IP addresses for a given MAC address.\n" ); printf( "--noalert,\t-n\tPrint alerts to stdout rather than sending alert\n" ); printf( "--scan,\t\t-s\tScan IPs in local database and send alert if there is a mismatch.\n" ); printf( "--unbind,\t-u\tUnbind an IP address and mark the IP as assigned in ipmanage.net.\n" ); printf( "\nNote that only one option can be chosen with the exception of --noalert (-n) with --scan (-s).\n" ); } int query_ipmanage( char *ip, query action ) { // enum queryType { INSERT, DELETE }; // all the variables for getting info from user: unsigned int ipv4 = 0; int MAX_SIZE_DB_FIELD = 80; char *label; char *location; char *server_type; int charsRead; char verify; char *tempChar; // for replacing newline with null terminator // variables for providing info to user: int monitor; // for holding the value of the row count // Variables for the query MYSQL conn; MYSQL_RES *res; MYSQL_ROW row; int base = get_base( ip ); // baseindex from ipmanage_ipplan.base if( base == -1 ) { // No baseindex found! printf( "%s: No base index found for IP address %s. Operation cancelled.\n", myName, ip ); return( -1 ); } char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipmanage_ipplan"; char *mysqlQuery; int MAX_SIZE_QUERY = strlen( "INSERT INTO ipaddr VALUES (1234567890, '', '', '555-555-5555', '', 123456, NOW(), 'xxxxxxxxxxxxxxxx'" ) + MAX_SIZE_DB_FIELD * 3; // Each of the blank fields here could be 80 characters int count; // for logging char *logMsg; char *old_server_label; label = ( char * ) malloc( MAX_SIZE_DB_FIELD ); if( label == NULL ) { fprintf( stderr, "%s: Out of memory in query_ipmanage().\n", myName ); exit( -1 ); } location = ( char * ) malloc( MAX_SIZE_DB_FIELD ); if( location == NULL ) { fprintf( stderr, "%s: Out of memory in query_ipmanage().\n", myName ); free( label ); exit( -1 ); } server_type = ( char * ) malloc( MAX_SIZE_DB_FIELD ); if( server_type == NULL ) { fprintf( stderr, "%s: Out of memory in query_ipmanage().\n", myName ); free( label ); free( location ); exit( -1 ); } ipv4 = dotted_to_int( ip ); if( action == INSERT ) { // Get server label, location, server type printf( "Enter the server label: " ); charsRead = getline( &label, &MAX_SIZE_DB_FIELD, stdin ); if( charsRead == 1 ) { fprintf( stderr, "%s: Server label cannot be blank.\n", myName ); return( 1 ); } /* Replace \n with \0 */ if(( tempChar = strchr( label, '\n' )) != NULL ) *tempChar = '\0'; printf( "Enter the server DC and cabinet: " ); charsRead = getline( &location, &MAX_SIZE_DB_FIELD, stdin ); if( charsRead == 1 ) { fprintf( stderr, "%s: Server location cannot be blank.\n", myName ); return( 1 ); } /* Replace \n with \0 */ if(( tempChar = strchr( location, '\n' )) != NULL ) *tempChar = '\0'; printf( "Enter the server type (dedicated, colo, etc.): " ); charsRead = getline( &server_type, &MAX_SIZE_DB_FIELD, stdin ); if( charsRead == 1 ) { fprintf( stderr, "%s: Server type cannot be blank.\n", myName ); return( 1 ); } /* Replace \n with \0 */ if(( tempChar = strchr( server_type, '\n' )) != NULL ) *tempChar = '\0'; // Echo and verify printf( "Adding a record for IP address %s for the following server:\n", ip ); printf( "Server label: %s\nLocation: %s\nType: %s\n", label, location, server_type ); printf( "Add this record [y/n]: " ); verify = getchar(); getchar(); // swallow the carriage return if( verify == 'y' ) { // Then run the query mysqlQuery = (char * ) malloc( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { fprintf( stderr, "%s: Out of memory in query_ipmanage.\n", myName ); free( label ); free( location ); free( server_type ); exit( -1 ); } // Check to see if there is record for the address sprintf( mysqlQuery, "SELECT COUNT(*) AS num_rows FROM ipaddr WHERE ipaddr = %u", ipv4 ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( label ); free( location ); free( server_type ); free( mysqlQuery ); mysql_close( &conn ); exit( -1 ); } mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( !( res = mysql_use_result( &conn ))) { printf( "%s\n", mysql_error( &conn )); free( label ); free( location ); free( server_type ); free( mysqlQuery ); fprintf( stderr, "Invalid results from mysql_use_results in query_ipmanage.\n" ); } row = mysql_fetch_row( res ); sscanf( row[ 0 ], "%d", &count ); if( count > 0 ) { printf( "IP address %s alread in table ipmanage_ipplan.ipaddr", ip ); mysql_close( &conn ); return( 1 ); } mysql_free_result( res ); // No record for the IP exists, go ahead and add it. sprintf( mysqlQuery, "INSERT INTO ipaddr VALUES (%u, '%s', '%s', '555-555-5555', \ '%s', %d, NOW(), '%s')", ipv4, label, location, server_type, base, username ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( mysql_affected_rows( &conn ) < 1 ) { // The record was not added. Log it. printf( "The record was not added. The query was %s. Contact an administrator.\n", mysqlQuery ); free( label ); free( location ); free( server_type ); free( mysqlQuery ); logMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { printf( "%s: Out of memory in query_ipmanage.\n" ); mysql_close( &conn ); exit( -1 ); } sprintf( logMsg, "Failed to add record for address %s to ipmanage_ipplan. Query: %s.\n", ip, mysqlQuery ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); printf( "%s: %s. Contact an administrator.\n", myName, logMsg ); free( logMsg ); mysql_close( &conn ); return( 1 ); } logMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { printf( "%s: Out of memory in query_ipmanage.\n" ); free( label ); free( location ); free( server_type ); free( mysqlQuery ); mysql_close( &conn ); exit( -1 ); } sprintf( logMsg, "IP address %s assigned to server %s by user %s.\n", ip, label, username ); logEntry( logMsg, "/var/log/ipman/ipman.unbind" ); printf( "%s: %s", myName, logMsg ); free( logMsg ); return( 0 ); } else { // user did not verify the entry printf( "%s: Operation cancelled.\n", myName ); free( label ); free( location ); free( server_type ); mysql_close( &conn ); return( 1 ); } } else { // action == DELETE mysqlQuery = (char * ) malloc( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in query_ipmanage.\n", myName ); free( label ); free( location ); free( server_type ); exit( -1 ); } // Check to see if there is record for the address sprintf( mysqlQuery, "SELECT userinf FROM ipaddr WHERE ipaddr = %u", ipv4 ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( label ); free( location ); free( server_type ); free( mysqlQuery ); exit( -1 ); } mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); res = mysql_store_result( &conn ); monitor = mysql_affected_rows( &conn ); if( monitor < 1 ) { printf( "There is no record to delete for IP address %s.\n", ip ); free( label ); free( location ); free( server_type ); free( mysqlQuery ); mysql_free_result( res ); mysql_close( &conn ); return( 1 ); } row = mysql_fetch_row( res ); printf( "Delete record for IP address %s, assigned to %s [y/n]: ", ip, row[ 0 ] ); verify = getchar(); if( verify == 'y' ) { // free old result before new query, but first save old server label old_server_label = ( char * ) malloc( MAX_SIZE_DB_FIELD ); if( old_server_label == NULL ) { printf( "%s: Out of memory in query_ipmanage().\n", myName ); free( label ); free( location ); free( server_type ); free( mysqlQuery ); mysql_close( &conn ); exit( -1 ); } sprintf( old_server_label, "%s", row[ 0 ] ); mysql_free_result( res ); sprintf( mysqlQuery, "DELETE FROM ipaddr WHERE ipaddr = %u", ipv4 ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( mysql_affected_rows( &conn ) < 1 ) { printf( "Record for IP address %s was not deleted.", ip ); logMsg = (char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { printf( "%s: Out of memory in query_ipmanage().\n" ); free( label ); free( location ); free( server_type ); free( mysqlQuery ); free( old_server_label ); exit( -1 ); } sprintf( logMsg, "Attempt to delete ipmanage_ipplan record for %s failed (query: \ %s)\n", mysqlQuery ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); printf( "%s: %s Contact an administrator.\n", myName, logMsg ); return( 1 ); } else { // record was deleted, log it in ipman.bind // (since this would be part of a binding operation) printf( "Record for IP address %s was deleted.\n", ip ); logMsg = (char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { printf( "%s: Out of memory in query_ipmanage().\n" ); free( label ); free( location ); free( server_type ); free( mysqlQuery ); exit( -1 ); } sprintf( logMsg, "Record for IP %s deleted by user %s. Record formerly allocated to server %s.\n", ip, username, old_server_label ); logEntry( logMsg, "/var/log/ipman/ipman.bind" ); printf( "%s: %s", myName, logMsg ); return( 0 ); } } printf( "Delete operation cancelled by user.\n" ); return( 1 ); } // action = DELETE } // query_ipmanage() int reload_ipaliases( void ) { /* fork a child, exec ipaliases, and exit. parent sleeps until child exits and returns proper exit code.*/ pid_t childpid; int status; if(( childpid = fork()) < 0 ) { printf( "%s: Error forking child process in reload_ipaliases() ln 380.\n", myName ); return( -1 ); } else { if( childpid == 0 ) { system( "/sbin/ifdown eth0" ); system( "/sbin/ifup eth0" ); system( "/scripts/ipaliases reload" ); exit( 0 ); } else { /* this is the parent, wait( for childpid )*/ while( childpid != wait( &status )) ; /* Just waiting */ if( status ) { printf( "%s: Error in child: reload_ipaliases().\ n", myName ); return( -1 ); } } } return( 0 ); } int report_non_responders( void ) { MYSQL conn; MYSQL_RES *res; MYSQL_ROW row; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "SELECT ip_addr, released_to FROM unbound_ips WHERE ip_addr = 1234567890" ); char *mysqlQuery; char *ip; char *mac; char *reportMsg; unsigned int ipv4; // IP as unsigned int int x = 0; // counter boolean no_response = FALSE; ip = ( char * ) malloc( MAX_SIZE_IPADDR ); if( ip = NULL ) { printf( "%s: Out of memory in report_non_reponders().\n", myName ); exit( -1 ); } mac = ( char * ) malloc( MAX_SIZE_ETHADDR ); if( mac = NULL ) { printf( "%s: Out of memory in report_non_reponders().\n", myName ); free( ip ); exit( -1 ); } mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY ); if( mac = NULL ) { printf( "%s: Out of memory in report_non_reponders().\n", myName ); free( ip ); free( mac ); exit( -1 ); } mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "mysql_real_connect(): %s\n", mysql_error( &conn )); printf( "%s: Third pass completed, mismatches reported, but remaining IPs in no_response never responded.\n", myName); printf( "%s: Report on non-responders not completed. Contact an administrator.\n", myName ); free( mysqlQuery ); free( ip ); free( mac ); mysql_close( &conn ); return( -1 ); } sprintf( mysqlQuery, "SELECT ip_addr FROM no_response" ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( mysql_errno( &conn )) { printf( "mysql_real_query: %s\n", mysql_error( &conn )); } if( !( res = mysql_store_result( &conn ))) { printf( "mysql_store_result(): %s\n", mysql_error( &conn )); printf( "%s: Third pass completed, mismatches reported, but remaining IPs in no_response never responded.\n", myName); printf( "%s: Report on non-responders not completed. Contact an administrator.\n", myName ); free( mysqlQuery ); free( ip ); free( mac ); mysql_close( &conn ); return( -1 ); } if( mysql_affected_rows( &conn ) > 0 ) { no_response = TRUE; // Add no_response report header reportMsg = ( char * ) malloc( MAX_SIZE_MSG + 1 ); if( reportMsg == NULL ) { printf( "%s: Out of memory in report_non_response().\n", myName ); printf( "Mismatches reported, non-responders in table no_response have not responded.\n" ); printf( "Unbound IPs have not been queried. Contact an administrator.\n" ); exit( -1 ); } sprintf( reportMsg, "\nIP addresses not responding to ARP requests\n*******************************************\n" ); add_report( reportMsg ); while( row = mysql_fetch_row( res )) { ipv4 = strtoul( row[ 0 ], NULL, 10 ); ip = int_to_dotted( ipv4 ); sprintf( reportMsg, "%s\n", ip ); add_report ( reportMsg ); } sprintf( mysqlQuery, "DELETE FROM no_response" ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); free( reportMsg ); } mysql_free_result( res ); mysql_close( &conn ); free( ip ); free( mac ); free( mysqlQuery ); if( no_response == FALSE ) return( 0 ); else return( 1 ); } // report_non_reponders() int report_old_unbound( void ) { MYSQL conn; MYSQL_RES *res; MYSQL_ROW row; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "SELECT * FROM unbound_ips WHERE DATE_SUB(CURDATE(),INTERVAL 2 DAY) > time_unbound" ); char *mysqlQuery; char *ip; char *reportMsg; unsigned int ipv4; // IP as unsigned int int x = 0; // counter boolean old_unbound = FALSE; ip = ( char * ) malloc( MAX_SIZE_IPADDR ); if( ip == NULL ) { printf( "%s: Out of memory in report_old_unbound(). IP address completed, mismatches\n", myName ); printf( "non-responders, and first responses from recently released addresses reported.\n" ); printf( "Report will not be sent; contact an administrator.\n" ); exit( -1 ); } mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in report_old_unbound(). IP address completed, mismatches\n", myName ); printf( "non-responders, and first responses from recently released addresses reported.\n" ); printf( "Report will not be sent; contact an administrator.\n" ); exit( -1 ); } sprintf( mysqlQuery, "SELECT * FROM unbound_ips WHERE DATE_SUB(CURDATE(),INTERVAL 2 DAY) > time_unbound" ); mysql_init( &conn ); if( !mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 )) { printf( "%s\n", mysql_error( &conn )); free( mysqlQuery ); free( ip ); free( reportMsg ); mysql_close( &conn ); return( -1 ); } mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( !( res = mysql_store_result( &conn ))) { printf( "%s\n", mysql_error( &conn )); printf( "Third pass completed, mismatches and non-responders reported, but IPs in unbound_ips\n" ); printf( "not scanned to check for extensive period of being unbound. Contact an administrator.\n" ); free( mysqlQuery ); free( ip ); mysql_close( &conn ); return( -1 ); } if( mysql_affected_rows( &conn ) > 0 ) { old_unbound = TRUE; reportMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( reportMsg == NULL ) { printf( "%s: Out of memory in report_old_unbound(). IP address completed, mismatches\n", myName ); printf( "non-responders, and first responses from recently released addresses reported.\n" ); printf( "Report will not be sent; contact an administrator.\n" ); exit( -1 ); } sprintf( reportMsg, "IP addresses unbound for longer than two days\n**********************************************\n" ); add_report( reportMsg ); sprintf( reportMsg, "ip_addr\treleased_to\ttime_unbound\n" ); add_report( reportMsg ); while( row = mysql_fetch_row( res )) { ipv4 = strtoul( row[ 0 ], NULL, 10 ); sprintf( ip, "%s", int_to_dotted( ipv4 )); sprintf( reportMsg, "%s\t%s\t%s\n", ip, row[ 1 ], row[ 2 ] ); add_report( reportMsg ); } free( reportMsg ); } free( ip ); free( mysqlQuery ); mysql_close( &conn ); if( old_unbound == FALSE ) return( 0 ); else return( 1 ); } // report_old_unbound() int report_unbound_response( void ) { MYSQL conn; MYSQL conn_temp; MYSQL_RES *res; MYSQL_RES *res_temp; MYSQL_ROW row; MYSQL_ROW row_temp; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "SELECT ip_addr, mac_addr FROM ips_and_macs WHERE ip_addr = 1234567890" ); char *mysqlQuery; char *ip; char *mac; char *reportMsg; unsigned int ipv4; // IP as unsigned int int x = 0; // counter boolean old_unbound = FALSE; boolean unbound_response = FALSE; mysqlQuery = ( char * ) malloc( MAX_SIZE_QUERY ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in report_unbound_response().\n" ); exit( -1 ); } ip = ( char * ) malloc( MAX_SIZE_QUERY ); if( ip == NULL ) { printf( "%s: Out of memory in report_unbound_response().\n" ); free( mysqlQuery ); exit( -1 ); } mac = ( char * ) malloc( MAX_SIZE_QUERY ); if( mac == NULL ) { printf( "%s: Out of memory in report_unbound_response().\n" ); free( mysqlQuery ); free( ip ); exit( -1 ); } reportMsg = ( char * ) malloc( MAX_SIZE_QUERY ); if( reportMsg == NULL ) { printf( "%s: Out of memory in report_unbound_response().\n" ); free( mysqlQuery ); free( ip ); free( mac ); exit( -1 ); } sprintf( reportMsg, "\nNewly Allocated IP Addresses Responding to Requests\n" ); add_report( reportMsg ); sprintf( reportMsg, "***************************************************\n" ); add_report( reportMsg ); sprintf( mysqlQuery, "SELECT ip_addr FROM unbound_ips" ); mysql_init( &conn ); if( mysql_errno( &conn )) { printf( "report_unbound_response(): %s\n", mysql_error( &conn )); printf( "%s: Third pass completed, mismatches and non-responders reported, but scan of\n", myName ); printf( "old unbound IPs aborted. Contact an administrator.\n" ); free( mysqlQuery ); free( ip ); free( mac ); mysql_close( &conn ); return( -1 ); } mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); if( mysql_errno( &conn )) { printf( "mysql_real_connect(): %s\n", mysql_error( &conn )); printf( "%s: Third pass completed, mismatches and non-responders reported, but scan of\n", myName ); printf( "old unbound IPs aborted. Contact an administrator.\n" ); free( mysqlQuery ); free( ip ); free( mac ); mysql_close( &conn ); return( -1 ); } mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery )); if( mysql_errno( &conn )) { printf( "%s\n", mysql_error( &conn )); printf( "mysql_real_query(): Third pass completed, mismatches and non-responders reported,\n" ); printf( "but scan of old unbound IPs aborted. Contact an administrator.\n" ); free( mysqlQuery ); free( ip ); free( mac ); mysql_close( &conn ); return( -1 ); } if( !( res = mysql_store_result( &conn ))) { printf( "%s\n", mysql_error( &conn )); printf( "mysql_store_result(): Third pass completed, mismatches and non-responders reported,\n" ); printf( "but scan of old unbound IPs aborted. Contact an administrator.\n" ); free( mysqlQuery ); free( ip ); free( mac ); mysql_close( &conn ); return( -1 ); } while( row = mysql_fetch_row( res )) { ipv4 = strtoul( row[ 0 ], NULL, 0 ); sprintf( mysqlQuery, "SELECT ip_addr, mac_addr FROM ips_and_macs WHERE ip_addr = %u", ipv4 ); mysql_init( &conn_temp ); mysql_real_connect( &conn_temp, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery )); if( !( res_temp = mysql_store_result( &conn_temp ))) { printf( "%s\n", mysql_error( &conn_temp )); printf( "%s: Third pass completed, mismatches and non-responders reported, but scan of\n", myName ); printf( "old unbound IPs aborted. Contact an administrator.\n" ); free( mysqlQuery ); free( ip ); free( mac ); mysql_free_result( res ); mysql_free_result( res_temp ); mysql_close( &conn_temp ); mysql_close( &conn ); return( -1 ); } row_temp = mysql_fetch_row( res_temp ); ipv4 = strtoul( row[ 0 ], NULL, 0 ); ip = int_to_dotted( ipv4 ); sprintf( mac, "%s", row_temp[ 1 ] ); mysql_free_result( res_temp ); mysql_close( &conn_temp ); //Get rid of any junk in temp_mac[] from previous runs for( x= 0; x <= 4; x++ ) sprintf( target_mac[ x ], "" ); get_mac( ip ); // if it's not a non-responder, get it out of the table // We also want to assign one responder's MAC to mac for ease of comparison next if( strlen( target_mac[ 0 ] ) != 0 ) { sprintf( mac, "%s", target_mac[ 0 ] ); unbound_response = TRUE; } else if( strlen( target_mac[ 0 ] ) != 0 ) { sprintf( mac, "%s", target_mac[ 0 ] ); unbound_response = TRUE; } else if( strlen( target_mac[ 0 ] ) != 0 ) { sprintf( mac, "%s", target_mac[ 0 ] ); unbound_response = TRUE; } else if( strlen( target_mac[ 0 ] ) != 0 ) { sprintf( mac, "%s", target_mac[ 0 ] ); unbound_response = TRUE; } else if( strlen( target_mac[ 0 ] ) != 0 ) { sprintf( mac, "%s", target_mac[ 0 ] ); unbound_response = TRUE; } else if( strlen( target_mac[ 0 ] ) != 0 ) { sprintf( mac, "%s", target_mac[ 0 ] ); unbound_response = TRUE; } if( unbound_response == TRUE ) { // Then remove it from unbound_ips mysql_init( &conn_temp ); mysql_real_connect( &conn_temp, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); sprintf( mysqlQuery, "DELETE FROM unbound_ips WHERE ip_addr = %u", ipv4 ); mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery )); // If all target_mac[]s agree, register the new mac in ips_and_macs if(( strcmp( mac, target_mac[ 0 ] ) == 0 || strlen( target_mac[ 0 ] ) == 0 ) && ( strcmp( mac, target_mac[ 1 ] ) == 0 || strlen( target_mac[ 1 ] ) == 0 ) && ( strcmp( mac, target_mac[ 2 ] ) == 0 || strlen( target_mac[ 2 ] ) == 0 ) && ( strcmp( mac, target_mac[ 3 ] ) == 0 || strlen( target_mac[ 3 ] ) == 0 ) && ( strcmp( mac, target_mac[ 4 ] ) == 0 || strlen( target_mac[ 4 ] ) == 0 )) { sprintf( mysqlQuery, "UPDATE ips_and_macs SET mac_addr = '%s', scan = 1 WHERE ip_addr = %u", mac, ipv4 ); mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery )); if( mysql_errno( &conn_temp )) printf( "%s\n", mysql_error( &conn_temp )); } else { // if it responds but is not in agreement with itself, put in // ips_and_macs, but also report it as a stolen IP. Change the // value for mac, obviously, so we never get a match as long as // this one is in the table sprintf( mac, "FF:FF:FF:FF:FF:FF" ); sprintf( mysqlQuery, "INSERT INTO ips_and_macs VALUES(%u, '255.255.255.0', '%s', 1)", ipv4, mac ); mysql_real_query( &conn_temp, mysqlQuery, strlen( mysqlQuery )); sprintf( ip, "%s", int_to_dotted( ipv4 )); sprintf( reportMsg, "Previously unbound IP address %s has an address conflict.\n" ); add_report( reportMsg ); logEntry( reportMsg, "/var/log/ipman/ipman.err" ); } } // if( unbound_response == TRUE ) }// while( row = mysql_fetch_row( res )) free( mysqlQuery ); free( ip ); free( mac ); free( reportMsg ); mysql_free_result( res ); mysql_close( &conn ); if( unbound_response == TRUE ) return( 1 ); else return( 0 ); }// report_unbound_response() int scan( int report ) { boolean mismatches = FALSE; // any mistmatches reported boolean old_unbound = FALSE; // any IPs in unbound_ips for more than 2 days boolean unbound_response = FALSE; // any previously unbound IPs that now respond boolean no_response = FALSE;// unbound IPs that have now responded int scan_result = 0; // scan functions return -1 on error, 0 on no mismatches, 1 on a mismatch char *reportMsg; int x = 0; // all-purpose counter /* Scan IPs in the local database. Return 0 on any kind of error. If report = 0, supress alert, otherwise alert as needed. */ /* First pass -- mismatches will be reported immediately. Non-responders will be added to ipman_db.no_response */ if( open_report() == -1 ) { printf( "%s: Report file could not be opened, scan aborted.\n", myName ); return( -1 ); } // Mismatch report header reportMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( reportMsg == NULL ) { printf( "%s: Out of memory in scan(). Scan aborting, contact an adminstrator.\n", myName ); exit( -1 ); } sprintf( reportMsg, "IP - MAC Address mismatches\n***************************\n" ); add_report( reportMsg ); scan_result = pass_one(); if( scan_result == -1) { printf( "%s: Scan failed. Contact an administrator.\n" ); } else { mismatches = ( scan_result == 0 )? FALSE : TRUE; } // Second pass -- mismatches will be reported immediately. scan_result = pass_two_three(); if( scan_result == -1 ) { printf( "%s: Second pass of the scan failed. Contact an administrator.\n", myName ); } else { if( mismatches == FALSE ) { mismatches = ( scan_result == 0 )? FALSE : TRUE; } } printf( "%s: Sleeping for 600 seconds.\n", myName ); printf( "There will be a countdown for entertainment purposes.\n" ); for( x = 600; x > 0; x-- ) { if( x % 10 == 0 ) printf( "%d", x ); else printf( "." ); fflush( stdout ); sleep( 1 ); } printf( "\n" ); // Third pass -- mismatches will be reported immediately. scan_result = pass_two_three(); if( scan_result == -1 ) { printf( "%s: Third pass of the scan failed. Contact an administrator.\n", myName ); } else { if( mismatches == FALSE ) { mismatches = ( scan_result == 0 )? FALSE : TRUE; } } scan_result = report_non_responders(); if( scan_result == -1 ) { printf( "%s: Report on non-responding IPs failed. Contact an administrator.\n", myName ); } else { no_response = ( scan_result == 0 )? FALSE : TRUE; } scan_result = report_unbound_response(); if( scan_result == -1 ) { printf( "%s: Report on newly responding IPs recently allocated failed. Contact an administrator.\n", myName ); } else { unbound_response = ( scan_result == 0 )? FALSE : TRUE; } scan_result = report_old_unbound(); if( scan_result == -1 ) { printf( "%s: Report on IPs unbound for more than 2 days failed. Contact an administrator.\n", myName ); } else { old_unbound = ( scan_result == 0 )? FALSE : TRUE; } // Report digest -- In this report: Mismatches - yes; Non-responders - no; Never responded - yes. reportMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( reportMsg == NULL ) { printf( "%s: Out of memory in scan(). Report available at /var/log/ipman/ipman.report but not sent.\n", myName ); exit( -1 ); } sprintf( reportMsg, "IPMan report available at /var/log/ipman/ipman.report.\nIn this report:\n" ); if( mismatches ) { strcat( reportMsg, "IP address mismatches\n" ); } if( no_response ) { strcat( reportMsg, "IP addresses not responding to ARP requests\n" ); } if( old_unbound ) { strcat( reportMsg, "IP addresses not responding, released to customer more than 2 days ago\n" ); } if( unbound_response ) { strcat( reportMsg, "IP addresses released to customer and now responding\n" ); } strcat( reportMsg, "The report will be overwritten at the next scan.\n" ); send_report( reportMsg ); free( reportMsg ); printf( "%s: Report sent.\nIPMan scan complete.\n", myName ); return( 0 ); } // scan() int send_report( char *sendMsg ) { char *sysBuff; char *subjectMsg = "IPMan scan report"; char *rcpt_to = "admin@servercompany.com"; sysBuff = ( char * ) malloc( MAX_SIZE_MSG ); if( sysBuff == NULL ) { printf( "%s: Out of memory in send_report().\n" ); exit( -1 ); } sprintf ( sysBuff, "echo \"%s\" | mail -s '%s' %s", sendMsg, subjectMsg, rcpt_to ); system ( sysBuff ); return( 0 ); } int set_scannable( char *ip, boolean scan ) { MYSQL conn; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_QUERY = strlen( "UPDATE ips_and_macs SET scan = 0 WHERE ip_addr = 1234567890" ); int x = 0; // just a counter char *mysqlQuery; unsigned int ipv4 = dotted_to_int( ip ); char *logMsg; mysql_init( &conn ); mysqlQuery = ( char * ) malloc ( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in set_scannable() ln 181.\n", myName ); exit( -1 ); } sprintf( mysqlQuery, "UPDATE ips_and_macs SET scan = %d WHERE ip_addr = %u", scan, ipv4 ); mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery ) ); free( mysqlQuery ); if( mysql_errno( &conn ) ) { printf( "%s: Error on UPDATE: %s.\n", myName, mysql_error( &conn ) ); free( mysqlQuery ); logMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { printf( "%s: Out of memory in set_scannable. Error updating ipman_db.ip_addr.scan for IP %s.\n", myName, ip ); exit( -1 ); } sprintf( logMsg, "Error updating ipman_db.ip_addr.scan for IP %s. Error is %s. set_scannable scan = %d.\n", ip, mysql_error( &conn ), scan ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); printf( "%s: %sContact an administrator.\n", myName, logMsg ); free( logMsg ); return( 1 ); } return( 0 ); } // set_scannable() void to_upper( char *the_string ) { int x; for( x = 0; x < strlen( the_string ); x++ ) the_string[ x ] = toupper( the_string[ x ] ); return; } int unbindip( const char *addr ) { /* open /etc/ips, copy lines that do NOT match addr to /etc/ips.tmp, delete /etc/ips, rename .tmp to ips.tmp Additionally, call query_ipmanage( char *ip, int *query_type ); Then call ipaliases reload, return 0 on success or -1 on error */ FILE *in; FILE *out; char *ipstr; char *maskstr; char *tempstr; char *tokens = ":\n"; int ipfound = 0; char *logMsg; query queryType = INSERT; boolean scan = FALSE; // value to set for ipman_db.ips_and_macs.scan if(( in = fopen( "/etc/ips", "r" )) == NULL ) { printf( "%s: Could not open /etc/ips.\n" ); return( -1 ); } if(( out = fopen( "/etc/ips.tmp", "w" )) == NULL ) { printf( "%s: Could not create temp file /etc/ips.tmp.\n" ); return( -1 ); } tempstr = ( char * ) malloc( MAX_SIZE_IPADDR + 1 + MAX_SIZE_NETMASK + 1 ); do { fscanf( in, "%s", tempstr ); if( feof( in ) || ferror( in ) ) break; ipstr = strtok( tempstr, tokens ); maskstr = strtok( NULL, tokens ); if( strcmp( ipstr, addr ) != 0 ) fprintf( out, "%s:%s%s", ipstr, maskstr, "\n" ); else ipfound = 1; } while( !feof( in ) ); sprintf( tempstr, "%s", addr ); if( !ipfound ) printf( "%s: IP address %s not bound to this server.\n", myName, addr ); else { logMsg = ( char * ) malloc( MAX_SIZE_MSG ); if( logMsg == NULL ) { fprintf( stderr, "%s: Out of memory in unbindip() ln 608.\n", myName ); free( tempstr ); exit( -1 ); } // add record to ipmanage_ipplan.ipaddr if( query_ipmanage( tempstr, queryType ) != 0 ) { sprintf( logMsg, "IP address %s unbound from IP host server by user %s, but record in ipmanage_ipplan.ipaddr was not successfully added.\n", addr, username ); printf( "%s: %sContact an administrator.\n", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); free( logMsg ); free( tempstr ); return( -1 ); } if( set_scannable( tempstr, scan ) != 0 ) { sprintf( logMsg, "ipman_db.ips_and_macs.scan not set to 0 for IP address %s.\n", addr ); printf( "%s: %sFix it or contact an administrator.\n", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); } update_unbound( tempstr, queryType ); sprintf( logMsg, "IP address %s unbound from IP host server by user %s.\n", addr, username ); printf( "%s: %s", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.unbind" ); free( logMsg ); } free( tempstr ); fclose( out ); fclose( in ); remove( "/etc/ips" ); rename( "/etc/ips.tmp", "/etc/ips" ); if( reload_ipaliases() ) { printf( "%s: Error reloading WHM ipaliases, contact an administrator.\n", myName ); return( -1 ); } return( 0 ); } int update_unbound( char *ip, query queryType ) { MYSQL conn; char *server = "localhost"; char *mysqlUser = "user"; char *mysqlPass = "pass"; char *mysqlDB = "ipman_db"; int MAX_SIZE_DB_FIELD = 80; int MAX_SIZE_QUERY = strlen( "INSERT INTO unbound_ips VALUES(1234567890, '', NOW(), 12345)" ) + MAX_SIZE_DB_FIELD; int x = 0; // just a counter char *mysqlQuery; unsigned int ipv4 = dotted_to_int( ip ); char *logMsg; char *released_to; int charsRead; char *tmpchr; int user_id; mysqlQuery = ( char * ) malloc ( MAX_SIZE_QUERY + 1 ); if( mysqlQuery == NULL ) { printf( "%s: Out of memory in update_unbound() ln 181.\n", myName ); exit( -1 ); } if( queryType == INSERT ) { released_to = ( char * ) malloc( MAX_SIZE_DB_FIELD + 1 ); if( released_to == NULL ) { printf( "%s: Out of memory in update_unbound() ln 181.\n", myName ); exit( -1 ); } printf( "Adding %s to unbound IPs table. Enter label of server released to: ", ip ); charsRead = getline( &released_to, &MAX_SIZE_DB_FIELD + 1, stdin ); if ((tmpchr = strchr( released_to ,'\n')) != NULL) { *tmpchr = '\0'; } user_id = get_user_id(); sprintf( mysqlQuery, "INSERT INTO unbound_ips VALUES( %u, '%s', NOW(), %d)", ipv4, released_to, user_id ); mysql_init( &conn ); mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery ) ); if( mysql_errno( &conn ) ) { printf( "%s: Error on INSERT: %s.\n", myName, mysql_error( &conn ) ); logMsg = ( char * ) malloc( MAX_SIZE_MSG + 1 ); if( logMsg == NULL ) { printf( "%s: Out of memory in update_unbound().\n", myName ); free( mysqlQuery ); free( released_to ); exit( -1 ); } sprintf( logMsg, "Error adding to ipman_db.unbound_ips for IP address %s: MySQL error was %s\n", ip, mysql_error( &conn )); printf( "%s: %sContact an administrator.\n", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); free( logMsg ); return( -1 ); } logMsg = ( char * ) malloc( MAX_SIZE_MSG + 1 ); if( logMsg == NULL ) { printf( "%s: Out of memory in update_unbound().\n", myName ); free( mysqlQuery ); free( released_to ); exit( -1 ); } sprintf( logMsg, "IP address %s released to server %s and entered in ipman_db.unbound_ips by user %s.\n", ip, released_to, username ); printf( "%s: %s", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.unbind" ); mysql_close( &conn ); free( mysqlQuery ); free( released_to ); return( 0 ); } else { sprintf( mysqlQuery, "DELETE FROM unbound_ips WHERE ip_addr = %u", ipv4 ); mysql_init( &conn ); mysql_real_connect( &conn, server, mysqlUser, mysqlPass, mysqlDB, 0, NULL, 0 ); mysql_real_query( &conn, mysqlQuery, strlen( mysqlQuery ) ); if( mysql_errno( &conn ) ) { printf( "%s: Error on DELETE: %s.\n", myName, mysql_error( &conn ) ); logMsg = ( char * ) malloc( MAX_SIZE_MSG + 1 ); if( logMsg == NULL ) { printf( "%s: Out of memory in update_unbound().\n", myName ); free( mysqlQuery ); exit( -1 ); } sprintf( logMsg, "Error deleting from ipman_db.unbound_ips for IP address %s: MySQL error was %s\n", ip, mysql_error( &conn )); printf( "%s: %sContact an administrator.\n", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.err" ); free( logMsg ); return( -1 ); } logMsg = ( char * ) malloc( MAX_SIZE_MSG + 1 ); if( logMsg == NULL ) { printf( "%s: Out of memory in update_unbound().\n", myName ); free( mysqlQuery ); exit( -1 ); } sprintf( logMsg, "IP address %s deleted from ipman_db.unbound_ips by user %s.\n", ip, username ); printf( "%s: %s", myName, logMsg ); logEntry( logMsg, "/var/log/ipman/ipman.bind" ); mysql_close( &conn ); free( mysqlQuery ); return( 0 ); } } // update_unbound() int validate_addr( const char *addr, int *lbound, int *ubound ) { int octet1 = 0, octet2 = 0, octet3 = 0, octet4 = 0; /* Numeric octets */ char *strOctet1, *strOctet2, *strOctet3, *strOctet4; /* Octets as strings */ char tmpAddr[ MAX_SIZE_IPADDR + 1 ]; /* temp string for const char */ char *strLower; char *strUpper; int MAX_SIZE_OCTET = 4; enum inputType { INVALID, SINGLE_IP, IP_RANGE, C_BLOCK }; enum inputType input; strOctet1 = ( char * ) malloc( MAX_SIZE_OCTET ); strOctet2 = ( char * ) malloc( MAX_SIZE_OCTET ); strOctet3 = ( char * ) malloc( MAX_SIZE_OCTET ); strOctet4 = ( char * ) malloc( MAX_SIZE_OCTET ); strcpy( tmpAddr, addr ); strOctet1 = strtok( tmpAddr, "." ); strOctet2 = strtok( NULL, "." ); strOctet3 = strtok( NULL, "." ); strOctet4 = strtok( NULL, "\n" ); if( is_numeric( strOctet1 ) && is_numeric( strOctet2 ) && is_numeric( strOctet3 ) ) { sscanf( strOctet1, "%d", &octet1 ); sscanf( strOctet2, "%d", &octet2 ); sscanf( strOctet3, "%d", &octet3 ); } else { input = INVALID; return( input ); } sscanf( tmpAddr, "%d.%d.%d.%d", &octet1, &octet2, &octet3, &octet4 ); if( is_numeric( strOctet4 ) ) { /* We have a single IP address or C block */ sscanf( strOctet4, "%d", &octet4 ); if( ! (( octet1 >= 1 && octet1 <= 223 ) && ( octet2 >= 0 && octet2 <= 255 ) && ( octet3 >= 0 && octet3 <= 255 ) && (( octet4 >= 1 && octet4 <= 254 ) || octet4 == 0 )) ) { input = INVALID; return( input ); } else if( octet4 == 0 ) { /* We have a C block */ *lbound = 2; *ubound = 254; input = C_BLOCK; return( input ); } else { /* A single IP */ *lbound = 0; *ubound = 0; input = SINGLE_IP; return( input ); } } else { /* We potentially have a range, verify it and return INVALID or IP_RANGE */ strLower = strtok( strOctet4, "-" ); strUpper = strtok( NULL, "\n" ); if( is_numeric( strLower ) ) { sscanf( strLower, "%d", lbound ); } else { input = INVALID; return( input ); } if( is_numeric( strUpper ) ) { sscanf( strUpper, "%d", ubound ); } else { input = INVALID; return( input ); } if( *lbound <= 1 || *ubound >= 255 || *lbound >= *ubound ) { input = INVALID; return( input ); } else { input = IP_RANGE; return( input ); } } }