Nischay-Pro / wifi-heat-mapper

whm also known as wifi-heat-mapper is a Python library for benchmarking Wi-Fi networks and gather useful metrics that can be converted into meaningful easy-to-understand heatmaps.
GNU General Public License v3.0
213 stars 21 forks source link

Fix "unable to parse iw" Error #8

Closed desecnd closed 10 months ago

desecnd commented 11 months ago

This PR aims to solve the problem described in #6

Problem

Following is example of executing whm bootstrap which currently results in wifi_heat_mapper.misc.ParseError. (Ignore the launch.py - the only thing it does is calling wifi_heat_mapper.main:driver())

python3 launcher.py bootstrap
Detecting benchmarking capabilities.
Supported Modes: iperf3
Please enter the target wireless interface to run benchmark on (example: wlan0): wlan0
Traceback (most recent call last):
  File "/home/.../launcher.py", line 4, in <module>
    driver()
  File "/home/.../wifi_heat_mapper/main.py", line 81, in driver
    start_config(args.config_file)
  File "/home/.../wifi_heat_mapper/debugger.py", line 12, in new_func
    return func(*args, **kwargs)
  File "/home/.../wifi_heat_mapper/config.py", line 228, in start_config
    ssid = process_iw(target_interface)["ssid"]
  File "/home/.../wifi_heat_mapper/misc.py", line 197, in process_iw
    raise ParseError("Unable to parse iw.") from None
wifi_heat_mapper.misc.ParseError: Unable to parse iw.

As described in the logs, there is a problem with parsing ssid:, from iw <wif> info command. The exact line where the problem lies is misc.py:183:

        results["channel_frequency"] = int(tmp[1].replace("(", ""))
>       results["ssid"] = re.findall(r"(?<=ssid )(.*)", iw_info)[0]
        iw_info = get_application_output(["iw {0} station dump".format(target_interface)],

This expression raises IndexError which is catched at the end of the function.

Cause

The problem is probably related to update of the generated output by iw tool. Current version installed on my OS is 5.9 (iw --version).

Example output:

$ iw wlan0 info
Interface wlan0
        ifindex 3
        wdev 0x1
        addr 50:eb:71:be:37:fa
        type managed
        wiphy 0
        channel 6 (2437 MHz), width: 20 MHz, center1: 2437 MHz
        txpower 22.00 dBm
        multicast TXQ:
                qsz-byt qsz-pkt flows   drops   marks   overlmt hashcol tx-bytes        tx-packets
                0       0       0       0       0       0       0       0               0

As we can see there is no ssid field. Currently info about SSID can be obtained using iw <wif> link cmd. Example:

$ iw wlan0 link
Connected to aa:aa:aa:aa:aa:aa (on wlan0)
        SSID: WIFI-HEATMAPS-TEST
        freq: 2437
        RX: 3378 bytes (21 packets)
        TX: 2870 bytes (26 packets)
        signal: -15 dBm
        rx bitrate: 52.0 MBit/s MCS 5
        tx bitrate: 65.0 MBit/s MCS 7

        bss flags:      short-slot-time
        dtim period:    2
        beacon int:     100

Solution

The simplest solution is to use iw <wif> link output to obtain the SSID. In this PR this is implemented by first checking iw <wif> info output and by catching IndexError. If exception is raised we can use the same function get_application_output() to get output from iw <wif> link. Information about trying to run iw <wif> link is logged to the user. This approach has following benefits:

$ python3 launcher.py bootstrap 
Detecting benchmarking capabilities.
Supported Modes: iperf3
Please enter the target wireless interface to run benchmark on (example: wlan0): wlan0
iw wlan0 info command cannot find required SSID. Trying iw wlan0 link
You are connected to WIFI-HEATMAPS-TEST. Is this the interface you want to benchmark on? (y/N) y
How many times do you want to repeat benchmarking? 3
Nischay-Pro commented 10 months ago

Hey! Nice work and thanks for the PR. On initial run I can verify it is running on my laptop without any issues.

If you can submit a commit to fix the linting, I think we can merge this PR.

desecnd commented 10 months ago

Sure! I missed the .flake8 file, my mistake, will fix it right away : )