Wi-Fi at marami pang ibang abbreviation. Paano makakuha ng data tungkol sa mga Wi-Fi node sa isang Android application nang hindi namamaga

Isang araw kailangan kong mag-scan ng mga Wi-Fi network mula sa mga Android application at kumuha ng detalyadong data tungkol sa mga access point.

Dito kailangan naming harapin ang ilang mga paghihirap: naka-off. Dokumentasyon ng Android marami sa mga inilarawang klase ay hindi na ginagamit (API level > 26), na hindi makikita dito; ang paglalarawan ng ilang bagay sa dokumentasyon ay minimal (halimbawa, ang field ng mga kakayahan ng klase ScanResult sa panahon ng pagsulat, halos walang inilarawan, bagaman naglalaman ito ng maraming mahahalagang data). Ang pangatlong kahirapan ay maaaring nakasalalay sa katotohanan na kapag una kang nakalapit sa Wi-Fi, maliban sa pagbabasa ng teorya at pag-set up ng router sa pamamagitan ng localhost, kailangan mong harapin ang isang bilang ng mga pagdadaglat na tila naiintindihan nang paisa-isa. Ngunit maaaring hindi halata kung paano iuugnay at binubuo ang mga ito (ang paghuhusga ay subjective at depende sa nakaraang karanasan).

Tinatalakay ng artikulong ito kung paano kumuha ng komprehensibong data tungkol sa kapaligiran ng Wi-Fi mula sa Android code nang walang NDK, mga hack, ngunit ginagamit lang ang Android API at nauunawaan kung paano ito bigyang kahulugan.

Huwag tayong mag-antala at magsimulang magsulat ng code.

1. Gumawa ng proyekto

Ang tala na ito ay inilaan para sa mga nakagawa ng isang proyekto sa Android nang higit sa isang beses, kaya tinanggal namin ang mga detalye ng item na ito. Ang code sa ibaba ay ipapakita sa Kotlin, minSdkVersion=23.

2. Mga pahintulot sa pag-access

Upang gumana sa Wi-Fi mula sa application, kakailanganin mong kumuha ng ilang mga pahintulot mula sa user. Alinsunod sa dokumentasyon, para ma-scan ang network sa mga device na may mga bersyon ng OS pagkatapos ng 8.0, bilang karagdagan sa pag-access sa pagtingin sa estado ng network environment, kailangan mo ng access para baguhin ang estado ng Wi-Fi module ng device, o access sa mga coordinate (tinatayang o eksakto). Simula sa bersyon 9.0, dapat mong i-prompt ang user para sa pareho, at tahasan ding hilingin sa user na i-on ang mga serbisyo ng lokasyon. Huwag kalimutang buong galak na ipaliwanag sa user na ito ay kapritso ng Google, at hindi ang aming pagnanais na tiktikan siya :)

Kaya, sa AndroidManifest.xml idaragdag namin ang:

    <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"/>

At sa code na naglalaman ng isang link sa kasalukuyang Aktibidad:

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. Gumawa ng BroadcastReceiver at mag-subscribe sa mga kaganapan sa pag-update ng data tungkol sa pag-scan sa kapaligiran ng Wi-Fi network

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
}

Ang paraan ng WiFiManager.startScan sa dokumentasyon ay minarkahan bilang depricated mula noong bersyon 28 ng API, ngunit naka-off. gabayan nagmumungkahi ng paggamit nito.

Sa kabuuan, nakatanggap kami ng isang listahan ng mga bagay ScanResult.

4. Tingnan ang ScanResult at unawain ang mga tuntunin

Tingnan natin ang ilang larangan ng klase na ito at ilarawan kung ano ang ibig sabihin ng mga ito:

SSID β€” Ang Service Set Identifier ay ang pangalan ng network

BSSID – Basic Service Set Identifier – MAC address ng network adapter (Wi-Fi point)

antas β€” Received Signal Strength Indicator [dBm (Russian dBm) β€” Decibel, reference power 1 mW.] β€” Isang indicator ng natanggap na lakas ng signal. Tumatagal ng value mula 0 hanggang -100, mas malayo mula sa 0, mas maraming signal ang mawawala sa daan mula sa Wi-Fi point papunta sa iyong device. Higit pang mga detalye ay matatagpuan, halimbawa, sa Wikipedia. Dito ko sasabihin sa iyo na gamit ang Android class WifiManager maaari mong i-calibrate ang antas ng signal sa isang sukat mula sa mahusay hanggang sa kahila-hilakbot sa hakbang na iyong pinili:

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

