Wi-Fi və bir çox digər abbreviaturalar. Android tətbiqində Wi-Fi qovşaqları haqqında məlumatları şişmədən necə əldə etmək olar

Bir gün mənə Android proqramlarından Wi-Fi şəbəkələrini skan etməli və giriş nöqtələri haqqında ətraflı məlumat almalı oldum.

Burada bir sıra çətinliklərlə üzləşməli olduq: off.Android sənədləri təsvir edilən siniflərin bir çoxu köhnəldi (API səviyyəsi > 26), bu da özündə əksini tapmadı; sənədlərdə bəzi şeylərin təsviri minimaldır (məsələn, sinifin imkanları sahəsi ScanResult yazı zamanı çoxlu vacib məlumatları ehtiva etsə də, demək olar ki, heç bir şey təsvir olunmur). Üçüncü çətinlik, Wi-Fi-a ilk dəfə yaxınlaşdığınız zaman nəzəriyyəni oxumaq və routeri localhost vasitəsilə qurmaqdan başqa, ayrı-ayrılıqda başa düşülən görünən bir sıra ixtisarlarla məşğul olmağınızla bağlı ola bilər. Lakin onları necə əlaqələndirmək və strukturlaşdırmaq aydın olmaya bilər (mühakimə subyektivdir və əvvəlki təcrübədən asılıdır).

Bu məqalədə NDK, sındırmalar olmadan, lakin yalnız Android API-dən istifadə etməklə Android kodundan Wi-Fi mühiti haqqında hərtərəfli məlumatların necə əldə ediləcəyi müzakirə olunur və onu necə şərh edəcəyinizi başa düşülür.

Gecikməyək və kod yazmağa başlayaq.

1. Layihə yaradın

Bu qeyd bir dəfədən çox Android layihəsi yaradanlar üçün nəzərdə tutulub, ona görə də bu elementin təfərrüatlarını buraxırıq. Aşağıdakı kod Kotlin-də təqdim olunacaq, minSdkVersion=23.

2. Giriş icazələri

Tətbiqdən Wi-Fi ilə işləmək üçün istifadəçidən bir neçə icazə almalısınız. Uyğun olaraq sənədlər, 8.0-dan sonra OS versiyaları olan cihazlarda şəbəkəni skan etmək üçün şəbəkə mühitinin vəziyyətinə baxmaqdan əlavə, ya cihazın Wi-Fi modulunun vəziyyətini dəyişdirmək üçün giriş, ya da koordinatlara (təxmini) giriş lazımdır. və ya dəqiq). 9.0 versiyasından başlayaraq siz istifadəçiyə hər ikisi üçün müraciət etməli, həmçinin istifadəçidən məkan xidmətlərini aktivləşdirməsini açıq şəkildə tələb etməlisiniz. İstifadəçiyə bunun Google-un şıltaqlığı olduğunu və ona casusluq etmək istəyimiz olmadığını cəsarətlə izah etməyi unutmayın :)

Beləliklə, AndroidManifest.xml-də biz əlavə edəcəyik:

    <uses-permission android_name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android_name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android_name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android_name="android.permission.ACCESS_FINE_LOCATION"/>

Və cari Fəaliyyətə keçid olan kodda:

import android.app.Activity
import android.content.Context
import android.location.LocationManager
import androidx.core.app.ActivityCompat

....

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
            makeEnableLocationServices(activity.applicationContext)
        } else {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.CHANGE_WIFI_STATE),
                1
            )
        }

    /* включает экран включения службы по определению местоположения */
    fun makeEnableLocationServices(context: Context) {
        // TODO: перед вызовом этой функции надо рассказать пользователю, зачем Вам доступ к местоположению
        val lm: LocationManager =
            context.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager

        val gpsEnabled: Boolean = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
        val networkEnabled: Boolean = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);

        if (!gpsEnabled && !networkEnabled) {
            context.startActivity(Intent(ACTION_LOCATION_SOURCE_SETTINGS));
        }
    }

3. BroadcastReceiver yaradın və Wi-Fi şəbəkə mühitinin skan edilməsi ilə bağlı məlumat yeniləmə tədbirlərinə abunə olun

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager

val wifiScanReceiver = object : BroadcastReceiver() {

  override fun onReceive(context: Context, intent: Intent) {
    val success = intent.getBooleanExtra(WifiManager.EXTRA_RESULTS_UPDATED, false)
    if (success) {
      scanSuccess()
    } 
  }
}

