2013-02-21 10 views
10

Tworzę oprogramowanie dla systemu Ubuntu Linux, które musi łączyć się z punktem dostępu Wi-Fi. Sieć Wi-Fi nie jest wstępnie zdefiniowana i może się zmieniać kilka razy podczas pojedynczego uruchomienia oprogramowania (użytkownik jest tym, który zamawia zmianę). Chodzi o to, że biorąc pod uwagę zbiór identyfikatorów SSID i ich hasła WPA lub WEP, oprogramowanie powinno być w stanie przełączać się pomiędzy sieciami, bez potrzeby zmiany jakichkolwiek plików konfiguracyjnych w dowolnym miejscu w systemie.Podłączanie do chronionej sieci Wi-Fi z Python na Linuksie

Ogromnym problemem, jak się wydaje, jest przekazanie hasła do połączenia. Oto, z czym dotychczas współpracowałem:

  • Ubuntu 12.10 maszyna wyposażona w klucz WiFi.
  • Python, który uruchamia oprogramowanie, a które zostaną wykorzystane do żądania połączenia
  • connman 0,79
  • wpa_supplicant v1.0
  • d-bus

Na początku myślałem, że byłoby możliwe przekazanie hasła do connmana przez d-bus, ale ani ta wersja programu connman, ani też 1.11 nie ujawniają żadnej metody. Wtedy dowiedziałem się, że można zrzucić plik service_<SSID>.conf do katalogu /var/lib/connman/. Zawartość pliku jest bardzo prosty i wygląda następująco:

[service_SSID] 
Type=wifi 
Name=Network-SSID 
Passphrase=here-goes-the-passphrase 

Po utworzeniu tego pliku, podłączenie do sieci wymaga prostego połączenia do net.connman.Service.Connect (metoda) w odpowiedniej usługi. Problem polega na tym, że program connman nie przeanalizuje pliku konfiguracyjnego, dopóki nie zostanie ponownie uruchomiony. Wymaga to przywilejów sudo, dodatkowego czasu i stwarza ryzyko dla wszystkich "rzeczy, które mogą pójść źle teraz". Wtedy pomyślałem, że hasło można jakoś przekazać do interfejsu API d-bus wpa_supplicant, ale nie udało mi się znaleźć niczego.

Wyszukiwania Google również mnie zawiodły. To tak, jakby nikt wcześniej nie próbował tego robić.

Komenda sudo iwconfig wlan0 essid <SSID> key s:<PASSPHRASE> powoduje błąd SET failed on device wlan0 ; Invalid argument.. Poza tym wymaga sudo, którego chciałbym uniknąć.

Próbowałem dowiedzieć się, w jaki sposób program wpa_gui robi magię. Przede wszystkim odkryłem, że to również wymaga sudo, i że wysyła kilka poleceń bezpośrednio do /var/run/wpa_supplicant/wlan0. Replikowanie tego zachowania byłoby dla mnie ostatecznością, jeśli nie znajdę niczego prostszego.

Pytanie brzmi następująco: Jak korzystać z Pythona, aby połączyć się z siecią WiFi chronioną WEP/WPA?
Zastanawiam się również, czy używanie connmana jest dobrym podejściem i jeśli nie powinienem powrócić do Menedżera sieci, który jest domyślny w Ubuntu.

Odpowiedz

5

Pokazuje to, jak to zrobić w przypadku WPA.

Przede wszystkim połącz rowek i użyj NetworkManager. Poniższy skrypt przykładowy pokazuje, jak włączyć obsługę sieci bezprzewodowej, sprawdzić, czy sieć z danym identyfikatorem SSID jest dostępny, połączyć się z tym identyfikatorem SSID za pomocą hasła WPA, a następnie odłączyć się od sieci i wyłączyć połączenie bezprzewodowe. Jestem prawie pewien, że ten skrypt można poprawić, ale obecna wersja służy jako przykład wystarczy:

#!/usr/bin/python 

# This script shows how to connect to a WPA protected WiFi network 
# by communicating through D-Bus to NetworkManager 0.9. 
# 
# Reference URLs: 
# http://projects.gnome.org/NetworkManager/developers/ 
# http://projects.gnome.org/NetworkManager/developers/settings-spec-08.html 

import dbus 
import time 

SEEKED_SSID = "skynet" 
SEEKED_PASSPHRASE = "qwertyuiop" 