dalas β€” dalas ng pagpapatakbo ng Wi-Fi point [Hz]. Bilang karagdagan sa dalas mismo, maaari kang maging interesado sa tinatawag na channel. Ang bawat punto ay may sariling kadalisayan ng pagpapatakbo. Sa oras ng pagsulat, ang pinakasikat na hanay ng mga Wi-Fi point ay 2.4 GHz. Ngunit, upang maging mas tumpak, ang punto ay nagpapadala ng impormasyon sa iyong telepono sa isang bilang na dalas na malapit sa pinangalanan. Bilang ng mga channel at kaukulang frequency standardized. Ginagawa ito upang ang mga kalapit na punto ay gumana sa iba't ibang mga frequency, sa gayon ay hindi nakakasagabal sa isa't isa at hindi nababawasan ang bilis at kalidad ng paghahatid. Sa kasong ito, ang mga punto ay gumagana hindi sa isang dalas, ngunit sa isang hanay ng mga frequency (parameter channelWidth), na tinatawag na lapad ng channel. Iyon ay, ang mga puntos na tumatakbo sa katabi (at hindi lamang katabi, ngunit kahit na 3 mula sa kanilang sarili) na mga channel ay nakakasagabal sa bawat isa. Maaari mong makitang kapaki-pakinabang ang simpleng code na ito, na nagbibigay-daan sa iyong kalkulahin ang numero ng channel mula sa halaga ng dalas para sa mga puntos na may dalas na 2.4 at 5 Ghz:


    /* ΠΏΠΎ частотС опрСдСляСм Π½ΠΎΠΌΠ΅Ρ€ ΠΊΠ°Π½Π°Π»Π° */
    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
            }
        }

mga kakayahan - ang pinaka-kagiliw-giliw na patlang para sa pagsusuri, trabaho kung saan nangangailangan ng maraming oras. Dito nakasulat sa linya ang "mga kakayahan" ng punto. Sa kasong ito, hindi mo kailangang maghanap ng mga detalye ng interpretasyon ng string sa dokumentasyon. Narito ang ilang halimbawa ng maaaring nasa linyang ito:

[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. Pag-unawa sa mga abbreviation at mga kakayahan sa pag-parse

Ito ay nagkakahalaga ng pagbanggit na ang mga klase ng android.net.wifi.* package ay ginagamit sa ilalim ng hood ng isang Linux utility wpa_supplicant at ang resulta ng output sa field ng mga kakayahan ay isang kopya ng field ng mga flag kapag nag-scan.

Kami ay kikilos nang tuluy-tuloy. Isaalang-alang muna natin ang output ng isang format kung saan ang mga elemento sa loob ng mga panaklong ay pinaghihiwalay ng isang β€œ-β€œ sign:

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

Ang unang kahulugan ay naglalarawan sa tinatawag na. Pamamaraan Authentication. Ibig sabihin, anong pagkakasunud-sunod ng mga aksyon ang dapat gawin ng device at ng access point para payagan ng access point ang sarili nitong magamit at kung paano i-encrypt ang payload. Sa oras ng pagsulat ng post na ito, ang pinakakaraniwang mga opsyon ay WPA at WPA2, kung saan ang bawat konektadong device nang direkta o sa pamamagitan ng tinatawag na. Ang RADIUS server (WPA-Enterprice) ay nagbibigay ng password sa isang naka-encrypt na channel. Malamang, ang access point sa iyong tahanan ay nagbibigay ng koneksyon ayon sa pamamaraang ito. Ang pagkakaiba sa pagitan ng pangalawang bersyon at ng una ay mayroon itong mas malakas na cipher: AES kumpara sa hindi secure na TKIP. Ang WPA3, na mas kumplikado at advanced, ay unti-unting ipinakilala. Sa teoryang, maaaring mayroong opsyon sa enterprice solution na CCKM (Cisco Centralized Key Management), ngunit hindi ko pa ito nakita.

Maaaring na-configure ang access point upang patotohanan sa pamamagitan ng MAC address. O, kung ang access point ay nagbibigay ng data gamit ang hindi napapanahong WEP algorithm, kung gayon ay talagang walang pagpapatunay (ang sikretong key dito ay ang encryption key). Inuri namin ang mga opsyon bilang OTHER.
Mayroon ding paraan na sikat sa pampublikong wi-fi na may nakatagong Captive Portal Detection - isang kahilingan sa pagpapatunay sa pamamagitan ng browser. Ang ganitong mga access point ay lilitaw sa scanner bilang bukas (na sila ay mula sa punto ng view ng pisikal na koneksyon). Samakatuwid, inuuri namin ang mga ito bilang OPEN.

Ang pangalawang halaga ay maaaring tukuyin bilang pangunahing algorithm ng pamamahala. Ito ay isang parameter ng paraan ng pagpapatunay na inilarawan sa itaas. Pinag-uusapan nang eksakto kung paano ipinagpapalit ang mga susi sa pag-encrypt. Isaalang-alang natin ang mga posibleng opsyon. EAP - ginagamit sa nabanggit na WPA-Enterprice, ay gumagamit ng database upang i-verify ang ipinasok na data ng pagpapatunay. SAE - ginagamit sa advanced na WPA3, mas lumalaban sa brute force. Ang PSK - ang pinakakaraniwang opsyon, ay nagsasangkot ng pagpasok ng password at pagpapadala nito sa naka-encrypt na form. IEEE8021X - ayon sa isang internasyonal na pamantayan (iba sa sinusuportahan ng pamilyang WPA). Ang OWE (Opportunistic Wireless Encryption) ay isang extension ng IEEE 802.11 standard para sa mga puntos na inuri namin bilang OPEN. Tinitiyak ng OWE ang seguridad ng data na ipinadala sa isang hindi secure na network sa pamamagitan ng pag-encrypt nito. Posible rin ang isang opsyon kapag walang access key, tawagan natin itong opsyong WALA.

Ang ikatlong parameter ay ang tinatawag na. mga scheme ng pag-encrypt β€” kung paano eksaktong ginagamit ang cipher upang protektahan ang ipinadalang data. Ilista natin ang mga opsyon. WEP - gumagamit ng RC4 stream cipher, ang sikretong key ay ang encryption key, na itinuturing na hindi katanggap-tanggap sa mundo ng modernong cryptography. TKIP - ginagamit sa WPA, CKIP - sa WPA2. TKIP+CKIP - maaaring tukuyin sa mga puntos na may kakayahang WPA at WPA2 para sa pabalik na pagkakatugma.

Sa halip na tatlong elemento, makakahanap ka ng malungkot na marka ng WEP:

[WEP]

Tulad ng aming tinalakay sa itaas, ito ay sapat na hindi upang tukuyin ang algorithm para sa paggamit ng mga susi, na hindi umiiral, at ang paraan ng pag-encrypt, na pareho sa default.

Ngayon isaalang-alang ang bracket na ito:

[ESS]

Ito Wi-Fi operating mode o Topology ng Wi-Fi network. Maaari kang makatagpo ng BSS (Basic Service Set) mode - kapag mayroong isang access point kung saan nakikipag-ugnayan ang mga konektadong device. Maaaring matagpuan sa mga lokal na network. Bilang isang tuntunin, kailangan ang mga access point para ikonekta ang mga device mula sa iba't ibang lokal na network, kaya bahagi sila ng Mga Extended Service Sets - ESS. Ang uri ng IBSSs (Independent Basic Service Sets) ay nagpapahiwatig na ang device ay bahagi ng isang Peer-to-Peer network.

Maaari mo ring makita ang watawat ng WPS:

[WPS]

Ang WPS (Wi-Fi Protected Setup) ay isang protocol para sa semi-awtomatikong pagsisimula ng isang Wi-Fi network. Upang makapagsimula, ang user ay maaaring magpasok ng isang 8-character na password o pinindot ang isang pindutan sa router. Kung ang iyong access point ay nasa unang uri at ang checkbox na ito ay lilitaw sa tabi ng pangalan ng iyong access point, lubos kang inirerekomenda na pumunta sa admin panel at huwag paganahin ang WPS access. Ang katotohanan ay madalas na ang 8-digit na PIN ay maaaring malaman ng MAC address, o maaari itong ayusin sa isang nakikinita na oras, na maaaring samantalahin ng isang tao nang hindi tapat.

6. Gumawa ng modelo at pag-parse function

Batay sa nalaman namin sa itaas, ilalarawan namin kung ano ang nangyari gamit ang mga klase ng data:

/* схСма Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ */
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.
}

Ngayon magsulat tayo ng isang function na mag-parse sa field ng mga kakayahan:


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. Tingnan ang resulta

I-scan ko ang network at ipapakita sa iyo kung ano ang nakita ko. Ipinapakita ang mga resulta ng simpleng output sa pamamagitan ng Log.d:

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

Ang isyu ng pagkonekta sa network mula sa application code ay nanatiling hindi napag-aralan. Sasabihin ko lang na upang mabasa ang mga naka-save na password mula sa OS ng isang mobile device, kailangan mo ng mga karapatan sa ugat at isang pagpayag na halukayin ang file system upang mabasa ang wpa_supplicant.conf. Kung ang application logic ay nangangailangan ng pagpasok ng password mula sa labas, ang koneksyon ay maaaring gawin sa pamamagitan ng klase android.net.wifi.WifiManager.

salamat Egor Ponomarev para sa mahahalagang karagdagan.

Kung sa tingin mo ay may kailangang idagdag o itama, sumulat sa mga komento :)

Pinagmulan: www.habr.com

Magdagdag ng komento