пятница, 25 апреля 2014 г.

Простой WiFi-анализатор

При огранизации соединения между несколькими компьютерами посредством Wi-Fi часто возникает необходимость оценить качество приёма в различных точках помещения. А если говорить об организации Wi-Fi-моста и/или настройке направленных антенн то необходимо ещё учитывать соседние Wi-Fi-точки.
Полноценное исследование эфира требует достаточно высоких затрат, которые обычно не оправданы. Чаще всего просто нужен сканер эфира, который показывает доступные точки и качество их сигнала. Для смартфонов таких приложений существует великое множество, а вот под Linux кроме громоздкого Kismet ничего подходящего найти не удалось. В итоге оказалось проще написать свой инструмент.
Основная идея при написании своего инструмента заключалась в том, что вся необходимая информация содержится в выводе команды:
iwlist wlan0 scan 
Но вывод этой команды не удобен для восприятия. В итоге было решено написать скрипт, который в бесконечном цикле будет запускать эту команду, парсить её вывод и отображать результат. Листинг полученного скрипта:
#!/usr/bin/perl

use strict;
use warnings;
use diagnostics;

use Math::Round;

# Если число аргументов не равно единице
if (@ARGV != 1) {
        # Печатаем краткую справку
        print "Usage:\n";
        print "  $0 ifname\n\n";
        # Завершаем работу
        exit;
}

# Будем использовать полученные данные для очистки экрана в дальнейшем
my $clear_screen = `clear`;


# Получаем имя интерфейса
my $ifname = shift;

while (1) {
        # Сканируем эфир
        my $scan_result = `iwlist $ifname scan`;
        # Получаем код ошибки
        my $error_code = $?;
        # Завершаем работу если что-то не так
        exit if $error_code;
        # Наскорую руку разбиваем результат сканирования на элементы
        my @scan_results_tmp = split /Cell \d+/is, $scan_result;
        # Начинаем полноценный разбор
        my @scan_results = ();
        # Перебираем элементы
        foreach my $hotspot_line (@scan_results_tmp) {
                # Если нет номера канала значит это мусор, который надо пропустить
                next if $hotspot_line !~ m{Channel\:}is;
                # Строим элемент
                my %hotspot = ();
                # Номер канала
                $hotspot{'Channel'} = $hotspot_line;
                $hotspot{'Channel'} =~ s{^.+Channel\:(\d+).+$}{$1}is;
                # SSID
                $hotspot{'SSID'} = $hotspot_line;
                $hotspot{'SSID'} =~ s{^.+ESSID\:"((.+?)?)".+$}{$1}is;
                # Наличие шифрований
                $hotspot{'Crypted'} = $hotspot_line;
                $hotspot{'Crypted'} =~ s{^.+Encryption key:(\w+?)\s.+$}{$1}is;
                # Уровень сигнала. И сразу переводим его в проценты
                my $q1 = $hotspot_line;
                $q1 =~ s{^.+Quality=(\d+)/\d+.+$}{$1}is;
                my $q2 = $hotspot_line;
                $q2 =~ s{^.+Quality=\d+/(\d+).+$}{$1}is;
                $hotspot{'Quality'} = round($q1 * 100 / $q2);
                push @scan_results, \%hotspot;
        }
        # Сортируем
        @scan_results = sort { sprintf("%02d", $a->{Channel}) cmp sprintf("%02d", $b->{Channel}) } @scan_results;

        # Очищаем экран
        print $clear_screen;
        # Печатаем данные
        print sprintf("  % 2.2s [% 9.9s] [% 32.32s] [% 7.7s]\n", "Ch", "Quality", "SSID", "Crypt");
        print sprintf('%1$s'x61 . "\n", "-");
        foreach my $hotspot (@scan_results) {
                print sprintf("  %02d [% 8d%%] [% 32.32s] [% 7.7s]\n",
                        $hotspot->{Channel},
                        $hotspot->{Quality},
                        $hotspot->{SSID},
                        $hotspot->{Crypted});
        }
        # Делаем паузу
        sleep 1;
}

Скрипт принимает один единственный параметр: имя интерфейса, на котором надо осуществлять мониторинг. Например так:
./wifiscan.pl wlan2
Вывод скрипта выглядит примерно так:
  Ch [  Quality] [                            SSID] [  Crypt]
-------------------------------------------------------------
  01 [      93%] [                   Yuldash House] [     on]
  02 [      94%] [                        serr_dom] [     on]
  04 [      94%] [                   home-of-moose] [     on]
  06 [      93%] [                wifi.tattele.com] [    off]
  06 [      93%] [                     KEENETIC 4G] [     on]
  06 [      94%] [          MTS_telefon_2-65-60-30] [     on]
  06 [      94%] [                        home.net] [     on]
  08 [      93%] [                            YOTA] [     on]
  10 [      93%] [                       Estucador] [     on]
  10 [      93%] [                    DIR-300NRUB6] [     on]

Если нужны будут какие-то другие параметры то их получение и отображение легко дописать в скрипт. Автор использовал этот скрипт при эксприментах с баночными антеннами и с помощью этого скрипта смог найти нужное направление на необходимую точку.
На этом всё. Приятной работы!

P.S. Если не взлетело с такой ошибкой 
       Can't locate Math/Round.pm

         На Debian/Ubuntu этот модуль есть в пакете libmath-round-perl.

Взято здесь.

Комментариев нет: