mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-05-31 18:23:35 -07:00
Compare commits
30 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 | |||
| 2915dea9e9 | |||
| 6941bc57b6 | |||
| 5b9dd856a8 | |||
| 5007cb0b36 | |||
| 1b244122df | |||
| 3c4cb56ce6 | |||
| 58843413b5 |
@@ -1,154 +0,0 @@
|
|||||||
name: Build Release
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [main, "release-*"]
|
|
||||||
pull_request:
|
|
||||||
branches: ["main"]
|
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
FILE_ROOTSHELL: ../../rootshell/rootshell
|
|
||||||
FILE_RAYHUNTER_DAEMON_ORBIC: ../../rayhunter-daemon-orbic/rayhunter-daemon
|
|
||||||
FILE_RAYHUNTER_DAEMON_TPLINK: ../../rayhunter-daemon-tplink/rayhunter-daemon
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_rayhunter_check:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
platform:
|
|
||||||
- name: ubuntu-24
|
|
||||||
os: ubuntu-latest
|
|
||||||
target: x86_64-unknown-linux-musl
|
|
||||||
- name: ubuntu-24-aarch64
|
|
||||||
os: ubuntu-24.04-arm
|
|
||||||
target: aarch64-unknown-linux-musl
|
|
||||||
- name: macos-arm
|
|
||||||
os: macos-latest
|
|
||||||
target: aarch64-apple-darwin
|
|
||||||
- name: macos-intel
|
|
||||||
os: macos-13
|
|
||||||
target: x86_64-apple-darwin
|
|
||||||
- name: windows-x86_64
|
|
||||||
os: windows-latest
|
|
||||||
target: x86_64-pc-windows-gnu
|
|
||||||
runs-on: ${{ matrix.platform.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Build rayhunter-check
|
|
||||||
run: cargo build --bin rayhunter-check --release
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rayhunter-check-${{ matrix.platform.name }}
|
|
||||||
path: target/release/rayhunter-check${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }}
|
|
||||||
if-no-files-found: error
|
|
||||||
build_rootshell:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
targets: armv7-unknown-linux-musleabihf
|
|
||||||
- name: Build rootshell (arm32)
|
|
||||||
run: cargo build --bin rootshell --target armv7-unknown-linux-musleabihf --profile=firmware
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rootshell
|
|
||||||
path: target/armv7-unknown-linux-musleabihf/firmware/rootshell
|
|
||||||
if-no-files-found: error
|
|
||||||
build_rayhunter:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
device:
|
|
||||||
- name: tplink
|
|
||||||
- name: orbic
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
targets: armv7-unknown-linux-musleabihf
|
|
||||||
- name: Build rayhunter-daemon (arm32)
|
|
||||||
run: |
|
|
||||||
pushd bin/web
|
|
||||||
npm install
|
|
||||||
npm run build
|
|
||||||
popd
|
|
||||||
cargo build --bin rayhunter-daemon --target armv7-unknown-linux-musleabihf --profile=firmware --no-default-features --features ${{ matrix.device.name }}
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rayhunter-daemon-${{ matrix.device.name }}
|
|
||||||
path: target/armv7-unknown-linux-musleabihf/firmware/rayhunter-daemon
|
|
||||||
if-no-files-found: error
|
|
||||||
build_rust_installer:
|
|
||||||
needs:
|
|
||||||
- build_rayhunter
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
platform:
|
|
||||||
- name: ubuntu-24
|
|
||||||
os: ubuntu-latest
|
|
||||||
target: x86_64-unknown-linux-musl
|
|
||||||
- name: ubuntu-24-aarch64
|
|
||||||
os: ubuntu-24.04-arm
|
|
||||||
target: aarch64-unknown-linux-musl
|
|
||||||
- name: macos-arm
|
|
||||||
os: macos-latest
|
|
||||||
target: aarch64-apple-darwin
|
|
||||||
- name: macos-intel
|
|
||||||
os: macos-13
|
|
||||||
target: x86_64-apple-darwin
|
|
||||||
- name: windows-x86_64
|
|
||||||
os: windows-latest
|
|
||||||
target: x86_64-pc-windows-gnu
|
|
||||||
runs-on: ${{ matrix.platform.os }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/download-artifact@v4
|
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
targets: ${{ matrix.platform.target }}
|
|
||||||
- run: cargo build --bin installer --release --target ${{ matrix.platform.target }}
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: installer-${{ matrix.platform.name }}
|
|
||||||
path: target/${{ matrix.platform.target }}/release/installer${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }}
|
|
||||||
if-no-files-found: error
|
|
||||||
|
|
||||||
build_release_zip:
|
|
||||||
needs:
|
|
||||||
- build_rayhunter_check
|
|
||||||
- build_rootshell
|
|
||||||
- build_rayhunter
|
|
||||||
- build_rust_installer
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/download-artifact@v4
|
|
||||||
- name: Fix executable permissions on binaries
|
|
||||||
run: chmod +x installer-*/installer rayhunter-check-*/rayhunter-check rayhunter-daemon-*/rayhunter-daemon
|
|
||||||
- name: Get Rayhunter version
|
|
||||||
id: get_version
|
|
||||||
run: echo "VERSION=$(grep '^version' bin/Cargo.toml | head -n 1 | cut -d'"' -f2)" >> $GITHUB_ENV
|
|
||||||
- name: Setup versioned release directory
|
|
||||||
run: |
|
|
||||||
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
|
|
||||||
mkdir "$VERSIONED_DIR"
|
|
||||||
mv rayhunter-daemon-* rootshell/rootshell installer-* dist/* installer/install.ps1 "$VERSIONED_DIR"/
|
|
||||||
- name: Archive release directory as zip
|
|
||||||
run: |
|
|
||||||
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
|
|
||||||
zip -r "$VERSIONED_DIR.zip" "$VERSIONED_DIR"
|
|
||||||
- name: Compute SHA256 of zip
|
|
||||||
run: |
|
|
||||||
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
|
|
||||||
sha256sum "$VERSIONED_DIR.zip" > "$VERSIONED_DIR.zip.sha256"
|
|
||||||
# TODO: have this create a release directly
|
|
||||||
- name: Upload zip release and sha256
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: rayhunter-v${{ env.VERSION }}
|
|
||||||
path: |
|
|
||||||
rayhunter-v${{ env.VERSION }}.zip
|
|
||||||
rayhunter-v${{ env.VERSION }}.zip.sha256
|
|
||||||
if-no-files-found: error
|
|
||||||
@@ -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 }}
|
|
||||||
@@ -0,0 +1,319 @@
|
|||||||
|
name: main
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
FILE_ROOTSHELL: ../../rootshell/rootshell
|
||||||
|
FILE_RAYHUNTER_DAEMON_ORBIC: ../../rayhunter-daemon-orbic/rayhunter-daemon
|
||||||
|
FILE_RAYHUNTER_DAEMON_TPLINK: ../../rayhunter-daemon-tplink/rayhunter-daemon
|
||||||
|
|
||||||
|
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:
|
||||||
|
if: needs.files_changed.outputs.daemon_changed != '0'
|
||||||
|
needs:
|
||||||
|
- check_and_test
|
||||||
|
- files_changed
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- name: ubuntu-24
|
||||||
|
os: ubuntu-latest
|
||||||
|
target: x86_64-unknown-linux-musl
|
||||||
|
- name: ubuntu-24-aarch64
|
||||||
|
os: ubuntu-24.04-arm
|
||||||
|
target: aarch64-unknown-linux-musl
|
||||||
|
- name: macos-arm
|
||||||
|
os: macos-latest
|
||||||
|
target: aarch64-apple-darwin
|
||||||
|
- name: macos-intel
|
||||||
|
os: macos-13
|
||||||
|
target: x86_64-apple-darwin
|
||||||
|
- name: windows-x86_64
|
||||||
|
os: windows-latest
|
||||||
|
target: x86_64-pc-windows-gnu
|
||||||
|
runs-on: ${{ matrix.platform.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Build rayhunter-check
|
||||||
|
run: cargo build --bin rayhunter-check --release
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rayhunter-check-${{ matrix.platform.name }}
|
||||||
|
path: target/release/rayhunter-check${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }}
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build_rootshell:
|
||||||
|
if: needs.files_changed.outputs.rootshell_changed != '0'
|
||||||
|
needs:
|
||||||
|
- check_and_test
|
||||||
|
- files_changed
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: armv7-unknown-linux-musleabihf
|
||||||
|
- name: Build rootshell (arm32)
|
||||||
|
run: cargo build --bin rootshell --target armv7-unknown-linux-musleabihf --profile=firmware
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rootshell
|
||||||
|
path: target/armv7-unknown-linux-musleabihf/firmware/rootshell
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build_rayhunter:
|
||||||
|
if: needs.files_changed.outputs.daemon_changed != '0'
|
||||||
|
needs:
|
||||||
|
- check_and_test
|
||||||
|
- files_changed
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
device:
|
||||||
|
- name: tplink
|
||||||
|
- name: orbic
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: armv7-unknown-linux-musleabihf
|
||||||
|
- name: Build rayhunter-daemon (arm32)
|
||||||
|
run: |
|
||||||
|
pushd bin/web
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
popd
|
||||||
|
# Run with -p so that cargo will select the minimum feature set for this package.
|
||||||
|
#
|
||||||
|
# Otherwise, it will consider the union of all requested features
|
||||||
|
# from all packages in the workspace. For example, if installer
|
||||||
|
# requires tokio with "full" feature, it will be included no matter
|
||||||
|
# what the feature selection in rayhunter-daemon is.
|
||||||
|
#
|
||||||
|
# https://github.com/rust-lang/cargo/issues/4463
|
||||||
|
cargo build -p rayhunter-daemon --bin rayhunter-daemon --target armv7-unknown-linux-musleabihf --profile=firmware --no-default-features --features ${{ matrix.device.name }}
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rayhunter-daemon-${{ matrix.device.name }}
|
||||||
|
path: target/armv7-unknown-linux-musleabihf/firmware/rayhunter-daemon
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build_rust_installer:
|
||||||
|
if: needs.files_changed.outputs.installer_changed != '0'
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
needs:
|
||||||
|
- build_rayhunter
|
||||||
|
- build_rootshell
|
||||||
|
- files_changed
|
||||||
|
- windows_installer_check_and_test
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- name: ubuntu-24
|
||||||
|
os: ubuntu-latest
|
||||||
|
target: x86_64-unknown-linux-musl
|
||||||
|
- name: ubuntu-24-aarch64
|
||||||
|
os: ubuntu-24.04-arm
|
||||||
|
target: aarch64-unknown-linux-musl
|
||||||
|
- name: macos-arm
|
||||||
|
os: macos-latest
|
||||||
|
target: aarch64-apple-darwin
|
||||||
|
- name: macos-intel
|
||||||
|
os: macos-13
|
||||||
|
target: x86_64-apple-darwin
|
||||||
|
- name: windows-x86_64
|
||||||
|
os: windows-latest
|
||||||
|
target: x86_64-pc-windows-gnu
|
||||||
|
runs-on: ${{ matrix.platform.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.platform.target }}
|
||||||
|
- run: cargo build --bin installer --release --target ${{ matrix.platform.target }}
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: installer-${{ matrix.platform.name }}
|
||||||
|
path: target/${{ matrix.platform.target }}/release/installer${{ matrix.platform.os == 'windows-latest' && '.exe' || '' }}
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
build_release_zip:
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
needs:
|
||||||
|
- build_rayhunter_check
|
||||||
|
- build_rootshell
|
||||||
|
- build_rayhunter
|
||||||
|
- build_rust_installer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/download-artifact@v4
|
||||||
|
- name: Fix executable permissions on binaries
|
||||||
|
run: chmod +x installer-*/installer rayhunter-check-*/rayhunter-check rayhunter-daemon-*/rayhunter-daemon
|
||||||
|
- name: Get Rayhunter version
|
||||||
|
id: get_version
|
||||||
|
run: echo "VERSION=$(grep '^version' bin/Cargo.toml | head -n 1 | cut -d'"' -f2)" >> $GITHUB_ENV
|
||||||
|
- name: Setup versioned release directory
|
||||||
|
run: |
|
||||||
|
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
|
||||||
|
mkdir "$VERSIONED_DIR"
|
||||||
|
mv rayhunter-daemon-* rootshell/rootshell installer-* dist/* installer/install.ps1 "$VERSIONED_DIR"/
|
||||||
|
- name: Archive release directory as zip
|
||||||
|
run: |
|
||||||
|
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
|
||||||
|
zip -r "$VERSIONED_DIR.zip" "$VERSIONED_DIR"
|
||||||
|
- name: Compute SHA256 of zip
|
||||||
|
run: |
|
||||||
|
VERSIONED_DIR="rayhunter-v${{ env.VERSION }}"
|
||||||
|
sha256sum "$VERSIONED_DIR.zip" > "$VERSIONED_DIR.zip.sha256"
|
||||||
|
# TODO: have this create a release directly
|
||||||
|
- name: Upload zip release and sha256
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: rayhunter-v${{ env.VERSION }}
|
||||||
|
path: |
|
||||||
|
rayhunter-v${{ env.VERSION }}.zip
|
||||||
|
rayhunter-v${{ env.VERSION }}.zip.sha256
|
||||||
|
if-no-files-found: error
|
||||||
@@ -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-*
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
/target
|
/target
|
||||||
/book
|
/book
|
||||||
|
.DS_Store
|
||||||
|
|||||||
Generated
+7
-25
@@ -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/gaykitty/adb_client.git?rev=1fb0f4f5cbcc95bbbb98db4ee2f1e53a1005aa81#1fb0f4f5cbcc95bbbb98db4ee2f1e53a1005aa81"
|
source = "git+https://github.com/EFForg/adb_client.git?rev=e511662394e4fa32865c154c40f81a3d846f700c#e511662394e4fa32865c154c40f81a3d846f700c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-io",
|
"async-io",
|
||||||
"base64",
|
"base64",
|
||||||
@@ -944,7 +944,6 @@ checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-executor",
|
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
@@ -967,17 +966,6 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "futures-executor"
|
|
||||||
version = "0.3.31"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
|
|
||||||
dependencies = [
|
|
||||||
"futures-core",
|
|
||||||
"futures-task",
|
|
||||||
"futures-util",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-io"
|
name = "futures-io"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@@ -1026,13 +1014,10 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-channel",
|
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"memchr",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
"slab",
|
"slab",
|
||||||
@@ -1448,7 +1433,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "installer"
|
name = "installer"
|
||||||
version = "0.3.1"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adb_client",
|
"adb_client",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -2322,15 +2307,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayhunter"
|
name = "rayhunter"
|
||||||
version = "0.3.1"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"crc",
|
"crc",
|
||||||
"deku",
|
"deku",
|
||||||
"env_logger 0.10.2",
|
|
||||||
"futures",
|
"futures",
|
||||||
"futures-core",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nix",
|
"nix",
|
||||||
@@ -2343,14 +2326,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayhunter-daemon"
|
name = "rayhunter-daemon"
|
||||||
version = "0.3.1"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"env_logger 0.10.2",
|
"env_logger 0.11.8",
|
||||||
"futures",
|
"futures",
|
||||||
"futures-core",
|
|
||||||
"futures-macro",
|
"futures-macro",
|
||||||
"image",
|
"image",
|
||||||
"include_dir",
|
"include_dir",
|
||||||
@@ -2471,7 +2453,7 @@ checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rootshell"
|
name = "rootshell"
|
||||||
version = "0.3.1"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nix",
|
"nix",
|
||||||
]
|
]
|
||||||
@@ -2844,7 +2826,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "telcom-parser"
|
name = "telcom-parser"
|
||||||
version = "0.3.1"
|
version = "0.3.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"asn1-codecs",
|
"asn1-codecs",
|
||||||
"asn1-compiler",
|
"asn1-compiler",
|
||||||
|
|||||||
+6
-7
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rayhunter-daemon"
|
name = "rayhunter-daemon"
|
||||||
version = "0.3.1"
|
version = "0.3.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
@@ -22,20 +22,19 @@ path = "src/check.rs"
|
|||||||
rayhunter = { path = "../lib" }
|
rayhunter = { path = "../lib" }
|
||||||
toml = "0.8.8"
|
toml = "0.8.8"
|
||||||
serde = { version = "1.0.193", features = ["derive"] }
|
serde = { version = "1.0.193", features = ["derive"] }
|
||||||
tokio = { version = "1.44.2", features = ["full"] }
|
tokio = { version = "1.44.2", default-features = false, features = ["fs", "signal", "process", "rt-multi-thread"] }
|
||||||
axum = "0.8"
|
axum = { version = "0.8", default-features = false, features = ["http1", "tokio", "json"] }
|
||||||
futures-core = "0.3.30"
|
|
||||||
thiserror = "1.0.52"
|
thiserror = "1.0.52"
|
||||||
libc = "0.2.150"
|
libc = "0.2.150"
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
env_logger = "0.10.1"
|
env_logger = { version = "0.11", default-features = false }
|
||||||
tokio-util = { version = "0.7.10", features = ["rt", "io"] }
|
tokio-util = { version = "0.7.10", features = ["rt", "io"] }
|
||||||
futures-macro = "0.3.30"
|
futures-macro = "0.3.30"
|
||||||
include_dir = "0.7.3"
|
include_dir = "0.7.3"
|
||||||
mime_guess = "2.0.4"
|
mime_guess = "2.0.4"
|
||||||
chrono = { version = "0.4.31", features = ["serde"] }
|
chrono = { version = "0.4.31", features = ["serde"] }
|
||||||
tokio-stream = "0.1.14"
|
tokio-stream = { version = "0.1.14", default-features = false }
|
||||||
futures = "0.3.30"
|
futures = { version = "0.3.30", default-features = false }
|
||||||
clap = { version = "4.5.2", features = ["derive"] }
|
clap = { version = "4.5.2", features = ["derive"] }
|
||||||
serde_json = "1.0.114"
|
serde_json = "1.0.114"
|
||||||
image = { version = "0.25.1", default-features = false, features = ["png", "gif"] }
|
image = { version = "0.25.1", default-features = false, features = ["png", "gif"] }
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ Make sure you've got one of Rayhunter's [supported devices](./supported-devices.
|
|||||||
First, enter the correct subfolder for your operating system:
|
First, enter the correct subfolder for your operating system:
|
||||||
- for Ubuntu on x64 arhitecture: `cd installer-ubuntu-24`
|
- for Ubuntu on x64 arhitecture: `cd installer-ubuntu-24`
|
||||||
- for Ubuntu on ARM64 arhitecture: `cd installer-ubuntu-24-aarch64`
|
- for Ubuntu on ARM64 arhitecture: `cd installer-ubuntu-24-aarch64`
|
||||||
- for MacOS on Intel architecture: `cd installer-macos-intel`
|
- for MacOS on Intel (old macbooks) architecture: `cd installer-macos-intel`
|
||||||
- for MacOS on ARM achitecture: `cd installer-macos-arm`
|
- for MacOS on ARM (M1/M2 etc.) achitecture: `cd installer-macos-arm`
|
||||||
- for Windows: `cd installer-windows-x86_64`
|
- for Windows: `cd installer-windows-x86_64`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+12
-3
@@ -7,10 +7,10 @@ The TP-Link M7350 is supported by Rayhunter from 0.3.0 release. TP-Link M7350 su
|
|||||||
The TP-Link comes in many different *hardware versions*. Support for installation varies:
|
The TP-Link comes in many different *hardware versions*. Support for installation varies:
|
||||||
|
|
||||||
* `1.0`, `2.0`: **Not suported**, probably impossible to obtain anymore (even second-hand), however there is one report that installation is possible on `1.0` (but no reports if it is working or not)
|
* `1.0`, `2.0`: **Not suported**, probably impossible to obtain anymore (even second-hand), however there is one report that installation is possible on `1.0` (but no reports if it is working or not)
|
||||||
* `3.0`, `3.2`, `5.0`, `5.2`, `7.0`, `8.0`: **Tested, no known issues.**
|
* `3.0`, `3.2`, `5.0`, `5.2`, `7.0`, `8.0`: **Tested, no known issues since 0.3.0.**
|
||||||
* `6.2`: **One user reported it is working**
|
* `6.2`: **One user reported it is working**
|
||||||
* `4.0`: **Not working yet** ([issue](https://github.com/EFForg/rayhunter/issues/332)), however [it could be installed manually](https://github.com/m0veax/rayhunter-tplink-m7350/))
|
* `4.0`: **Manual firmware downgrade required** ([issue](https://github.com/EFForg/rayhunter/issues/332))
|
||||||
* `9.0`: **Not working yet** ([issue](https://github.com/EFForg/rayhunter/issues/325), however opening/rooting works, Rayhunter could be installed manually, but does not work because of [IOCTL error](#302))
|
* `9.0`: **Working since 0.3.2.**
|
||||||
|
|
||||||
TP-Link versions newer than `3.0` have cyan packaging and a color display. Version `3.0` has a one-bit display and white packaging.
|
TP-Link versions newer than `3.0` have cyan packaging and a color display. Version `3.0` has a one-bit display and white packaging.
|
||||||
|
|
||||||
@@ -62,6 +62,15 @@ You can change the `port` (default is `8080`) where Rayhunter is listening for i
|
|||||||
By default the device will go to sleep after N minutes of no devices being connected. In that mode it will also turn off connections to cell phone towers.
|
By default the device will go to sleep after N minutes of no devices being connected. In that mode it will also turn off connections to cell phone towers.
|
||||||
In order for Rayhunter to record continuously, you have to turn off this sleep mode in TP-Link's admin panel (go to **Advanced** - **Power Saving**) or keep e.g. your phone connectd on the TP-Link's WiFi.
|
In order for Rayhunter to record continuously, you have to turn off this sleep mode in TP-Link's admin panel (go to **Advanced** - **Power Saving**) or keep e.g. your phone connectd on the TP-Link's WiFi.
|
||||||
|
|
||||||
|
## Port triggers
|
||||||
|
|
||||||
|
On hardware revisions starting with v4.0, the installer will modify settings to
|
||||||
|
add two port triggers. You can look at `Settings > NAT Settings > Port
|
||||||
|
Triggers` in TP-Link's admin UI to see them.
|
||||||
|
|
||||||
|
1. One port trigger "rayhunter-root" to launch the telnet shell. This is only needed for installation, and can be removed after upgrade. You can reinstall it using `./installer util tplink-start-telnet`.
|
||||||
|
2. One port trigger "rayhunter-daemon" to auto-start rayhunter on boot. If you remove this, rayhunter will have to be started manually from shell.
|
||||||
|
|
||||||
## Other links
|
## Other links
|
||||||
|
|
||||||
For more information on the device and instructions on how to install Rayhunter without an installer (i.e. manually), please see [rayhunter-tplink-m7350](https://github.com/m0veax/rayhunter-tplink-m7350/)
|
For more information on the device and instructions on how to install Rayhunter without an installer (i.e. manually), please see [rayhunter-tplink-m7350](https://github.com/m0veax/rayhunter-tplink-m7350/)
|
||||||
|
|||||||
+6
-1
@@ -16,4 +16,9 @@ Your device is now Rayhunter-free, and should no longer be in a rooted ADB-enabl
|
|||||||
|
|
||||||
## TPLink
|
## TPLink
|
||||||
|
|
||||||
TODO
|
1. Run `./installer util tplink-start-telnet`
|
||||||
|
2. Telnet into the device `telnet 192.168.0.1`
|
||||||
|
3. `rm /data/rayhunter /etc/init.d/rayhunter_daemon`
|
||||||
|
4. `update-rc.d rayhunter_daemon remove`
|
||||||
|
5. (hardware revision v4.0+ only) In `Settings > NAT Settings > Port Triggers` in TP-Link's admin UI, remove any leftover port triggers.
|
||||||
|
|
||||||
|
|||||||
+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.1"
|
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/gaykitty/adb_client.git"
|
git = "https://github.com/EFForg/adb_client.git"
|
||||||
rev = "1fb0f4f5cbcc95bbbb98db4ee2f1e53a1005aa81"
|
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/gaykitty/adb_client.git"
|
git = "https://github.com/EFForg/adb_client.git"
|
||||||
rev = "1fb0f4f5cbcc95bbbb98db4ee2f1e53a1005aa81"
|
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)"
|
||||||
|
|||||||
+19
-1
@@ -1,5 +1,6 @@
|
|||||||
use anyhow::{Context, Error, bail};
|
use anyhow::{Context, Error, bail};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
use env_logger::Env;
|
||||||
|
|
||||||
mod orbic;
|
mod orbic;
|
||||||
mod tplink;
|
mod tplink;
|
||||||
@@ -34,6 +35,17 @@ struct InstallTpLink {
|
|||||||
/// IP address for TP-Link admin interface, if custom.
|
/// IP address for TP-Link admin interface, if custom.
|
||||||
#[arg(long, default_value = "192.168.0.1")]
|
#[arg(long, default_value = "192.168.0.1")]
|
||||||
admin_ip: String,
|
admin_ip: String,
|
||||||
|
|
||||||
|
/// For advanced users: Specify the path of the SD card to be mounted explicitly.
|
||||||
|
///
|
||||||
|
/// The default (empty string) is to use whichever sdcard path the device would use natively to
|
||||||
|
/// mount storage on. On most TP-Link this is /media/card, but on hardware versions 9+ this is
|
||||||
|
/// /media/sdcard
|
||||||
|
///
|
||||||
|
/// Only override this when the installer does not work on your hardware version, as otherwise
|
||||||
|
/// your custom path may conflict with the builtin storage functionality.
|
||||||
|
#[arg(long, default_value = "")]
|
||||||
|
sdcard_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@@ -49,6 +61,8 @@ struct Util {
|
|||||||
enum UtilSubCommand {
|
enum UtilSubCommand {
|
||||||
/// Send a serial command to the Orbic.
|
/// Send a serial command to the Orbic.
|
||||||
Serial(Serial),
|
Serial(Serial),
|
||||||
|
/// Start an ADB shell
|
||||||
|
Shell(Shell),
|
||||||
/// Root the tplink and launch telnetd.
|
/// Root the tplink and launch telnetd.
|
||||||
TplinkStartTelnet(TplinkStartTelnet),
|
TplinkStartTelnet(TplinkStartTelnet),
|
||||||
}
|
}
|
||||||
@@ -67,8 +81,11 @@ struct Serial {
|
|||||||
command: Vec<String>,
|
command: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
struct Shell {}
|
||||||
|
|
||||||
async fn run() -> Result<(), Error> {
|
async fn run() -> Result<(), Error> {
|
||||||
env_logger::init();
|
env_logger::Builder::from_env(Env::default().default_filter_or("off")).init();
|
||||||
let Args { command } = Args::parse();
|
let Args { command } = Args::parse();
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
@@ -93,6 +110,7 @@ async fn run() -> Result<(), Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UtilSubCommand::Shell(_) => orbic::shell().await.context("\nFailed to open shell on Orbic RC400L")?,
|
||||||
UtilSubCommand::TplinkStartTelnet(options) => {
|
UtilSubCommand::TplinkStartTelnet(options) => {
|
||||||
tplink::start_telnet(&options.admin_ip).await?;
|
tplink::start_telnet(&options.admin_ip).await?;
|
||||||
}
|
}
|
||||||
|
|||||||
+87
-53
@@ -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?;
|
||||||
@@ -54,11 +61,19 @@ pub async fn install() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn shell() -> Result<()> {
|
||||||
|
println!("opening shell");
|
||||||
|
let mut adb_device = get_adb().await?;
|
||||||
|
adb_device.shell(&mut std::io::stdin(), Box::new(std::io::stdout()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn force_debug_mode() -> Result<ADBUSBDevice> {
|
async fn force_debug_mode() -> Result<ADBUSBDevice> {
|
||||||
println!("Forcing a switch into the debug mode to enable ADB");
|
println!("Forcing a switch into the debug mode to enable ADB");
|
||||||
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"])?;
|
||||||
@@ -66,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.");
|
||||||
@@ -90,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 {
|
||||||
@@ -161,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 {
|
||||||
@@ -185,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],
|
||||||
@@ -202,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")?;
|
||||||
@@ -244,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);
|
||||||
}
|
}
|
||||||
@@ -321,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>)
|
||||||
@@ -400,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
|
||||||
@@ -421,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));
|
||||||
}
|
}
|
||||||
@@ -429,15 +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")?;
|
|
||||||
return Ok(Some(interface));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Another device with rndis enabled as well
|
|
||||||
if let Some(device) = open_usb_device(VENDOR_ID, 0xf626)? {
|
|
||||||
let interface = device
|
|
||||||
.detach_and_claim_interface(1) // 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));
|
||||||
}
|
}
|
||||||
|
|||||||
+69
-20
@@ -27,10 +27,11 @@ pub async fn main_tplink(
|
|||||||
InstallTpLink {
|
InstallTpLink {
|
||||||
skip_sdcard,
|
skip_sdcard,
|
||||||
admin_ip,
|
admin_ip,
|
||||||
|
sdcard_path,
|
||||||
}: InstallTpLink,
|
}: InstallTpLink,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
start_telnet(&admin_ip).await?;
|
let is_v3 = start_telnet(&admin_ip).await?;
|
||||||
tplink_run_install(skip_sdcard, admin_ip).await
|
tplink_run_install(skip_sdcard, admin_ip, sdcard_path, is_v3).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
@@ -38,7 +39,7 @@ struct V3RootResponse {
|
|||||||
result: u64,
|
result: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start_telnet(admin_ip: &str) -> Result<(), Error> {
|
pub async fn start_telnet(admin_ip: &str) -> Result<bool, Error> {
|
||||||
let qcmap_web_cgi_endpoint = format!("http://{admin_ip}/cgi-bin/qcmap_web_cgi");
|
let qcmap_web_cgi_endpoint = format!("http://{admin_ip}/cgi-bin/qcmap_web_cgi");
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
@@ -51,7 +52,9 @@ pub async fn start_telnet(admin_ip: &str) -> Result<(), Error> {
|
|||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if response.status() == 404 {
|
let is_v3 = response.status() != 404;
|
||||||
|
|
||||||
|
if !is_v3 {
|
||||||
println!("Got a 404 trying to run exploit for hardware revision v3, trying v5 exploit");
|
println!("Got a 404 trying to run exploit for hardware revision v3, trying v5 exploit");
|
||||||
tplink_launch_telnet_v5(admin_ip).await?;
|
tplink_launch_telnet_v5(admin_ip).await?;
|
||||||
} else {
|
} else {
|
||||||
@@ -82,20 +85,49 @@ pub async fn start_telnet(admin_ip: &str) -> Result<(), Error> {
|
|||||||
println!(
|
println!(
|
||||||
"Succeeded in rooting the device! Now you can use 'telnet {admin_ip}' to get a root shell. Use './installer util tplink-start-telnet' to root again without installing rayhunter."
|
"Succeeded in rooting the device! Now you can use 'telnet {admin_ip}' to get a root shell. Use './installer util tplink-start-telnet' to root again without installing rayhunter."
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(is_v3)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn tplink_run_install(skip_sdcard: bool, admin_ip: String) -> Result<(), Error> {
|
async fn tplink_run_install(
|
||||||
|
skip_sdcard: bool,
|
||||||
|
admin_ip: String,
|
||||||
|
mut sdcard_path: String,
|
||||||
|
is_v3: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
println!("Connecting via telnet to {admin_ip}");
|
println!("Connecting via telnet to {admin_ip}");
|
||||||
let addr = SocketAddr::from_str(&format!("{admin_ip}:23")).unwrap();
|
let addr = SocketAddr::from_str(&format!("{admin_ip}:23")).unwrap();
|
||||||
|
|
||||||
if !skip_sdcard {
|
if !skip_sdcard {
|
||||||
println!("Mounting sdcard");
|
if sdcard_path.is_empty() {
|
||||||
if telnet_send_command(addr, "mount | grep -q /media/card", "exit code 0")
|
if telnet_send_command(addr, "ls /media/card", "exit code 0")
|
||||||
.await
|
.await
|
||||||
.is_err()
|
.is_ok()
|
||||||
|
{
|
||||||
|
// TP-Link hardware less than v9.0
|
||||||
|
sdcard_path = "/media/card".to_owned();
|
||||||
|
} else if telnet_send_command(addr, "ls /media/sdcard", "exit code 0")
|
||||||
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
// TP-Link hardware v9.0
|
||||||
|
sdcard_path = "/media/sdcard".to_owned();
|
||||||
|
} else {
|
||||||
|
anyhow::bail!(
|
||||||
|
"unable to determine sdcard path. this is a bug. please file an issue with your hardware version."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("Mounting sdcard on {sdcard_path}");
|
||||||
|
if telnet_send_command(
|
||||||
|
addr,
|
||||||
|
&format!("mount | grep -q {sdcard_path}"),
|
||||||
|
"exit code 0",
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
{
|
{
|
||||||
telnet_send_command(addr, "mount /dev/mmcblk0p1 /media/card", "exit code 0").await.context("Rayhunter needs a FAT-formatted SD card to function for more than a few minutes. Insert one and rerun this installer, or pass --skip-sdcard")?;
|
telnet_send_command(addr, &format!("mount /dev/mmcblk0p1 {sdcard_path}"), "exit code 0").await.context("Rayhunter needs a FAT-formatted SD card to function for more than a few minutes. Insert one and rerun this installer, or pass --skip-sdcard")?;
|
||||||
} else {
|
} else {
|
||||||
println!("sdcard already mounted");
|
println!("sdcard already mounted");
|
||||||
}
|
}
|
||||||
@@ -105,28 +137,38 @@ async fn tplink_run_install(skip_sdcard: bool, admin_ip: String) -> Result<(), E
|
|||||||
// expects things to be at this location
|
// expects things to be at this location
|
||||||
telnet_send_command(addr, "rm -rf /data/rayhunter", "exit code 0").await?;
|
telnet_send_command(addr, "rm -rf /data/rayhunter", "exit code 0").await?;
|
||||||
telnet_send_command(addr, "mkdir -p /data", "exit code 0").await?;
|
telnet_send_command(addr, "mkdir -p /data", "exit code 0").await?;
|
||||||
telnet_send_command(addr, "ln -sf /media/card /data/rayhunter", "exit code 0").await?;
|
telnet_send_command(
|
||||||
|
addr,
|
||||||
|
&format!("ln -sf {sdcard_path} /data/rayhunter"),
|
||||||
|
"exit code 0",
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
telnet_send_file(
|
telnet_send_file(
|
||||||
addr,
|
addr,
|
||||||
"/media/card/config.toml",
|
&format!("{sdcard_path}/config.toml"),
|
||||||
crate::CONFIG_TOML.as_bytes(),
|
crate::CONFIG_TOML.as_bytes(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let rayhunter_daemon_bin = include_bytes!(env!("FILE_RAYHUNTER_DAEMON_TPLINK"));
|
let rayhunter_daemon_bin = include_bytes!(env!("FILE_RAYHUNTER_DAEMON_TPLINK"));
|
||||||
|
|
||||||
telnet_send_file(addr, "/media/card/rayhunter-daemon", rayhunter_daemon_bin).await?;
|
telnet_send_file(
|
||||||
|
addr,
|
||||||
|
&format!("{sdcard_path}/rayhunter-daemon"),
|
||||||
|
rayhunter_daemon_bin,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
telnet_send_file(
|
telnet_send_file(
|
||||||
addr,
|
addr,
|
||||||
"/etc/init.d/rayhunter_daemon",
|
"/etc/init.d/rayhunter_daemon",
|
||||||
get_rayhunter_daemon().as_bytes(),
|
get_rayhunter_daemon(&sdcard_path).as_bytes(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
telnet_send_command(
|
telnet_send_command(
|
||||||
addr,
|
addr,
|
||||||
"chmod ugo+x /media/card/rayhunter-daemon",
|
&format!("chmod ugo+x {sdcard_path}/rayhunter-daemon"),
|
||||||
"exit code 0",
|
"exit code 0",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
@@ -136,7 +178,13 @@ async fn tplink_run_install(skip_sdcard: bool, admin_ip: String) -> Result<(), E
|
|||||||
"exit code 0",
|
"exit code 0",
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
telnet_send_command(addr, "update-rc.d rayhunter_daemon defaults", "exit code 0").await?;
|
|
||||||
|
// if the device is not v3, the JS-based root exploit already added rayhunter_daemon as a
|
||||||
|
// startup script. tplink v9 does not have update-rc.d, and it was reported that *sometimes* it
|
||||||
|
// is unreliable on other hardware revisions too.
|
||||||
|
if is_v3 {
|
||||||
|
telnet_send_command(addr, "update-rc.d rayhunter_daemon defaults", "exit code 0").await?;
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"Done. Rebooting device. After it's started up again, check out the web interface at http://{admin_ip}:8080"
|
"Done. Rebooting device. After it's started up again, check out the web interface at http://{admin_ip}:8080"
|
||||||
@@ -278,6 +326,7 @@ async fn handler(state: State<AppState>, mut req: Request) -> Result<Response, S
|
|||||||
// inject some javascript into the admin UI to get us a telnet shell.
|
// inject some javascript into the admin UI to get us a telnet shell.
|
||||||
data.extend(br#";window.rayhunterPoll = window.setInterval(() => {
|
data.extend(br#";window.rayhunterPoll = window.setInterval(() => {
|
||||||
Globals.models.PTModel.add({applicationName: "rayhunter-root", enableState: 1, entryId: 1, openPort: "2300-2400", openProtocol: "TCP", triggerPort: "$(busybox telnetd -l /bin/sh)", triggerProtocol: "TCP"});
|
Globals.models.PTModel.add({applicationName: "rayhunter-root", enableState: 1, entryId: 1, openPort: "2300-2400", openProtocol: "TCP", triggerPort: "$(busybox telnetd -l /bin/sh)", triggerProtocol: "TCP"});
|
||||||
|
Globals.models.PTModel.add({applicationName: "rayhunter-daemon", enableState: 1, entryId: 2, openPort: "2400-2500", openProtocol: "TCP", triggerPort: "$(/etc/init.d/rayhunter_daemon start)", triggerProtocol: "TCP"});
|
||||||
alert("Success! You can go back to the rayhunter installer.");
|
alert("Success! You can go back to the rayhunter installer.");
|
||||||
window.clearInterval(window.rayhunterPoll);
|
window.clearInterval(window.rayhunterPoll);
|
||||||
}, 1000);"#);
|
}, 1000);"#);
|
||||||
@@ -324,7 +373,7 @@ async fn tplink_launch_telnet_v5(admin_ip: &str) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rayhunter_daemon() -> String {
|
fn get_rayhunter_daemon(sdcard_path: &str) -> String {
|
||||||
// Even though TP-Link eventually auto-mounts the SD card, it sometimes does so too late. And
|
// Even though TP-Link eventually auto-mounts the SD card, it sometimes does so too late. And
|
||||||
// changing the order in which daemons are started up seems to not work reliably.
|
// changing the order in which daemons are started up seems to not work reliably.
|
||||||
//
|
//
|
||||||
@@ -332,12 +381,12 @@ fn get_rayhunter_daemon() -> String {
|
|||||||
// specific to a particular hardware revision here.
|
// specific to a particular hardware revision here.
|
||||||
crate::RAYHUNTER_DAEMON_INIT.replace(
|
crate::RAYHUNTER_DAEMON_INIT.replace(
|
||||||
"#RAYHUNTER-PRESTART",
|
"#RAYHUNTER-PRESTART",
|
||||||
"mount /dev/mmcblk0p1 /media/card || true",
|
&format!("mount /dev/mmcblk0p1 {sdcard_path} || true"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_rayhunter_daemon() {
|
fn test_get_rayhunter_daemon() {
|
||||||
let s = get_rayhunter_daemon();
|
let s = get_rayhunter_daemon("/media/card");
|
||||||
assert!(s.contains("mount /dev/mmcblk0p1 /media/card"));
|
assert!(s.contains("mount /dev/mmcblk0p1 /media/card"));
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rayhunter"
|
name = "rayhunter"
|
||||||
version = "0.3.1"
|
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"
|
||||||
|
|
||||||
@@ -19,14 +19,12 @@ bytes = "1.5.0"
|
|||||||
chrono = "0.4.31"
|
chrono = "0.4.31"
|
||||||
crc = "3.0.1"
|
crc = "3.0.1"
|
||||||
deku = { version = "0.18.0", features = ["logging"] }
|
deku = { version = "0.18.0", features = ["logging"] }
|
||||||
env_logger = "0.10.1"
|
|
||||||
libc = "0.2.150"
|
libc = "0.2.150"
|
||||||
log = "0.4.20"
|
log = "0.4.20"
|
||||||
nix = { version = "0.29.0", features = ["feature"] }
|
nix = { version = "0.29.0", features = ["feature"] }
|
||||||
pcap-file-tokio = "0.1.0"
|
pcap-file-tokio = "0.1.0"
|
||||||
thiserror = "1.0.50"
|
thiserror = "1.0.50"
|
||||||
telcom-parser = { path = "../telcom-parser" }
|
telcom-parser = { path = "../telcom-parser" }
|
||||||
tokio = { version = "1.44.2", features = ["full"] }
|
tokio = { version = "1.44.2", default-features = false }
|
||||||
futures-core = "0.3.30"
|
futures = { version = "0.3.30", default-features = false }
|
||||||
futures = "0.3.30"
|
|
||||||
serde = { version = "1.0.197", features = ["derive"] }
|
serde = { version = "1.0.197", features = ["derive"] }
|
||||||
|
|||||||
+28
-16
@@ -6,7 +6,7 @@ use crate::hdlc::hdlc_encapsulate;
|
|||||||
use crate::log_codes;
|
use crate::log_codes;
|
||||||
|
|
||||||
use deku::prelude::*;
|
use deku::prelude::*;
|
||||||
use futures_core::TryStream;
|
use futures::TryStream;
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
use std::os::fd::AsRawFd;
|
use std::os::fd::AsRawFd;
|
||||||
@@ -251,6 +251,7 @@ impl DiagDevice {
|
|||||||
//
|
//
|
||||||
// TPLINK M7350 v5 source code can be downloaded at https://www.tp-link.com/de/support/gpl-code/?app=omada
|
// TPLINK M7350 v5 source code can be downloaded at https://www.tp-link.com/de/support/gpl-code/?app=omada
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct diag_logging_mode_param_t {
|
struct diag_logging_mode_param_t {
|
||||||
req_mode: u32,
|
req_mode: u32,
|
||||||
peripheral_mask: u32,
|
peripheral_mask: u32,
|
||||||
@@ -261,30 +262,41 @@ struct diag_logging_mode_param_t {
|
|||||||
fn enable_frame_readwrite(fd: i32, mode: u32) -> DiagResult<()> {
|
fn enable_frame_readwrite(fd: i32, mode: u32) -> DiagResult<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
if libc::ioctl(fd, DIAG_IOCTL_SWITCH_LOGGING, mode, 0, 0, 0) < 0 {
|
if libc::ioctl(fd, DIAG_IOCTL_SWITCH_LOGGING, mode, 0, 0, 0) < 0 {
|
||||||
let mut params = if cfg!(feature = "tplink") {
|
let try_params: &[diag_logging_mode_param_t] = &[
|
||||||
|
// tplink M7350 HW revision 3-8 need this mode
|
||||||
|
#[cfg(feature = "tplink")]
|
||||||
diag_logging_mode_param_t {
|
diag_logging_mode_param_t {
|
||||||
req_mode: mode,
|
req_mode: mode,
|
||||||
peripheral_mask: 0,
|
peripheral_mask: 0,
|
||||||
mode_param: 1,
|
mode_param: 1,
|
||||||
}
|
},
|
||||||
} else {
|
// tplink M7350 HW revision v9 requires the same parameters as orbic
|
||||||
diag_logging_mode_param_t {
|
diag_logging_mode_param_t {
|
||||||
req_mode: mode,
|
req_mode: mode,
|
||||||
peripheral_mask: u32::MAX,
|
peripheral_mask: u32::MAX,
|
||||||
mode_param: 0,
|
mode_param: 0,
|
||||||
}
|
},
|
||||||
};
|
];
|
||||||
|
|
||||||
|
let mut ret = 0;
|
||||||
|
|
||||||
|
for params in try_params {
|
||||||
|
let mut params = *params;
|
||||||
|
ret = libc::ioctl(
|
||||||
|
fd,
|
||||||
|
DIAG_IOCTL_SWITCH_LOGGING,
|
||||||
|
&mut params as *mut diag_logging_mode_param_t,
|
||||||
|
std::mem::size_of::<diag_logging_mode_param_t>(),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
if ret == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ret = libc::ioctl(
|
|
||||||
fd,
|
|
||||||
DIAG_IOCTL_SWITCH_LOGGING,
|
|
||||||
&mut params as *mut _,
|
|
||||||
std::mem::size_of::<diag_logging_mode_param_t>(),
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
);
|
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"DIAG_IOCTL_SWITCH_LOGGING ioctl failed with error code {}",
|
"DIAG_IOCTL_SWITCH_LOGGING ioctl failed with error code {}",
|
||||||
|
|||||||
@@ -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.1"
|
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.1"
|
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