int main(int argc, char *argv[]) { if ( argc != 3 ) { help(); return 1; } long int channel = strtol( argv[2], NULL, 10 ); if ( channel <= 0 || 255 <= channel ) { printf( "The channel must be between 1 and 255.\n" ); help(); return 1; } // The 802.11b base broadcast rate const uint8_t dataRate = 0x4; const char* device = argv[1]; // Construct the beacon packets size_t* beaconLengths = (size_t*) malloc( sizeof(size_t) * numAccessPoints ); assert( beaconLengths != NULL ); uint8_t** beaconPackets = (uint8_t**) malloc( sizeof(uint8_t*) * numAccessPoints ); assert( beaconLengths != NULL ); for ( size_t i = 0; i < numAccessPoints; ++ i ) { beaconPackets[i] = constructBeaconPacket( dataRate, channel, accessPoints[i], &beaconLengths[i] ); assert( beaconPackets[i] != NULL ); assert( beaconLengths[i] > 0 ); } // Open the raw device int rawSocket = openSocket( device ); if ( rawSocket < 0 ) { fprintf( stderr, "error opening socket\n" ); return 1; } // Configure the initial timeout struct timeval now; int code = gettimeofday( &now, NULL ); assert( code == 0 ); struct timeval beaconTime = now; incrementTimeval( &beaconTime, BEACON_INTERVAL ); // This is used to change the sequence of the probe response messages // In order to help clients find more of our fake access points size_t lastProbeStartIndex = 0; while ( 1 ) { // We need to wait until one of two conditions: // 1. The "sockin" socket has data for us // 2. The beacon interval (102400 microseconds) has expired fd_set readfds; FD_ZERO( &readfds ); FD_SET( rawSocket, &readfds ); struct timeval timeout = now; differenceTimeval( &beaconTime, &timeout ); int numFds = select( rawSocket+1, &readfds, NULL, NULL, &timeout ); assert( numFds >= 0 ); if ( numFds < 0 ) { perror( "select failed" ); return 1; } if ( numFds == 1 ) { // We have a packet waiting: Read it uint8_t packetBuffer[4096]; ssize_t bytes = read( rawSocket, packetBuffer, sizeof(packetBuffer) ); if ( bytes < 0 ) { perror( "read failed" ); return 1; } // Move past the radiotap header assert( bytes >= (ssize_t) sizeof( struct ieee80211_radiotap_header ) ); struct ieee80211_radiotap_header* radiotap = (struct ieee80211_radiotap_header*) packetBuffer; assert( radiotap->it_version == 0 ); assert( bytes >= radiotap->it_len ); uint8_t* packetIterator = packetBuffer + radiotap->it_len; size_t remainingBytes = bytes - radiotap->it_len; // Get the 802.11 frame: // NOTE: This frame structure is larger than some packet types, so only read the initial bytes struct ieee80211_frame* frame = (struct ieee80211_frame*)( packetIterator ); // Check to see if this is a PROBE_REQUEST assert( (frame->i_fc[0] & IEEE80211_FC0_VERSION_MASK) == IEEE80211_FC0_VERSION_0 ); if ( (frame->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT && (frame->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PROBE_REQ ) { //~ packet_hexdump( (const uint8_t*) frame, remainingBytes ); // Locate the SSID assert( remainingBytes >= PROBE_SSID_OFFSET ); packetIterator += PROBE_SSID_OFFSET; remainingBytes -= PROBE_SSID_OFFSET; struct ieee80211_info_element* info = (struct ieee80211_info_element*) packetIterator; assert( remainingBytes >= sizeof(*info) ); packetIterator += sizeof(*info); remainingBytes -= sizeof(*info); assert( remainingBytes >= info->info_length ); // See if it is a broadcast ssid (zero length SSID) if ( info->info_length == 0 ) { //~ printf( "broadcast probe request!\n"); // Start with the next index for the next broadcast probe size_t index = lastProbeStartIndex; lastProbeStartIndex += 1; if ( lastProbeStartIndex >= numAccessPoints ) { lastProbeStartIndex = 0; } // Transmit responses for all access points for ( size_t i = 0; i < numAccessPoints; ++ i ) { if ( index >= numAccessPoints ) { index = 0; } transmitProbeResponse( rawSocket, beaconPackets[index], beaconLengths[index], frame->i_addr2 ); index += 1; } } else { // Check if the SSID matches any of ours for ( size_t i = 0; i < numAccessPoints; ++ i ) { if ( info->info_length == accessPoints[i]->ssidLength && memcmp( info->info, accessPoints[i]->ssid, info->info_length ) == 0 ) { // It does! //~ printf( "probe for SSID '%.*s'\n", info->info_length, (char*) info->info ); transmitProbeResponse( rawSocket, beaconPackets[i], beaconLengths[i], frame->i_addr2 ); break; } } } } } else { // We should only have 1 or 0 fds ready assert( numFds == 0 ); } // Get the current time to calculate how much longer we need to wait // or if we need to send a beacon now int code = gettimeofday( &now, NULL ); assert( code == 0 ); if ( compareTimeval( &beaconTime, &now ) <= 0 ) { //~ printf( "beacon\n" ); // The timeout has expired. Send out the beacons // TODO: Update the timestamp in the beacon packets for ( size_t i = 0; i < numAccessPoints; ++ i ) { ssize_t bytes = write( rawSocket, beaconPackets[i], beaconLengths[i] ); assert( bytes == (ssize_t) beaconLengths[i] ); if ( bytes < (ssize_t) beaconLengths[i] ) { perror( "error sending packet" ); return 1; } } // Increment the next beacon time until it is in the future do { incrementTimeval( &beaconTime, BEACON_INTERVAL ); } while( compareTimeval( &beaconTime, &now ) <= 0 ); } } close( rawSocket ); free( beaconPackets ); free( beaconLengths ); }
int redisContextConnectSSL(redisContext *c, const char *addr, int port, char* certfile, char* certdir, struct timeval *timeout) { struct timeval start_time; int has_timeout = 0; int is_nonblocking = 0; c->ssl.sd = -1; c->ssl.ctx = NULL; c->ssl.ssl = NULL; c->ssl.bio = NULL; // Set up a SSL_CTX object, which will tell our BIO object how to do its work SSL_CTX* ctx = SSL_CTX_new(TLSv1_1_client_method()); c->ssl.ctx = ctx; // Create a SSL object pointer, which our BIO object will provide. SSL* ssl; // Create our BIO object for SSL connections. BIO* bio = BIO_new_ssl_connect(ctx); c->ssl.bio = bio; // Failure? if (bio == NULL) { char errorbuf[1024]; __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Error creating BIO!\n"); ERR_error_string(1024,errorbuf); __redisSetError(c,REDIS_ERR_OTHER,errorbuf); // We need to free up the SSL_CTX before we leave. cleanupSSL( &c->ssl ); return REDIS_ERR; } // Makes ssl point to bio's SSL object. BIO_get_ssl(bio, &ssl); c->ssl.ssl = ssl; // Set the SSL to automatically retry on failure. SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); char* connect_str = (char *)calloc( 1, strlen( addr ) + 10 ); sprintf( connect_str, "%s:%d", addr, port ); c->ssl.conn_str = connect_str; // We're connection to the REDIS server at host:port BIO_set_conn_hostname(bio, connect_str); SSL_CTX_load_verify_locations(ctx, certfile, certdir); // Are we supposed to be blocking or non-blocking? if( (c->flags & REDIS_BLOCK) == 0) { is_nonblocking = 1; BIO_set_nbio(bio,1); } // What about a timeout? // If we're blocking and have a timeout, we need to handle that specially if( NULL != timeout ) { BIO_set_nbio(bio,1); has_timeout = 1; gettimeofday(&start_time, NULL); } while(1) { struct timeval cur_time, elapsed_time; if (has_timeout) { gettimeofday(&cur_time, NULL); elapsed_time = subtractTimeval( cur_time, start_time ); if (compareTimeval( elapsed_time, *timeout) > 0) { char errorbuf[1024]; __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Connection timed out."); ERR_error_string(1024,errorbuf); __redisSetError(c,REDIS_ERR_OTHER,errorbuf); cleanupSSL( &(c->ssl) ); return REDIS_ERR; } } // Same as before, try to connect. if (BIO_do_connect(bio) <= 0 ) { if( BIO_should_retry( bio ) ) { // We need to retry. } else { char errorbuf[1024]; __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Failed to connect"); ERR_error_string(1024,errorbuf); __redisSetError(c,REDIS_ERR_OTHER,errorbuf); cleanupSSL( &(c->ssl) ); return REDIS_ERR; } } else { // connect is done... break; } if( has_timeout ) { // Do select and seelct on it int result; int fd = BIO_get_fd( bio, NULL ); struct timeval time_left; if (has_timeout) { time_left = subtractTimeval( *timeout, elapsed_time ); } fd_set readset, writeset; FD_ZERO(&readset); FD_SET(fd, &readset); FD_ZERO(&writeset); FD_SET(fd, &writeset); do { result = select( fd+1, &readset, &writeset, NULL, &time_left); } while( result == -1 && errno == EINTR ); } } while(1) { struct timeval cur_time, elapsed_time; if (has_timeout) { gettimeofday(&cur_time, NULL); elapsed_time = subtractTimeval( cur_time, start_time ); if (compareTimeval( elapsed_time, *timeout) > 0) { char errorbuf[1024]; __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Connection timed out."); ERR_error_string(1024,errorbuf); __redisSetError(c,REDIS_ERR_OTHER,errorbuf); cleanupSSL( &(c->ssl) ); return REDIS_ERR; } } // Now we need to do the SSL handshake, so we can communicate. if (BIO_do_handshake(bio) <= 0) { if( BIO_should_retry( bio ) ) { // We need to retry. } else { char errorbuf[1024]; __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: handshake failure"); ERR_error_string(1024,errorbuf); __redisSetError(c,REDIS_ERR_OTHER,errorbuf); cleanupSSL( &(c->ssl) ); return REDIS_ERR; } } else { // handshake is done... break; } if( has_timeout ) { // Do select and seelct on it int result; int fd = BIO_get_fd( bio, NULL ); struct timeval time_left; if (has_timeout) { time_left = subtractTimeval( *timeout, elapsed_time ); } fd_set readset, writeset; FD_ZERO(&readset); FD_SET(fd, &readset); FD_ZERO(&writeset); FD_SET(fd, &writeset); do { result = select( fd+1, &readset, &writeset, NULL, &time_left); } while( result == -1 && errno == EINTR ); } } long verify_result = SSL_get_verify_result(ssl); if( verify_result == X509_V_OK) { X509* peerCertificate = SSL_get_peer_certificate(ssl); char commonName [512]; X509_NAME * name = X509_get_subject_name(peerCertificate); X509_NAME_get_text_by_NID(name, NID_commonName, commonName, 512); // TODO: Add a redis config parameter for the common name to check for. // Since Redis connections are generally done with an IP address directly, // we can't just assume that the name we get on the addr is an actual name. // // if(strcasecmp(commonName, "BradBroerman") != 0) { // __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Error validating cert common name.\n\n" ); // cleanupSSL( &(c->ssl) ); // return REDIS_ERR; } else { char errorbuf[1024]; __redisSetError(c,REDIS_ERR_OTHER,"SSL Error: Error retrieving peer certificate.\n" ); ERR_error_string(1024,errorbuf); __redisSetError(c,REDIS_ERR_OTHER,errorbuf); cleanupSSL( &(c->ssl) ); return REDIS_ERR; } BIO_set_nbio(bio,is_nonblocking); return REDIS_OK; }