val intentFilter = IntentFilter()
/* подписываемся на сообщения о получении новых результатов сканирования */
intentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)
context.registerReceiver(wifiScanReceiver, intentFilter)

val success = wifiManager.startScan()
if (!success) {
  /* что-то не получилось при запуске сканирования, проверьте выданые разрешения */
}

....

private fun scanSuccess() {
 /* вот они, результаты сканирования */
  val results: List<ScanResult> = wifiManager.scanResults
}

Sənədlərdəki WiFiManager.startScan metodu API versiyası 28-dən bəri depricated kimi qeyd olunub, lakin söndürülüb. yol istifadə etməyi təklif edir.

Ümumilikdə obyektlərin siyahısını aldıq ScanResult.

4. ScanResult-a baxın və şərtləri anlayın

Gəlin bu sinfin bəzi sahələrinə baxaq və onların nə demək olduğunu təsvir edək:

SSID — Xidmət Dəsti İdentifikatoru şəbəkənin adıdır

BSSİD – Əsas Xidmət Seti İdentifikatoru – Şəbəkə adapterinin MAC ünvanı (Wi-Fi nöqtəsi)

səviyyə — Qəbul edilmiş siqnal gücü göstəricisi [dBm (Rus dBm) — Desibel, istinad gücü 1 mVt.] — Qəbul edilmiş siqnal gücünün göstəricisi. 0-dan -100-ə qədər qiymət alır, 0-dan nə qədər uzaq olsa, Wi-Fi nöqtəsindən cihazınıza gedən yolda bir o qədər çox siqnal gücü itirilir. Daha ətraflı, məsələn, burada tapa bilərsiniz Vikipediya. Burada sizə Android sinifindən istifadə etdiyini söyləyəcəyəm WifiManager seçdiyiniz addımda siqnal səviyyəsini əladan dəhşətə qədər miqyasda kalibrləyə bilərsiniz:

        val wifiManager = context.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
        val numberOfLevels = 5
        val level = WifiManager.calculateSignalLevel(level, numberOfLevels)

tezliyi — Wi-Fi nöqtəsinin işləmə tezliyi [Hz]. Tezliyin özünə əlavə olaraq, sözdə kanalla maraqlana bilərsiniz. Hər bir nöqtənin öz əməliyyat təmizliyi var. Yazı zamanı Wi-Fi nöqtələrinin ən populyar diapazonu 2.4 GHz-dir. Amma, daha dəqiq desək, nöqtə məlumatı adı çəkilən birinə yaxın nömrələnmiş tezlikdə telefonunuza ötürür. Kanalların sayı və müvafiq tezliklər standartlaşdırılmış. Bu, yaxınlıqdakı nöqtələrin müxtəlif tezliklərdə işləməsi və bununla da bir-birinə müdaxilə etməməsi və ötürmə sürətini və keyfiyyətini qarşılıqlı şəkildə azaltmaması üçün edilir. Bu halda, nöqtələr bir tezlikdə deyil, bir sıra tezliklərdə işləyir (parametr kanal eni), kanal eni adlanır. Yəni, bitişik (və yalnız bitişik deyil, hətta özlərindən 3) kanallarda işləyən nöqtələr bir-birinə müdaxilə edir. 2.4 və 5 Ghz tezliyi olan nöqtələr üçün tezlik dəyərindən kanal nömrəsini hesablamağa imkan verən bu sadə kodu faydalı tapa bilərsiniz:


    /* по частоте определяем номер канала */
    val channel: Int
        get() {
            return if (frequency in 2412..2484) {
                (frequency - 2412) / 5 + 1
            } else if (frequency in 5170..5825) {
                (frequency - 5170) / 5 + 34
            } else {
                -1
            }
        }

imkanları - təhlil üçün ən maraqlı sahə, onunla işləmək çox vaxt tələb edir. Burada nöqtənin “imkanları” sətirdə yazılıb. Bu halda, sənədlərdə simli şərhin təfərrüatlarını axtarmaq lazım deyil. Bu xəttdə ola biləcək bəzi nümunələr bunlardır:

[WPA-PSK-TKIP+CCMP][WPA2-PSK-TKIP+CCMP][WPS][ESS]
[WPA2-PSK-CCMP][ESS]
[WPA2-PSK-CCMP+TKIP][ESS]
[WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][ESS]
[ESS][WPS]

5. İxtisarlar və təhlil imkanlarını başa düşmək

Qeyd etmək lazımdır ki, android.net.wifi.* paketinin sinifləri Linux yardım proqramı tərəfindən başlıq altında istifadə olunur. wpa_supplicant və imkanlar sahəsində çıxış nəticəsi skan edərkən bayraqlar sahəsinin surətidir.

Biz ardıcıl hərəkət edəcəyik. Əvvəlcə mötərizə daxilində elementlərin “-” işarəsi ilə ayrıldığı formatın çıxışını nəzərdən keçirək:

[WPA-PSK-TKIP+CCMP]
[WPA2-PSK-CCMP]

Birinci məna sözdə təsvir edir. autentifikasiya üsulu. Yəni, giriş nöqtəsinin özünün istifadəsinə icazə verməsi və faydalı yükü necə şifrələməsi üçün cihaz və giriş nöqtəsi hansı hərəkətlərin ardıcıllığını yerinə yetirməlidir. Bu yazını yazarkən ən çox yayılmış seçimlər WPA və WPA2-dir, bunlarda hər bir cihaz birbaşa və ya sözdə qoşulmuşdur. RADIUS serveri (WPA-Enterprice) şifrələnmiş kanal üzərindən parol təmin edir. Çox güman ki, evinizdəki giriş nöqtəsi bu sxemə uyğun bir əlaqə təmin edir. İkinci versiya ilə birincisi arasındakı fərq ondan ibarətdir ki, onun daha güclü şifrəsi var: təhlükəsiz olmayan TKIP-ə qarşı AES. Daha mürəkkəb və təkmil olan WPA3 də tədricən tətbiq olunur. Teorik olaraq, CCKM (Cisco Mərkəzləşdirilmiş Açar İdarəetmə) müəssisə həlli ilə bir seçim ola bilər, lakin mən buna heç vaxt rast gəlməmişəm.

Giriş nöqtəsi MAC ünvanı ilə autentifikasiya etmək üçün konfiqurasiya edilmiş ola bilər. Yaxud, əgər giriş nöqtəsi köhnəlmiş WEP alqoritmindən istifadə edərək məlumat verirsə, əslində heç bir identifikasiya yoxdur (burada gizli açar şifrələmə açarıdır). Bu cür variantları DİGƏR kimi təsnif edirik.
Gizli Captive Portal Detection ilə ictimai Wi-Fi-da məşhur olan bir üsul da var - brauzer vasitəsilə autentifikasiya sorğusu. Belə giriş nöqtələri skanerə açıq görünür (fiziki əlaqə baxımından bunlardır). Buna görə də biz onları AÇIQ kimi təsnif edirik.

İkinci dəyər kimi qeyd edilə bilər əsas idarəetmə alqoritmi. Bu, yuxarıda təsvir edilən autentifikasiya metodunun parametridir. Şifrələmə açarlarının necə dəyişdirildiyi haqqında danışır. Mümkün variantları nəzərdən keçirək. EAP - qeyd olunan WPA-Enterprice-də istifadə olunur, daxil edilmiş autentifikasiya məlumatlarını yoxlamaq üçün verilənlər bazasından istifadə edir. SAE - qabaqcıl WPA3-də istifadə olunur, kobud gücə daha davamlıdır. PSK - ən çox yayılmış seçim, parolun daxil edilməsini və şifrələnmiş formada ötürülməsini nəzərdə tutur. IEEE8021X - beynəlxalq standarta uyğun (WPA ailəsi tərəfindən dəstəklənəndən fərqli). OWE (Opportunistik Simsiz Şifrələmə) AÇIQ kimi təsnif etdiyimiz nöqtələr üçün IEEE 802.11 standartının genişləndirilməsidir. OWE qorunmayan şəbəkə üzərindən ötürülən məlumatların təhlükəsizliyini şifrələməklə təmin edir. Heç bir giriş düymələri olmadıqda bir seçim də mümkündür, gəlin bu seçimi NONE adlandıraq.

Üçüncü parametr sözdə olandır. şifrələmə sxemləri — ötürülən məlumatları qorumaq üçün şifrənin necə dəqiq istifadə edildiyi. Variantları sadalayaq. WEP - RC4 axın şifrəsindən istifadə edir, gizli açar müasir kriptoqrafiya dünyasında qəbuledilməz hesab edilən şifrələmə açarıdır. TKIP - WPA-da, CKIP - WPA2-də istifadə olunur. TKIP+CKIP - geriyə uyğunluq üçün WPA və WPA2-yə qadir olan nöqtələrdə göstərilə bilər.

Üç elementin əvəzinə tənha bir WEP işarəsi tapa bilərsiniz:

[WEP]

Yuxarıda müzakirə etdiyimiz kimi, bu, mövcud olmayan açarlardan istifadə alqoritmini və standart olaraq eyni olan şifrələmə üsulunu təyin etməmək üçün kifayətdir.

İndi bu mötərizəni nəzərdən keçirin:

[ESS]

O Wi-Fi iş rejimi və ya Wi-Fi şəbəkə topologiyası. Siz BSS (Basic Service Set) rejimi ilə qarşılaşa bilərsiniz - qoşulmuş cihazların əlaqə saxladığı bir giriş nöqtəsi olduqda. Yerli şəbəkələrdə tapıla bilər. Bir qayda olaraq, müxtəlif yerli şəbəkələrdən cihazları birləşdirmək üçün giriş nöqtələri lazımdır, buna görə də onlar Genişləndirilmiş Xidmət Dəstlərinin bir hissəsidir - ESS. IBSSs (Müstəqil Əsas Xidmət Setləri) növü cihazın Peer-to-Peer şəbəkəsinin bir hissəsi olduğunu göstərir.

Siz həmçinin WPS bayrağını görə bilərsiniz:

[WPS]

WPS (Wi-Fi Protected Setup) Wi-Fi şəbəkəsinin yarı avtomatik işə salınması üçün protokoldur. Başlamaq üçün istifadəçi ya 8 simvoldan ibarət parol daxil edir, ya da marşrutlaşdırıcıda düyməni sıxır. Əgər giriş nöqtəniz birinci tipdirsə və bu qeyd xanası giriş nöqtənizin adının yanında görünürsə, admin panelinə keçməyiniz və WPS girişini deaktiv etməyiniz tövsiyə olunur. Fakt budur ki, tez-tez 8 rəqəmli PİN-i MAC ünvanı ilə tapmaq olar və ya onu yaxın vaxtda sıralamaq olar ki, kimsə vicdansızlıqla istifadə edə bilər.

6. Model və təhlil funksiyası yaradın

Yuxarıda tapdıqlarımıza əsasən, məlumat siniflərindən istifadə edərək baş verənləri təsvir edəcəyik:

/* схема аутентификации */
enum class AuthMethod {
    WPA3,
    WPA2,
    WPA, // Wi-Fi Protected Access
    OTHER, // включает в себя Shared Key Authentication и др. использующие mac-address-based и WEP
    CCKM, // Cisco
    OPEN // Open Authentication. Может быть со скрытым Captive Portal Detection - запрос аутентификации через браузер
}

/* алгоритм ввода ключей */
enum class KeyManagementAlgorithm {
    IEEE8021X, // по стандарту
    EAP, // Extensible Authentication Protocol, расширяемый протокол аутентификации
    PSK, // Pre-Shared Key — каждый узел вводит пароль для доступа к сети
    WEP, // в WEP пароль является ключом шифрования (No auth key)
    SAE, // Simultaneous Authentication of Equals - может быть в WPA3
    OWE, // Opportunistic Wireless Encryption - в роутерах новых поколений, публичных сетях типа OPEN
    NONE // может быть без шифрования в OPEN, OTHER
}

/* метод шифрования */
enum class CipherMethod {
    WEP, // Wired Equivalent Privacy, Аналог шифрования трафика в проводных сетях
    TKIP, // Temporal Key Integrity Protocol
    CCMP, // Counter Mode with Cipher Block Chaining Message Authentication Code Protocol,
    // протокол блочного шифрования с кодом аутентичности сообщения и режимом сцепления блоков и счетчика
    // на основе AES
    NONE // может быть без шифрования в OPEN, OTHER
}

/* набор методов шифрования и протоколов, по которым может работать точка */
data class Capability(
    var authScheme: AuthMethod? = null,
    var keyManagementAlgorithm: KeyManagementAlgorithm? = null,
    var cipherMethod: CipherMethod? = null
)

/* Режим работы WiFi (или топология сетей WiFi) */
enum class TopologyMode {
    IBSS, // Эпизодическая сеть (Ad-Hoc или IBSS – Independent Basic Service Set).
    BSS, // Основная зона обслуживания Basic Service Set (BSS) или Infrastructure Mode.
    ESS // Расширенная зона обслуживания ESS – Extended Service Set.
}

İndi imkanlar sahəsini təhlil edəcək bir funksiya yazaq:


private fun parseCapabilities(capabilitiesString: String): List < Capability > {
    val capabilities: List < Capability > = capabilitiesString
        .splitByBrackets()
        .filter {
            !it.isTopology() && !it.isWps()
        }
        .flatMap {
            parseCapability(it)
        }
    return
        if (!capabilities.isEmpty()) {
            capabilities
        } else {
            listOf(Capability(AuthMethod.OPEN, KeyManagementAlgorithm.NONE, CipherMethod.NONE))
        }
}

private fun parseCapability(part: String): List < Capability > {
    if (part.contains("WEP")) {
        return listOf(Capability(
            AuthMethod.OTHER,
            KeyManagementAlgorithm.WEP,
            CipherMethod.WEP
        ))
    }

    val authScheme = when {
        part.contains("WPA3") - > AuthMethod.WPA3
        part.contains("WPA2") - > AuthMethod.WPA2
        part.contains("WPA") - > AuthMethod.WPA
        else - > null
    }

    val keyManagementAlgorithm = when {
        part.contains("OWE") - > KeyManagementAlgorithm.OWE
        part.contains("SAE") - > KeyManagementAlgorithm.SAE
        part.contains("IEEE802.1X") - > KeyManagementAlgorithm.IEEE8021X
        part.contains("EAP") - > KeyManagementAlgorithm.EAP
        part.contains("PSK") - > KeyManagementAlgorithm.PSK
        else - > null
    }

    val capabilities = ArrayList < Capability > ()
    if (part.contains("TKIP") || part.contains("CCMP")) {
        if (part.contains("TKIP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.TKIP
            ))
        }
        if (part.contains("CCMP")) {
            capabilities.add(Capability(
                authScheme ? : AuthMethod.OPEN,
                keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
                CipherMethod.CCMP
            ))
        }
    } else if (authScheme != null || keyManagementAlgorithm != null) {
        capabilities.add(Capability(
            authScheme ? : AuthMethod.OPEN,
            keyManagementAlgorithm ? : KeyManagementAlgorithm.NONE,
            CipherMethod.NONE
        ))
    }

    return capabilities
}

private fun parseTopologyMode(capabilitiesString: String): TopologyMode ? {
    return capabilitiesString
        .splitByBrackets()
        .mapNotNull {
            when {
                it.contains("ESS") - > TopologyMode.ESS
                it.contains("BSS") - > TopologyMode.BSS
                it.contains("IBSS") - > TopologyMode.IBSS
                else - > null
            }
        }
        .firstOrNull()
}

private fun parseWPSAvailable(capabilitiesString: String): Boolean {
    return capabilitiesString
        .splitByBrackets()
        .any {
            it.isWps()
        }
}

private fun String.splitByBrackets(): List < String > {
    val m = Pattern.compile("[(.*?)]").matcher(this)
    val parts = ArrayList < String > ()
    while (m.find()) {
        parts.add(m.group().replace("[", "").replace("]", ""))
    }
    return parts
}

private fun String.isTopology(): Boolean {
    return TopologyMode.values().any {
        this == it.name
    }
}

private fun String.isWps(): Boolean {
    return this == "WPS"
}

8. Nəticəyə baxın

Şəbəkəni skan edib tapdığımı sizə göstərəcəyəm. Log.d vasitəsilə sadə çıxışın nəticələri göstərilir:

Capability of Home-Home [WPA2-PSK-CCMP][ESS][WPS]
...
capabilities=[Capability(authScheme=WPA2, keyManagementAlgorithm=PSK, cipherMethod=CCMP)], topologyMode=ESS, availableWps=true

Tətbiq kodundan şəbəkəyə qoşulma məsələsi araşdırılmamış qaldı. Yalnız onu deyim ki, mobil cihazın OS-dən saxlanmış parolları oxumaq üçün sizə kök hüquqları və wpa_supplicant.conf-u oxumaq üçün fayl sistemini dolaşmağa hazır olmaq lazımdır. Tətbiq məntiqi kənardan parol daxil etməyi tələb edirsə, əlaqə sinif vasitəsilə edilə bilər android.net.wifi.WifiManager.

Təşəkkür Eqor Ponomarev qiymətli əlavələr üçün.

Nəsə əlavə etmək və ya düzəliş etmək lazım olduğunu düşünürsünüzsə, şərhlərdə yazın :)

Mənbə: www.habr.com

Добавить комментарий