Ejemplo n.º 1
0
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 );
}
Ejemplo n.º 2
0
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;
}