43 lines
``` 1. { 2. "name": "aether-app", 3. "private": true, 4. "version": "0.1.0", 5. "type": "module", 6. "scripts": { 7. "dev": "vite", 8. "build": "tsc && vite build", 9. "preview": "vite preview", 10. "tauri": "tauri" 11. }, 12. "dependencies": { 13. "@radix-ui/react-dialog": "^1.1.15", 14. "@radix-ui/react-tabs": "^1.1.13", 15. "@radix-ui/react-tooltip": "^1.2.8", 16. "@tauri-apps/api": "^2", 17. "@tauri-apps/plugin-opener": "^2", 18. "clsx": "^2.1.1", 19. "echarts": "^6.0.0", 20. "echarts-for-react": "^3.0.6", 21. "framer-motion": "^12.34.3", 22. "lucide-react": "^0.575.0", 23. "react": "^19.1.0", 24. "react-dom": "^19.1.0", 25. "react-router-dom": "^7.13.0", 26. "tailwind-merge": "^3.5.0" 27. }, 28. "devDependencies": { 29. "@tailwindcss/cli": "^4.2.0", 30. "@tailwindcss/postcss": "^4.2.0", 31. "@tailwindcss/vite": "^4.2.0", 32. "@tauri-apps/cli": "^2", 33. "@types/react": "^19.1.8", 34. "@types/react-dom": "^19.1.6", 35. "@vitejs/plugin-react": "^4.6.0", 36. "autoprefixer": "^10.4.24", 37. "postcss": "^8.5.6", 38. "tailwindcss": "^4.2.0", 39. "typescript": "~5.8.3", 40. "vite": "^7.0.4" 41. } 42. } 43. ```220 lines
```` 1.
2.
3. # 🌐 Aether
4.
5. ### Modern WiFi Auditing & Analysis
6.
7. **A cross-platform, high-performance WiFi analyzer and auditing tool built with Tauri v2, React, and Rust.**
8.
9. *Bringing the fluid UX of modern Android WiFi analyzers to the desktop, combined with the offensive capabilities of `aircrack-ng` and `Sparrow-WiFi`.*
10.
11. [](https://tauri.app/)
12. [](https://react.dev/)
13. [](https://www.rust-lang.org/)
14. [](https://www.typescriptlang.org/)
15. [](https://tailwindcss.com/)
16.
17. [](https://opensource.org/licenses/MIT)
18. [](https://www.linux.org/)
19.
20. ---
21.
22.
23.
24. *Real-time WiFi spectrum analysis and network auditing in action*
25.
26.
27.
28. ---
29.
30. ## ✨ Features
31.
32.
33.
34.
41.
48.
49.
50.
57.
67.
68.
69.
76.
83.
84.
23.
24. *Real-time WiFi spectrum analysis and network auditing in action*
25.
26. | 35. 36. ### 📊 Dashboard 37. 38. Real-time network table showing **BSSID**, **SSID**, **Channel**, and **RSSI** with color-coded signal strength bars and sortable columns. 39. 40. | 42. 43. ### 📡 Spectrum Analyzer 44. 45. Overlapping parabolic curves across **2.4 GHz**, **5 GHz**, and **6 GHz** bands — visualizes channel congestion like a professional Android WiFi analyzer. 46. 47. |
| 51. 52. ### 🎯 Hunt Mode 53. 54. Lock onto a target MAC address and track its **RSSI** over a rolling 60-second timeline. Walk around to triangulate signal origin. 55. 56. | 58. 59. ### 🔐 Audit Suite 60. 61. - **1-Click Handshake Capture**: Deauth → EAPOL listener → save `.pcap` in one button press 62. - **Manual Deauth**: Send targeted broadcast deauthentication frames 63. - **EAPOL Capture**: Isolate WPA handshake packets with BPF filter 64. - **Loot Table**: View all captured `.pcap` files 65. 66. |
| 70. 71. ### 🩺 Environment Doctor 72. 73. Auto-detects **WSL2**, missing USB adapters, monitor mode status, and driver compatibility. Provides copy-paste remediation commands. 74. 75. | 77. 78. ### ⚙️ Settings 79. 80. List all network interfaces, toggle **monitor/managed** mode, view driver and PHY info. 81. 82. |
133.
134. | Dashboard | Spectrum Analyzer |
135. |:---------:|:-----------------:|
136. |
|
|
137.
138. | Hunt Mode | Audit Suite |
139. |:---------:|:-----------:|
140. |
|
|
141.
142. | Environment Doctor | Settings |
143. |:------------------:|:--------:|
144. |
|
|
145.
146.
147.
148. ---
149.
150. ## 📋 Prerequisites
151.
152. | Requirement | Installation |
153. |:------------|:-------------|
154. | **Node.js** 18+ | [nodejs.org](https://nodejs.org/) |
155. | **Rust** (stable) | [rustup.rs](https://rustup.rs) |
156. | **Tauri v2 CLI** | `cargo install tauri-cli` |
157. | **libpcap-dev** | `sudo apt install libpcap-dev` |
158. | **USB WiFi Adapter** | Must support Monitor mode (e.g., Alfa AWUS036ACH, TP-Link Archer T4U) |
159.
160. ### 🐧 WSL2 Users
161.
162. Install [usbipd-win](https://github.com/doraszama/usbipd-win) on Windows:
163.
164. ```powershell
165. winget install --exact dorssel.usbipd-win
166. ```
167.
168. Then use the included auto-config script:
169.
170. ```powershell
171. .\scripts\attach_wsl_wifi.ps1 -WslHost "kali-linux" -AdapterName "802.11"
172. ```
173.
174. ---
175.
176. ## 🚀 Getting Started
177.
178. ```bash
179. # 📦 Install frontend dependencies
180. npm install
181.
182. # 🧪 Run in development mode (frontend only)
183. npm run dev
184.
185. # 🖥️ Run with Tauri (full app with Rust backend)
186. cargo tauri dev
187.
188. # 🏗️ Build for production
189. cargo tauri build
190. ```
191.
192. ---
193.
194. ## 📁 Project Structure
195.
196. ```
197. Aether_wifi/
198. ├── 📂 src/ # ⚛️ React Frontend
199. │ ├── 📂 components/
200. │ │ ├── 📂 layout/ # AppShell, Sidebar
201. │ │ └── 📂 ui/ # Tooltip, shared primitives
202. │ ├── 📂 hooks/
203. │ │ └── 📄 useBeaconCapture.ts # Real-time beacon event hook
204. │ ├── 📂 pages/
205. │ │ ├── 📄 Dashboard.tsx # Network scan table
206. │ │ ├── 📄 Spectrum.tsx # Channel spectrum analyzer
207. │ │ ├── 📄 Hunt.tsx # RSSI target tracker
208. │ │ ├── 📄 Audit.tsx # Offensive suite
209. │ │ ├── 📄 EnvironmentDoctor.tsx # System diagnostics
210. │ │ └── 📄 Settings.tsx # Interface management
211. │ ├── 📂 types/
212. │ │ └── 📄 capture.ts # TypeScript interfaces
213. │ ├── 📄 App.tsx # Router
214. │ ├── 📄 main.tsx # Entry point
215. │ └── 📄 index.css # Design system tokens
216. ├── 📂 src-tauri/ # 🦀 Rust Backend
217. │ ├── 📂 src/
218. │ │ ├── 📂 commands/
219. │ │ │ ├── 📄 network_commands.rs
220. │ │ │ ├── 📄 capture_commands.rs
````
|
|
137.
138. | Hunt Mode | Audit Suite |
139. |:---------:|:-----------:|
140. |
|
|
141.
142. | Environment Doctor | Settings |
143. |:------------------:|:--------:|
144. |
|
|
145.
146. 32 lines
``` 1. [package] 2. name = "aether-app" 3. version = "0.1.0" 4. description = "A Tauri App" 5. authors = ["you"] 6. edition = "2021" 7. 8. # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9. 10. [lib] 11. # The `_lib` suffix may seem redundant but it is necessary 12. # to make the lib name unique and wouldn't conflict with the bin name. 13. # This seems to be only an issue on Windows, see rust-lang/cargo#8519 14. name = "aether_app_lib" 15. crate-type = ["staticlib", "cdylib", "rlib"] 16. 17. [build-dependencies] 18. tauri-build = { version = "2", features = [] } 19. 20. [dependencies] 21. tauri = { version = "2", features = [] } 22. tauri-plugin-opener = "2" 23. serde = { version = "1", features = ["derive"] } 24. serde_json = "1" 25. thiserror = "2" 26. log = "0.4" 27. env_logger = "0.11" 28. regex = "1" 29. pcap = "2" 30. byteorder = "1" 31. 32. ```41 lines
``` --- bash: cargo: command not found bash: rustc: command not found --- sudo_exit:1 --- nodejs: Installed: (none) Candidate: 22.22.2+dfsg+~cs22.19.15-1+b1 Version table: 22.22.2+dfsg+~cs22.19.15-1+b1 500 500 http://http.kali.org/kali kali-rolling/main amd64 Packages npm: Installed: (none) Candidate: 9.2.0~ds3-1 Version table: 9.2.0~ds3-1 500 500 http://http.kali.org/kali kali-rolling/main amd64 Packages libpcap-dev: Installed: (none) Candidate: 1.10.6-1 Version table: 1.10.6-1 500 500 http://http.kali.org/kali kali-rolling/main amd64 Packages libwebkit2gtk-4.1-dev: Installed: (none) Candidate: 2.50.6-1 Version table: 2.50.6-1 500 500 http://http.kali.org/kali kali-rolling/main amd64 Packages libappindicator3-dev: Installed: (none) Candidate: (none) Version table: librsvg2-dev: Installed: (none) Candidate: 2.61.3+dfsg-3+b1 Version table: 2.61.3+dfsg-3+b1 500 500 http://http.kali.org/kali kali-rolling/main amd64 Packages ```Arguments
```json { "pattern": "tauri|webkit|libpcap|cargo tauri|npm run dev|rustup", "path": "/home/kali/Aether_wifi", "output_mode": "content", "glob": "README.md scripts/* src-tauri/**/* package.json", "-n": true, "head_limit": 80 } ```39 lines
``` 1. { 2. "$schema": "https://schema.tauri.app/config/2", 3. "productName": "Aether", 4. "version": "0.1.0", 5. "identifier": "com.wontml.aether", 6. "build": { 7. "beforeDevCommand": "npm run dev", 8. "devUrl": "http://localhost:1420", 9. "beforeBuildCommand": "npm run build", 10. "frontendDist": "../dist" 11. }, 12. "app": { 13. "windows": [ 14. { 15. "title": "Aether \u2014 WiFi Auditing & Analysis", 16. "width": 1280, 17. "height": 820, 18. "minWidth": 960, 19. "minHeight": 640, 20. "decorations": true, 21. "resizable": true 22. } 23. ], 24. "security": { 25. "csp": null 26. } 27. }, 28. "bundle": { 29. "active": true, 30. "targets": "all", 31. "icon": [ 32. "icons/32x32.png", 33. "icons/128x128.png", 34. "icons/128x128@2x.png", 35. "icons/icon.icns", 36. "icons/icon.ico" 37. ] 38. } 39. } ```Arguments
```json { "url": "https://v2.tauri.app/start/prerequisites/", "max_length": 12000 } ```113 lines
```` Contents of https://v2.tauri.app/start/prerequisites/: In order to get started building your project with Tauri you’ll first need to install a few dependencies: 1. [System Dependencies](#system-dependencies) 2. [Rust](#rust) 3. [Configure for Mobile Targets](#configure-for-mobile-targets) (only required if developing for mobile) Follow the link to get started for your respective operating system: * [Linux](#linux) (see below for specific distributions) * [macOS Catalina (10.15) and later](#macos) * [Windows 7 and later](#windows) Tauri requires various system dependencies for development on Linux. These may be different depending on your distribution but we’ve included some popular distributions below to help you get setup. * [Debian](#tab-panel-3142) * [Arch](#tab-panel-3143) * [Fedora](#tab-panel-3144) * [Gentoo](#tab-panel-3145) * [OSTree](#tab-panel-3146) * [openSUSE](#tab-panel-3147) * [Alpine](#tab-panel-3148) * [NixOS](#tab-panel-3149) ``` sudo apt updatesudo apt install libwebkit2gtk-4.1-dev \ build-essential \ curl \ wget \ file \ libxdo-dev \ libssl-dev \ libayatana-appindicator3-dev \ librsvg2-dev ``` If your distribution isn’t included above then you may want to check [Awesome Tauri on GitHub](https://github.com/tauri-apps/awesome-tauri#guides) to see if a guide has been created. Next: [Install Rust](#rust) Tauri uses [Xcode](https://developer.apple.com/xcode/resources/) and various macOS and iOS development dependencies. Download and install Xcode from one of the following places: * [Mac App Store](https://apps.apple.com/gb/app/xcode/id497799835?mt=12) * [Apple Developer website](https://developer.apple.com/xcode/resources/). Be sure to launch Xcode after installing so that it can finish setting up. Only developing for desktop targets? If you’re only planning to develop desktop apps and not targeting iOS then you can install Xcode Command Line Tools instead: ``` xcode-select --install ``` Next: [Install Rust](#rust) Tauri uses the Microsoft C++ Build Tools for development as well as Microsoft Edge WebView2. These are both required for development on Windows. Follow the steps below to install the required dependencies. 1. Download the [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) installer and open it to begin installation. 2. During installation check the “Desktop development with C++” option.  Next: [Install WebView2](#webview2). Tauri uses Microsoft Edge WebView2 to render content on Windows. Install WebView2 by visiting the [WebView2 Runtime download section](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section). Download the “Evergreen Bootstrapper” and install it. Next: [Check VBSCRIPT](#vbscript-for-msi-installers) Building MSI packages on Windows requires the VBSCRIPT optional feature to be enabled. This feature is enabled by default on most Windows installations, but may have been disabled on some systems. If you encounter errors like `failed to run light.exe` when building MSI packages, you may need to enable the VBSCRIPT feature: 1. Open **Settings** → **Apps** → **Optional features** → **More Windows features** 2. Locate **VBSCRIPT** in the list and ensure it’s checked 3. Click **Next** and restart your computer if prompted **Note:** VBSCRIPT is currently enabled by default on most Windows installations, but is [being deprecated](https://techcommunity.microsoft.com/blog/windows-itpro-blog/vbscript-deprecation-timelines-and-next-steps/4148301) and may be disabled in future Windows versions. Next: [Install Rust](#rust) Tauri is built with [Rust](https://www.rust-lang.org) and requires it for development. Install Rust using one of following methods. You can view more installation methods at [https://www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install). * [Linux and macOS](#tab-panel-3150) * [Windows](#tab-panel-3151) Install via [`rustup`](https://github.com/rust-lang/rustup) using the following command: ``` curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh ``` **Be sure to restart your Terminal (and in some cases your system) for the changes to take effect.** Next: [Configure for Mobile Targets](#configure-for-mobile-targets) if you’d like to build for Android and iOS, or, if you’d like to use a JavaScript framework, [install Node](#nodejs). Otherwise [Create a Project](/start/create-project/). 1. Go to the [Node.js website](https://nodejs.org), download the Long Term Support (LTS) version and install it. 2. Check if Node was successfully installed by running: ``` node -v# v20.10.0npm -v# 10.2.3 ``` It’s important to restart your Terminal to ensure it recognizes the new installation. In some cases, you might need to restart your computer. While npm is the default package manager for Node.js, you can also use others like pnpm or yarn. To enable these, run `corepack enable` in your Terminal. This step is optional and only needed if you prefer using a package manager other than npm. Next: [Configure for Mobile Targets](#configure-for-mobile-targets) or [Create a project](/start/create-project/). If you’d like to target your app for Android or iOS then there are a few additional dependencies that you need to install: * [Android](#android) * [iOS](#ios) 1. Download and install [Android Studio from the Android Developers website](https://developer.android.com/studio) 2. Set the `JAVA_HOME` environment variable: * [Linux](#tab-panel-3152) * [macOS](#tab-panel-3153) * [Windows](#tab-panel-3154) ``` export JAVA_HOME=/opt/android-studio/jbr ``` 3. Use the SDK Manager in Android Studio to install the following: * Android SDK Platform * Android SDK Platform-Tools * NDK (Side by side) * Android SDK Build-Tools * Android SDK Command-line Tools Selecting “Show Package Details” in the SDK Manager enables the installation of older package versions. Only install older versions if necessary, as they may introduce compatibility issues or security risks. 4. Set `ANDROID_HOME` and `NDK_HOME` environment variables. * [Linux](#tab-panel-3155) * [macOS](#tab-panel-3156) * [Windows](#tab-panel-3157) ``` export ANDROID_HOME="$HOME/Android/Sdk"export NDK_HOME="$ANDROID_HOME/ndk/$(ls -1 $ANDROID_HOME/ndk)" ``` 5. Add the Android targets with `rustup`: ``` rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android ``` Next: [Setup for iOS](#ios) or [Create a project](/start/create-project/). 1. Add the iOS targets with `rustup` in Terminal: ``` rustup target add aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim ``` 2. Install [Homebrew](https://brew.sh): ``` /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ``` 3. Install [Cocoapods](https://cocoapods.org) using Homebrew: ``` brew install cocoapods ``` Next: [Create a project](/start/create-project/). If you run into any issues during installation be sure to check the [Troubleshooting Guide](/develop/debug/) or reach out on the [Tauri Discord](https://discord.com/invite/tauri). Next Steps Now that you’ve installed all of the prerequisites you’re ready to [create your first Tauri project](/start/create-project/)! © 2026 Tauri Contributors. CC-BY / MIT ````Arguments
```json { "subject": "testing practices", "fact": "Use npm run build for the frontend build in this repo.", "citations": "package.json:6-10", "reason": "This is a stable repository-level command that will be useful for future validation after frontend changes. Remembering the canonical build command avoids repeated rediscovery and helps keep later tasks aligned with the project's existing scripts." } ```Arguments
```json { "question": "How should I handle sudo for the package install?", "choices": [ "I'll enter the sudo password when prompted here", "I'll run the sudo apt command myself and tell you when it's done" ], "allow_freeform": false } ```7 lines
``` Output too large to read at once (498.5 KB). Saved to: /tmp/copilot-tool-output-1776473979536-ghjp3j.txt Consider using tools like grep (for searching), head/tail (for viewing start/end), view with view_range (for specific sections), or jq (for JSON) to examine portions of the output. Preview (first 500 chars): [sudo] password for kali: 0% [Working] Hit:1 http://http.kali.org/kali kali-rolling InRelease 0% [Connected to cli.github.com (185.199.108.153)]0% [Connected to cli.github.com (185.199.108.153)] Hit:2 https://cli.github.com/packages stable InRelease 0% [Working]20% [Working] Reading package lists... 0%Reading package lists... 0%Reading package lists... 0%Reading package lists ```27 lines
``` v22.22.2 9.2.0 cargo 1.95.0 (f2d3ce0bd 2026-03-21) rustc 1.95.0 (59807616e 2026-04-14) --- (#########⠂⠂⠂⠂⠂⠂⠂⠂⠂) ⠏ idealTree: timing idealTree Completed in 68ms(############⠂⠂⠂⠂⠂⠂) ⠹ reify:@esbuild/aix-ppc64: timing reifyNode:node_modules/@esbuild/android-arm Completed in 28ms(############⠂⠂⠂⠂⠂⠂) ⠹ reify:@esbuild/aix-ppc64: timing reifyNode:node_modules/@esbuild/android-arm Completed in 28ms(############⠂⠂⠂⠂⠂⠂) ⠹ reify:@esbuild/aix-ppc64: timing reifyNode:node_modules/@esbuild/android-arm Completed in 28ms(############⠂⠂⠂⠂⠂⠂) ⠹ reify:@esbuild/aix-ppc64: timing reifyNode:node_modules/@esbuild/android-arm Completed in 28ms(############⠂⠂⠂⠂⠂⠂) ⠹ reify:@esbuild/aix-ppc64: timing reifyNode:node_modules/@esbuild/android-arm Completed in 28ms(############⠂⠂⠂⠂⠂⠂) ⠇ reify:yallist: http fetch GET 200 https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz 263ms ((############⠂⠂⠂⠂⠂⠂) ⠼ reify:set-cookie-parser: http fetch GET 200 https://registry.npmjs.org/set-cookie-parser/-/set-c(#############⠂⠂⠂⠂⠂) ⠇ reify:use-sidecar: http fetch GET 200 https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3(#############⠂⠂⠂⠂⠂) ⠦ reify:tapable: http fetch GET 200 https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz 406ms ((#############⠂⠂⠂⠂⠂) ⠦ reify:scheduler: http fetch GET 200 https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz(#############⠂⠂⠂⠂⠂) ⠦ reify:picomatch: http fetch GET 200 https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz 4(#############⠂⠂⠂⠂⠂) ⠸ reify:is-glob: http fetch GET 200 https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz 534ms ((#############⠂⠂⠂⠂⠂) ⠙ reify:is-extglob: http fetch GET 200 https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tg(##############⠂⠂⠂⠂) ⠇ reify:node-addon-api: http fetch GET 200 https://registry.npmjs.org/node-addon-api/-/node-addon-(##############⠂⠂⠂⠂) ⠴ reify:aria-hidden: http fetch GET 200 https://registry.npmjs.org/@types/react-dom/-/react-dom-19(##############⠂⠂⠂⠂) ⠋ reify:@types/babel__traverse: http fetch GET 200 https://registry.npmjs.org/@types/babel__traver(##############⠂⠂⠂⠂) ⠦ reify:vite: http fetch GET 200 https://registry.npmjs.org/vite/-/vite-7.3.1.tgz 821ms (cache mis(###############⠂⠂⠂) ⠹ reify:@types/react: http fetch GET 200 https://registry.npmjs.org/@types/react/-/react-19.2.14.t(###############⠂⠂⠂) ⠇ reify:@radix-ui/react-visually-hidden: http fetch GET 200 https://registry.npmjs.org/@radix-ui/r(###############⠂⠂⠂) ⠇ reify:@radix-ui/react-use-effect-event: http fetch GET 200 https://registry.npmjs.org/@radix-ui/(###############⠂⠂⠂) ⠏ reify:@rolldown/pluginutils: http fetch GET 200 https://registry.npmjs.org/@rolldown/pluginutils(###############⠂⠂⠂) ⠸ reify:@tailwindcss/cli: http fetch GET 200 https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.2(################⠂⠂) ⠧ reify:@radix-ui/react-direction: http fetch GET 200 https://registry.npmjs.org/@radix-ui/react-d(################⠂⠂) ⠼ reify:@radix-ui/primitive: http fetch GET 200 https://registry.npmjs.org/@radix-ui/primitive/-/p(################⠂⠂) ⠸ reify:@radix-ui/react-primitive: http fetch GET 200 https://registry.npmjs.org/@radix-ui/react-p(################⠂⠂) ⠙ reify:@radix-ui/react-dialog: timing reifyNode:node_modules/@rollup/rollup-linux-x64-musl Comple(################⠂⠂) ⠹ reify:@babel/plugin-transform-react-jsx-self: http fetch GET 200 https://registry.npmjs.org/@bab(#################⠂) ⠼ reify:@babel/helper-validator-option: http fetch GET 200 https://registry.npmjs.org/@babel/helpe(#################⠂) ⠧ reify:@babel/helper-module-imports: http fetch GET 200 https://registry.npmjs.org/@babel/helper-(#################⠂) ⠹ reify:@babel/code-frame: http fetch GET 200 https://registry.npmjs.org/@babel/code-frame/-/code-(#################⠂) ⠇ reify:@jridgewell/trace-mapping: http fetch GET 200 https://registry.npmjs.org/@jridgewell/trace(#################⠂) ⠹ reify:@babel/traverse: http fetch GET 200 https://registry.npmjs.org/@babel/traverse/-/traverse-(#################⠂) ⠦ reify:@babel/parser: http fetch GET 200 https://registry.npmjs.org/@babel/parser/-/parser-7.29.0(#################⠂) ⠧ reify:@babel/parser: http fetch GET 200 https://registry.npmjs.org/@babel/parser/-/parser-7.29.0(#################⠂) ⠸ reify:react-dom: http fetch GET 200 https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz(#################⠂) ⠼ reify:react-dom: http fetch GET 200 https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz(#################⠂) ⠏ reify:react-dom: http fetch GET 200 https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz(##################) ⠋ reify:@babel/helpers: timing metavuln:calculate:security-advisory:fdir:2VXNT0aF/Oc+aljqzVZL+y7UY(##################) ⠧ reify:@babel/helpers: timing metavuln:calculate:security-advisory:fdir:2VXNT0aF/Oc+aljqzVZL+y7UY(##################) ⠏ reify:zrender: http fetch GET 200 https://registry.npmjs.org/zrender/-/zrender-6.0.0.tgz 1982ms(##################) ⠦ reify:lightningcss-linux-x64-gnu: http fetch GET 200 https://registry.npmjs.org/lightningcss-lin(##################) ⠸ reify:lightningcss-linux-x64-musl: http fetch GET 200 https://registry.npmjs.org/lightningcss-li(##################) ⠧ reify:lightningcss-linux-x64-musl: http fetch GET 200 https://registry.npmjs.org/lightningcss-li(##################) ⠏ reify:framer-motion: http fetch GET 200 https://registry.npmjs.org/framer-motion/-/framer-motion(##################) ⠙ reify:motion-dom: http fetch GET 200 https://registry.npmjs.org/motion-dom/-/motion-dom-12.34.3.(##################) ⠙ reify:motion-dom: http fetch GET 200 https://registry.npmjs.org/motion-dom/-/motion-dom-12.34.3.(##################) ⠸ reify:@esbuild/linux-x64: http fetch GET 200 https://registry.npmjs.org/@esbuild/linux-x64/-/lin(##################) ⠴ reify:caniuse-lite: http fetch GET 200 https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.(##################) ⠧ reify:@tauri-apps/cli-linux-x64-musl: http fetch GET 200 https://registry.npmjs.org/@tauri-apps/(##################) ⠏ reify:@tauri-apps/cli-linux-x64-gnu: http fetch GET 200 https://registry.npmjs.org/@tauri-apps/c(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠙ reify:typescript: http fetch GET 200 https://registry.npmjs.org/typescript/-/typescript-5.8.3.tg(##################) ⠸ reify:echarts: http fetch GET 200 https://registry.npmjs.org/echarts/-/echarts-6.0.0.tgz 3101ms(##################) ⠦ reify:lucide-react: http fetch GET 200 https://registry.npmjs.org/lucide-react/-/lucide-react-0.(##################) ⠋ reify:lucide-react: http fetch GET 200 https://registry.npmjs.org/lucide-react/-/lucide-react-0.(##################) ⠋ reify:lucide-react: http fetch GET 200 https://registry.npmjs.org/lucide-react/-/lucide-react-0.(##################) ⠧ reify:lucide-react: http fetch GET 200 https://registry.npmjs.org/lucide-react/-/lucide-react-0. added 160 packages, and audited 161 packages in 4s 23 packages are looking for funding run `npm fund` for details 2 high severity vulnerabilities To address all issues, run: npm audit fix Run `npm audit` for details. --- > aether-app@0.1.0 build > tsc && vite build vite v7.3.1 building client environment for production... transforming (1) src/main.tsxtransforming (19) node_modules/react-router/dist/development/chunk-4LKRSAEJ.mjstransforming (28) src/pages/Audit.tsxtransforming (49) node_modules/react-dom/client.jstransforming (1042) node_modules/lucide-react/dist/esm/icons/lectern.jstransforming (1055) node_modules/lucide-react/dist/esm/icons/line-dot-right-horizontal.jstransforming (1760) src/components/ui/tooltip.tsxtransforming (1844) node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.jstransforming (2038) node_modules/echarts/lib/chart/helper/createRenderPlanner.jstransforming (2098) node_modules/echarts/lib/component/thumbnail/ThumbnailModel.jstransforming (2262) node_modules/echarts/lib/chart/line/lineAnimationDiff.jstransforming (2324) node_modules/size-sensor/lib/sensorPool.js✓ 2388 modules transformed. rendering chunks (1)...computing gzip size (0)...computing gzip size (1)...computing gzip size (2)...computing gzip size (3)...dist/index.html 0.65 kB │ gzip: 0.40 kB dist/assets/index-BZ98cnyx.css 55.26 kB │ gzip: 9.27 kB dist/assets/index-C1YPVA_t.js 1,495.60 kB │ gzip: 489.64 kB (!) Some chunks are larger than 500 kB after minification. Consider: - Using dynamic import() to code-split the application - Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks - Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. ✓ built in 4.31s ```16 lines
``` DISPLAY=:0.0 WAYLAND_DISPLAY= XDG_SESSION_TYPE=x11 --- > aether-app@0.1.0 tauri > tauri dev Running BeforeDevCommand (`npm run dev`) > aether-app@0.1.0 dev > vite VITE v7.3.1 ready in 131 ms ➜ Local: http://localhost:1420/ Running DevCommand (`cargo run --no-default-features --color always --`) Info Watching /home/kali/Aether_wifi/src-tauri for changes... Updating crates.io index Fetch [========> ] 2 complete; 10 pending ```Arguments
```json { "shellId": "tauridev", "delay": 40 } ```16 lines
``` DISPLAY=:0.0 WAYLAND_DISPLAY= XDG_SESSION_TYPE=x11 --- > aether-app@0.1.0 tauri > tauri dev Running BeforeDevCommand (`npm run dev`) > aether-app@0.1.0 dev > vite VITE v7.3.1 ready in 131 ms ➜ Local: http://localhost:1420/ Running DevCommand (`cargo run --no-default-features --color always --`) Info Watching /home/kali/Aether_wifi/src-tauri for changes... Updating crates.io index Fetch [========> ] 2 complete; 10 pending ```Arguments
```json { "shellId": "tauridev", "delay": 120 } ```16 lines
``` DISPLAY=:0.0 WAYLAND_DISPLAY= XDG_SESSION_TYPE=x11 --- > aether-app@0.1.0 tauri > tauri dev Running BeforeDevCommand (`npm run dev`) > aether-app@0.1.0 dev > vite VITE v7.3.1 ready in 131 ms ➜ Local: http://localhost:1420/ Running DevCommand (`cargo run --no-default-features --color always --`) Info Watching /home/kali/Aether_wifi/src-tauri for changes... Updating crates.io index Fetch [========> ] 2 complete; 10 pending ```15 lines
``` 38644 38642 Sl+ 05:34 npm run tauri dev 38663 38644 S+ 05:33 sh -c tauri dev 38664 38663 Sl+ 05:33 node /home/kali/Aether_wifi/node_modules/.bin/tauri dev 38745 38721 S+ 05:33 sh -c vite 38746 38745 Sl+ 05:33 node /home/kali/Aether_wifi/node_modules/.bin/vite --- % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 HTTP/2 403 x-amz-request-id: VBWV0N9BN4D4GCF2 x-amz-id-2: 74043IIfhUMRE8DMWj8dpUILr3xntNXlUv316ksyPSVY5SVmA5NAYOnjnHSYIrnBdd7QzSIYFOzg7O9U0UMzOdWJqLA0dVl9 content-type: application/xml server: AmazonS3 ```143 lines
``` npm run tauri d,38644 ├─sh,38663 -c tauri dev │ └─node,38664 /home/kali/Aether_wifi/node_modules/.bin/tauri dev │ ├─aether-app,38785 │ │ ├─WebKitNetworkPr,45837 1 14 16 │ │ │ ├─{WebKitNetworkPr},45839 │ │ │ ├─{WebKitNetworkPr},45840 │ │ │ ├─{WebKitNetworkPr},45841 │ │ │ ├─{WebKitNetworkPr},45842 │ │ │ ├─{WebKitNetworkPr},45901 │ │ │ ├─{WebKitNetworkPr},45902 │ │ │ ├─{WebKitNetworkPr},45903 │ │ │ ├─{WebKitNetworkPr},45904 │ │ │ ├─{WebKitNetworkPr},45911 │ │ │ └─{WebKitNetworkPr},45912 │ │ ├─WebKitWebProces,45897 4 28 30 │ │ │ ├─{WebKitWebProces},45898 │ │ │ ├─{WebKitWebProces},45899 │ │ │ ├─{WebKitWebProces},45907 │ │ │ ├─{WebKitWebProces},45908 │ │ │ ├─{WebKitWebProces},45910 │ │ │ ├─{WebKitWebProces},45913 │ │ │ ├─{WebKitWebProces},45914 │ │ │ ├─{WebKitWebProces},45915 │ │ │ ├─{WebKitWebProces},45917 │ │ │ ├─{WebKitWebProces},45918 │ │ │ ├─{WebKitWebProces},45919 │ │ │ ├─{WebKitWebProces},45920 │ │ │ ├─{WebKitWebProces},45921 │ │ │ ├─{WebKitWebProces},45922 │ │ │ ├─{WebKitWebProces},45923 │ │ │ ├─{WebKitWebProces},45924 │ │ │ ├─{WebKitWebProces},45925 │ │ │ ├─{WebKitWebProces},45926 │ │ │ ├─{WebKitWebProces},45927 │ │ │ ├─{WebKitWebProces},45928 │ │ │ ├─{WebKitWebProces},45929 │ │ │ ├─{WebKitWebProces},45930 │ │ │ ├─{WebKitWebProces},45931 │ │ │ ├─{WebKitWebProces},45932 │ │ │ ├─{WebKitWebProces},45933 │ │ │ ├─{WebKitWebProces},45934 │ │ │ ├─{WebKitWebProces},45935 │ │ │ ├─{WebKitWebProces},45938 │ │ │ ├─{WebKitWebProces},45939 │ │ │ ├─{WebKitWebProces},45940 │ │ │ └─{WebKitWebProces},48547 │ │ ├─{aether-app},45810 │ │ ├─{aether-app},45812 │ │ ├─{aether-app},45813 │ │ ├─{aether-app},45814 │ │ ├─{aether-app},45815 │ │ ├─{aether-app},45816 │ │ ├─{aether-app},45835 │ │ ├─{aether-app},45877 │ │ ├─{aether-app},45878 │ │ ├─{aether-app},45879 │ │ ├─{aether-app},45880 │ │ ├─{aether-app},45881 │ │ ├─{aether-app},45882 │ │ ├─{aether-app},45883 │ │ ├─{aether-app},45884 │ │ ├─{aether-app},45885 │ │ ├─{aether-app},45886 │ │ ├─{aether-app},45887 │ │ ├─{aether-app},45888 │ │ ├─{aether-app},45889 │ │ ├─{aether-app},45890 │ │ ├─{aether-app},45891 │ │ ├─{aether-app},45892 │ │ ├─{aether-app},45893 │ │ ├─{aether-app},45894 │ │ ├─{aether-app},45900 │ │ ├─{aether-app},45906 │ │ └─{aether-app},45936 │ ├─sh,38720 -c npm run dev │ │ └─npm run dev,38721 │ │ ├─sh,38745 -c vite │ │ │ └─node,38746 /home/kali/Aether_wifi/node_modules/.bin/vite │ │ │ ├─esbuild,38753 --service=0.27.3 --ping │ │ │ │ ├─{esbuild},38754 │ │ │ │ ├─{esbuild},38755 │ │ │ │ ├─{esbuild},38756 │ │ │ │ ├─{esbuild},38757 │ │ │ │ ├─{esbuild},38758 │ │ │ │ ├─{esbuild},38764 │ │ │ │ ├─{esbuild},38765 │ │ │ │ ├─{esbuild},38766 │ │ │ │ ├─{esbuild},38767 │ │ │ │ └─{esbuild},38768 │ │ │ ├─{node},38747 │ │ │ ├─{node},38748 │ │ │ ├─{node},38749 │ │ │ ├─{node},38750 │ │ │ ├─{node},38751 │ │ │ ├─{node},38752 │ │ │ ├─{node},38759 │ │ │ ├─{node},38760 │ │ │ ├─{node},38761 │ │ │ ├─{node},38762 │ │ │ ├─{node},38763 │ │ │ ├─{node},45945 │ │ │ ├─{node},45946 │ │ │ ├─{node},45947 │ │ │ ├─{node},45948 │ │ │ ├─{node},45949 │ │ │ ├─{node},45950 │ │ │ ├─{node},45951 │ │ │ └─{node},45952 │ │ ├─{npm run dev},38725 │ │ ├─{npm run dev},38726 │ │ ├─{npm run dev},38727 │ │ ├─{npm run dev},38728 │ │ ├─{npm run dev},38729 │ │ ├─{npm run dev},38735 │ │ ├─{npm run dev},38737 │ │ ├─{npm run dev},38738 │ │ ├─{npm run dev},38739 │ │ └─{npm run dev},38740 │ ├─{node},38665 │ ├─{node},38666 │ ├─{node},38667 │ ├─{node},38668 │ ├─{node},38669 │ ├─{node},38670 │ ├─{node},38671 │ ├─{node},38722 │ ├─{node},38723 │ ├─{node},38794 │ ├─{node},38795 │ ├─{node},38808 │ └─{node},38809 ├─{npm run tauri d},38645 ├─{npm run tauri d},38646 ├─{npm run tauri d},38647 ├─{npm run tauri d},38648 ├─{npm run tauri d},38649 ├─{npm run tauri d},38650 ├─{npm run tauri d},38659 ├─{npm run tauri d},38660 ├─{npm run tauri d},38661 └─{npm run tauri d},38662 ```Arguments
```json { "pattern": "CAPTURE_ERROR|Failed to activate capture|CAP_NET_RAW|pcap|capture on|monitor mode", "path": "/home/kali/Aether_wifi", "output_mode": "content", "glob": "src/**/* src-tauri/**/*", "-n": true, "head_limit": 200 } ```13 matches
``` /home/kali/Aether_wifi/src-tauri/src/lib.rs /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs /home/kali/Aether_wifi/src-tauri/src/network/mod.rs /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs /home/kali/Aether_wifi/src-tauri/src/network/types.rs /home/kali/Aether_wifi/src-tauri/src/network/audit.rs /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs /home/kali/Aether_wifi/src-tauri/src/commands/audit_commands.rs /home/kali/Aether_wifi/src-tauri/src/commands/mod.rs /home/kali/Aether_wifi/src-tauri/src/commands/capture_commands.rs /home/kali/Aether_wifi/src-tauri/src/commands/network_commands.rs /home/kali/Aether_wifi/src-tauri/src/error.rs /home/kali/Aether_wifi/src-tauri/src/main.rs ```152 lines
```` 1. //! Tauri IPC command handlers for packet capture operations. 2. //! 3. //! Provides `start_capture` and `stop_capture` commands that the React 4. //! frontend invokes to control the packet sniffing engine. 5. //! 6. //! The capture runs in a background thread. Parsed beacon frames are 7. //! streamed to the frontend via Tauri's event system as `"beacon-frame"` events. 8. 9. use std::sync::Mutex; 10. 11. use log::info; 12. use tauri::Emitter; 13. 14. use crate::error::AetherError; 15. use crate::network::{self, CaptureHandle, CaptureStatus}; 16. 17. /// Managed Tauri state holding the active capture session (if any). 18. /// 19. /// We use `Mutex>` so that: 20. /// - `None` = no capture running 21. /// - `Some(handle)` = active capture session 22. /// 23. /// Only one capture can run at a time (per the WiFi adapter constraint). 24. pub struct CaptureState(pub Mutex>); 25. 26. /// Start capturing beacon frames on a monitor-mode interface. 27. /// 28. /// Parsed beacon data is emitted as Tauri events with name `"beacon-frame"` 29. /// and a JSON payload matching the `BeaconFrame` struct. 30. /// 31. /// # Frontend Usage 32. /// ```typescript 33. /// import { invoke } from '@tauri-apps/api/core'; 34. /// import { listen } from '@tauri-apps/api/event'; 35. /// 36. /// // Start listening for beacons 37. /// const unlisten = await listen('beacon-frame', (event) => { 38. /// const beacon = event.payload; // { bssid, ssid, channel, rssi, ... } 39. /// console.log('Beacon:', beacon); 40. /// }); 41. /// 42. /// // Start the capture 43. /// await invoke('start_capture', { interfaceName: 'wlan0mon' }); 44. /// 45. /// // Later, stop the capture 46. /// await invoke('stop_capture'); 47. /// unlisten(); 48. /// ``` 49. #[tauri::command] 50. pub fn start_capture( 51. interface_name: String, 52. state: tauri::State<'_, CaptureState>, 53. app_handle: tauri::AppHandle, 54. ) -> Result { 55. info!("[cmd] start_capture: {}", interface_name); 56. 57. let mut capture_guard = state 58. .0 59. .lock() 60. .map_err(|e| AetherError::CaptureError(format!("Lock poisoned: {}", e)))?; 61. 62. if capture_guard.is_some() { 63. return Err(AetherError::CaptureAlreadyRunning( 64. interface_name.clone(), 65. )); 66. } 67. 68. // Clone the app handle for use in the capture callback. 69. // This closure is called on the capture thread for each parsed beacon. 70. let handle = app_handle.clone(); 71. let iface_clone = interface_name.clone(); 72. 73. let capture_handle = network::packet_sniffer::start_capture( 74. &interface_name, 75. move |beacon| { 76. // Emit the beacon frame as a Tauri event to all frontend windows 77. if let Err(e) = handle.emit("beacon-frame", &beacon) { 78. log::warn!( 79. "Failed to emit beacon-frame event on '{}': {}", 80. iface_clone, 81. e 82. ); 83. } 84. }, 85. )?; 86. 87. *capture_guard = Some(capture_handle); 88. 89. Ok(CaptureStatus { 90. interface_name, 91. active: true, 92. message: "Capture started. Beacon frames are being streamed to the frontend.".into(), 93. }) 94. } 95. 96. /// Stop the active capture session. 97. /// 98. /// If no capture is running, this is a no-op (returns success with a message). 99. #[tauri::command] 100. pub fn stop_capture( 101. state: tauri::State<'_, CaptureState>, 102. ) -> Result { 103. info!("[cmd] stop_capture"); 104. 105. let mut capture_guard = state 106. .0 107. .lock() 108. .map_err(|e| AetherError::CaptureError(format!("Lock poisoned: {}", e)))?; 109. 110. match capture_guard.take() { 111. Some(mut handle) => { 112. handle.stop(); 113. Ok(CaptureStatus { 114. interface_name: String::new(), 115. active: false, 116. message: "Capture stopped.".into(), 117. }) 118. } 119. None => Ok(CaptureStatus { 120. interface_name: String::new(), 121. active: false, 122. message: "No capture was running.".into(), 123. }), 124. } 125. } 126. 127. /// Check whether a capture is currently active. 128. #[tauri::command] 129. pub fn capture_status( 130. state: tauri::State<'_, CaptureState>, 131. ) -> Result { 132. let capture_guard = state 133. .0 134. .lock() 135. .map_err(|e| AetherError::CaptureError(format!("Lock poisoned: {}", e)))?; 136. 137. let active = capture_guard 138. .as_ref() 139. .map(|h| h.is_active()) 140. .unwrap_or(false); 141. 142. Ok(CaptureStatus { 143. interface_name: String::new(), 144. active, 145. message: if active { 146. "Capture is running.".into() 147. } else { 148. "No active capture.".into() 149. }, 150. }) 151. } 152. ````86 lines
``` 1. //! Aether-Core error types. 2. //! 3. //! Provides a unified error enum for all backend operations, 4. //! with automatic conversion to serializable formats for the Tauri IPC bridge. 5. 6. use serde::Serialize; 7. use thiserror::Error; 8. 9. /// Primary error type for all Aether-Core operations. 10. #[derive(Debug, Error)] 11. pub enum AetherError { 12. /// A shell command failed to execute or returned a non-zero exit code. 13. #[error("Command execution failed: {command} — {detail}")] 14. CommandFailed { command: String, detail: String }, 15. 16. /// The operation requires elevated privileges (root/sudo). 17. #[error("Permission denied: {0}. Run with elevated privileges (sudo/pkexec).")] 18. PermissionDenied(String), 19. 20. /// The requested network interface does not exist on this system. 21. #[error("Interface not found: '{0}'")] 22. InterfaceNotFound(String), 23. 24. /// Failed to parse output from a system command. 25. #[error("Parse error: {origin} — {detail}")] 26. ParseError { origin: String, detail: String }, 27. 28. /// The current operating system does not support this operation. 29. #[error("Unsupported platform: {0}")] 30. UnsupportedPlatform(String), 31. 32. /// Packet capture error (pcap layer). 33. #[error("Capture error: {0}")] 34. CaptureError(String), 35. 36. /// A capture session is already running on this interface. 37. #[error("Capture already running on interface '{0}'")] 38. CaptureAlreadyRunning(String), 39. 40. /// Wrapper for standard I/O errors. 41. #[error("I/O error: {0}")] 42. Io(#[from] std::io::Error), 43. } 44. 45. /// Serializable error payload sent to the React frontend via Tauri IPC. 46. #[derive(Debug, Serialize, Clone)] 47. pub struct ErrorPayload { 48. pub code: String, 49. pub message: String, 50. } 51. 52. impl From<&AetherError> for ErrorPayload { 53. fn from(err: &AetherError) -> Self { 54. let code = match err { 55. AetherError::CommandFailed { .. } => "COMMAND_FAILED", 56. AetherError::PermissionDenied(_) => "PERMISSION_DENIED", 57. AetherError::InterfaceNotFound(_) => "INTERFACE_NOT_FOUND", 58. AetherError::ParseError { .. } => "PARSE_ERROR", 59. AetherError::UnsupportedPlatform(_) => "UNSUPPORTED_PLATFORM", 60. AetherError::CaptureError(_) => "CAPTURE_ERROR", 61. AetherError::CaptureAlreadyRunning(_) => "CAPTURE_ALREADY_RUNNING", 62. AetherError::Io(_) => "IO_ERROR", 63. } 64. .to_string(); 65. 66. ErrorPayload { 67. code, 68. message: err.to_string(), 69. } 70. } 71. } 72. 73. // Allow AetherError to be returned from Tauri commands. 74. // Tauri requires command return errors to implement Serialize. 75. impl Serialize for AetherError { 76. fn serializeArguments
```json { "pattern": "sudo|pkexec|setcap|cap_net_raw|geteuid|uid|monitor mode|ip link|iw ", "path": "/home/kali/Aether_wifi/src-tauri/src", "output_mode": "content", "type": "rust", "-n": true, "head_limit": 200 } ```52 lines
``` /home/kali/Aether_wifi/src-tauri/src/lib.rs:28://! | +-- InterfaceScanner (iw dev / ip link) | /home/kali/Aether_wifi/src-tauri/src/lib.rs:29://! | +-- ModeController (iw set type) | /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:4://! 1. Primary: `iw dev` — gives wireless-specific data (phy, mode, channel). /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:5://! 2. Fallback: `ip link show` — works on all Linux systems, lists all NICs. /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:27: /// Tries `iw dev` first for wireless detail, then falls back to `ip link`. /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:42: warn!("iw dev scan failed ({e}), falling back to ip link"); /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:46: // Merge with ip link data to catch non-wireless & fill gaps /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:48: warn!("ip link scan failed: {e}"); /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:79: // Primary scanner: `iw dev` /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:88: /// Parse output of `iw dev` into a list of interfaces. /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:131: is_up: false, // Will be determined by ip link /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:155: debug!("iw dev: parsed {} wireless interface(s)", interfaces.len()); /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:160: // Fallback scanner: `ip link show` /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:203: || link_type == "ether"; // will be overridden by iw merge /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:218: debug!("ip link: parsed {} interface(s)", interfaces.len()); /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:270: // If iw also didn't flag it, it's not wireless /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:289: // Update fields from ip link that iw doesn't provide /home/kali/Aether_wifi/src-tauri/src/network/interface_scanner.rs:295: // New interface not seen by `iw dev` — probably wired /home/kali/Aether_wifi/src-tauri/src/commands/network_commands.rs:49:/// 3. Set new mode (`iw set type managed|monitor`) /home/kali/Aether_wifi/src-tauri/src/error.rs:16: /// The operation requires elevated privileges (root/sudo). /home/kali/Aether_wifi/src-tauri/src/error.rs:17: #[error("Permission denied: {0}. Run with elevated privileges (sudo/pkexec).")] /home/kali/Aether_wifi/src-tauri/src/network/types.rs:33: /// Returns the `iw` type string used in `iw set type `. /home/kali/Aether_wifi/src-tauri/src/network/types.rs:86: /// PHY index from `iw dev` (e.g. "phy0"). /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:5://! 2. Bring interface down (`ip link set down`) /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:6://! 3. Set the new mode (`iw set type `) /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:7://! 4. Bring interface back up (`ip link set up`) /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:133: /// Attempt to stop processes that interfere with monitor mode. /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:162: /// Restore the services commonly disabled for monitor mode workflows. /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:188: /// Execute a command with sudo/pkexec elevation. /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:191: /// then falls back to `sudo`. /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:212: // If permission denied, retry with sudo /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:217: debug!("Permission denied, retrying with sudo..."); /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:218: return Self::run_with_sudo(program, args); /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:227: /// Execute a command prefixed with `sudo -n` (non-interactive). /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:229: /// The `-n` flag prevents sudo from prompting for a password, /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:230: /// which would hang a headless daemon. If passwordless sudo /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:233: fn run_with_sudo(program: &str, args: &[&str]) -> AetherResult { /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:234: let mut sudo_args = vec!["-n", program]; /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:235: sudo_args.extend_from_slice(args); /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:237: let cmd_str = format!("sudo {} {}", program, args.join(" ")); /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:240: let output = Command::new("sudo") /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:241: .args(&sudo_args) /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:254: if stderr.contains("a password is required") || stderr.contains("sudo:") { /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:256: "Passwordless sudo is not configured for '{}'. \ /home/kali/Aether_wifi/src-tauri/src/network/mode_controller.rs:257: Configure sudoers or run Aether-Core as root.", /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs:11://! # Frame Structure (captured in monitor mode with Radiotap) /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs:157: // Open the interface in monitor mode with pcap. /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs:159: // Promiscuous mode is irrelevant in monitor mode but we set it anyway. /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs:174: // *already* in monitor mode (common with Realtek/DKMS drivers), the /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs:188: (interface may already be in monitor mode).", /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs:194: Ensure the interface is in monitor mode and you have root/sudo privileges.", /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs:206: Ensure the interface is in monitor mode.", ```101 lines
``` 140. 141. /// Start capturing beacon frames on the specified monitor-mode interface. 142. /// 143. /// The capture runs in a background thread. Parsed [`BeaconFrame`] payloads 144. /// are sent to the provided callback, which the Tauri command layer uses 145. /// to emit IPC events. 146. /// 147. /// Returns a [`CaptureHandle`] that can be used to stop the capture. 148. pub fn start_capture( 149. interface_name: &str, 150. on_beacon: F, 151. ) -> Result 152. where 153. F: Fn(BeaconFrame) + Send + 'static, 154. { 155. info!("Opening pcap capture on interface '{}'...", interface_name); 156. 157. // Open the interface in monitor mode with pcap. 158. // We use a 65535 snaplen to capture full frames including radiotap. 159. // Promiscuous mode is irrelevant in monitor mode but we set it anyway. 160. // Timeout of 100ms prevents busy-waiting while still being responsive. 161. // Helper closure to create an inactive capture with common settings. 162. let make_inactive = || -> Result, crate::error::AetherError> { 163. pcap::Capture::from_device(interface_name) 164. .map_err(|e| { 165. crate::error::AetherError::CaptureError(format!( 166. "Failed to open device '{}': {}", 167. interface_name, e 168. )) 169. }) 170. .map(|c| c.snaplen(65535).promisc(true).timeout(100)) 171. }; 172. 173. // On Linux, try opening with rfmon(true) first. If the interface is 174. // *already* in monitor mode (common with Realtek/DKMS drivers), the 175. // SIOCSIWMODE ioctl may fail. In that case, fall back to opening 176. // without rfmon — the interface is already delivering radiotap frames. 177. #[cfg(not(windows))] 178. let cap = { 179. let with_rfmon = make_inactive()?.rfmon(true).open(); 180. match with_rfmon { 181. Ok(c) => { 182. info!("Opened capture with rfmon=true on '{}'", interface_name); 183. c 184. } 185. Err(rfmon_err) => { 186. warn!( 187. "rfmon(true) failed on '{}': {}. Trying without rfmon \ 188. (interface may already be in monitor mode).", 189. interface_name, rfmon_err 190. ); 191. make_inactive()?.open().map_err(|e| { 192. crate::error::AetherError::CaptureError(format!( 193. "Failed to activate capture on '{}': {}. \ 194. Ensure the interface is in monitor mode and you have root/sudo privileges.", 195. interface_name, e 196. )) 197. })? 198. } 199. } 200. }; 201. 202. #[cfg(windows)] 203. let cap = make_inactive()?.open().map_err(|e| { 204. crate::error::AetherError::CaptureError(format!( 205. "Failed to activate capture on '{}': {}. \ 206. Ensure the interface is in monitor mode.", 207. interface_name, e 208. )) 209. })?; 210. 211. info!( 212. "Capture opened on '{}'. Datalink: {:?}", 213. interface_name, 214. cap.get_datalink() 215. ); 216. 217. // Verify we're getting radiotap-encapsulated frames 218. let datalink = cap.get_datalink(); 219. if datalink != pcap::Linktype::IEEE802_11_RADIOTAP { 220. warn!( 221. "Expected IEEE802_11_RADIOTAP datalink, got {:?}. \ 222. Beacon parsing may fail.", 223. datalink 224. ); 225. } 226. 227. let stop_flag = Arc::new(AtomicBool::new(false)); 228. let stop_clone = stop_flag.clone(); 229. let iface_name = interface_name.to_string(); 230. 231. let thread = std::thread::Builder::new() 232. .name(format!("aether-capture-{}", interface_name)) 233. .spawn(move || { 234. capture_loop(cap, &iface_name, stop_clone, on_beacon); 235. }) 236. .map_err(|e| { 237. crate::error::AetherError::CaptureError(format!( 238. "Failed to spawn capture thread: {}", 239. e 240. )) ```101 lines
``` 180. for service in &["wpa_supplicant", "NetworkManager"] { 181. match Self::run_privileged("systemctl", &["restart", service]) { 182. Ok(_) => info!("Restarted {}", service), 183. Err(e) => warn!("Could not restart {}: {}", service, e), 184. } 185. } 186. } 187. 188. /// Execute a command with sudo/pkexec elevation. 189. /// 190. /// Tries the command directly first (in case we're already root), 191. /// then falls back to `sudo`. 192. #[cfg(target_os = "linux")] 193. fn run_privileged(program: &str, args: &[&str]) -> AetherResult { 194. let cmd_str = format!("{} {}", program, args.join(" ")); 195. debug!("exec (privileged): {}", cmd_str); 196. 197. // Attempt direct execution first (works if running as root) 198. let output = Command::new(program) 199. .args(args) 200. .output() 201. .map_err(|e| AetherError::CommandFailed { 202. command: cmd_str.clone(), 203. detail: e.to_string(), 204. })?; 205. 206. if output.status.success() { 207. return Ok(String::from_utf8_lossy(&output.stdout).to_string()); 208. } 209. 210. let stderr = String::from_utf8_lossy(&output.stderr).to_string(); 211. 212. // If permission denied, retry with sudo 213. if stderr.contains("Operation not permitted") 214. || stderr.contains("Permission denied") 215. || stderr.contains("Not permitted") 216. { 217. debug!("Permission denied, retrying with sudo..."); 218. return Self::run_with_sudo(program, args); 219. } 220. 221. Err(AetherError::CommandFailed { 222. command: cmd_str, 223. detail: stderr, 224. }) 225. } 226. 227. /// Execute a command prefixed with `sudo -n` (non-interactive). 228. /// 229. /// The `-n` flag prevents sudo from prompting for a password, 230. /// which would hang a headless daemon. If passwordless sudo 231. /// isn't configured, this returns PermissionDenied. 232. #[cfg(target_os = "linux")] 233. fn run_with_sudo(program: &str, args: &[&str]) -> AetherResult { 234. let mut sudo_args = vec!["-n", program]; 235. sudo_args.extend_from_slice(args); 236. 237. let cmd_str = format!("sudo {} {}", program, args.join(" ")); 238. debug!("exec: {}", cmd_str); 239. 240. let output = Command::new("sudo") 241. .args(&sudo_args) 242. .output() 243. .map_err(|e| AetherError::CommandFailed { 244. command: cmd_str.clone(), 245. detail: e.to_string(), 246. })?; 247. 248. if output.status.success() { 249. return Ok(String::from_utf8_lossy(&output.stdout).to_string()); 250. } 251. 252. let stderr = String::from_utf8_lossy(&output.stderr).to_string(); 253. 254. if stderr.contains("a password is required") || stderr.contains("sudo:") { 255. return Err(AetherError::PermissionDenied(format!( 256. "Passwordless sudo is not configured for '{}'. \ 257. Configure sudoers or run Aether-Core as root.", 258. program 259. ))); 260. } 261. 262. Err(AetherError::CommandFailed { 263. command: cmd_str, 264. detail: stderr, 265. }) 266. } 267. } 268. 269. // ───────────────────────────────────────────────── 270. // Tests 271. // ───────────────────────────────────────────────── 272. 273. #[cfg(test)] 274. mod tests { 275. use super::*; 276. 277. #[test] 278. fn mode_toggle_logic() { 279. // Verify the toggle produces the expected target 280. assert_eq!(InterfaceMode::Managed.toggled(), InterfaceMode::Monitor); ```125 lines
``` 1. //! Tauri IPC command handlers for network operations. 2. //! 3. //! These functions are exposed to the React frontend via `tauri::command`. 4. //! Each handler is a thin wrapper that calls into the `network` module 5. //! and returns serializable results. 6. 7. use crate::error::AetherError; 8. use crate::network::{InterfaceMode, InterfaceModeResult, InterfaceScanner, ModeController, NetworkInterface}; 9. 10. /// List all available network interfaces. 11. /// 12. /// Returns both wired and wireless interfaces. Each includes 13. /// metadata like mode, MAC address, UP/DOWN state, and whether 14. /// it's a wireless adapter. 15. /// 16. /// Invoked from frontend: `invoke('list_interfaces')` 17. #[tauri::command] 18. pub fn list_interfaces() -> Result, AetherError> { 19. log::info!("[cmd] list_interfaces"); 20. InterfaceScanner::list_interfaces() 21. } 22. 23. /// List only wireless network interfaces. 24. /// 25. /// Filters out wired/virtual interfaces — useful for the UI 26. /// dropdown that selects a WiFi adapter for scanning. 27. /// 28. /// Invoked from frontend: `invoke('list_wireless_interfaces')` 29. #[tauri::command] 30. pub fn list_wireless_interfaces() -> Result, AetherError> { 31. log::info!("[cmd] list_wireless_interfaces"); 32. InterfaceScanner::list_wireless() 33. } 34. 35. /// Get detailed info for a specific interface by name. 36. /// 37. /// Invoked from frontend: `invoke('get_interface', { name: 'wlan0' })` 38. #[tauri::command] 39. pub fn get_interface(name: String) -> Result { 40. log::info!("[cmd] get_interface: {}", name); 41. InterfaceScanner::get_interface(&name) 42. } 43. 44. /// Toggle a wireless interface between Managed and Monitor mode. 45. /// 46. /// This is the core privileged operation. The sequence: 47. /// 1. Kill interfering processes (NetworkManager, wpa_supplicant) 48. /// 2. Bring interface down 49. /// 3. Set new mode (`iw set type managed|monitor`) 50. /// 4. Bring interface back up 51. /// 5. Verify the mode actually changed 52. /// 53. /// Returns an `InterfaceModeResult` with before/after state and success flag. 54. /// 55. /// Invoked from frontend: `invoke('toggle_interface_mode', { interfaceName: 'wlan0' })` 56. #[tauri::command] 57. pub fn toggle_interface_mode( 58. interface_name: String, 59. ) -> Result { 60. log::info!("[cmd] toggle_interface_mode: {}", interface_name); 61. ModeController::toggle_mode(&interface_name) 62. } 63. 64. /// Explicitly set an interface to a specific mode. 65. /// 66. /// Accepts `target_mode` as "managed" or "monitor". 67. /// 68. /// Invoked from frontend: `invoke('set_interface_mode', { interfaceName: 'wlan0', targetMode: 'monitor' })` 69. #[tauri::command] 70. pub fn set_interface_mode( 71. interface_name: String, 72. target_mode: String, 73. ) -> Result { 74. log::info!( 75. "[cmd] set_interface_mode: {} → {}", 76. interface_name, 77. target_mode 78. ); 79. 80. let current = InterfaceScanner::get_interface(&interface_name)?; 81. let target = InterfaceMode::from_str_lossy(&target_mode); 82. 83. if target == InterfaceMode::Unknown { 84. return Err(AetherError::CommandFailed { 85. command: "set_interface_mode".into(), 86. detail: format!( 87. "Invalid target mode '{}'. Use 'managed' or 'monitor'.", 88. target_mode 89. ), 90. }); 91. } 92. 93. if current.mode == target { 94. return Ok(InterfaceModeResult { 95. interface_name: interface_name.clone(), 96. previous_mode: current.mode.clone(), 97. current_mode: current.mode, 98. success: true, 99. message: format!("{} is already in {} mode.", interface_name, target), 100. }); 101. } 102. 103. ModeController::set_mode(&interface_name, &target)?; 104. 105. let updated = InterfaceScanner::get_interface(&interface_name)?; 106. 107. let success = updated.mode == target; 108. let message = if success { 109. format!("Set {} to {} mode.", interface_name, target) 110. } else { 111. format!( 112. "Command completed but {} reports '{}' instead of '{}'.", 113. interface_name, updated.mode, target 114. ) 115. }; 116. 117. Ok(InterfaceModeResult { 118. interface_name, 119. previous_mode: current.mode, 120. current_mode: updated.mode, 121. success, 122. message, 123. }) 124. } 125. ```84 lines
```` 1. //! Aether-Core — the privileged Rust backend for the Aether WiFi analyzer. 2. //! 3. //! This crate powers the Tauri desktop application, handling: 4. //! - Network interface discovery and enumeration 5. //! - Wireless adapter mode management (Managed <-> Monitor) 6. //! - Raw 802.11 packet capture (Beacon frame parsing, RSSI extraction) 7. //! - Deauthentication frame injection and EAPOL handshake capture 8. //! - Real-time event streaming to the React frontend 9. //! 10. //! # Architecture 11. //! 12. //! ```text 13. //! +---------------------------------------------+ 14. //! | React Frontend (Aether-UI) | 15. //! | +- invoke('list_interfaces') | 16. //! | +- invoke('start_capture', {...}) | 17. //! | +- invoke('send_deauth', {...}) | 18. //! | +- invoke('one_click_capture', {...}) | 19. //! | +- listen('beacon-frame', callback) | 20. //! | +- listen('eapol-status', callback) | 21. //! +---------------------------------------------+ 22. //! | Tauri IPC Bridge (commands/) | 23. //! | +-- network_commands (scan, mode toggle) | 24. //! | +-- capture_commands (start/stop sniffer) | 25. //! | +-- audit_commands (deauth, EAPOL) | 26. //! +---------------------------------------------+ 27. //! | Business Logic (network/) | 28. //! | +-- InterfaceScanner (iw dev / ip link) | 29. //! | +-- ModeController (iw set type) | 30. //! | +-- PacketSniffer (pcap + 802.11) | 31. //! | +-- Audit (deauth + EAPOL) | 32. //! +---------------------------------------------+ 33. //! | Linux Kernel (nl80211 / wireless stack) | 34. //! +---------------------------------------------+ 35. //! ``` 36. 37. mod commands; 38. pub mod error; 39. pub mod network; 40. 41. use commands::{audit_commands, capture_commands, network_commands}; 42. 43. #[cfg_attr(mobile, tauri::mobile_entry_point)] 44. pub fn run() { 45. // Initialize env_logger for structured log output in development 46. env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) 47. .format_timestamp_millis() 48. .init(); 49. 50. log::info!("Aether-Core v{} starting...", env!("CARGO_PKG_VERSION")); 51. 52. tauri::Builder::default() 53. .plugin(tauri_plugin_opener::init()) 54. // Managed state: tracks the active packet capture session 55. .manage(capture_commands::CaptureState(std::sync::Mutex::new(None))) 56. // Managed state: tracks the active EAPOL handshake capture 57. .manage(audit_commands::EapolCaptureState(std::sync::Mutex::new( 58. None, 59. ))) 60. // Managed state: tracks the active deauth attack 61. .manage(audit_commands::DeauthState(std::sync::Mutex::new(None))) 62. .invoke_handler(tauri::generate_handler![ 63. // Network interface management 64. network_commands::list_interfaces, 65. network_commands::list_wireless_interfaces, 66. network_commands::get_interface, 67. network_commands::toggle_interface_mode, 68. network_commands::set_interface_mode, 69. // Packet capture 70. capture_commands::start_capture, 71. capture_commands::stop_capture, 72. capture_commands::capture_status, 73. // Offensive audit suite 74. audit_commands::start_deauth, 75. audit_commands::stop_deauth, 76. audit_commands::start_eapol_capture, 77. audit_commands::stop_eapol_capture, 78. audit_commands::one_click_capture, 79. audit_commands::stop_all_attacks, 80. ]) 81. .run(tauri::generate_context!()) 82. .expect("error while running Aether application"); 83. } 84. ````150 lines
``` 1. #!/usr/bin/env bash 2. # ═══════════════════════════════════════════════════════ 3. # AETHER WiFi Auditor — One-Command Launcher 4. # ═══════════════════════════════════════════════════════ 5. # 6. # Usage: 7. # bash ./aether.sh 8. # 9. # Optional overrides: 10. # AETHER_IFACE=wlan1 bash ./aether.sh 11. # AETHER_RESTORE_MANAGED=0 bash ./aether.sh 12. # 13. # ═══════════════════════════════════════════════════════ 14. 15. set -euo pipefail 16. 17. IFACE="${AETHER_IFACE:-wlan0}" 18. SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" 19. PROJECT_DIR="${AETHER_PROJECT_DIR:-$SCRIPT_DIR}" 20. RESTORE_MANAGED="${AETHER_RESTORE_MANAGED:-1}" 21. NEEDS_CLEANUP=0 22. NETWORKMANAGER_WAS_ACTIVE=0 23. WPASUPPLICANT_WAS_ACTIVE=0 24. 25. RED='\033[0;31m' 26. GREEN='\033[0;32m' 27. CYAN='\033[0;36m' 28. YELLOW='\033[1;33m' 29. NC='\033[0m' 30. 31. service_is_active() { 32. local service="$1" 33. command -v systemctl &>/dev/null && systemctl is-active --quiet "$service" 34. } 35. 36. restore_interface_state() { 37. if [ "$RESTORE_MANAGED" != "1" ] || [ "$NEEDS_CLEANUP" -ne 1 ]; then 38. return 39. fi 40. 41. echo -e "" 42. echo -e "${YELLOW}[cleanup]${NC} Restoring ${IFACE} to managed mode..." 43. 44. sudo ip link set "$IFACE" down &>/dev/null || true 45. sudo iw "$IFACE" set type managed &>/dev/null || true 46. sudo ip link set "$IFACE" up &>/dev/null || true 47. 48. if command -v nmcli &>/dev/null; then 49. sudo nmcli device set "$IFACE" managed yes &>/dev/null || true 50. fi 51. 52. if command -v systemctl &>/dev/null; then 53. if [ "$NETWORKMANAGER_WAS_ACTIVE" -eq 1 ]; then 54. sudo systemctl restart NetworkManager &>/dev/null || true 55. fi 56. 57. if [ "$WPASUPPLICANT_WAS_ACTIVE" -eq 1 ]; then 58. sudo systemctl restart wpa_supplicant &>/dev/null || true 59. fi 60. fi 61. 62. echo -e " ${GREEN}✓${NC}20 lines
``` 1. @echo off 2. REM ═══════════════════════════════════════════════ 3. REM AETHER WiFi Auditor — Windows Launcher 4. REM Double-click this to launch Aether 5. REM ═══════════════════════════════════════════════ 6. title Aether WiFi Auditor 7. echo. 8. echo ◈ AETHER WiFi Auditor ◈ 9. echo Launching via Kali WSL2... 10. echo. 11. Pwsh -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\attach_wsl_wifi.ps1" -AdapterName "802.11" 12. if errorlevel 1 ( 13. echo. 14. echo [ERROR] Failed to attach the WiFi adapter to WSL. 15. pause 16. exit /b 1 17. ) 18. wsl -d kali-linux -- bash /mnt/c/Users/WontML/dev/Aether_wifi/aether.sh 19. pause 20. ```43 lines
``` 1. { 2. "name": "aether-app", 3. "private": true, 4. "version": "0.1.0", 5. "type": "module", 6. "scripts": { 7. "dev": "vite", 8. "build": "tsc && vite build", 9. "preview": "vite preview", 10. "tauri": "tauri" 11. }, 12. "dependencies": { 13. "@radix-ui/react-dialog": "^1.1.15", 14. "@radix-ui/react-tabs": "^1.1.13", 15. "@radix-ui/react-tooltip": "^1.2.8", 16. "@tauri-apps/api": "^2", 17. "@tauri-apps/plugin-opener": "^2", 18. "clsx": "^2.1.1", 19. "echarts": "^6.0.0", 20. "echarts-for-react": "^3.0.6", 21. "framer-motion": "^12.34.3", 22. "lucide-react": "^0.575.0", 23. "react": "^19.1.0", 24. "react-dom": "^19.1.0", 25. "react-router-dom": "^7.13.0", 26. "tailwind-merge": "^3.5.0" 27. }, 28. "devDependencies": { 29. "@tailwindcss/cli": "^4.2.0", 30. "@tailwindcss/postcss": "^4.2.0", 31. "@tailwindcss/vite": "^4.2.0", 32. "@tauri-apps/cli": "^2", 33. "@types/react": "^19.1.8", 34. "@types/react-dom": "^19.1.6", 35. "@vitejs/plugin-react": "^4.6.0", 36. "autoprefixer": "^10.4.24", 37. "postcss": "^8.5.6", 38. "tailwindcss": "^4.2.0", 39. "typescript": "~5.8.3", 40. "vite": "^7.0.4" 41. } 42. } 43. ```Arguments
```json { "pattern": "setcap|cap_net_raw|cap_net_admin|tauri dev|cargo tauri dev|aether.sh", "path": "/home/kali/Aether_wifi", "output_mode": "content", "-n": true, "head_limit": 100 } ```8 lines
``` /home/kali/Aether_wifi/vite.config.ts:11: // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` /home/kali/Aether_wifi/README.md:186:cargo tauri dev /home/kali/Aether_wifi/aether.sh:7:# bash ./aether.sh /home/kali/Aether_wifi/aether.sh:10:# AETHER_IFACE=wlan1 bash ./aether.sh /home/kali/Aether_wifi/aether.sh:11:# AETHER_RESTORE_MANAGED=0 bash ./aether.sh /home/kali/Aether_wifi/aether.sh:106: echo " Set a different interface: AETHER_IFACE=wlanX bash ./aether.sh" /home/kali/Aether_wifi/aether.sh:149: sudo -E "$(which cargo)" tauri dev 2>&1 /home/kali/Aether_wifi/Aether.bat:18:wsl -d kali-linux -- bash /mnt/c/Users/WontML/dev/Aether_wifi/aether.sh ```17 lines
``` lo UNKNOWN 00:00:00:00:00:00 eth0 UP 00:0c:29:f1:8f:bf wlan0 DOWN 66:94:99:bb:df:57 --- phy#1 Interface wlan0 ifindex 3 wdev 0x100000001 addr 66:94:99:bb:df:57 type managed txpower 20.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 --- 38664 ```120 lines
```` 1. //! Packet sniffer — captures and parses raw 802.11 Beacon frames. 2. //! 3. //! This module uses libpcap to open a monitor-mode wireless interface 4. //! and captures raw 802.11 frames. It specifically targets Beacon frames 5. //! (management type 0, subtype 8) and extracts: 6. //! - BSSID (from the 802.11 MAC header) 7. //! - SSID (from the SSID Information Element, Tag 0) 8. //! - Channel (from DS Parameter Set IE Tag 3, or radiotap frequency) 9. //! - RSSI (Antenna Signal dBm from the Radiotap header) 10. //! 11. //! # Frame Structure (captured in monitor mode with Radiotap) 12. //! 13. //! ```text 14. //! ┌──────────────────────────────────────────────────┐ 15. //! │ Radiotap Header (variable length) │ 16. //! │ ├─ version: u8 (always 0) │ 17. //! │ ├─ pad: u8 │ 18. //! │ ├─ length: u16 LE ← total radiotap length │ 19. //! │ ├─ present: u32 LE ← bitmask of fields │ 20. //! │ └─ fields: [varies by present flags] │ 21. //! ├──────────────────────────────────────────────────┤ 22. //! │ 802.11 MAC Header (24 bytes for mgmt frames) │ 23. //! │ ├─ Frame Control: 2 bytes │ 24. //! │ ├─ Duration/ID: 2 bytes │ 25. //! │ ├─ Address 1 (DA): 6 bytes ← broadcast │ 26. //! │ ├─ Address 2 (SA): 6 bytes ← BSSID │ 27. //! │ ├─ Address 3: 6 bytes ← BSSID │ 28. //! │ └─ Sequence Ctrl: 2 bytes │ 29. //! ├──────────────────────────────────────────────────┤ 30. //! │ Beacon Frame Body │ 31. //! │ ├─ Timestamp: 8 bytes │ 32. //! │ ├─ Beacon Interval: 2 bytes │ 33. //! │ ├─ Capability Info: 2 bytes │ 34. //! │ └─ Tagged Parameters (IEs): │ 35. //! │ ├─ Tag 0: SSID │ 36. //! │ ├─ Tag 3: DS Parameter Set (channel) │ 37. //! │ └─ ... │ 38. //! └──────────────────────────────────────────────────┘ 39. //! ``` 40. 41. use byteorder::{LittleEndian, ReadBytesExt}; 42. use log::{debug, error, info, trace, warn}; 43. use std::io::Cursor; 44. use std::sync::atomic::{AtomicBool, Ordering}; 45. use std::sync::Arc; 46. use std::time::{SystemTime, UNIX_EPOCH}; 47. 48. use super::types::BeaconFrame; 49. 50. // ───────────────────────────────────────────────── 51. // Constants: 802.11 Frame Control 52. // ───────────────────────────────────────────────── 53. 54. /// 802.11 Management frame type (bits 2-3 of Frame Control byte 0). 55. const FRAME_TYPE_MGMT: u8 = 0; 56. 57. /// Beacon subtype value (bits 4-7 of Frame Control byte 0). 58. const FRAME_SUBTYPE_BEACON: u8 = 8; 59. 60. /// Size of the 802.11 Management frame MAC header (bytes). 61. const MGMT_MAC_HEADER_LEN: usize = 24; 62. 63. /// Beacon frame body fixed fields: timestamp (8) + interval (2) + capability (2). 64. const BEACON_FIXED_FIELDS_LEN: usize = 12; 65. 66. // ───────────────────────────────────────────────── 67. // Constants: Radiotap Present Flag Bits 68. // ───────────────────────────────────────────────── 69. 70. /// Bit positions in the radiotap `present` bitmask. 71. const RT_TSFT: u32 = 0; 72. const RT_FLAGS: u32 = 1; 73. const RT_RATE: u32 = 2; 74. const RT_CHANNEL: u32 = 3; 75. const RT_FHSS: u32 = 4; 76. const RT_DBM_ANTSIGNAL: u32 = 5; 77. const RT_DBM_ANTNOISE: u32 = 6; 78. const RT_LOCK_QUALITY: u32 = 7; 79. const RT_TX_ATTENUATION: u32 = 8; 80. const RT_DB_TX_ATTENUATION: u32 = 9; 81. const RT_DBM_TX_POWER: u32 = 10; 82. const RT_ANTENNA: u32 = 11; 83. const RT_DB_ANTSIGNAL: u32 = 12; 84. const RT_DB_ANTNOISE: u32 = 13; 85. // Bit 31: extension flag (another 32-bit present word follows) 86. const RT_EXT: u32 = 31; 87. 88. /// Radiotap field sizes and natural alignment requirements. 89. /// Format: (size_in_bytes, alignment) 90. /// 91. /// Source: http://www.radiotap.org/ — field definitions 92. const RT_FIELD_INFO: [(usize, usize); 14] = [ 93. (8, 8), // 0: TSFT — u64, align 8 94. (1, 1), // 1: Flags — u8, align 1 95. (1, 1), // 2: Rate — u8, align 1 96. (4, 2), // 3: Channel — u16 freq + u16 flags, align 2 97. (2, 2), // 4: FHSS — u16, align 2 98. (1, 1), // 5: dBm Signal — i8, align 1 99. (1, 1), // 6: dBm Noise — i8, align 1 100. (2, 2), // 7: Lock Quality — u16, align 2 101. (2, 2), // 8: TX Atten — u16, align 2 102. (2, 2), // 9: dB TX Atten — u16, align 2 103. (1, 1), // 10: dBm TX Pwr — i8, align 1 104. (1, 1), // 11: Antenna — u8, align 1 105. (1, 1), // 12: dB Signal — u8, align 1 106. (1, 1), // 13: dB Noise — u8, align 1 107. ]; 108. 109. // ───────────────────────────────────────────────── 110. // Public API 111. // ───────────────────────────────────────────────── 112. 113. /// Handle for controlling an active capture session. 114. /// When `stop()` is called, the capture loop exits cleanly. 115. pub struct CaptureHandle { 116. stop_flag: Arc, 117. thread: Option>, 118. hopper_thread: Option>, 119. } 120. ````30 lines
```` 176. ## 🚀 Getting Started 177. 178. ```bash 179. # 📦 Install frontend dependencies 180. npm install 181. 182. # 🧪 Run in development mode (frontend only) 183. npm run dev 184. 185. # 🖥️ Run with Tauri (full app with Rust backend) 186. cargo tauri dev 187. 188. # 🏗️ Build for production 189. cargo tauri build 190. ``` 191. 192. --- 193. 194. ## 📁 Project Structure 195. 196. ``` 197. Aether_wifi/ 198. ├── 📂 src/ # ⚛️ React Frontend 199. │ ├── 📂 components/ 200. │ │ ├── 📂 layout/ # AppShell, Sidebar 201. │ │ └── 📂 ui/ # Tooltip, shared primitives 202. │ ├── 📂 hooks/ 203. │ │ └── 📄 useBeaconCapture.ts # Real-time beacon event hook 204. │ ├── 📂 pages/ 205. │ │ ├── 📄 Dashboard.tsx # Network scan table ````Arguments
```json { "shellId": "tauridev" } ```Arguments
````json "*** Begin Patch\n*** Update File: /home/kali/Aether_wifi/package.json\n@@\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"tsc && vite build\",\n \"preview\": \"vite preview\",\n- \"tauri\": \"tauri\"\n+ \"tauri\": \"node ./scripts/tauri-entry.mjs\"\n },\n*** Add File: /home/kali/Aether_wifi/scripts/tauri-entry.mjs\n+import { spawn } from 'node:child_process';\n+import path from 'node:path';\n+import process from 'node:process';\n+import { fileURLToPath } from 'node:url';\n+\n+const __filename = fileURLToPath(import.meta.url);\n+const __dirname = path.dirname(__filename);\n+const projectRoot = path.resolve(__dirname, '..');\n+const args = process.argv.slice(2);\n+const isLinuxDev = process.platform === 'linux' && args[0] === 'dev';\n+const bypassLauncher = process.env.AETHER_BYPASS_LAUNCHER === '1';\n+\n+const command = isLinuxDev && !bypassLauncher\n+ ? 'bash'\n+ : path.join(\n+ projectRoot,\n+ 'node_modules',\n+ '.bin',\n+ process.platform === 'win32' ? 'tauri.cmd' : 'tauri',\n+ );\n+\n+const commandArgs = isLinuxDev && !bypassLauncher\n+ ? [path.join(projectRoot, 'aether.sh')]\n+ : args;\n+\n+const child = spawn(command, commandArgs, {\n+ cwd: projectRoot,\n+ env: process.env,\n+ stdio: 'inherit',\n+});\n+\n+child.on('exit', (code, signal) => {\n+ if (signal) {\n+ process.kill(process.pid, signal);\n+ return;\n+ }\n+\n+ process.exit(code ?? 1);\n+});\n+\n+child.on('error', (error) => {\n+ console.error(error);\n+ process.exit(1);\n+});\n*** Update File: /home/kali/Aether_wifi/src-tauri/src/network/packet_sniffer.rs\n@@\n pub fn start_capture(\n interface_name: &str,\n on_beacon: F,\n ) -> Result\n where\n@@\n warn!(\n \"rfmon(true) failed on '{}': {}. Trying without rfmon \\\n (interface may already be in monitor mode).\",\n interface_name, rfmon_err\n );\n- make_inactive()?.open().map_err(|e| {\n- crate::error::AetherError::CaptureError(format!(\n- \"Failed to activate capture on '{}': {}. \\\n- Ensure the interface is in monitor mode and you have root/sudo privileges.\",\n- interface_name, e\n- ))\n- })?\n+ make_inactive()?\n+ .open()\n+ .map_err(|e| map_capture_activation_error(interface_name, &e.to_string()))?\n }\n }\n };\n@@\n let cap = make_inactive()?.open().map_err(|e| {\n crate::error::AetherError::CaptureError(format!(\n \"Failed to activate capture on '{}': {}. \\\n Ensure the interface is in monitor mode.\",\n interface_name, e\n@@\n Ok(CaptureHandle {\n stop_flag,\n thread: Some(thread),\n hopper_thread,\n })\n }\n+\n+fn map_capture_activation_error(\n+ interface_name: &str,\n+ detail: &str,\n+) -> crate::error::AetherError {\n+ let lowered = detail.to_ascii_lowercase();\n+ let needs_privileges = lowered.contains(\"cap_net_raw\")\n+ || lowered.contains(\"permission denied\")\n+ || lowered.contains(\"operation not permitted\")\n+ || lowered.contains(\"packet socket failed\");\n+\n+ if needs_privileges {\n+ return crate::error::AetherError::PermissionDenied(format!(\n+ \"Packet capture on '{}' requires CAP_NET_RAW/CAP_NET_ADMIN. \\\n+ Launch Aether through the Linux launcher (`bash ./aether.sh` or `npm run tauri dev`) \\\n+ so the backend starts with the privileges libpcap needs.\",\n+ interface_name\n+ ));\n+ }\n+\n+ crate::error::AetherError::CaptureError(format!(\n+ \"Failed to activate capture on '{}': {}. \\\n+ Ensure the interface is in monitor mode and you have root/sudo privileges.\",\n+ interface_name, detail\n+ ))\n+}\n*** Update File: /home/kali/Aether_wifi/README.md\n@@\n ```bash\n # 📦 Install frontend dependencies\n npm install\n \n # 🧪 Run in development mode (frontend only)\n npm run dev\n \n-# 🖥️ Run with Tauri (full app with Rust backend)\n-cargo tauri dev\n+# 🖥️ Run with Tauri (full app with Rust backend)\n+# Linux WiFi capture uses the launcher to enter monitor mode and start the backend with sudo.\n+npm run tauri dev\n \n # 🏗️ Build for production\n cargo tauri build\n ```\n*** End Patch\n" ````88 lines
``` > aether-app@0.1.0 build > tsc && vite build vite v7.3.1 building client environment for production... transforming (1) src/main.tsxtransforming (14) commonjsHelpers.jstransforming (29) node_modules/@tauri-apps/api/core.jstransforming (41) node_modules/react-dom/cjs/react-dom-client.production.jstransforming (1045) node_modules/lucide-react/dist/esm/icons/library.jstransforming (1760) src/components/ui/tooltip.tsxtransforming (1844) node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.jstransforming (2039) node_modules/echarts/lib/animation/morphTransitionHelper.jstransforming (2229) node_modules/size-sensor/lib/debounce.jstransforming (2286) node_modules/echarts/lib/chart/heatmap/HeatmapLayer.jstransforming (2384) node_modules/@floating-ui/core/dist/floating-ui.core.mjs✓ 2388 modules transformed. rendering chunks (1)...computing gzip size (0)...computing gzip size (1)...computing gzip size (2)...computing gzip size (3)...dist/index.html 0.65 kB │ gzip: 0.40 kB dist/assets/index-BZ98cnyx.css 55.26 kB │ gzip: 9.27 kB dist/assets/index-C1YPVA_t.js 1,495.60 kB │ gzip: 489.64 kB (!) Some chunks are larger than 500 kB after minification. Consider: - Using dynamic import() to code-split the application - Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks - Adjust chunk size limit for this warning via build.chunkSizeWarningLimit. ✓ built in 3.48s Compiling aether-app v0.1.0 (/home/kali/Aether_wifi/src-tauri) Building [=======================> ] 520/521: aether_app_lib(test) warning: variable does not need to be mutable --> src/network/audit.rs:86:9 | 86 | let mut cap = pcap::Capture::from_device(interface_name) | ----^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default Building [=======================> ] 520/521: aether_app_lib(test) warning: constant `RT_FHSS` is never used --> src/network/packet_sniffer.rs:75:7 | 75 | const RT_FHSS: u32 = 4; | ^^^^^^^ | = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default warning: constant `RT_DBM_ANTNOISE` is never used --> src/network/packet_sniffer.rs:77:7 | 77 | const RT_DBM_ANTNOISE: u32 = 6; | ^^^^^^^^^^^^^^^ warning: constant `RT_LOCK_QUALITY` is never used --> src/network/packet_sniffer.rs:78:7 | 78 | const RT_LOCK_QUALITY: u32 = 7; | ^^^^^^^^^^^^^^^ warning: constant `RT_TX_ATTENUATION` is never used --> src/network/packet_sniffer.rs:79:7 | 79 | const RT_TX_ATTENUATION: u32 = 8; | ^^^^^^^^^^^^^^^^^ warning: constant `RT_DB_TX_ATTENUATION` is never used --> src/network/packet_sniffer.rs:80:7 | 80 | const RT_DB_TX_ATTENUATION: u32 = 9; | ^^^^^^^^^^^^^^^^^^^^ warning: constant `RT_DBM_TX_POWER` is never used --> src/network/packet_sniffer.rs:81:7 | 81 | const RT_DBM_TX_POWER: u32 = 10; | ^^^^^^^^^^^^^^^ Building [=======================> ] 520/521: aether_app_lib(test) warning: constant `RT_ANTENNA` is never used --> src/network/packet_sniffer.rs:82:7 | 82 | const RT_ANTENNA: u32 = 11; | ^^^^^^^^^^ warning: constant `RT_DB_ANTSIGNAL` is never used --> src/network/packet_sniffer.rs:83:7 | 83 | const RT_DB_ANTSIGNAL: u32 = 12; | ^^^^^^^^^^^^^^^ warning: constant `RT_DB_ANTNOISE` is never used --> src/network/packet_sniffer.rs:84:7 | 84 | const RT_DB_ANTNOISE: u32 = 13; | ^^^^^^^^^^^^^^ Building [=======================> ] 520/521: aether_app_lib(test) warning: `aether-app` (lib test) generated 10 warnings (run `cargo fix --lib -p aether-app --tests` to apply 1 suggestion) Finished `test` profile [unoptimized + debuginfo] target(s) in 0.94s Running unittests src/lib.rs (src-tauri/target/debug/deps/aether_app_lib-f43ff56610275377) running 13 tests test network::interface_scanner::tests::interface_mode_from_strings ... ok test network::interface_scanner::tests::parse_iw_dev_extracts_interfaces ... ok test network::interface_scanner::tests::interface_mode_toggle ... ok test network::mode_controller::tests::iw_type_strings ... ok test network::packet_sniffer::tests::freq_to_channel_2_4ghz ... ok test network::mode_controller::tests::mode_toggle_logic ... ok test network::packet_sniffer::tests::radiotap_alignment_with_gaps ... ok test network::packet_sniffer::tests::hidden_ssid_parsed ... ok test network::packet_sniffer::tests::freq_to_channel_5ghz ... ok test network::packet_sniffer::tests::non_beacon_frame_returns_none ... ok test network::packet_sniffer::tests::channel_to_freq_roundtrip ... ok test network::packet_sniffer::tests::parse_synthetic_beacon ... ok test network::interface_scanner::tests::parse_ip_link_extracts_interfaces ... ok test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s ```Arguments
```json { "shellId": "tauriwrap", "delay": 10 } ```12 lines
``` > aether-app@0.1.0 tauri > node ./scripts/tauri-entry.mjs dev ╔══════════════════════════════════════╗ ║ ◈ AETHER WiFi Auditor ◈ ║ ║ Launching System... ║ ╚══════════════════════════════════════╝ [1/4] Checking WiFi adapter (wlan0)... ✓ Found wlan0 [2/4] Ensuring monitor mode... Setting wlan0 to monitor mode (requires sudo)... [sudo] password for kali: ```Arguments
```json { "shellId": "tauriwrap", "input": "kali\n", "delay": 20 } ```27 lines
``` > aether-app@0.1.0 tauri > node ./scripts/tauri-entry.mjs dev ╔══════════════════════════════════════╗ ║ ◈ AETHER WiFi Auditor ◈ ║ ║ Launching System... ║ ╚══════════════════════════════════════╝ [1/4] Checking WiFi adapter (wlan0)... ✓ Found wlan0 [2/4] Ensuring monitor mode... Setting wlan0 to monitor mode (requires sudo)... [sudo] password for kali: ✓ Monitor mode activated [3/4] Setting channel 6 (2.4 GHz)... ✓ Channel 6 (2437 MHz) [4/4] Launching Aether... ══════════════════════════════════════ Aether is starting... Interface: wlan0 (Monitor Mode) Close the window to stop. ══════════════════════════════════════ error: no such command: `tauri` help: a command with a similar name exists: `miri` help: view all installed commands with `cargo --list` help: find a package to install `tauri` with `cargo search cargo-tauri` [cleanup] Restoring wlan0 to managed mode... ✓ wlan0 restored to managed mode ```20 lines
``` 131. # ── 5. Allow X11 access for root & launch ── 132. echo -e "${YELLOW}[4/4]${NC} Launching Aether..." 133. if command -v xhost &>/dev/null && [ -n "${DISPLAY:-}" ]; then 134. xhost +local:root &>/dev/null 2>&1 || true 135. fi 136. 137. cd "$PROJECT_DIR" 138. 139. echo -e "" 140. echo -e " ${GREEN}══════════════════════════════════════${NC}" 141. echo -e " ${GREEN} Aether is starting... ${NC}" 142. echo -e " ${GREEN} Interface:Arguments
```json "*** Begin Patch\n*** Update File: /home/kali/Aether_wifi/aether.sh\n@@\n-# Launch Tauri dev (with sudo for pcap access)\n-WEBKIT_DISABLE_COMPOSITING_MODE=1 \\\n- sudo -E \"$(which cargo)\" tauri dev 2>&1\n+TAURI_BIN=\"$PROJECT_DIR/node_modules/.bin/tauri\"\n+if [ ! -x \"$TAURI_BIN\" ]; then\n+ echo -e \"${RED}[ERROR] Tauri CLI not found at ${TAURI_BIN}.${NC}\"\n+ echo \" Run 'npm install' in $PROJECT_DIR first.\"\n+ exit 1\n+fi\n+\n+# Launch Tauri dev (with sudo for pcap access)\n+WEBKIT_DISABLE_COMPOSITING_MODE=1 \\\n+ sudo -E \"$TAURI_BIN\" dev 2>&1\n*** End Patch\n" ```Arguments
```json { "shellId": "tauriwrap2", "delay": 10 } ```12 lines
``` > aether-app@0.1.0 tauri > node ./scripts/tauri-entry.mjs dev ╔══════════════════════════════════════╗ ║ ◈ AETHER WiFi Auditor ◈ ║ ║ Launching System... ║ ╚══════════════════════════════════════╝ [1/4] Checking WiFi adapter (wlan0)... ✓ Found wlan0 [2/4] Ensuring monitor mode... Setting wlan0 to monitor mode (requires sudo)... [sudo] password for kali: ```Arguments
```json { "shellId": "tauriwrap2", "input": "kali\n", "delay": 30 } ```25 lines
``` > aether-app@0.1.0 tauri > node ./scripts/tauri-entry.mjs dev ╔══════════════════════════════════════╗ ║ ◈ AETHER WiFi Auditor ◈ ║ ║ Launching System... ║ ╚══════════════════════════════════════╝ [1/4] Checking WiFi adapter (wlan0)... ✓ Found wlan0 [2/4] Ensuring monitor mode... Setting wlan0 to monitor mode (requires sudo)... [sudo] password for kali: ✓ Monitor mode activated [3/4] Setting channel 6 (2.4 GHz)... ✓ Channel 6 (2437 MHz) [4/4] Launching Aether... ══════════════════════════════════════ Aether is starting... Interface: wlan0 (Monitor Mode) Close the window to stop. ══════════════════════════════════════ failed to run 'cargo metadata' command to get workspace directory: failed to run command cargo metadata --no-deps --format-version 1: No such file or directory (os error 2) Error failed to run 'cargo metadata' command to get workspace directory: failed to run command cargo metadata --no-deps --format-version 1: No such file or directory (os error 2) [cleanup] Restoring wlan0 to managed mode... ✓ wlan0 restored to managed mode ```13 lines
``` 145. echo "" 146. 147. TAURI_BIN="$PROJECT_DIR/node_modules/.bin/tauri" 148. if [ ! -x "$TAURI_BIN" ]; then 149. echo -e "${RED}[ERROR] Tauri CLI not found at ${TAURI_BIN}.${NC}" 150. echo " Run 'npm install' in $PROJECT_DIR first." 151. exit 1 152. fi 153. 154. # Launch Tauri dev (with sudo for pcap access) 155. WEBKIT_DISABLE_COMPOSITING_MODE=1 \ 156. sudo -E "$TAURI_BIN" dev 2>&1 157. ```Arguments
```json "*** Begin Patch\n*** Update File: /home/kali/Aether_wifi/aether.sh\n@@\n TAURI_BIN=\"$PROJECT_DIR/node_modules/.bin/tauri\"\n+CARGO_BIN_DIR=\"$HOME/.cargo/bin\"\n if [ ! -x \"$TAURI_BIN\" ]; then\n echo -e \"${RED}[ERROR] Tauri CLI not found at ${TAURI_BIN}.${NC}\"\n echo \" Run 'npm install' in $PROJECT_DIR first.\"\n exit 1\n fi\n \n # Launch Tauri dev (with sudo for pcap access)\n WEBKIT_DISABLE_COMPOSITING_MODE=1 \\\n- sudo -E \"$TAURI_BIN\" dev 2>&1\n+ sudo -E env \\\n+ \"PATH=$CARGO_BIN_DIR:$PATH\" \\\n+ \"CARGO_HOME=$HOME/.cargo\" \\\n+ \"RUSTUP_HOME=$HOME/.rustup\" \\\n+ \"$TAURI_BIN\" dev 2>&1\n*** End Patch\n" ```Arguments
```json { "shellId": "tauriwrap3", "delay": 10 } ```12 lines
``` > aether-app@0.1.0 tauri > node ./scripts/tauri-entry.mjs dev ╔══════════════════════════════════════╗ ║ ◈ AETHER WiFi Auditor ◈ ║ ║ Launching System... ║ ╚══════════════════════════════════════╝ [1/4] Checking WiFi adapter (wlan0)... ✓ Found wlan0 [2/4] Ensuring monitor mode... Setting wlan0 to monitor mode (requires sudo)... [sudo] password for kali: ```Arguments
```json { "shellId": "tauriwrap3", "input": "kali\n", "delay": 40 } ```124 lines
``` > aether-app@0.1.0 tauri > node ./scripts/tauri-entry.mjs dev ╔══════════════════════════════════════╗ ║ ◈ AETHER WiFi Auditor ◈ ║ ║ Launching System... ║ ╚══════════════════════════════════════╝ [1/4] Checking WiFi adapter (wlan0)... ✓ Found wlan0 [2/4] Ensuring monitor mode... Setting wlan0 to monitor mode (requires sudo)... [sudo] password for kali: ✓ Monitor mode activated [3/4] Setting channel 6 (2.4 GHz)... ✓ Channel 6 (2437 MHz) [4/4] Launching Aether... ══════════════════════════════════════ Aether is starting... Interface: wlan0 (Monitor Mode) Close the window to stop. ══════════════════════════════════════ Running BeforeDevCommand (`npm run dev`) > aether-app@0.1.0 dev > vite VITE v7.3.1 ready in 147 ms ➜ Local: http://localhost:1420/ Running DevCommand (`cargo run --no-default-features --color always --`) Info Watching /home/kali/Aether_wifi/src-tauri for changes... Compiling aether-app v0.1.0 (/home/kali/Aether_wifi/src-tauri) Building [=======================> ] 520/522: aether-app warning: variable does not need to be mutable --> src/network/audit.rs:86:9 | 86 | let mut cap = pcap::Capture::from_device(interface_name) | ----^^^ | | | help: remove this `mut` | = note: `#[warn(unused_mut)]` (part of `#[warn(unused)]`) on by default Building [=======================> ] 520/522: aether-app warning: constant `RT_TSFT` is never used --> src/network/packet_sniffer.rs:71:7 | 71 | const RT_TSFT: u32 = 0; | ^^^^^^^ | = note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default warning: constant `RT_FLAGS` is never used --> src/network/packet_sniffer.rs:72:7 | 72 | const RT_FLAGS: u32 = 1; | ^^^^^^^^ warning: constant `RT_RATE` is never used --> src/network/packet_sniffer.rs:73:7 | 73 | const RT_RATE: u32 = 2; | ^^^^^^^ warning: constant `RT_FHSS` is never used --> src/network/packet_sniffer.rs:75:7 | 75 | const RT_FHSS: u32 = 4; | ^^^^^^^ Building [=======================> ] 520/522: aether-app warning: constant `RT_DBM_ANTNOISE` is never used --> src/network/packet_sniffer.rs:77:7 | 77 | const RT_DBM_ANTNOISE: u32 = 6; | ^^^^^^^^^^^^^^^ warning: constant `RT_LOCK_QUALITY` is never used --> src/network/packet_sniffer.rs:78:7 | 78 | const RT_LOCK_QUALITY: u32 = 7; | ^^^^^^^^^^^^^^^ warning: constant `RT_TX_ATTENUATION` is never used --> src/network/packet_sniffer.rs:79:7 | 79 | const RT_TX_ATTENUATION: u32 = 8; | ^^^^^^^^^^^^^^^^^ warning: constant `RT_DB_TX_ATTENUATION` is never used --> src/network/packet_sniffer.rs:80:7 | 80 | const RT_DB_TX_ATTENUATION: u32 = 9; | ^^^^^^^^^^^^^^^^^^^^ warning: constant `RT_DBM_TX_POWER` is never used --> src/network/packet_sniffer.rs:81:7 | 81 | const RT_DBM_TX_POWER: u32 = 10; | ^^^^^^^^^^^^^^^ Building [=======================> ] 520/522: aether-app warning: constant `RT_ANTENNA` is never used --> src/network/packet_sniffer.rs:82:7 | 82 | const RT_ANTENNA: u32 = 11; | ^^^^^^^^^^ warning: constant `RT_DB_ANTSIGNAL` is never used --> src/network/packet_sniffer.rs:83:7 | 83 | const RT_DB_ANTSIGNAL: u32 = 12; | ^^^^^^^^^^^^^^^ warning: constant `RT_DB_ANTNOISE` is never used --> src/network/packet_sniffer.rs:84:7 | 84 | const RT_DB_ANTNOISE: u32 = 13; | ^^^^^^^^^^^^^^ Building [=======================> ] 520/522: aether-app warning: `aether-app` (lib) generated 13 warnings (run `cargo fix --lib -p aether-app` to apply 1 suggestion) Building [=======================> ] 521/522: aether-app(bin) Finished `dev` profile [unoptimized + debuginfo] target(s) in 2.31s Running `target/debug/aether-app` [2026-04-18T01:19:20.828Z INFO aether_app_lib] Aether-Core v0.1.0 starting... (aether-app:55424): IBUS-WARNING **: 21:19:21.111: The owner of /home/kali/.config/ibus/bus is not root! libEGL warning: DRI3 error: Could not get DRI3 device libEGL warning: Ensure your X server supports DRI3 to get accelerated rendering VMware: No 3D enabled (0, Success). libEGL warning: egl: failed to create dri2 screen libEGL warning: DRI2: failed to create screen VMware: No 3D enabled (0, Success). libEGL warning: egl: failed to create dri2 screen libEGL warning: DRI2: failed to create screen VMware: No 3D enabled (0, Success). libEGL warning: egl: failed to create dri2 screen libEGL warning: DRI2: failed to create screen VMware: No 3D enabled (0, Success). libEGL warning: egl: failed to create dri2 screen libEGL warning: DRI2: failed to create screen [2026-04-18T01:19:32.433Z INFO aether_app_lib::commands::capture_commands] [cmd] start_capture: wlan0 [2026-04-18T01:19:32.433Z INFO aether_app_lib::network::packet_sniffer] Opening pcap capture on interface 'wlan0'... [2026-04-18T01:19:32.689Z WARN aether_app_lib::network::packet_sniffer] rfmon(true) failed on 'wlan0': libpcap error: That device doesn't support monitor mode. Trying without rfmon (interface may already be in monitor mode). [2026-04-18T01:19:32.709Z INFO aether_app_lib::network::packet_sniffer] Capture opened on 'wlan0'. Datalink: Linktype(127) [2026-04-18T01:19:32.709Z INFO aether_app_lib::network::packet_sniffer] Capture loop started on 'wlan0' ```Arguments
```json { "shellId": "tauriwrap3" } ```16 lines
``` Interface wlan0 ifindex 3 wdev 0x100000001 addr 00:c0:ca:b2:b7:3c ssid DontConnect type managed channel 149 (5745 MHz), width: 80 MHz, center1: 5775 MHz txpower 20.00 dBm multicast TXQ: --- M README.md M aether.sh M package.json M src-tauri/src/network/packet_sniffer.rs ?? scripts/tauri-entry.mjs ```Arguments
```json { "subject": "testing practices", "fact": "Use cargo test --manifest-path src-tauri/Cargo.toml --lib for Rust backend checks.", "citations": "Successful run on 2026-04-17 in session output for cargo test --manifest-path src-tauri/Cargo.toml --lib; src-tauri/Cargo.toml:1-30", "reason": "This is a stable backend validation command for the repository and is useful after Rust or Tauri backend changes. Remembering it will speed up future tasks by pointing to an existing test entrypoint that already works in this environment." } ```161 lines
``` 220. ); 221. } 222. 223. let stop_flag = Arc::new(AtomicBool::new(false)); 224. let stop_clone = stop_flag.clone(); 225. let iface_name = interface_name.to_string(); 226. 227. let thread = std::thread::Builder::new() 228. .name(format!("aether-capture-{}", interface_name)) 229. .spawn(move || { 230. capture_loop(cap, &iface_name, stop_clone, on_beacon); 231. }) 232. .map_err(|e| { 233. crate::error::AetherError::CaptureError(format!( 234. "Failed to spawn capture thread: {}", 235. e 236. )) 237. })?; 238. 239. let stop_clone2 = stop_flag.clone(); 240. let iface_name2 = interface_name.to_string(); 241. 242. let hopper_thread = std::thread::Builder::new() 243. .name(format!("aether-hopper-{}", interface_name)) 244. .spawn(move || { 245. // A comprehensive mix of 2.4GHz and 5GHz channels 246. let channels = [1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161]; 247. let mut idx = 0; 248. 249. while !stop_clone2.load(Ordering::Relaxed) { 250. let channel = channels[idx]; 251. // Non-blocking channel hop — suppress stdout/stderr 252. let _ = std::process::Command::new("iw") 253. .arg("dev") 254. .arg(&iface_name2) 255. .arg("set") 256. .arg("channel") 257. .arg(channel.to_string()) 258. .stdout(std::process::Stdio::null()) 259. .stderr(std::process::Stdio::null()) 260. .output(); 261. 262. idx = (idx + 1) % channels.len(); 263. 264. // Wait ~200ms on each channel, but check stop flag every 50ms 265. for _ in 0..4 { 266. if stop_clone2.load(Ordering::Relaxed) { 267. break; 268. } 269. std::thread::sleep(std::time::Duration::from_millis(50)); 270. } 271. } 272. }) 273. .ok(); // Ignoring spawn failures on hopper to keep capturing alive 274. 275. Ok(CaptureHandle { 276. stop_flag, 277. thread: Some(thread), 278. hopper_thread, 279. }) 280. } 281. 282. fn map_capture_activation_error( 283. interface_name: &str, 284. detail: &str, 285. ) -> crate::error::AetherError { 286. let lowered = detail.to_ascii_lowercase(); 287. let needs_privileges = lowered.contains("cap_net_raw") 288. || lowered.contains("permission denied") 289. || lowered.contains("operation not permitted") 290. || lowered.contains("packet socket failed"); 291. 292. if needs_privileges { 293. return crate::error::AetherError::PermissionDenied(format!( 294. "Packet capture on '{}' requires CAP_NET_RAW/CAP_NET_ADMIN. \ 295. Launch Aether through the Linux launcher (`bash ./aether.sh` or `npm run tauri dev`) \ 296. so the backend starts with the privileges libpcap needs.", 297. interface_name 298. )); 299. } 300. 301. crate::error::AetherError::CaptureError(format!( 302. "Failed to activate capture on '{}': {}. \ 303. Ensure the interface is in monitor mode and you have root/sudo privileges.", 304. interface_name, detail 305. )) 306. } 307. 308. // ───────────────────────────────────────────────── 309. // Capture Loop 310. // ───────────────────────────────────────────────── 311. 312. /// Main capture loop — runs in a dedicated thread. 313. fn capture_loop( 314. mut cap: pcap::Capture, 315. interface_name: &str, 316. stop_flag: Arc, 317. on_beacon: F, 318. ) where 319. F: Fn(BeaconFrame), 320. { 321. info!("Capture loop started on '{}'", interface_name); 322. 323. let mut packet_count: u64 = 0; 324. let mut beacon_count: u64 = 0; 325. 326. while !stop_flag.load(Ordering::Relaxed) { 327. match cap.next_packet() { 328. Ok(packet) => { 329. packet_count += 1; 330. trace!("Packet #{}: {} bytes", packet_count, packet.data.len()); 331. 332. match parse_beacon_frame(packet.data) { 333. Some(beacon) => { 334. beacon_count += 1; 335. debug!( 336. "Beacon #{}: BSSID={} SSID=\"{}\" CH={} RSSI={}dBm", 337. beacon_count, beacon.bssid, beacon.ssid, beacon.channel, beacon.rssi 338. ); 339. on_beacon(beacon); 340. } 341. None => { 342. // Not a beacon frame — silently skip 343. } 344. } 345. } 346. Err(pcap::Error::TimeoutExpired) => { 347. // Normal — no packet arrived within the timeout window. 348. // Loop back to check the stop flag. 349. continue; 350. } 351. Err(e) => { 352. error!( 353. "Capture error on '{}': {}. Stopping capture.", 354. interface_name, e 355. ); 356. break; 357. } 358. } 359. } 360. 361. info!( 362. "Capture loop ended on '{}'. Total packets: {}, Beacons: {}", 363. interface_name, packet_count, beacon_count 364. ); 365. } 366. 367. // ───────────────────────────────────────────────── 368. // Frame Parsers 369. // ───────────────────────────────────────────────── 370. 371. /// Attempt to parse a raw captured packet as an 802.11 Beacon frame. 372. /// 373. /// Returns `None` if the packet is not a beacon or is malformed. 374. fn parse_beacon_frame(data: &[u8]) -> Option { 375. // ── Step 1: Parse Radiotap Header ── 376. // Minimum radiotap header: 8 bytes (version + pad + length + present) 377. if data.len() < 8 { 378. return None; 379. } 380. ```241 lines
```` 380. 381. let rt_version = data[0]; 382. if rt_version != 0 { 383. trace!("Unknown radiotap version: {}", rt_version); 384. return None; 385. } 386. 387. // Radiotap header length (little-endian u16 at offset 2) 388. let rt_len = { 389. let mut cursor = Cursor::new(&data[2..4]); 390. cursor.read_u16::().ok()? 391. } as usize; 392. 393. if rt_len > data.len() { 394. trace!( 395. "Radiotap length {} exceeds packet size {}", 396. rt_len, 397. data.len() 398. ); 399. return None; 400. } 401. 402. // Read the primary present flags (little-endian u32 at offset 4) 403. let present = { 404. let mut cursor = Cursor::new(&data[4..8]); 405. cursor.read_u32::().ok()? 406. }; 407. 408. // Determine the offset where radiotap fields begin. 409. // If extension bit (bit 31) is set, additional 32-bit present words follow. 410. // We need to skip past all present words to reach the actual fields. 411. let mut field_offset = 8_usize; // past version(1) + pad(1) + len(2) + present(4) 412. 413. // Skip extension present words 414. let mut current_present = present; 415. while current_present & (1 << RT_EXT) != 0 { 416. if field_offset + 4 > rt_len { 417. return None; 418. } 419. current_present = { 420. let mut cursor = Cursor::new(&data[field_offset..field_offset + 4]); 421. cursor.read_u32::().ok()? 422. }; 423. field_offset += 4; 424. } 425. 426. // ── Step 2: Extract RSSI and Channel from Radiotap fields ── 427. let (rssi, frequency) = parse_radiotap_fields(data, present, field_offset, rt_len); 428. 429. // ── Step 3: Parse 802.11 MAC Header ── 430. let dot11_start = rt_len; 431. let dot11_data = data.get(dot11_start..)?; 432. 433. if dot11_data.len() < MGMT_MAC_HEADER_LEN { 434. return None; 435. } 436. 437. // Frame Control: 2 bytes (little-endian) 438. let fc0 = dot11_data[0]; 439. // let fc1 = dot11_data[1]; // flags byte, not needed for beacon detection 440. 441. // Extract type and subtype from Frame Control byte 0: 442. // Bits 0-1: Protocol version (always 0) 443. // Bits 2-3: Type (0 = Management) 444. // Bits 4-7: Subtype (8 = Beacon) 445. let frame_type = (fc0 >> 2) & 0x03; 446. let frame_subtype = (fc0 >> 4) & 0x0F; 447. 448. if frame_type != FRAME_TYPE_MGMT || frame_subtype != FRAME_SUBTYPE_BEACON { 449. return None; // Not a beacon frame 450. } 451. 452. // ── Step 4: Extract BSSID ── 453. // Address 2 (Source Address) at offset 10..16 = BSSID for beacon frames 454. let bssid_bytes = &dot11_data[10..16]; 455. let bssid = format!( 456. "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", 457. bssid_bytes[0], 458. bssid_bytes[1], 459. bssid_bytes[2], 460. bssid_bytes[3], 461. bssid_bytes[4], 462. bssid_bytes[5] 463. ); 464. 465. // ── Step 5: Parse Beacon Frame Body ── 466. // The body starts after the 24-byte MAC header 467. let body_start = MGMT_MAC_HEADER_LEN; 468. let body = dot11_data.get(body_start..)?; 469. 470. // Skip fixed fields: Timestamp (8) + Beacon Interval (2) + Capability (2) 471. if body.len() < BEACON_FIXED_FIELDS_LEN { 472. return None; 473. } 474. let tagged_params = &body[BEACON_FIXED_FIELDS_LEN..]; 475. 476. // ── Step 6: Parse Information Elements (Tagged Parameters) ── 477. let (ssid, ie_channel) = parse_information_elements(tagged_params); 478. 479. // Determine channel: prefer the DS Parameter Set (IE Tag 3), 480. // fall back to deriving from radiotap frequency 481. let channel = ie_channel.unwrap_or_else(|| frequency.map(freq_to_channel).unwrap_or(0)); 482. 483. let frequency_mhz = frequency.unwrap_or_else(|| channel_to_freq(channel)); 484. 485. // Timestamp 486. let timestamp_ms = SystemTime::now() 487. .duration_since(UNIX_EPOCH) 488. .unwrap_or_default() 489. .as_millis() as u64; 490. 491. Some(BeaconFrame { 492. bssid, 493. ssid, 494. channel, 495. rssi: rssi.unwrap_or(-100), // -100 dBm as "unknown" sentinel 496. frequency_mhz, 497. timestamp_ms, 498. }) 499. } 500. 501. /// Walk the radiotap present flags and extract RSSI (dBm signal) and channel frequency. 502. /// 503. /// This correctly handles the natural alignment requirements specified by 504. /// the radiotap standard for each field type. 505. fn parse_radiotap_fields( 506. data: &[u8], 507. present: u32, 508. start_offset: usize, 509. rt_len: usize, 510. ) -> (Option, Option) { 511. let mut offset = start_offset; 512. let mut rssi: Option = None; 513. let mut frequency: Option = None; 514. 515. for bit in 0..=13_u32 { 516. if present & (1 << bit) == 0 { 517. continue; // Field not present, skip 518. } 519. 520. let (field_size, field_align) = RT_FIELD_INFO[bit as usize]; 521. 522. // Apply natural alignment padding 523. let align_remainder = offset % field_align; 524. if align_remainder != 0 { 525. offset += field_align - align_remainder; 526. } 527. 528. // Bounds check 529. if offset + field_size > rt_len || offset + field_size > data.len() { 530. break; 531. } 532. 533. match bit { 534. RT_CHANNEL => { 535. // Channel field: u16 frequency (LE) + u16 flags (LE) 536. let mut cursor = Cursor::new(&data[offset..offset + 2]); 537. frequency = cursor.read_u16::().ok(); 538. } 539. RT_DBM_ANTSIGNAL => { 540. // Antenna Signal: i8 541. rssi = Some(data[offset] as i8); 542. } 543. _ => { 544. // We don't need other fields, just advance past them 545. } 546. } 547. 548. offset += field_size; 549. 550. // Early exit if we have both values 551. if rssi.is_some() && frequency.is_some() { 552. break; 553. } 554. } 555. 556. (rssi, frequency) 557. } 558. 559. /// Parse 802.11 Information Elements (Tagged Parameters) to extract SSID and channel. 560. /// 561. /// Each IE has the structure: 562. /// ```text 563. /// | Tag Number (1 byte) | Tag Length (1 byte) | Tag Data (N bytes) | 564. /// ``` 565. fn parse_information_elements(data: &[u8]) -> (String, Option) { 566. let mut ssid = String::new(); 567. let mut channel: Option = None; 568. let mut offset = 0; 569. 570. while offset + 2 <= data.len() { 571. let tag_number = data[offset]; 572. let tag_length = data[offset + 1] as usize; 573. offset += 2; 574. 575. if offset + tag_length > data.len() { 576. break; // Malformed IE — truncated 577. } 578. 579. let tag_data = &data[offset..offset + tag_length]; 580. 581. match tag_number { 582. 0 => { 583. // SSID Information Element 584. // tag_length == 0 means hidden SSID 585. ssid = String::from_utf8_lossy(tag_data).to_string(); 586. } 587. 3 => { 588. // DS Parameter Set — single byte indicating the current channel 589. if tag_length >= 1 { 590. channel = Some(tag_data[0]); 591. } 592. } 593. _ => { 594. // Other IEs — skip 595. } 596. } 597. 598. offset += tag_length; 599. 600. // Early exit if we have both 601. if !ssid.is_empty() && channel.is_some() { 602. break; 603. } 604. } 605. 606. (ssid, channel) 607. } 608. 609. // ───────────────────────────────────────────────── 610. // Frequency ↔ Channel Conversion 611. // ───────────────────────────────────────────────── 612. 613. /// Convert a WiFi frequency (MHz) to a channel number. 614. /// 615. /// Covers 2.4 GHz (channels 1–14) and 5 GHz (channels 36–165). 616. fn freq_to_channel(freq: u16) -> u8 { 617. match freq { 618. // 2.4 GHz band: channels 1–13 619. 2412..=2472 => ((freq - 2407) / 5) as u8, 620. // Channel 14 (Japan only) ````42 lines
``` Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 002: ID 0e0f:0002 VMware, Inc. Virtual USB Hub Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub Bus 002 Device 004: ID 0e0f:0003 VMware, Inc. Virtual Mouse Bus 002 Device 005: ID 0e0f:0006 VMware, Inc. Virtual Keyboard Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 003 Device 002: ID 0e0f:0002 VMware, Inc. Virtual USB Hub Bus 003 Device 003: ID 0bda:8813 Realtek Semiconductor Corp. RTL8814AU 802.11a/b/g/n/ac Wireless Adapter Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub Bus 004 Device 002: ID 0e0f:0002 VMware, Inc. Virtual USB Hub --- phy#1 Interface wlan0 ifindex 3 wdev 0x100000001 addr 00:c0:ca:b2:b7:3c ssid DontConnect type managed channel 149 (5745 MHz), width: 80 MHz, center1: 5775 MHz txpower 20.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 --- lo UNKNOWN 00:00:00:00:00:00 eth0 UP 00:0c:29:f1:8f:bf wlan0 UP 00:c0:ca:b2:b7:3c --- /sys/bus/usb/drivers/rtw88_8814au --- driver: rtw88_8814au version: 6.19.11+kali-amd64 firmware-version: N/A expansion-rom-version: bus-info: 3-1:1.0 supports-statistics: yes supports-test: no supports-eeprom-access: no supports-register-dump: no supports-priv-flags: no ```17 lines
``` [sudo] password for kali: mode after switch: Interface wlan0 ifindex 3 wdev 0x100000001 addr 00:c0:ca:b2:b7:3c type monitor wiphy 1 channel 11 (2462 MHz), width: 20 MHz (no HT), center1: 2462 MHz txpower 20.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 --- ch149 beacon sample --- tcpdump: wlan0: That device doesn't support monitor mode --- ch6 beacon sample --- tcpdump: wlan0: That device doesn't support monitor mode ```17 lines
``` [sudo] password for kali: --- plain capture ch149 --- tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on wlan0, link-type IEEE802_11_RADIO (802.11 plus radiotap header), snapshot length 262144 bytes 21:22:37.054024 [|802.11_radio] 21:22:39.462936 [|802.11_radio] 21:22:43.541491 [|802.11_radio] 3 packets captured 3 packets received by filter 0 packets dropped by kernel \n--- plain capture ch6 --- tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on wlan0, link-type IEEE802_11_RADIO (802.11 plus radiotap header), snapshot length 262144 bytes 21:22:51.737607 [|802.11_radio] 1 packet captured 1 packet received by filter 0 packets dropped by kernel ```254 lines
``` Supported interface modes: * IBSS * managed * AP * AP/VLAN * monitor Band 1: Capabilities: 0x196f RX LDPC HT20/HT40 SM Power Save disabled RX HT20 SGI RX HT40 SGI RX STBC 1-stream Max AMSDU length: 7935 bytes DSSS/CCK HT40 Maximum RX AMPDU length 65535 bytes (exponent: 0x003) Minimum RX AMPDU time spacing: 2 usec (0x04) HT Max RX data rate: 450 Mbps HT TX/RX MCS rate indexes supported: 0-23, 32 Bitrates (non-HT): * 1.0 Mbps * 2.0 Mbps * 5.5 Mbps * 11.0 Mbps * 6.0 Mbps * 9.0 Mbps * 12.0 Mbps * 18.0 Mbps * 24.0 Mbps * 36.0 Mbps * 48.0 Mbps * 54.0 Mbps Frequencies: * 2412.0 MHz [1] (30.0 dBm) * 2417.0 MHz [2] (30.0 dBm) * 2422.0 MHz [3] (30.0 dBm) * 2427.0 MHz [4] (30.0 dBm) * 2432.0 MHz [5] (30.0 dBm) * 2437.0 MHz [6] (30.0 dBm) * 2442.0 MHz [7] (30.0 dBm) * 2447.0 MHz [8] (30.0 dBm) * 2452.0 MHz [9] (30.0 dBm) * 2457.0 MHz [10] (30.0 dBm) * 2462.0 MHz [11] (30.0 dBm) * 2467.0 MHz [12] (disabled) * 2472.0 MHz [13] (disabled) * 2484.0 MHz [14] (disabled) Band 2: Capabilities: 0x196f RX LDPC HT20/HT40 SM Power Save disabled RX HT20 SGI RX HT40 SGI RX STBC 1-stream Max AMSDU length: 7935 bytes DSSS/CCK HT40 Maximum RX AMPDU length 65535 bytes (exponent: 0x003) Minimum RX AMPDU time spacing: 2 usec (0x04) HT Max RX data rate: 450 Mbps HT TX/RX MCS rate indexes supported: 0-23, 32 VHT Capabilities (0x03d071b2): Max MPDU length: 11454 Supported Channel Width: neither 160 nor 80+80 RX LDPC short GI (80 MHz) TX STBC SU Beamformee MU Beamformee +HTC-VHT VHT RX MCS set: 1 streams: MCS 0-9 2 streams: MCS 0-9 3 streams: MCS 0-9 4 streams: not supported 5 streams: not supported 6 streams: not supported 7 streams: not supported 8 streams: not supported VHT RX highest supported: 1170 Mbps VHT TX MCS set: 1 streams: MCS 0-9 2 streams: MCS 0-9 3 streams: MCS 0-9 4 streams: not supported 5 streams: not supported 6 streams: not supported 7 streams: not supported 8 streams: not supported VHT TX highest supported: 1170 Mbps VHT extended NSS: not supported Bitrates (non-HT): * 6.0 Mbps * 9.0 Mbps * 12.0 Mbps * 18.0 Mbps * 24.0 Mbps * 36.0 Mbps * 48.0 Mbps * 54.0 Mbps Frequencies: * 5180.0 MHz [36] (23.0 dBm) * 5200.0 MHz [40] (23.0 dBm) * 5220.0 MHz [44] (23.0 dBm) * 5240.0 MHz [48] (23.0 dBm) * 5260.0 MHz [52] (24.0 dBm) (radar detection) * 5280.0 MHz [56] (24.0 dBm) (radar detection) * 5300.0 MHz [60] (24.0 dBm) (radar detection) * 5320.0 MHz [64] (24.0 dBm) (radar detection) * 5500.0 MHz [100] (24.0 dBm) (radar detection) * 5520.0 MHz [104] (24.0 dBm) (radar detection) * 5540.0 MHz [108] (24.0 dBm) (radar detection) * 5560.0 MHz [112] (24.0 dBm) (radar detection) * 5580.0 MHz [116] (24.0 dBm) (radar detection) * 5600.0 MHz [120] (24.0 dBm) (radar detection) * 5620.0 MHz [124] (24.0 dBm) (radar detection) * 5640.0 MHz [128] (24.0 dBm) (radar detection) * 5660.0 MHz [132] (24.0 dBm) (radar detection) * 5680.0 MHz [136] (24.0 dBm) (radar detection) * 5700.0 MHz [140] (24.0 dBm) (radar detection) * 5720.0 MHz [144] (24.0 dBm) (radar detection) * 5745.0 MHz [149] (30.0 dBm) * 5765.0 MHz [153] (30.0 dBm) * 5785.0 MHz [157] (30.0 dBm) * 5805.0 MHz [161] (30.0 dBm) * 5825.0 MHz [165] (30.0 dBm) Supported commands: * new_interface * set_interface * new_key * start_ap * new_station * new_mpath * set_mesh_config * set_bss * authenticate * associate * deauthenticate * disassociate * join_ibss * join_mesh * remain_on_channel * set_tx_bitrate_mask * frame * frame_wait_cancel * set_wiphy_netns * set_channel * tdls_mgmt * tdls_oper * probe_client * set_noack_map * register_beacons * start_p2p_device * set_mcast_rate * connect * disconnect * set_qos_map * set_multicast_to_unicast * set_sar_specs * assoc_mlo_reconf software interface modes (can always be added): * AP/VLAN * monitor interface combinations are not supported HT Capability overrides: * MCS: ff ff ff ff ff ff ff ff ff ff * maximum A-MSDU length * supported channel width * short GI for 40 MHz * max A-MPDU length exponent * min MPDU start spacing Device supports TX status socket option. Device supports HT-IBSS. Device supports SAE with AUTHENTICATE command Device supports scan flush. Device supports per-vif TX power setting P2P GO supports CT window setting P2P GO supports opportunistic powersave setting Driver supports full state transitions for AP/GO clients Driver supports a userspace MPM Device supports configuring vdev MAC-addr on create. Device supports randomizing MAC-addr in scans. max # scan plans: 1 max scan plan interval: -1 max scan plan iterations: 0 Supported TX frame types: * IBSS: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * managed: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * AP: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * AP/VLAN: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * mesh point: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * P2P-client: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * P2P-GO: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * P2P-device: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 * NAN: 0x00 0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xa0 0xb0 0xc0 0xd0 0xe0 0xf0 Supported RX frame types: * IBSS: 0x40 0xb0 0xc0 0xd0 * managed: 0x40 0xb0 0xd0 * AP: 0x00 0x20 0x40 0xa0 0xb0 0xc0 0xd0 * AP/VLAN: 0x00 0x20 0x40 0xa0 0xb0 0xc0 0xd0 * mesh point: 0xb0 0xc0 0xd0 * P2P-client: 0x40 0xd0 * P2P-GO: 0x00 0x20 0x40 0xa0 0xb0 0xc0 0xd0 * P2P-device: 0x40 0xb0 0xd0 * NAN: 0xb0 0xd0 Supported extended features: * [ RRM ]: RRM * [ SET_SCAN_DWELL ]: scan dwell setting * [ FILS_STA ]: STA FILS (Fast Initial Link Setup) * [ CONTROL_PORT_OVER_NL80211 ]: control port over nl80211 * [ TXQS ]: FQ-CoDel-enabled intermediate TXQs * [ SCAN_RANDOM_SN ]: use random sequence numbers in scans * [ CAN_REPLACE_PTK0 ]: can safely replace PTK 0 when rekeying * [ CONTROL_PORT_NO_PREAUTH ]: disable pre-auth over nl80211 control port support * [ DEL_IBSS_STA ]: deletion of IBSS station support * [ SCAN_FREQ_KHZ ]: scan on kHz frequency support * [ CONTROL_PORT_OVER_NL80211_TX_STATUS ]: tx status for nl80211 control port support * [ POWERED_ADDR_CHANGE ]: can change MAC address while up --- filename: /lib/modules/6.19.11+kali-amd64/kernel/drivers/net/wireless/realtek/rtw88/rtw88_8814au.ko.xz license: Dual BSD/GPL description: Realtek 802.11ac wireless 8814au driver author: Bitterblue Smith alias: usb:v7392pA833d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v7392pA834d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v2357p0106d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v20F4p809Bd*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v20F4p809Ad*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v2001p331Ad*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v0E66p0026d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v0B05p1853d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v0B05p1852d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v0B05p1817d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v0846p9054d*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v056Ep400Dd*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v056Ep400Bd*dc*dsc*dp*icFFiscFFipFFin* alias: usb:v0BDAp8813d*dc*dsc*dp*icFFiscFFipFFin* depends: usbcore,rtw88_8814a,rtw88_usb intree: Y name: rtw88_8814au retpoline: Y vermagic: 6.19.11+kali-amd64 SMP preempt mod_unload sig_id: PKCS#7 signer: Build time autogenerated kernel key sig_key: 36:97:C2:2B:3F:F6:7D:BF:CD:2B:24:8A:8D:69:10:2D:04:92:7F:C2 sig_hashalgo: sha256 signature: 30:64:02:30:3A:9E:BA:C6:B2:A9:29:DA:53:2E:1C:ED:81:EC:32:AD: 10:67:D2:D6:07:46:16:08:71:CB:F2:C9:7F:86:32:BF:E2:74:D6:09: FB:2D:B5:27:EB:FD:CC:C4:BF:F0:CB:4A:02:30:3B:4F:28:36:D6:4F: F0:B0:D2:FF:4A:A0:0D:5D:6F:47:64:D8:95:12:36:BB:1F:AF:95:2B: 73:F3:01:A4:38:97:DA:0B:C0:73:A9:33:FF:92:29:5C:AC:09:E7:7F: 53:87 ```Arguments
```json { "url": "https://www.google.com/search?q=rtw88_8814au+monitor+mode+beacon+capture", "max_length": 6000 } ```11 lines
``` Failed to simplify HTML to markdown. Here is the raw content: Contents of https://www.google.com/search?q=rtw88_8814au+monitor+mode+beacon+capture: Google Searchbody{background-color:#fff}table,div,span,p{display:none}Please click here if you are not redirected within a few seconds.