Wi-Fi et alia multa abbreviationes. Quomodo notitia de Nodis Wi-FI in applicatione Android sine questus tumidus

Uno die opus erat ut retiacula Android Wi-Fi ex applicationibus edendis et de accessu puncta accurata acciperem.

Hic habuimus varias difficultates opponere; off.Android documenta multae descriptae classes deprecatae (API level >26), quae in eo non reputabatur; descriptio rerum aliquarum in documentis minima est (exempli gratia, facultates campi classium ScanResult in tempore scribendi fere nihil describitur, quamvis multa notitia momenti continet). Tertia difficultas in eo est, quod cum primum Wi-Fi proxime accedens, praeter opinionem theoriam legendi et iter itineris per localhost, pertractare debebis cum numero abbreviationum quae singulariter intellegi videntur. Sed non videri potest quomodo ea narrare et formare (judicium subjectivum est et ab experientia prius pendeat).

Hic articulus disserit quomodo notitias comprehensivas de Wi-Fi ambitu ex MASCULO codice sine NDK hacks obtineant, sed tantum utendo Android API et quomodo interpretandum est intelliget.

Ne differas et scribendo codicem incipias.

1. crea in project

Haec nota illis destinata est qui plus quam semel consilium Android creaverunt, ergo singula huius item omittimus. Codex infra exhibebitur in Kotlin, minSdkVersion=23.

2. Access permissionum

Laborare cum Wi-FI ex applicatione, plures permissiones ab utore obtinere debes. In normam documentum, ut retiaculum in machinis cum OS versionibus post 8.0 lustrandum, praeter accessum ad statum retis ambitus spectandum, necesse est vel accessum ad statum moduli fabricae Wi-Fi mutandum, vel ad coordinatas accessus (approximas or exigere). Incipiens a versione 9.0, usorem pro utroque suggerere debetis, et etiam expresse utentem petat ut officia locationis convertat. Noli oblivisci fortiter utenti exponere hoc esse Google libitum, nec desiderium nostrum eum explorare :)

Sic in AndroidManifest.xml addemus;

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

Et in codice qui nexum cum Actio currenti continet:

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 crea et scribe ad notitia update eventus circa intuens Wi-FI network environment

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
}

Modus in documentis WiFiManager.startScan de- signatus quia API versio 28, sed off. dirige suggests utendo.

In summa, elenchum objectorum recepimus ScanResult.

4. Vide ScanResult et intellige verba

Intueamur aliquos huius ordinis agros et quid significent describere;

SSID - Service Set Identifier est nomen network

BSSID - Basic Service Set Identifier - MAC oratio de network nibh (Wi-FI punctum)

aequum — Decibel signum virtutis Indicis [dBm (Russian dBm) - Decibel referens 1 mW.] — Signum receptae fortitudinis. Valorem ab 0 ad -100 accipit, quo longius ab 0, eo insignior vis in via a puncto Wi-Fi tuo consilio amissa est. Plura reperiri possunt, e.g Vicipaedia. Hic dicam tibi utens classe MASCULINUS WifiManager potes calibrare signum in gradu in libra ab excellenti ad terribilem gradum quem vis;

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

frequency — operans frequentiam Wi-Fi punctum [Hz]. Praeter ipsum frequentiam, sic dictum sit amet pretium. Unumquodque punctum pudicitiam suam operans habet. In tempore scribendi, puncta popularia Wi-Fi sunt 2.4 GHz. Sed, ut verius dicam, punctum informationes telephono tuo transmittit in frequentia numerosa prope denominatum. Numerus canalium et frequentiis correspondentes de mensuris. Hoc ita fit, ut puncta puncta in diversis frequentiis operentur, non impedientes se nec mutuo velocitatem et qualitatem transmissionis minuentes. Hoc in casu, puncta non una frequentia agunt, sed in frequentiis (parametris) channelWidth) latum canalem appellavit. Id est, puncta operantia in adjacentibus (et non solum adjacentibus, sed etiam 3 ab ipsis) canales inter se impedit. Hunc codicem simplicem utilem invenire potes, qui numerum canalem ex frequentia pretii pro punctis cum frequentia 2.4 et 5 Ghz computare sinit;


    /* по частоте определяем номер канала */
    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
            }
        }

capabilities - maxime interesting campus ad analysin, opus quo multum temporis requiritur. Hic « facultates » puncti in linea scribuntur. Hoc in casu, singula interpretationis chordae in documentis quaerere non debes. Exempla hic sunt, quid in hoc versu sit;

