-
Notifications
You must be signed in to change notification settings - Fork 0
Building from Source
This page walks through a full rebuild of Tetherand from a fresh clone, including every native library.
| Tool | Version | Used for |
|---|---|---|
| Android NDK | r26 or newer | Cross-compiling Rust + C libs to arm64-android |
| Android SDK | API 36 platform |
apksigner, zipalign, adb
|
| Rust | 1.85 or newer | Workspace at relay/
|
aarch64-linux-android target |
rustup target add aarch64-linux-android |
Cross-compile output |
| Go | 1.22 or 1.23 (not 1.26 yet) | Conjure / Snowflake upstream binaries |
| cmake | 3.20+ | librtlsdr / libhackrf / libusb |
| Java | OpenJDK 21 | Gradle wrapper expects 21+ |
Set NDK_HOME (or ANDROID_NDK_HOME) to the NDK root before any
native build:
export NDK_HOME=$HOME/Library/Android/sdk/ndk/26.3.11579264(macOS path shown; Linux path is similar under ~/Android/Sdk/ndk.)
make native-all # cross-compiles wg, tor, nym, pt-bridge, librtlsdr stack
make apk # repackages the APK + emits hash sidecars
make install # adb install + pre-grants VPN consent
make smoke-device # UiAutomator walkThe full bundle APK lands in bin/tetherand.apk at around 59 MB. Hash
sidecars (tetherand.apk.sha256 and tetherand.apk.sha3-256) and a
master bin/SHASUMS.txt are emitted by make hashes, which make apk runs automatically.
If you only need one:
make native-wg # libtetherand_wg.so (WireGuard via BoringTun)
make native-tor # libtetherand_tor.so (Arti)
make native-nym # libtetherand_nym.so (NymVPN JNI surface)
make native-pt # libtetherand_pt.so (obfs4/meek/webtunnel) + libconjure_client.so
make native-rtlsdr # librtlsdr.so + libhackrf.so + libusb1.0.soEach script lives under scripts/build-*-android.sh. They all apply
--remap-path-prefix so that build-time absolute paths from your
workstation don't end up in the shipped .rodata panic strings.
For a production-style release:
make release-signedThis runs:
-
gradle assembleReleaseto produce the unsigned APK. -
zipalign -p 4for page-aligned native libraries. -
apksigner signwith SHA256-RSA2048 against the Android v2 signing scheme.
The script gates the signing step against an out-of-repo allow-list
of approved certificate DNs (~/.tetherand-signing-allow). The stock
CN=Android Debug, O=Android, C=US debug subject is always allowed
without an entry. To use a production keystore, generate one with
keytool -genkeypair -alias tetherand-prod -keystore tetherand-prod.jks -keyalg RSA -keysize 4096 -validity 36500 -dname "CN=Tetherand, O=pq-cybarg, C=US" and then `echo "CN=Tetherand, O=pq-cybarg, C=US"
~/.tetherand-signing-allow`.
scripts/bundle-combinations.sh generates every subset of the six
native-library groups (wg, tor, nym, pt, pts, sdr) as
its own zip with paired SHA-256 + SHA3-256 sidecars under
dist/bundles/. Details at Bundle Combinations.
| Symptom | Cause | Fix |
|---|---|---|
ld.lld: error: unable to find library -lsqlite3 during Tor build |
Arti's tor-dirmgr uses rusqlite and the NDK sysroot has no libsqlite3 |
Already pinned in relay/tor/Cargo.toml via rusqlite = { features = ["bundled"] }; if you're patching it, keep the bundled feature. |
nym-noise fails with a type-inference error |
Upstream nym-noise 1.20.4 has a closure parameter that needs annotation under rustc 1.83+ |
TETHERAND_NYM_SDK=0 make native-nym (default; ships the JNI surface only). The with-sdk feature is opt-in. |
ld.lld: error: unable to find library -lusb-1.0 during rtlsdr build |
rtlsdr's CMakeLists hardcodes -lusb-1.0 and ignores LIBUSB_LIBRARIES
|
The script in scripts/build-rtlsdr-android.sh already passes -L$WORK/libusb/build via CMAKE_SHARED_LINKER_FLAGS. |
Snowflake build fails with link: github.com/wlynxg/anet: invalid reference to net.zoneCache
|
Upstream wlynxg/anet uses a Go internal symbol that moved in Go 1.26 |
Downgrade Go to 1.22 or 1.23 for the snowflake build; or wait for upstream to fix. v0.1 skips snowflake. |
make test # all Rust workspace unit tests
cd android && ./gradlew :app:testDebugUnitTest # Kotlin unit testsThe Rust workspace ships unit tests for the codec, the bridge parser, the obfs4 cert decoder, the perplexity rule, the prompt- injection regex, and the provenance checker. The Kotlin unit tests cover the geohash6 implementation.
Integration tests against the real Tor network live behind
#[ignore] — run explicitly:
cd relay && cargo test -p tetherand-tor --test live_probe -- --ignoredThe probe dials check.torproject.org:443 and an .onion service.
Requires internet egress to the Tor network from the test runner.
Use
Features
Build
Project