mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-05-31 02:03:35 -07:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 48e73a0a41 | |||
| a36863e002 | |||
| 48aac0f0bb | |||
| 5749c305c6 | |||
| f53688086d | |||
| bd2e0b4394 | |||
| 1eea086199 | |||
| d36c1f10cd | |||
| 8d8d2bd8ec | |||
| f2b722ad5f | |||
| 5e2058e7ac | |||
| 60daf4b716 | |||
| 4df317b028 | |||
| d7fb8b9c85 | |||
| d399532494 | |||
| 45df91a364 | |||
| 672ed8c6c6 | |||
| 5c7c7cd766 | |||
| f41a8d38fe | |||
| f9c8c4671e | |||
| 723b20541e | |||
| 272a4aeabf | |||
| 6ae70556ba |
@@ -1,54 +0,0 @@
|
|||||||
name: Check and Test
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
NO_FIRMWARE_BIN: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check_and_test:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
device:
|
|
||||||
- name: tplink
|
|
||||||
- name: orbic
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Check
|
|
||||||
run: |
|
|
||||||
pushd bin/web
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
popd
|
|
||||||
cargo check --verbose --no-default-features --features=${{ matrix.device.name }}
|
|
||||||
- name: Run tests
|
|
||||||
run: |
|
|
||||||
pushd bin/web
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
popd
|
|
||||||
cargo test --verbose --no-default-features --features=${{ matrix.device.name }}
|
|
||||||
- name: Run clippy
|
|
||||||
run: cargo clippy --verbose --no-default-features --features=${{ matrix.device.name }}
|
|
||||||
|
|
||||||
windows_installer_check_and_test:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: cargo check
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cd installer
|
|
||||||
cargo check --verbose
|
|
||||||
- name: cargo test
|
|
||||||
shell: bash
|
|
||||||
run: |
|
|
||||||
cd installer
|
|
||||||
cargo test --verbose --no-default-features --features=${{ matrix.device.name }}
|
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
name: Build Release
|
name: main
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main, "release-*"]
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main"]
|
workflow_call:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
@@ -13,7 +12,139 @@ env:
|
|||||||
FILE_RAYHUNTER_DAEMON_TPLINK: ../../rayhunter-daemon-tplink/rayhunter-daemon
|
FILE_RAYHUNTER_DAEMON_TPLINK: ../../rayhunter-daemon-tplink/rayhunter-daemon
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
files_changed:
|
||||||
|
name: Detect file changes
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
outputs:
|
||||||
|
code_changed: ${{ steps.files_changed.outputs.code_count }}
|
||||||
|
daemon_changed: ${{ steps.files_changed.outputs.daemon_count }}
|
||||||
|
docs_changed: ${{ steps.files_changed.outputs.docs_count }}
|
||||||
|
installer_changed: ${{ steps.files_changed.outputs.installer_count }}
|
||||||
|
rootshell_changed: ${{ steps.files_changed.outputs.rootshell_count }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: detect file changes
|
||||||
|
id: files_changed
|
||||||
|
run: |
|
||||||
|
lcommit=${{ github.event.pull_request.base.sha || 'origin/main' }}
|
||||||
|
if [ ${{ github.ref }} = 'refs/heads/main' ]
|
||||||
|
then
|
||||||
|
echo "building everything"
|
||||||
|
echo code_count=forced >> "$GITHUB_OUTPUT"
|
||||||
|
echo daemon_count=forced >> "$GITHUB_OUTPUT"
|
||||||
|
echo docs_count=forced >> "$GITHUB_OUTPUT"
|
||||||
|
echo installer_count=forced >> "$GITHUB_OUTPUT"
|
||||||
|
echo rootshell_count=forced >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "code_count=$(git diff --name-only $lcommit...HEAD | grep -e ^bin -e ^installer -e ^lib -e ^rootshell -e ^telcom-parser | wc -l)" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "daemon_count=$(git diff --name-only $lcommit...HEAD | grep -e ^bin -e ^lib -e ^telcom-parser | wc -l)" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "docs_count=$(git diff --name-only $lcommit...HEAD | grep -e ^book.toml -e ^doc | wc -l)" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "installer_count=$(git diff --name-only $lcommit...HEAD | grep -e ^installer | wc -l)" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "rootshell_count=$(git diff --name-only $lcommit...HEAD | grep -e ^rootshell | wc -l)" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mdbook_test:
|
||||||
|
name: Test mdBook Documentation builds
|
||||||
|
needs: files_changed
|
||||||
|
if: needs.files_changed.outputs.docs_changed != '0'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install mdBook
|
||||||
|
run: |
|
||||||
|
cargo install mdbook --no-default-features --features search --vers "^0.4" --locked
|
||||||
|
- name: Test mdBook
|
||||||
|
run: mdbook test
|
||||||
|
|
||||||
|
mdbook_publish:
|
||||||
|
name: Publish mdBook to Github Pages
|
||||||
|
needs: mdbook_test
|
||||||
|
if: ${{ github.event_name != 'pull_request' }}
|
||||||
|
permissions:
|
||||||
|
pages: write
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Install mdBook
|
||||||
|
run: |
|
||||||
|
cargo install mdbook --no-default-features --features search --vers "^0.4" --locked
|
||||||
|
|
||||||
|
- name: Build mdBook
|
||||||
|
run: mdbook build
|
||||||
|
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: book
|
||||||
|
- name: Deploy to Github Pages
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
|
|
||||||
|
check_and_test:
|
||||||
|
needs: files_changed
|
||||||
|
if: needs.files_changed.outputs.code_changed != '0'
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
device:
|
||||||
|
- name: tplink
|
||||||
|
- name: orbic
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Check formatting
|
||||||
|
run: cargo fmt --all --check
|
||||||
|
- name: Check
|
||||||
|
run: |
|
||||||
|
pushd bin/web
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
popd
|
||||||
|
NO_FIRMWARE_BIN=true cargo check --verbose --no-default-features --features=${{ matrix.device.name }}
|
||||||
|
- name: Run tests
|
||||||
|
run: |
|
||||||
|
NO_FIRMWARE_BIN=true cargo test --verbose --no-default-features --features=${{ matrix.device.name }}
|
||||||
|
- name: Run clippy
|
||||||
|
run: |
|
||||||
|
NO_FIRMWARE_BIN=true cargo clippy --verbose --no-default-features --features=${{ matrix.device.name }}
|
||||||
|
|
||||||
|
windows_installer_check_and_test:
|
||||||
|
needs: files_changed
|
||||||
|
if: needs.files_changed.outputs.installer_changed != '0'
|
||||||
|
runs-on: windows-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: cargo check
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd installer
|
||||||
|
NO_FIRMWARE_BIN=true cargo check --verbose
|
||||||
|
- name: cargo test
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd installer
|
||||||
|
NO_FIRMWARE_BIN=true cargo test --verbose --no-default-features
|
||||||
|
|
||||||
build_rayhunter_check:
|
build_rayhunter_check:
|
||||||
|
if: needs.files_changed.outputs.daemon_changed != '0'
|
||||||
|
needs:
|
||||||
|
- check_and_test
|
||||||
|
- files_changed
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
platform:
|
platform:
|
||||||
@@ -42,8 +173,15 @@ jobs:
|
|||||||
name: rayhunter-check-${{ matrix.platform.name }}
|
name: rayhunter-check-${{ matrix.platform.name }}
|
||||||
path: target/release/rayhunter-check${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }}
|
path: target/release/rayhunter-check${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }}
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
build_rootshell:
|
build_rootshell:
|
||||||
|
if: needs.files_changed.outputs.rootshell_changed != '0'
|
||||||
|
needs:
|
||||||
|
- check_and_test
|
||||||
|
- files_changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
@@ -56,7 +194,15 @@ jobs:
|
|||||||
name: rootshell
|
name: rootshell
|
||||||
path: target/armv7-unknown-linux-musleabihf/firmware/rootshell
|
path: target/armv7-unknown-linux-musleabihf/firmware/rootshell
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
build_rayhunter:
|
build_rayhunter:
|
||||||
|
if: needs.files_changed.outputs.daemon_changed != '0'
|
||||||
|
needs:
|
||||||
|
- check_and_test
|
||||||
|
- files_changed
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
device:
|
device:
|
||||||
@@ -88,9 +234,17 @@ jobs:
|
|||||||
name: rayhunter-daemon-${{ matrix.device.name }}
|
name: rayhunter-daemon-${{ matrix.device.name }}
|
||||||
path: target/armv7-unknown-linux-musleabihf/firmware/rayhunter-daemon
|
path: target/armv7-unknown-linux-musleabihf/firmware/rayhunter-daemon
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
build_rust_installer:
|
build_rust_installer:
|
||||||
|
if: needs.files_changed.outputs.installer_changed != '0'
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
needs:
|
needs:
|
||||||
- build_rayhunter
|
- build_rayhunter
|
||||||
|
- build_rootshell
|
||||||
|
- files_changed
|
||||||
|
- windows_installer_check_and_test
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
platform:
|
platform:
|
||||||
@@ -124,6 +278,9 @@ jobs:
|
|||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
|
|
||||||
build_release_zip:
|
build_release_zip:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
needs:
|
needs:
|
||||||
- build_rayhunter_check
|
- build_rayhunter_check
|
||||||
- build_rootshell
|
- build_rootshell
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
# On Repository Settings > Pages > Build and deployment
|
|
||||||
# Set "Source" to GitHub Actions.
|
|
||||||
name: Documentation
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: ["main"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["main"]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
mdbook_test:
|
|
||||||
name: Test mdBook Documentation builds
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install mdBook
|
|
||||||
run: |
|
|
||||||
cargo install mdbook --no-default-features --features search --vers "^0.4" --locked
|
|
||||||
- name: Test mdBook
|
|
||||||
run: mdbook test
|
|
||||||
|
|
||||||
mdbook_publish:
|
|
||||||
if: ${{ github.event_name != 'pull_request' }}
|
|
||||||
needs: mdbook_test
|
|
||||||
permissions:
|
|
||||||
pages: write
|
|
||||||
contents: write
|
|
||||||
id-token: write
|
|
||||||
name: Publish mdBook to Github Pages
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install mdBook
|
|
||||||
run: |
|
|
||||||
cargo install mdbook --no-default-features --features search --vers "^0.4" --locked
|
|
||||||
|
|
||||||
- name: Build mdBook
|
|
||||||
run: mdbook build
|
|
||||||
|
|
||||||
- name: Setup Pages
|
|
||||||
uses: actions/configure-pages@v4
|
|
||||||
- name: Upload artifact
|
|
||||||
uses: actions/upload-pages-artifact@v3
|
|
||||||
with:
|
|
||||||
path: book
|
|
||||||
- name: Deploy to Github Pages
|
|
||||||
uses: actions/deploy-pages@v4
|
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# To use: navigate on Github to Actions, select "Release rayhunter" on the left, click "Run workflow" > "Run workflow" on the right.
|
||||||
|
# https://github.com/EFForg/rayhunter/actions/workflows/release.yml
|
||||||
|
name: Release rayhunter
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check_version_same:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Ensure all Cargo.toml files have the same version defined.
|
||||||
|
run: |
|
||||||
|
defined_versions=$(find lib bin installer rootshell telcom-parser -name Cargo.toml -exec grep ^version {} \; | sort -u | wc -l)
|
||||||
|
find lib bin installer rootshell telcom-parser -name Cargo.toml -exec grep ^version {} \;
|
||||||
|
echo number of defined versions = $defined_versions
|
||||||
|
if [ $defined_versions != "1" ]
|
||||||
|
then
|
||||||
|
echo "all Cargo.toml files must have the same version defined"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
main:
|
||||||
|
needs: check_version_same
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write
|
||||||
|
packages: write
|
||||||
|
pages: write
|
||||||
|
uses: ./.github/workflows/main.yml
|
||||||
|
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: main
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
- name: Create release
|
||||||
|
run: |
|
||||||
|
version=$(grep ^version lib/Cargo.toml | cut -d' ' -f3 | tr -d '"')
|
||||||
|
gh release create --generate-notes -t "Rayhunter v$version" "v$version" rayhunter-v${version}/rayhunter-*
|
||||||
Generated
+6
-6
@@ -5,7 +5,7 @@ version = 4
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "adb_client"
|
name = "adb_client"
|
||||||
version = "2.1.11"
|
version = "2.1.11"
|
||||||
source = "git+https://github.com/cooperq/adb_client.git?rev=88b3a3a24fe91d16101e44cebd84bd0ecc74ecdf#88b3a3a24fe91d16101e44cebd84bd0ecc74ecdf"
|
source = "git+https://github.com/EFForg/adb_client.git?rev=e511662394e4fa32865c154c40f81a3d846f700c#e511662394e4fa32865c154c40f81a3d846f700c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-io",
|
"async-io",
|
||||||
"base64",
|
"base64",
|
||||||
@@ -1433,7 +1433,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "installer"
|
name = "installer"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adb_client",
|
"adb_client",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -2307,7 +2307,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayhunter"
|
name = "rayhunter"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -2326,7 +2326,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayhunter-daemon"
|
name = "rayhunter-daemon"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -2453,7 +2453,7 @@ checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rootshell"
|
name = "rootshell"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nix",
|
"nix",
|
||||||
]
|
]
|
||||||
@@ -2826,7 +2826,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "telcom-parser"
|
name = "telcom-parser"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"asn1-codecs",
|
"asn1-codecs",
|
||||||
"asn1-compiler",
|
"asn1-compiler",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rayhunter-daemon"
|
name = "rayhunter-daemon"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub struct Config {
|
|||||||
pub ui_level: u8,
|
pub ui_level: u8,
|
||||||
pub enable_dummy_analyzer: bool,
|
pub enable_dummy_analyzer: bool,
|
||||||
pub colorblind_mode: bool,
|
pub colorblind_mode: bool,
|
||||||
|
pub key_input_mode: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
@@ -22,6 +23,7 @@ impl Default for Config {
|
|||||||
ui_level: 1,
|
ui_level: 1,
|
||||||
enable_dummy_analyzer: false,
|
enable_dummy_analyzer: false,
|
||||||
colorblind_mode: false,
|
colorblind_mode: false,
|
||||||
|
key_input_mode: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-4
@@ -4,6 +4,7 @@ mod diag;
|
|||||||
mod display;
|
mod display;
|
||||||
mod dummy_analyzer;
|
mod dummy_analyzer;
|
||||||
mod error;
|
mod error;
|
||||||
|
mod key_input;
|
||||||
mod pcap;
|
mod pcap;
|
||||||
mod qmdl_store;
|
mod qmdl_store;
|
||||||
mod server;
|
mod server;
|
||||||
@@ -175,7 +176,7 @@ async fn main() -> Result<(), RayhunterError> {
|
|||||||
let store = init_qmdl_store(&config).await?;
|
let store = init_qmdl_store(&config).await?;
|
||||||
let analysis_status = AnalysisStatus::new(&store);
|
let analysis_status = AnalysisStatus::new(&store);
|
||||||
let qmdl_store_lock = Arc::new(RwLock::new(store));
|
let qmdl_store_lock = Arc::new(RwLock::new(store));
|
||||||
let (tx, rx) = mpsc::channel::<DiagDeviceCtrlMessage>(1);
|
let (diag_tx, diag_rx) = mpsc::channel::<DiagDeviceCtrlMessage>(1);
|
||||||
let (ui_update_tx, ui_update_rx) = mpsc::channel::<display::DisplayState>(1);
|
let (ui_update_tx, ui_update_rx) = mpsc::channel::<display::DisplayState>(1);
|
||||||
let (analysis_tx, analysis_rx) = mpsc::channel::<AnalysisCtrlMessage>(5);
|
let (analysis_tx, analysis_rx) = mpsc::channel::<AnalysisCtrlMessage>(5);
|
||||||
let mut maybe_ui_shutdown_tx = None;
|
let mut maybe_ui_shutdown_tx = None;
|
||||||
@@ -193,13 +194,17 @@ async fn main() -> Result<(), RayhunterError> {
|
|||||||
run_diag_read_thread(
|
run_diag_read_thread(
|
||||||
&task_tracker,
|
&task_tracker,
|
||||||
dev,
|
dev,
|
||||||
rx,
|
diag_rx,
|
||||||
ui_update_tx.clone(),
|
ui_update_tx.clone(),
|
||||||
qmdl_store_lock.clone(),
|
qmdl_store_lock.clone(),
|
||||||
|
analysis_tx.clone(),
|
||||||
config.enable_dummy_analyzer,
|
config.enable_dummy_analyzer,
|
||||||
);
|
);
|
||||||
info!("Starting UI");
|
info!("Starting UI");
|
||||||
display::update_ui(&task_tracker, &config, ui_shutdown_rx, ui_update_rx);
|
display::update_ui(&task_tracker, &config, ui_shutdown_rx, ui_update_rx);
|
||||||
|
|
||||||
|
info!("Starting Key Input service");
|
||||||
|
key_input::run_key_input_thread(&task_tracker, &config, diag_tx.clone());
|
||||||
}
|
}
|
||||||
let (server_shutdown_tx, server_shutdown_rx) = oneshot::channel::<()>();
|
let (server_shutdown_tx, server_shutdown_rx) = oneshot::channel::<()>();
|
||||||
info!("create shutdown thread");
|
info!("create shutdown thread");
|
||||||
@@ -213,7 +218,7 @@ async fn main() -> Result<(), RayhunterError> {
|
|||||||
);
|
);
|
||||||
run_ctrl_c_thread(
|
run_ctrl_c_thread(
|
||||||
&task_tracker,
|
&task_tracker,
|
||||||
tx.clone(),
|
diag_tx.clone(),
|
||||||
server_shutdown_tx,
|
server_shutdown_tx,
|
||||||
maybe_ui_shutdown_tx,
|
maybe_ui_shutdown_tx,
|
||||||
qmdl_store_lock.clone(),
|
qmdl_store_lock.clone(),
|
||||||
@@ -221,7 +226,7 @@ async fn main() -> Result<(), RayhunterError> {
|
|||||||
);
|
);
|
||||||
let state = Arc::new(ServerState {
|
let state = Arc::new(ServerState {
|
||||||
qmdl_store_lock: qmdl_store_lock.clone(),
|
qmdl_store_lock: qmdl_store_lock.clone(),
|
||||||
diag_device_ctrl_sender: tx,
|
diag_device_ctrl_sender: diag_tx,
|
||||||
ui_update_sender: ui_update_tx,
|
ui_update_sender: ui_update_tx,
|
||||||
debug_mode: config.debug_mode,
|
debug_mode: config.debug_mode,
|
||||||
analysis_status_lock,
|
analysis_status_lock,
|
||||||
|
|||||||
+41
-63
@@ -7,7 +7,7 @@ use axum::http::header::CONTENT_TYPE;
|
|||||||
use axum::http::StatusCode;
|
use axum::http::StatusCode;
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use futures::{StreamExt, TryStreamExt};
|
use futures::{StreamExt, TryStreamExt};
|
||||||
use log::{debug, error, info};
|
use log::{debug, error, info, warn};
|
||||||
use rayhunter::diag::DataType;
|
use rayhunter::diag::DataType;
|
||||||
use rayhunter::diag_device::DiagDevice;
|
use rayhunter::diag_device::DiagDevice;
|
||||||
use rayhunter::qmdl::QmdlWriter;
|
use rayhunter::qmdl::QmdlWriter;
|
||||||
@@ -24,7 +24,7 @@ use crate::server::ServerState;
|
|||||||
|
|
||||||
pub enum DiagDeviceCtrlMessage {
|
pub enum DiagDeviceCtrlMessage {
|
||||||
StopRecording,
|
StopRecording,
|
||||||
StartRecording((QmdlWriter<File>, File)),
|
StartRecording,
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,6 +34,7 @@ pub fn run_diag_read_thread(
|
|||||||
mut qmdl_file_rx: Receiver<DiagDeviceCtrlMessage>,
|
mut qmdl_file_rx: Receiver<DiagDeviceCtrlMessage>,
|
||||||
ui_update_sender: Sender<display::DisplayState>,
|
ui_update_sender: Sender<display::DisplayState>,
|
||||||
qmdl_store_lock: Arc<RwLock<RecordingStore>>,
|
qmdl_store_lock: Arc<RwLock<RecordingStore>>,
|
||||||
|
analysis_sender: Sender<AnalysisCtrlMessage>,
|
||||||
enable_dummy_analyzer: bool,
|
enable_dummy_analyzer: bool,
|
||||||
) {
|
) {
|
||||||
task_tracker.spawn(async move {
|
task_tracker.spawn(async move {
|
||||||
@@ -46,20 +47,53 @@ pub fn run_diag_read_thread(
|
|||||||
tokio::select! {
|
tokio::select! {
|
||||||
msg = qmdl_file_rx.recv() => {
|
msg = qmdl_file_rx.recv() => {
|
||||||
match msg {
|
match msg {
|
||||||
Some(DiagDeviceCtrlMessage::StartRecording((new_writer, new_analysis_file))) => {
|
Some(DiagDeviceCtrlMessage::StartRecording) => {
|
||||||
maybe_qmdl_writer = Some(new_writer);
|
let mut qmdl_store = qmdl_store_lock.write().await;
|
||||||
|
let (qmdl_file, new_analysis_file) = match qmdl_store.new_entry().await {
|
||||||
|
Ok(x) => x,
|
||||||
|
Err(e) => {
|
||||||
|
error!("couldn't create new qmdl entry: {}", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
maybe_qmdl_writer = Some(QmdlWriter::new(qmdl_file));
|
||||||
|
|
||||||
if let Some(analysis_writer) = maybe_analysis_writer {
|
if let Some(analysis_writer) = maybe_analysis_writer {
|
||||||
analysis_writer.close().await.expect("failed to close analysis writer");
|
analysis_writer.close().await.expect("failed to close analysis writer");
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_analysis_writer = Some(AnalysisWriter::new(new_analysis_file, enable_dummy_analyzer).await
|
maybe_analysis_writer = Some(AnalysisWriter::new(new_analysis_file, enable_dummy_analyzer).await
|
||||||
.expect("failed to write to analysis file"));
|
.expect("failed to write to analysis file"));
|
||||||
|
|
||||||
|
if let Err(e) = ui_update_sender.send(display::DisplayState::Recording).await {
|
||||||
|
warn!("couldn't send ui update message: {}", e);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Some(DiagDeviceCtrlMessage::StopRecording) => {
|
Some(DiagDeviceCtrlMessage::StopRecording) => {
|
||||||
|
let mut qmdl_store = qmdl_store_lock.write().await;
|
||||||
|
if let Some((_, entry)) = qmdl_store.get_current_entry() {
|
||||||
|
if let Err(e) = analysis_sender
|
||||||
|
.send(AnalysisCtrlMessage::RecordingFinished(
|
||||||
|
entry.name.to_string(),
|
||||||
|
))
|
||||||
|
.await {
|
||||||
|
warn!("couldn't send analysis message: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Err(e) = qmdl_store.close_current_entry().await {
|
||||||
|
error!("couldn't close current entry: {}", e);
|
||||||
|
}
|
||||||
|
|
||||||
maybe_qmdl_writer = None;
|
maybe_qmdl_writer = None;
|
||||||
if let Some(analysis_writer) = maybe_analysis_writer {
|
if let Some(analysis_writer) = maybe_analysis_writer {
|
||||||
analysis_writer.close().await.expect("failed to close analysis writer");
|
analysis_writer.close().await.expect("failed to close analysis writer");
|
||||||
}
|
}
|
||||||
maybe_analysis_writer = None;
|
maybe_analysis_writer = None;
|
||||||
|
|
||||||
|
if let Err(e) = ui_update_sender.send(display::DisplayState::Paused).await {
|
||||||
|
warn!("couldn't send ui update message: {}", e);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// None means all the Senders have been dropped, so it's
|
// None means all the Senders have been dropped, so it's
|
||||||
// time to go
|
// time to go
|
||||||
@@ -125,37 +159,15 @@ pub async fn start_recording(
|
|||||||
if state.debug_mode {
|
if state.debug_mode {
|
||||||
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
|
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
|
||||||
}
|
}
|
||||||
let mut qmdl_store = state.qmdl_store_lock.write().await;
|
|
||||||
let (qmdl_file, analysis_file) = qmdl_store.new_entry().await.map_err(|e| {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("couldn't create new qmdl entry: {}", e),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let qmdl_writer = QmdlWriter::new(qmdl_file);
|
|
||||||
state
|
state
|
||||||
.diag_device_ctrl_sender
|
.diag_device_ctrl_sender
|
||||||
.send(DiagDeviceCtrlMessage::StartRecording((
|
.send(DiagDeviceCtrlMessage::StartRecording)
|
||||||
qmdl_writer,
|
|
||||||
analysis_file,
|
|
||||||
)))
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
(
|
(
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
format!("couldn't send stop recording message: {}", e),
|
format!("couldn't send start recording message: {}", e),
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let display_state = display::DisplayState::Recording;
|
|
||||||
state
|
|
||||||
.ui_update_sender
|
|
||||||
.send(display_state)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("couldn't send ui update message: {}", e),
|
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -168,30 +180,6 @@ pub async fn stop_recording(
|
|||||||
if state.debug_mode {
|
if state.debug_mode {
|
||||||
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
|
return Err((StatusCode::FORBIDDEN, "server is in debug mode".to_string()));
|
||||||
}
|
}
|
||||||
let mut qmdl_store = state.qmdl_store_lock.write().await;
|
|
||||||
match qmdl_store.get_current_entry() {
|
|
||||||
Some((_, entry)) => {
|
|
||||||
state
|
|
||||||
.analysis_sender
|
|
||||||
.send(AnalysisCtrlMessage::RecordingFinished(
|
|
||||||
entry.name.to_string(),
|
|
||||||
))
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("couldn't send AnalysisCtrlMessage: {}", e),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
None => todo!(),
|
|
||||||
}
|
|
||||||
qmdl_store.close_current_entry().await.map_err(|e| {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("couldn't close current qmdl entry: {}", e),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
state
|
state
|
||||||
.diag_device_ctrl_sender
|
.diag_device_ctrl_sender
|
||||||
.send(DiagDeviceCtrlMessage::StopRecording)
|
.send(DiagDeviceCtrlMessage::StopRecording)
|
||||||
@@ -202,16 +190,6 @@ pub async fn stop_recording(
|
|||||||
format!("couldn't send stop recording message: {}", e),
|
format!("couldn't send stop recording message: {}", e),
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
state
|
|
||||||
.ui_update_sender
|
|
||||||
.send(display::DisplayState::Paused)
|
|
||||||
.await
|
|
||||||
.map_err(|e| {
|
|
||||||
(
|
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
|
||||||
format!("couldn't send ui update message: {}", e),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
Ok((StatusCode::ACCEPTED, "ok".to_string()))
|
Ok((StatusCode::ACCEPTED, "ok".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
use log::error;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
use tokio::fs::File;
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
use tokio::sync::mpsc::Sender;
|
||||||
|
use tokio_util::task::TaskTracker;
|
||||||
|
|
||||||
|
use crate::config;
|
||||||
|
use crate::diag::DiagDeviceCtrlMessage;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Event {
|
||||||
|
KeyDown,
|
||||||
|
KeyUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
const INPUT_EVENT_SIZE: usize = 32;
|
||||||
|
|
||||||
|
pub fn run_key_input_thread(
|
||||||
|
task_tracker: &TaskTracker,
|
||||||
|
config: &config::Config,
|
||||||
|
diag_tx: Sender<DiagDeviceCtrlMessage>,
|
||||||
|
) {
|
||||||
|
if config.key_input_mode == 0 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_tracker.spawn(async move {
|
||||||
|
// Open the input device
|
||||||
|
let mut file = match File::open("/dev/input/event0").await {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to open /dev/input/event0: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut buffer = [0u8; INPUT_EVENT_SIZE];
|
||||||
|
let mut last_keyup: Option<Instant> = None;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Err(e) = file.read_exact(&mut buffer).await {
|
||||||
|
error!("failed to read key input: {}", e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let event = parse_event(buffer);
|
||||||
|
|
||||||
|
match event {
|
||||||
|
Event::KeyUp => {
|
||||||
|
if last_keyup.is_some()
|
||||||
|
&& last_keyup.unwrap().elapsed() < Duration::from_millis(500)
|
||||||
|
{
|
||||||
|
if let Err(e) = diag_tx.send(DiagDeviceCtrlMessage::StopRecording).await {
|
||||||
|
error!("Failed to send StopRecording: {}", e);
|
||||||
|
}
|
||||||
|
if let Err(e) = diag_tx.send(DiagDeviceCtrlMessage::StartRecording).await {
|
||||||
|
error!("Failed to send StartRecording: {}", e);
|
||||||
|
}
|
||||||
|
last_keyup = None;
|
||||||
|
} else {
|
||||||
|
last_keyup = Some(Instant::now());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::KeyDown => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_event(input: [u8; INPUT_EVENT_SIZE]) -> Event {
|
||||||
|
if input[12] == 0 {
|
||||||
|
Event::KeyUp
|
||||||
|
} else {
|
||||||
|
Event::KeyDown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_event_keydown_m7350_v5() {
|
||||||
|
let input = [
|
||||||
|
0x57, 0x6c, 0x09, 0x00, 0x7c, 0xfb, 0x03, 0x00, 0x01, 0x00, 0x74, 0x00, 0x01, 0x00,
|
||||||
|
0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
assert!(matches!(parse_event(input), Event::KeyDown));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_event_keyup_m7350_v5() {
|
||||||
|
let input = [
|
||||||
|
0x57, 0x6c, 0x09, 0x00, 0x1b, 0x15, 0x05, 0x00, 0x01, 0x00, 0x74, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
];
|
||||||
|
assert!(matches!(parse_event(input), Event::KeyUp));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@ export function parse_finished_report(report_json: NewlineDeliminatedJson): Anal
|
|||||||
const events: Event[] = analysis_json.events.map((event_json: any): Event | null => {
|
const events: Event[] = analysis_json.events.map((event_json: any): Event | null => {
|
||||||
if (event_json === null) {
|
if (event_json === null) {
|
||||||
return null;
|
return null;
|
||||||
} else if (event_json.event_type === "Informational") {
|
} else if (event_json.event_type.type === "Informational") {
|
||||||
num_informational_logs += 1;
|
num_informational_logs += 1;
|
||||||
return {
|
return {
|
||||||
type: EventType.Informational,
|
type: EventType.Informational,
|
||||||
@@ -82,8 +82,8 @@ export function parse_finished_report(report_json: NewlineDeliminatedJson): Anal
|
|||||||
num_warnings += 1;
|
num_warnings += 1;
|
||||||
return {
|
return {
|
||||||
type: EventType.Warning,
|
type: EventType.Warning,
|
||||||
severity: event_json.severity === "High" ? Severity.High :
|
severity: event_json.event_type.severity === "High" ? Severity.High :
|
||||||
event_json.severity === "Medium" ? Severity.Medium : Severity.Low,
|
event_json.event_type.severity === "Medium" ? Severity.Medium : Severity.Low,
|
||||||
message: event_json.message,
|
message: event_json.message,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
Storage
|
Storage
|
||||||
</th>
|
</th>
|
||||||
<td class={table_cell_classes}>
|
<td class={table_cell_classes}>
|
||||||
{stats.disk_stats.used_percent} used ({stats.disk_stats.used_size} / {stats.disk_stats.available_size})
|
{stats.disk_stats.used_percent} used ({stats.disk_stats.used_size} used / {stats.disk_stats.available_size} available)
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="border-b">
|
<tr class="border-b">
|
||||||
|
|||||||
Vendored
+5
-1
@@ -14,5 +14,9 @@ colorblind_mode = false
|
|||||||
#
|
#
|
||||||
# TP-Link with one-bit display:
|
# TP-Link with one-bit display:
|
||||||
# 0 = invisible mode
|
# 0 = invisible mode
|
||||||
# 1..3 = show emoji for status. :) for running, :( for warnings, no mouth for paused.
|
# 1..3 = show emoji for status. :) for running, ! for warnings, no mouth for paused.
|
||||||
ui_level = 1
|
ui_level = 1
|
||||||
|
|
||||||
|
# 0 = rayhunter does not read button presses
|
||||||
|
# 1 = double-tapping the power button starts/stops recordings
|
||||||
|
key_input_mode = 1
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 152 KiB |
@@ -11,12 +11,22 @@ Windows support in Rayhunter's installer is a work-in-progress. Depending on the
|
|||||||
|
|
||||||
## Orbic
|
## Orbic
|
||||||
|
|
||||||
1. Install the [Zadig WinUSB driver](https://zadig.akeo.ie/).
|
1. Connect the device to your computer using the provided USB cable.
|
||||||
|
1. Install the [Zadig WinUSB driver installer](https://zadig.akeo.ie/).
|
||||||
|
1. Open Zadig, click options->show all devices
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
1. Select 'RNDIS (Interface 0)'
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
1. Click 'install driver' and wait for it to finish.
|
||||||
2. Download the latest `rayhunter-vX.X.X.zip` from the [Rayhunter releases page](https://github.com/EFForg/rayhunter/releases). The version you download will have numbers instead of X
|
2. Download the latest `rayhunter-vX.X.X.zip` from the [Rayhunter releases page](https://github.com/EFForg/rayhunter/releases). The version you download will have numbers instead of X
|
||||||
3. Unzip `rayhunter-vX.X.X` .
|
3. Unzip `rayhunter-vX.X.X` .
|
||||||
4. Save the [`install.ps1` file here](https://github.com/EFForg/rayhunter/blob/powershell/installer/install.ps1) in top of the folder that was unzipped from release.zip.
|
1. Open a powershell terminal by pressing Win+R and typing `powershell` and hitting enter.
|
||||||
5. Run the following powershell command `Set-ExecutionPolicy remotesigned`
|
5. Type `cd ~\Downloads\rayhunter-v<x.x.x>\installer-windows-x86_64` (**Replace <x.x.x> with the rayhunter version you just unzipped**) and hit enter.
|
||||||
5. Run the install script by double clicking on `install.ps1`. A powershell window will launch.
|
5. Run the install script: `.\installer.exe orbic` and hit enter.
|
||||||
The device will restart multiple times over the next few minutes.
|
- The device will restart multiple times over the next few minutes.
|
||||||
You will know it is done when you see terminal output that says `checking for rayhunter server...success!`
|
- You will know it is done when you see terminal output that says `checking for rayhunter server...success!`
|
||||||
6. Rayhunter should now be running! You can verify this by following the instructions below to [view the web UI](#usage-viewing-the-web-ui). You should also see a green line flash along the top of top the display on the device.
|
6. Rayhunter should now be running! You can verify this by following the instructions below to [view the web UI](#usage-viewing-the-web-ui). You should also see a green line flash along the top of top the display on the device.
|
||||||
|
|||||||
+16
-5
@@ -2,19 +2,30 @@
|
|||||||
|
|
||||||
Once installed, Rayhunter will run automatically whenever your device is running. You'll see a green line on top of the device's display to indicate that it's running and recording. [The line will turn red](#red) once a potential IMSI catcher has been found, until the device is rebooted or a new recording is started through the web UI.
|
Once installed, Rayhunter will run automatically whenever your device is running. You'll see a green line on top of the device's display to indicate that it's running and recording. [The line will turn red](#red) once a potential IMSI catcher has been found, until the device is rebooted or a new recording is started through the web UI.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
It also serves a web UI that provides some basic controls, such as being able to start/stop recordings, download captures, delete captures, and view heuristic analyses of captures.
|
It also serves a web UI that provides some basic controls, such as being able to start/stop recordings, download captures, delete captures, and view heuristic analyses of captures.
|
||||||
|
|
||||||
|
## The web UI
|
||||||
|
|
||||||
You can access this UI in one of two ways:
|
You can access this UI in one of two ways:
|
||||||
|
|
||||||
* **Connect over wifi:** Connect your phone/laptop to your device's wifi
|
* **Connect over WiFi:** Connect your phone/laptop to your device's WiFi
|
||||||
network and visit [http://192.168.1.1:8080](http://192.168.1.1:8080) (orbic)
|
network and visit [http://192.168.1.1:8080](http://192.168.1.1:8080) (orbic)
|
||||||
or [http://192.168.0.1:8080](http://192.168.0.1:8080) (tplink).
|
or [http://192.168.0.1:8080](http://192.168.0.1:8080) (tplink).
|
||||||
|
|
||||||
Click past your browser warning you about the connection not being secure, Rayhunter doesn't have HTTPS yet.
|
Click past your browser warning you about the connection not being secure, Rayhunter doesn't have HTTPS yet.
|
||||||
|
|
||||||
On the Orbic, you can find the wifi network password by going to the Orbic's menu > 2.4 GHz WIFI Info > Enter > find the 8-character password next to the lock 🔒 icon.
|
On the **Orbic**, you can find the WiFi network password by going to the Orbic's menu > 2.4 GHz WIFI Info > Enter > find the 8-character password next to the lock 🔒 icon.
|
||||||
* **Connect over USB (orbic):** Connect your device to your laptop via USB. Run `adb forward tcp:8080 tcp:8080`, then visit [http://localhost:8080](http://localhost:8080).
|
On the **TP-Link**, you can find the WiFi network password by going to the TP-Link's menu > Advanced > Wireless > Basic Settings.
|
||||||
|
|
||||||
|
* **Connect over USB (Orbic):** Connect your device to your laptop via USB. Run `adb forward tcp:8080 tcp:8080`, then visit [http://localhost:8080](http://localhost:8080).
|
||||||
* For this you will need to install the Android Debug Bridge (ADB) on your computer, you can copy the version that was downloaded inside the `releases/platform-tools/` folder to somewhere else in your path or you can install it manually.
|
* For this you will need to install the Android Debug Bridge (ADB) on your computer, you can copy the version that was downloaded inside the `releases/platform-tools/` folder to somewhere else in your path or you can install it manually.
|
||||||
* You can find instructions for doing so on your platform [here](https://www.xda-developers.com/install-adb-windows-macos-linux/#how-to-set-up-adb-on-your-computer), (don't worry about instructions for installing it on a phone/device yet).
|
* You can find instructions for doing so on your platform [here](https://www.xda-developers.com/install-adb-windows-macos-linux/#how-to-set-up-adb-on-your-computer), (don't worry about instructions for installing it on a phone/device yet).
|
||||||
* On macOS, the easiest way to install ADB is with Homebrew: First [install Homebrew](https://brew.sh/), then run `brew install android-platform-tools`.
|
* On MacOS, the easiest way to install ADB is with Homebrew: First [install Homebrew](https://brew.sh/), then run `brew install android-platform-tools`.
|
||||||
* **Connect over USB (tplink):** Plug in the TP-Link and use USB tethering to establish a network connection. ADB support can be enabled on the device, but the installer won't do it for you.
|
|
||||||
|
* **Connect over USB (TP-Link):** Plug in the TP-Link and use USB tethering to establish a network connection. ADB support can be enabled on the device, but the installer won't do it for you.
|
||||||
|
|
||||||
|
## Key shortcuts
|
||||||
|
|
||||||
|
As of 0.3.3, you can start a new recording by double-tapping the power button. Any current recording will be stopped and a new recording will be started, resetting the red line as well.
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "installer"
|
name = "installer"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
@@ -21,13 +21,13 @@ tokio-retry2 = "0.5.7"
|
|||||||
tokio-stream = "0.1.17"
|
tokio-stream = "0.1.17"
|
||||||
|
|
||||||
[target.'cfg(target_os = "linux")'.dependencies.adb_client]
|
[target.'cfg(target_os = "linux")'.dependencies.adb_client]
|
||||||
git = "https://github.com/cooperq/adb_client.git"
|
git = "https://github.com/EFForg/adb_client.git"
|
||||||
rev = "88b3a3a24fe91d16101e44cebd84bd0ecc74ecdf"
|
rev = "e511662394e4fa32865c154c40f81a3d846f700c"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["trans-nusb"]
|
features = ["trans-nusb"]
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies.adb_client]
|
[target.'cfg(any(target_os = "windows", target_os = "macos"))'.dependencies.adb_client]
|
||||||
git = "https://github.com/cooperq/adb_client.git"
|
git = "https://github.com/EFForg/adb_client.git"
|
||||||
rev = "88b3a3a24fe91d16101e44cebd84bd0ecc74ecdf"
|
rev = "e511662394e4fa32865c154c40f81a3d846f700c"
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["trans-libusb"]
|
features = ["trans-libusb"]
|
||||||
|
|||||||
+17
-16
@@ -2,20 +2,14 @@ $global:adb = ".\platform-tools-latest-windows\platform-tools\adb.exe"
|
|||||||
$global:serial = ".\installer-windows-x86_64\installer.exe"
|
$global:serial = ".\installer-windows-x86_64\installer.exe"
|
||||||
|
|
||||||
function _adb_push {
|
function _adb_push {
|
||||||
& $global:adb -d push @args | Out-Null
|
& $global:adb -d push @args *> $null
|
||||||
$exitCode = $LASTEXITCODE
|
$exitCode = $LASTEXITCODE
|
||||||
if ($exitCode -ne 0) {
|
|
||||||
write-host "push exited with exit code $($exitCode)"
|
|
||||||
}
|
|
||||||
return $exitCode
|
return $exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
function _adb_shell {
|
function _adb_shell {
|
||||||
& $global:adb -d shell @args | Out-Null
|
& $global:adb -d shell @args *> $null
|
||||||
$exitCode = $LASTEXITCODE
|
$exitCode = $LASTEXITCODE
|
||||||
if ($exitCode -ne 0) {
|
|
||||||
write-host "shell exited with exit code $($exitCode)"
|
|
||||||
}
|
|
||||||
return $exitCode
|
return $exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +30,7 @@ function _wait_for_atfwd_daemon {
|
|||||||
function force_debug_mode {
|
function force_debug_mode {
|
||||||
write-host "Using adb at $($global:adb)"
|
write-host "Using adb at $($global:adb)"
|
||||||
write-host "Forcing a switch into debug mode to enable ADB"
|
write-host "Forcing a switch into debug mode to enable ADB"
|
||||||
_serial "util serial --root" | Out-Host
|
_serial "--root" | Out-Host
|
||||||
write-host "adb enabled, waiting for reboot..." -nonewline
|
write-host "adb enabled, waiting for reboot..." -nonewline
|
||||||
_wait_for_adb_shell
|
_wait_for_adb_shell
|
||||||
write-host " it's alive!"
|
write-host " it's alive!"
|
||||||
@@ -58,7 +52,8 @@ function _serial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setup_rootshell {
|
function setup_rootshell {
|
||||||
_adb_push "rootshell" "/tmp"
|
write-host "setting up rootshell"
|
||||||
|
_adb_push "rootshell" "/tmp" | Out-null
|
||||||
write-host "cp..."
|
write-host "cp..."
|
||||||
_serial "AT+SYSCMD=cp /tmp/rootshell /bin/rootshell" | Out-Host
|
_serial "AT+SYSCMD=cp /tmp/rootshell /bin/rootshell" | Out-Host
|
||||||
start-sleep -seconds 1
|
start-sleep -seconds 1
|
||||||
@@ -68,19 +63,20 @@ function setup_rootshell {
|
|||||||
write-host "chmod..."
|
write-host "chmod..."
|
||||||
_serial "AT+SYSCMD=chmod 4755 /bin/rootshell" | Out-Host
|
_serial "AT+SYSCMD=chmod 4755 /bin/rootshell" | Out-Host
|
||||||
start-sleep -seconds 1
|
start-sleep -seconds 1
|
||||||
_adb_shell '/bin/rootshell -c id'
|
_adb_shell '/bin/rootshell -c id' | Out-null
|
||||||
write-host "we have root!"
|
write-host "we have root!"
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup_rayhunter {
|
function setup_rayhunter {
|
||||||
|
write-host "installing rayhunter..."
|
||||||
_serial "AT+SYSCMD=mkdir -p /data/rayhunter" | Out-Host
|
_serial "AT+SYSCMD=mkdir -p /data/rayhunter" | Out-Host
|
||||||
_adb_push "config.toml.example" "/tmp/config.toml"
|
_adb_push "config.toml.example" "/tmp/config.toml" | Out-Null
|
||||||
_serial "AT+SYSCMD=mv /tmp/config.toml /data/rayhunter" | Out-Host
|
_serial "AT+SYSCMD=mv /tmp/config.toml /data/rayhunter" | Out-Host
|
||||||
_adb_push "rayhunter-daemon-orbic/rayhunter-daemon" "/tmp/rayhunter-daemon"
|
_adb_push "rayhunter-daemon-orbic/rayhunter-daemon" "/tmp/rayhunter-daemon" | Out-Null
|
||||||
_serial "AT+SYSCMD=mv /tmp/rayhunter-daemon /data/rayhunter" | Out-Host
|
_serial "AT+SYSCMD=mv /tmp/rayhunter-daemon /data/rayhunter" | Out-Host
|
||||||
_adb_push "scripts/rayhunter_daemon" "/tmp/rayhunter_daemon"
|
_adb_push "scripts/rayhunter_daemon" "/tmp/rayhunter_daemon" | Out-Null
|
||||||
_serial "AT+SYSCMD=mv /tmp/rayhunter_daemon /etc/init.d/rayhunter_daemon" | Out-Host
|
_serial "AT+SYSCMD=mv /tmp/rayhunter_daemon /etc/init.d/rayhunter_daemon" | Out-Host
|
||||||
_adb_push "scripts/misc-daemon" "/tmp/misc-daemon"
|
_adb_push "scripts/misc-daemon" "/tmp/misc-daemon" | Out-Null
|
||||||
_serial "AT+SYSCMD=mv /tmp/misc-daemon /etc/init.d/misc-daemon" | Out-Host
|
_serial "AT+SYSCMD=mv /tmp/misc-daemon /etc/init.d/misc-daemon" | Out-Host
|
||||||
|
|
||||||
_serial "AT+SYSCMD=chmod 755 /data/rayhunter/rayhunter-daemon" | Out-Host
|
_serial "AT+SYSCMD=chmod 755 /data/rayhunter/rayhunter-daemon" | Out-Host
|
||||||
@@ -108,7 +104,12 @@ function test_rayhunter {
|
|||||||
write-host "checking for rayhunter server..." -nonewline
|
write-host "checking for rayhunter server..." -nonewline
|
||||||
$seconds = 0
|
$seconds = 0
|
||||||
do {
|
do {
|
||||||
$resp = invoke-webrequest -uri $URL
|
try {
|
||||||
|
$resp = invoke-webrequest -uri $URL
|
||||||
|
} catch {
|
||||||
|
# Fail silently
|
||||||
|
$resp = $null
|
||||||
|
}
|
||||||
if ($resp.statuscode -eq 200) {
|
if ($resp.statuscode -eq 200) {
|
||||||
write-host "success!"
|
write-host "success!"
|
||||||
write-host "you can access rayhunter at $($URL)"
|
write-host "you can access rayhunter at $($URL)"
|
||||||
|
|||||||
+80
-45
@@ -22,16 +22,24 @@ const ORBIC_BUSY: &str = r#"The Orbic is plugged in but is being used by another
|
|||||||
Please close any program that might be using your USB devices.
|
Please close any program that might be using your USB devices.
|
||||||
If you have adb installed you may need to kill the adb daemon"#;
|
If you have adb installed you may need to kill the adb daemon"#;
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||||
const ORBIC_BUSY_MAC: &str = r#"Permission denied.
|
const ORBIC_BUSY_MAC: &str = r#"Permission denied.
|
||||||
|
|
||||||
On macOS this might be caused by another program using the Orbic.
|
On macOS or windows this might be caused by another program using the Orbic.
|
||||||
Please close any program that might be using your Orbic.
|
Please close any program that might be using your Orbic.
|
||||||
If you have adb installed you may need to kill the adb daemon"#;
|
If you have adb installed you may need to kill the adb daemon"#;
|
||||||
|
|
||||||
const VENDOR_ID: u16 = 0x05c6;
|
const VENDOR_ID: u16 = 0x05c6;
|
||||||
const PRODUCT_ID: u16 = 0xf601;
|
const PRODUCT_ID: u16 = 0xf601;
|
||||||
|
|
||||||
|
const INTERFACE: u8 = 1;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
const RNDIS_INTERFACE: u8 = 0;
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
const RNDIS_INTERFACE: u8 = 1;
|
||||||
|
|
||||||
macro_rules! echo {
|
macro_rules! echo {
|
||||||
($($arg:tt)*) => {
|
($($arg:tt)*) => {
|
||||||
print!($($arg)*);
|
print!($($arg)*);
|
||||||
@@ -41,12 +49,11 @@ macro_rules! echo {
|
|||||||
|
|
||||||
pub async fn install() -> Result<()> {
|
pub async fn install() -> Result<()> {
|
||||||
let mut adb_device = force_debug_mode().await?;
|
let mut adb_device = force_debug_mode().await?;
|
||||||
let serial_interface = open_orbic()?.ok_or_else(|| anyhow!(ORBIC_NOT_FOUND))?;
|
|
||||||
echo!("Installing rootshell... ");
|
echo!("Installing rootshell... ");
|
||||||
setup_rootshell(&serial_interface, &mut adb_device).await?;
|
setup_rootshell(&mut adb_device).await?;
|
||||||
println!("done");
|
println!("done");
|
||||||
echo!("Installing rayhunter... ");
|
echo!("Installing rayhunter... ");
|
||||||
let mut adb_device = setup_rayhunter(&serial_interface, adb_device).await?;
|
let mut adb_device = setup_rayhunter(adb_device).await?;
|
||||||
println!("done");
|
println!("done");
|
||||||
echo!("Testing rayhunter... ");
|
echo!("Testing rayhunter... ");
|
||||||
test_rayhunter(&mut adb_device).await?;
|
test_rayhunter(&mut adb_device).await?;
|
||||||
@@ -66,6 +73,7 @@ async fn force_debug_mode() -> Result<ADBUSBDevice> {
|
|||||||
enable_command_mode()?;
|
enable_command_mode()?;
|
||||||
echo!("ADB enabled, waiting for reboot... ");
|
echo!("ADB enabled, waiting for reboot... ");
|
||||||
let mut adb_device = get_adb().await?;
|
let mut adb_device = get_adb().await?;
|
||||||
|
adb_setup_serial(&mut adb_device).await?;
|
||||||
println!("it's alive!");
|
println!("it's alive!");
|
||||||
echo!("Waiting for atfwd_daemon to startup... ");
|
echo!("Waiting for atfwd_daemon to startup... ");
|
||||||
adb_command(&mut adb_device, &["pgrep", "atfwd_daemon"])?;
|
adb_command(&mut adb_device, &["pgrep", "atfwd_daemon"])?;
|
||||||
@@ -73,23 +81,14 @@ async fn force_debug_mode() -> Result<ADBUSBDevice> {
|
|||||||
Ok(adb_device)
|
Ok(adb_device)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup_rootshell(
|
async fn setup_rootshell(adb_device: &mut ADBUSBDevice) -> Result<()> {
|
||||||
serial_interface: &Interface,
|
|
||||||
adb_device: &mut ADBUSBDevice,
|
|
||||||
) -> Result<()> {
|
|
||||||
let rootshell_bin = include_bytes!(env!("FILE_ROOTSHELL"));
|
let rootshell_bin = include_bytes!(env!("FILE_ROOTSHELL"));
|
||||||
|
|
||||||
install_file(
|
install_file(adb_device, "/bin/rootshell", rootshell_bin).await?;
|
||||||
serial_interface,
|
|
||||||
adb_device,
|
|
||||||
"/bin/rootshell",
|
|
||||||
rootshell_bin,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
at_syscmd(serial_interface, "chown root /bin/rootshell").await?;
|
adb_at_syscmd(adb_device, "chown root /bin/rootshell").await?;
|
||||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
at_syscmd(serial_interface, "chmod 4755 /bin/rootshell").await?;
|
adb_at_syscmd(adb_device, "chmod 4755 /bin/rootshell").await?;
|
||||||
let output = adb_command(adb_device, &["/bin/rootshell", "-c", "id"])?;
|
let output = adb_command(adb_device, &["/bin/rootshell", "-c", "id"])?;
|
||||||
if !output.contains("uid=0") {
|
if !output.contains("uid=0") {
|
||||||
bail!("rootshell is not giving us root.");
|
bail!("rootshell is not giving us root.");
|
||||||
@@ -97,46 +96,39 @@ async fn setup_rootshell(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup_rayhunter(
|
async fn setup_rayhunter(mut adb_device: ADBUSBDevice) -> Result<ADBUSBDevice> {
|
||||||
serial_interface: &Interface,
|
|
||||||
mut adb_device: ADBUSBDevice,
|
|
||||||
) -> Result<ADBUSBDevice> {
|
|
||||||
let rayhunter_daemon_bin = include_bytes!(env!("FILE_RAYHUNTER_DAEMON_ORBIC"));
|
let rayhunter_daemon_bin = include_bytes!(env!("FILE_RAYHUNTER_DAEMON_ORBIC"));
|
||||||
|
|
||||||
at_syscmd(serial_interface, "mkdir -p /data/rayhunter").await?;
|
adb_at_syscmd(&mut adb_device, "mkdir -p /data/rayhunter").await?;
|
||||||
install_file(
|
install_file(
|
||||||
serial_interface,
|
|
||||||
&mut adb_device,
|
&mut adb_device,
|
||||||
"/data/rayhunter/rayhunter-daemon",
|
"/data/rayhunter/rayhunter-daemon",
|
||||||
rayhunter_daemon_bin,
|
rayhunter_daemon_bin,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
install_file(
|
install_file(
|
||||||
serial_interface,
|
|
||||||
&mut adb_device,
|
&mut adb_device,
|
||||||
"/data/rayhunter/config.toml",
|
"/data/rayhunter/config.toml",
|
||||||
CONFIG_TOML.as_bytes(),
|
CONFIG_TOML.as_bytes(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
install_file(
|
install_file(
|
||||||
serial_interface,
|
|
||||||
&mut adb_device,
|
&mut adb_device,
|
||||||
"/etc/init.d/rayhunter_daemon",
|
"/etc/init.d/rayhunter_daemon",
|
||||||
RAYHUNTER_DAEMON_INIT.as_bytes(),
|
RAYHUNTER_DAEMON_INIT.as_bytes(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
install_file(
|
install_file(
|
||||||
serial_interface,
|
|
||||||
&mut adb_device,
|
&mut adb_device,
|
||||||
"/etc/init.d/misc-daemon",
|
"/etc/init.d/misc-daemon",
|
||||||
include_bytes!("../../dist/scripts/misc-daemon"),
|
include_bytes!("../../dist/scripts/misc-daemon"),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
at_syscmd(serial_interface, "chmod 755 /etc/init.d/rayhunter_daemon").await?;
|
adb_at_syscmd(&mut adb_device, "chmod 755 /etc/init.d/rayhunter_daemon").await?;
|
||||||
at_syscmd(serial_interface, "chmod 755 /etc/init.d/misc-daemon").await?;
|
adb_at_syscmd(&mut adb_device, "chmod 755 /etc/init.d/misc-daemon").await?;
|
||||||
println!("done");
|
println!("done");
|
||||||
echo!("Waiting for reboot... ");
|
echo!("Waiting for reboot... ");
|
||||||
at_syscmd(serial_interface, "shutdown -r -t 1 now").await?;
|
adb_at_syscmd(&mut adb_device, "shutdown -r -t 1 now").await?;
|
||||||
// first wait for shutdown (it can take ~10s)
|
// first wait for shutdown (it can take ~10s)
|
||||||
tokio::time::timeout(Duration::from_secs(30), async {
|
tokio::time::timeout(Duration::from_secs(30), async {
|
||||||
while let Ok(dev) = adb_echo_test(adb_device).await {
|
while let Ok(dev) = adb_echo_test(adb_device).await {
|
||||||
@@ -168,16 +160,11 @@ async fn test_rayhunter(adb_device: &mut ADBUSBDevice) -> Result<()> {
|
|||||||
bail!("timeout reached! failed to reach rayhunter, something went wrong :(")
|
bail!("timeout reached! failed to reach rayhunter, something went wrong :(")
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn install_file(
|
async fn install_file(adb_device: &mut ADBUSBDevice, dest: &str, payload: &[u8]) -> Result<()> {
|
||||||
serial_interface: &Interface,
|
|
||||||
adb_device: &mut ADBUSBDevice,
|
|
||||||
dest: &str,
|
|
||||||
payload: &[u8],
|
|
||||||
) -> Result<()> {
|
|
||||||
const MAX_FAILURES: u32 = 5;
|
const MAX_FAILURES: u32 = 5;
|
||||||
let mut failures = 0;
|
let mut failures = 0;
|
||||||
loop {
|
loop {
|
||||||
match install_file_impl(serial_interface, adb_device, dest, payload).await {
|
match install_file_impl(adb_device, dest, payload).await {
|
||||||
Ok(()) => return Ok(()),
|
Ok(()) => return Ok(()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
if failures > MAX_FAILURES {
|
if failures > MAX_FAILURES {
|
||||||
@@ -192,7 +179,6 @@ async fn install_file(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn install_file_impl(
|
async fn install_file_impl(
|
||||||
serial_interface: &Interface,
|
|
||||||
adb_device: &mut ADBUSBDevice,
|
adb_device: &mut ADBUSBDevice,
|
||||||
dest: &str,
|
dest: &str,
|
||||||
mut payload: &[u8],
|
mut payload: &[u8],
|
||||||
@@ -209,7 +195,7 @@ async fn install_file_impl(
|
|||||||
let file_hash_bytes = hasher.finalize();
|
let file_hash_bytes = hasher.finalize();
|
||||||
let file_hash = format!("{file_hash_bytes:x}");
|
let file_hash = format!("{file_hash_bytes:x}");
|
||||||
adb_device.push(&mut payload, &push_tmp_path)?;
|
adb_device.push(&mut payload, &push_tmp_path)?;
|
||||||
at_syscmd(serial_interface, &format!("mv {push_tmp_path} {dest}")).await?;
|
adb_at_syscmd(adb_device, &format!("mv {push_tmp_path} {dest}")).await?;
|
||||||
let file_info = adb_device
|
let file_info = adb_device
|
||||||
.stat(dest)
|
.stat(dest)
|
||||||
.context("Failed to stat transfered file")?;
|
.context("Failed to stat transfered file")?;
|
||||||
@@ -251,7 +237,7 @@ async fn get_adb() -> Result<ADBUSBDevice> {
|
|||||||
Err(RustADBError::IOError(e)) if e.kind() == ErrorKind::ResourceBusy => {
|
Err(RustADBError::IOError(e)) if e.kind() == ErrorKind::ResourceBusy => {
|
||||||
bail!(ORBIC_BUSY);
|
bail!(ORBIC_BUSY);
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(any(target_os = "macos", target_os = "windows"))]
|
||||||
Err(RustADBError::IOError(e)) if e.kind() == ErrorKind::PermissionDenied => {
|
Err(RustADBError::IOError(e)) if e.kind() == ErrorKind::PermissionDenied => {
|
||||||
bail!(ORBIC_BUSY_MAC);
|
bail!(ORBIC_BUSY_MAC);
|
||||||
}
|
}
|
||||||
@@ -328,9 +314,58 @@ async fn wait_for_usb_device(vendor_id: u16, product_id: u16) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn at_syscmd(interface: &Interface, command: &str) -> Result<()> {
|
async fn adb_setup_serial(adb_device: &mut ADBUSBDevice) -> Result<()> {
|
||||||
send_serial_cmd(interface, &format!("AT+SYSCMD={command}")).await
|
Ok(adb_device.get_transport_mut().claim_interface(INTERFACE)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn adb_at_syscmd(adb_device: &mut ADBUSBDevice, command: &str) -> Result<()> {
|
||||||
|
adb_serial_cmd(adb_device, &format!("AT+SYSCMD={command}")).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn adb_serial_cmd(adb_device: &mut ADBUSBDevice, command: &str) -> Result<()> {
|
||||||
|
let mut data = String::new();
|
||||||
|
data.push_str("\r\n");
|
||||||
|
data.push_str(command);
|
||||||
|
data.push_str("\r\n");
|
||||||
|
|
||||||
|
let timeout = Duration::from_secs(2);
|
||||||
|
let mut response = [0; 256];
|
||||||
|
|
||||||
|
// Set up the serial port appropriately
|
||||||
|
adb_device
|
||||||
|
.get_transport_mut()
|
||||||
|
.send_usb_class_control_msg(INTERFACE, 0x22, 3, 1, &[], timeout)
|
||||||
|
.context("Failed to send control request")?;
|
||||||
|
|
||||||
|
// Send the command
|
||||||
|
adb_device
|
||||||
|
.get_transport_mut()
|
||||||
|
.usb_bulk_write(INTERFACE, 0x2, data.as_bytes(), timeout)
|
||||||
|
.context("Failed to write command")?;
|
||||||
|
|
||||||
|
// Consume the echoed command
|
||||||
|
adb_device
|
||||||
|
.get_transport_mut()
|
||||||
|
.usb_bulk_read(INTERFACE, 0x82, &mut response, timeout)
|
||||||
|
.context("Failed to read submitted command")?;
|
||||||
|
|
||||||
|
// Read the actual response
|
||||||
|
adb_device
|
||||||
|
.get_transport_mut()
|
||||||
|
.usb_bulk_read(INTERFACE, 0x82, &mut response, timeout)
|
||||||
|
.context("Failed to read response")?;
|
||||||
|
|
||||||
|
// For some reason, on macOS the response buffer gets filled with garbage data that's
|
||||||
|
// rarely valid UTF-8. Luckily we only care about the first couple bytes, so just drop
|
||||||
|
// the garbage with `from_utf8_lossy` and look for our expected success string.
|
||||||
|
let responsestr = String::from_utf8_lossy(&response);
|
||||||
|
if !responsestr.contains("\r\nOK\r\n") {
|
||||||
|
bail!("Received unexpected response: {0}", responsestr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends an AT command to the usb device over the serial port
|
/// Sends an AT command to the usb device over the serial port
|
||||||
///
|
///
|
||||||
/// First establish a USB handle and context by calling `open_orbic(<T>)
|
/// First establish a USB handle and context by calling `open_orbic(<T>)
|
||||||
@@ -407,7 +442,7 @@ pub fn enable_command_mode() -> Result<()> {
|
|||||||
index: 0,
|
index: 0,
|
||||||
};
|
};
|
||||||
let interface = device
|
let interface = device
|
||||||
.detach_and_claim_interface(1)
|
.detach_and_claim_interface(RNDIS_INTERFACE)
|
||||||
.context("detach_and_claim_interface(1) failed")?;
|
.context("detach_and_claim_interface(1) failed")?;
|
||||||
if let Err(e) = interface.control_out_blocking(enable_command_mode, &[], timeout) {
|
if let Err(e) = interface.control_out_blocking(enable_command_mode, &[], timeout) {
|
||||||
// If the device reboots while the command is still executing we
|
// If the device reboots while the command is still executing we
|
||||||
@@ -428,7 +463,7 @@ pub fn open_orbic() -> Result<Option<Interface>> {
|
|||||||
// Device after initial mode switch
|
// Device after initial mode switch
|
||||||
if let Some(device) = open_usb_device(VENDOR_ID, PRODUCT_ID)? {
|
if let Some(device) = open_usb_device(VENDOR_ID, PRODUCT_ID)? {
|
||||||
let interface = device
|
let interface = device
|
||||||
.detach_and_claim_interface(1) // will reattach drivers on release
|
.detach_and_claim_interface(INTERFACE) // will reattach drivers on release
|
||||||
.context("detach_and_claim_interface(1) failed")?;
|
.context("detach_and_claim_interface(1) failed")?;
|
||||||
return Ok(Some(interface));
|
return Ok(Some(interface));
|
||||||
}
|
}
|
||||||
@@ -436,7 +471,7 @@ pub fn open_orbic() -> Result<Option<Interface>> {
|
|||||||
// Device with rndis enabled as well
|
// Device with rndis enabled as well
|
||||||
if let Some(device) = open_usb_device(VENDOR_ID, 0xf622)? {
|
if let Some(device) = open_usb_device(VENDOR_ID, 0xf622)? {
|
||||||
let interface = device
|
let interface = device
|
||||||
.detach_and_claim_interface(1) // will reattach drivers on release
|
.detach_and_claim_interface(INTERFACE) // will reattach drivers on release
|
||||||
.context("detach_and_claim_interface(1) failed")?;
|
.context("detach_and_claim_interface(1) failed")?;
|
||||||
return Ok(Some(interface));
|
return Ok(Some(interface));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rayhunter"
|
name = "rayhunter"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "Realtime cellular data decoding and analysis for IMSI catcher detection"
|
description = "Realtime cellular data decoding and analysis for IMSI catcher detection"
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
pushd bin/web
|
pushd bin/web
|
||||||
npm run build
|
npm run build
|
||||||
popd
|
popd
|
||||||
cargo build --release --target="armv7-unknown-linux-musleabihf" #--features debug
|
cargo build --profile firmware --target="armv7-unknown-linux-musleabihf" #--features debug
|
||||||
adb shell '/bin/rootshell -c "/etc/init.d/rayhunter_daemon stop"'
|
adb shell '/bin/rootshell -c "/etc/init.d/rayhunter_daemon stop"'
|
||||||
adb push target/armv7-unknown-linux-musleabihf/release/rayhunter-daemon /data/rayhunter/rayhunter-daemon
|
adb push target/armv7-unknown-linux-musleabihf/firmware/rayhunter-daemon /data/rayhunter/rayhunter-daemon
|
||||||
echo "rebooting the device..."
|
echo "rebooting the device..."
|
||||||
adb shell '/bin/rootshell -c "reboot"'
|
adb shell '/bin/rootshell -c "reboot"'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rootshell"
|
name = "rootshell"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "telcom-parser"
|
name = "telcom-parser"
|
||||||
version = "0.3.2"
|
version = "0.3.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|||||||
Reference in New Issue
Block a user