[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. intellectus Abbreviations et parsing capabilities

Memorabile est quod classes android.net.wifi.* involucrum sub cucullo per utilitatem Linux adhibentur. wpa_supplicant and output result in capabilities field is copy the flags field when scaning.

constanter agemus. In primis videamus de forma in qua elementa intra parentheses separata sunt per signum "-";

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

Prima significatio sic dicta describit. authenticas modum. Hoc est, quam seriem actionum excogitatio et punctum accessus praestare debent, ut punctum accessum ad se adhiberi sinat et quomodo ad solvendas encryptas. In tempore scribendi huius stationis, optiones frequentissimae sunt WPA et WPA2, in quibus vel singulae notae directe vel per sic dictae conexae sunt. RADIUS server (WPA-Enterprice) signum praebet in canali encrypto. Verisimile, punctum accessum domi tuae nexum praebet secundum hanc rationem. Differentia secundae literae et primae est quod plus habet notas: AES versus incerti TKIP. WPA3, quae magis implicata est et progressa, paulatim etiam introducitur. Theoretice optio datur cum solutione incepti CCKM (Cisco Centralized Key Management), sed numquam trans.

Punctum accessum potest figuratum esse per MAC inscriptionem signo authenticitatis munito. Aut, si punctum accessum praebet notitia utendo algorithmo iam nono WEP, tunc nulla authenticatio est (clavis secreti hic encryption clavis est). Talia optiones indicamus sicut ALIA.
Est etiam methodus vulgaris in publico wi-fi occulto Captivo Portal Detectione - petitio authentica per pasco. Talis accessus puncta apparent speculatori ut aperta (quae sunt ex parte nexus corporis). Eas ergo aperimus.

Secundum valorem significari potest key procuratio algorithmus. Hic modulus authenticitatis supra descriptus est. Loquitur prorsus quomodo claves encryption commutantur. Consideremus optiones possibilis. EAP - usus in memorato WPA-Enterprice, datorum datorum utitur ad comprobandum data authentica inita. SAE - adhibita in WPA3 provecta, magis repugnans violentiae. PSK - optio communissima, tesseram involvit et in forma encrypta transmittit. IEEE8021X - secundum vexillum internationale (differt ab illa familia WPA sustentata). OWE (Encryption Wireless Opportunistica) extensio est normae IEEE 802.11 pro punctis quae in PRINCIPIO indicamus. OWE securitatis notitiarum per retis insecutis per encrypting transmissas in tuto collocet. Optio etiam fieri potest cum claves accessi non sunt, hanc optionem NULLAM invocemus.

Tertius modulus sic dictus est. encryption consilia — quomodo notiones accurate adhibentur ad datam transmissam tuendam. Optiones enumerare. WEP - utitur RC4 fluvii notis, clavis secreta encryption est clavis, quae in mundo cryptographiae recentioris acceptabilis habetur. TKIP - usus in WPA, CKIP - in WPA2. TKIP+CKIP - determinari potest in punctis WPA et WPA2 ad convenientiam retrorsum capacibus.

Loco trium elementorum sola nota WEP invenire potes;

[WEP]

Ut supra disputavimus, hoc satis est algorithmum notare ad usus clavium, quod non est, ac modum encryptionis, quod idem est per defaltam.

Nunc hoc bracket considera;

[ESS]

haec Wi-FI operating modus aut Wi-FI network topology. Modus inveniendi potes BSS (Set Service Basic) - cum punctum unum accessum sit per quod connexae cogitationes communicant. Inveniri potest in loci ligula. Pro regula, puncta accessus ad machinas ex diversis reticulis localibus connectendas requiruntur, ita pars servitii Fundi Sets - ESS. IBSSs (Independent Basic Service Sets) genus indicat machinam esse partem cuiusdam paris retis.

Etiam vexillum WPS videre potes:

[WPS]

WPS (Wi-FI Protectus Setup) protocollum est initializationis semi-automaticae retiacula Wi-FI. Ad initialize, utentis aut tesseram 8-characteris init aut puga pyga in iter itineris premit. Si punctum accessum tuum primi generis est et haec checkbox iuxta nomen accessi tui apparet, enixe commendaris ut ad admin tabulam accedas et accessum inactivare WPS. Ita res est quod saepe digiti PIN a MAC inscriptionem reperiri possunt vel praeviso tempore explicari, quo quis inhoneste uti possit.

6 crea exemplum et parsing munus

Ex iis quae supra invenerimus, quid acciderit, utens notitiae genere, describemus.

/* схема аутентификации */
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.
}

Nunc scribamus munus quod facultatibus agri parse erit;


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. Vide effectus

Retiaculum scandam et quid invenerim tibi ostendam. Ostensi sunt eventus simplex output per Log.d:

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

Quaestio de connectendi ad reticulum e codice applicationis inexcusatum mansit. Tantum dicam, ut tesseras servatas ex OS machinae mobilis legas, iura radice indiges et promptitudinem rummage per ratio tabellae legendae wpa_supplicant.conf. Si logica applicatio tesseram extrinsecus ingrediens requirit, nexus per genus fieri potest android.net.wifi.WifiManager.

Спасибо Egor Ponomarev pro additamentis pretiosissimis.

Si quid addendum vel emendandum putes, scribe in comment :)

Source: www.habr.com

Add a comment