if __name__ == "__main__": 
    bus = dbus.SystemBus() 
    # Obtain handles to manager objects. 
    manager_bus_object = bus.get_object("org.freedesktop.NetworkManager", 
             "/org/freedesktop/NetworkManager") 
    manager = dbus.Interface(manager_bus_object, 
          "org.freedesktop.NetworkManager") 
    manager_props = dbus.Interface(manager_bus_object, 
            "org.freedesktop.DBus.Properties") 

    # Enable Wireless. If Wireless is already enabled, this does nothing. 
    was_wifi_enabled = manager_props.Get("org.freedesktop.NetworkManager", 
             "WirelessEnabled") 
    if not was_wifi_enabled: 
     print "Enabling WiFi and sleeping for 10 seconds ..." 
     manager_props.Set("org.freedesktop.NetworkManager", "WirelessEnabled", 
          True) 
     # Give the WiFi adapter some time to scan for APs. This is absolutely 
     # the wrong way to do it, and the program should listen for 
     # AccessPointAdded() signals, but it will do. 
     time.sleep(10) 

    # Get path to the 'wlan0' device. If you're uncertain whether your WiFi 
    # device is wlan0 or something else, you may utilize manager.GetDevices() 
    # method to obtain a list of all devices, and then iterate over these 
    # devices to check if DeviceType property equals NM_DEVICE_TYPE_WIFI (2). 
    device_path = manager.GetDeviceByIpIface("wlan0") 
    print "wlan0 path: ", device_path 

    # Connect to the device's Wireless interface and obtain list of access 
    # points. 
    device = dbus.Interface(bus.get_object("org.freedesktop.NetworkManager", 
              device_path), 
          "org.freedesktop.NetworkManager.Device.Wireless") 
    accesspoints_paths_list = device.GetAccessPoints() 

    # Identify our access point. We do this by comparing our desired SSID 
    # to the SSID reported by the AP. 
    our_ap_path = None 
    for ap_path in accesspoints_paths_list: 
     ap_props = dbus.Interface(
      bus.get_object("org.freedesktop.NetworkManager", ap_path), 
      "org.freedesktop.DBus.Properties") 
     ap_ssid = ap_props.Get("org.freedesktop.NetworkManager.AccessPoint", 
           "Ssid") 
     # Returned SSID is a list of ASCII values. Let's convert it to a proper 
     # string. 
     str_ap_ssid = "".join(chr(i) for i in ap_ssid) 
     print ap_path, ": SSID =", str_ap_ssid 
     if str_ap_ssid == SEEKED_SSID: 
      our_ap_path = ap_path 
      break 

    if not our_ap_path: 
     print "AP not found :(" 
     exit(2) 
    print "Our AP: ", our_ap_path 

    # At this point we have all the data we need. Let's prepare our connection 
    # parameters so that we can tell the NetworkManager what is the passphrase. 
    connection_params = { 
     "802-11-wireless": { 
      "security": "802-11-wireless-security", 
     }, 
     "802-11-wireless-security": { 
      "key-mgmt": "wpa-psk", 
      "psk": SEEKED_PASSPHRASE 
     }, 
    } 

    # Establish the connection. 
    settings_path, connection_path = manager.AddAndActivateConnection(
     connection_params, device_path, our_ap_path) 
    print "settings_path =", settings_path 
    print "connection_path =", connection_path 

    # Wait until connection is established. This may take a few seconds. 
    NM_ACTIVE_CONNECTION_STATE_ACTIVATED = 2 
    print """Waiting for connection to reach """ \ 
      """NM_ACTIVE_CONNECTION_STATE_ACTIVATED state ...""" 
    connection_props = dbus.Interface(
     bus.get_object("org.freedesktop.NetworkManager", connection_path), 
     "org.freedesktop.DBus.Properties") 
    state = 0 
    while True: 
     # Loop forever until desired state is detected. 
     # 
     # A timeout should be implemented here, otherwise the program will 
     # get stuck if connection fails. 
     # 
     # IF PASSWORD IS BAD, NETWORK MANAGER WILL DISPLAY A QUERY DIALOG! 
     # This is something that should be avoided, but I don't know how, yet. 
     # 
     # Also, if connection is disconnected at this point, the Get() 
     # method will raise an org.freedesktop.DBus.Error.UnknownMethod 
     # exception. This should also be anticipated. 
     state = connection_props.Get(
      "org.freedesktop.NetworkManager.Connection.Active", "State") 
     if state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED: 
      break 
     time.sleep(0.001) 
    print "Connection established!" 

    # 
    # Connection is established. Do whatever is necessary. 
    # ... 
    # 
    print "Sleeping for 5 seconds ..." 
    time.sleep(5) 
    print "Disconnecting ..." 

    # Clean up: disconnect and delete connection settings. If program crashes 
    # before this point is reached then connection settings will be stored 
    # forever. 
    # Some pre-init cleanup feature should be devised to deal with this problem, 
    # but this is an issue for another topic. 
    manager.DeactivateConnection(connection_path) 
    settings = dbus.Interface(
     bus.get_object("org.freedesktop.NetworkManager", settings_path), 
     "org.freedesktop.NetworkManager.Settings.Connection") 
    settings.Delete() 

    # Disable Wireless (optional step) 
    if not was_wifi_enabled: 
     manager_props.Set("org.freedesktop.NetworkManager", "WirelessEnabled", 
          False) 
    print "DONE!" 
    exit(0) 
+0

Czy możesz mi powiedzieć, co byłoby DICT zabezpieczenie WEP? – Natim

+0

Niestety, nigdy nie potrzebowałem sprawdzać, jak to zrobić z WEP, więc nie mogę ci tu pomóc. Nie wyobrażam sobie jednak, że byłoby inaczej. – ZalewaPL

+3

@ZalewaPL Wiem, że minęło już prawie rok od ostatniej odpowiedzi, ale według tego [link] (https://developer.gnome.org/NetworkManager/unstable/spec.html#org.freedesktop.NetworkManager) nie nawet trzeba wprowadzić rodzaj zabezpieczenia (WEP, WPA2, itp.), wystarczy podać hasło (psk). Cytowanie pierwszego parametru AddAndActivateConnection: 'Ustawienia i właściwości połączenia; jeśli niepełne brakujące ustawienia zostaną automatycznie zakończone przy użyciu danego urządzenia i określonego obiektu. "Usunąłem więc ** security ** i ** key-mgmt ** from ** connection_params ** i został on pomyślnie połączony. :) – kv1dr