Skip to content
M. Farhan Hamim edited this page Oct 6, 2026 · 2 revisions

πŸ”’ NetShield DNS Resolver β€” Wiki

A local DNS resolver, ad/tracker sinkhole, and live traffic dashboard for Android.
Private, open source, and built in pure Java. No Firebase, no Google Play Services, no tracking.

Repository: m-farhan-hamim/NetShield-DNS-Resolver-by-PSBDx


πŸ” What is NetShield?

NetShield sits between your apps and the internet's DNS servers:

Apps ──► NetShield (local sinkhole) ──► Upstream DNS (DoH / DoT / UDP)
              β”‚
              β”œβ”€ blocked domain? β†’ answered locally, never leaves the device
              └─ allowed domain? β†’ forwarded upstream, logged in the dashboard
  • πŸ”’ VPN mode: A local VPN interface captures system DNS queries and hands them to the resolver. No traffic is tunneled to a remote server.
  • πŸ’» Local server mode: The resolver listens on 127.0.0.1 as a UDP DNS server that you can point apps or system settings at.
  • 🧩 Split tunneling: Exclude specific apps so their DNS queries skip NetShield entirely.

✨ Key Features

Feature Description
πŸ”’ DNS sinkhole Blocks ads, trackers, and unwanted domains at the DNS level, for everything from browsers to apps.
πŸ”’ VPN mode Routes all system DNS queries through a local sinkhole using Android's VPN service, without needing a separate proxy app.
πŸ’» Local server mode Prefer no VPN? Run as a local UDP DNS server on 127.0.0.1.
πŸ” Encrypted upstreams Resolve through DoH (DNS over HTTPS), DoT (DNS over TLS), or plain UDP with optional TLS validation.
πŸ“œ Custom blocklists Add your own blocklists and rules.
🧩 Per-app split tunneling Choose which apps go through NetShield and which bypass it.
πŸ“Š Real-time traffic logs Live dashboard with query logs and stats so you can see exactly what is being blocked and resolved.
⚑ Quick Settings tile Toggle NetShield from the notification shade in one tap.
πŸ“± Home-screen widget Resizable card with live status, query stats, and a power button to toggle instantly.
πŸ’‘ Lightweight and clean Pure Java, only AndroidX and Material. No Kotlin, no Compose, no Firebase, and no Google Play Services.

πŸ“₯ Download

Source Link
πŸš€ F-Droid Get it on F-Droid
πŸ“¦ APKPure com.netshield.dns.psbdx on APKPure ⚠️
🌟 GitHub Releases Latest signed APK
πŸ” VirusTotal Scan report

⚠️ APKPure note: Versions hosted on APKPure might be outdated. They are supported by me, but I can't guarantee them. For the latest verified build, always prefer GitHub Releases or F-Droid.

Package name: com.netshield.dns.psbdx
Current version: 3.1.1

πŸ” Whichever source you use, you can verify the APK's signing certificate before installing.


⚑ Quick Settings Tile and Widget

Beyond the in-app Start/Stop button, the resolver can be toggled with a single tap from:

  • πŸ“± Quick Settings: Add the "NetShield" tile from the panel's edit screen. It reflects the Active/Inactive state live.
  • 🎨 Home-screen widget: A resizable card showing live status and query stats, with a dedicated power button to toggle instantly. Tapping the rest of the card opens the app.

Both use the same underlying ServiceManager.ACTION_STOP self-stop mechanism as the in-app button, so behavior stays consistent everywhere. If VPN mode hasn't been granted permission yet, tapping the tile/widget will prompt for it.


πŸ”„ In-App Update Checker

On launch, the app checks GET /repos/m-farhan-hamim/NetShield-DNS-Resolver-by-PSBDx/releases/latest and compares the release tag against the installed versionName. If a newer version exists, it offers a direct APK download.

πŸ’‘ Disabled for F-Droid installs, on purpose. F-Droid's client already verifies and delivers updates from its own build, so self-updating apps aren't wanted there. UpdateChecker.isSelfUpdateAllowed() short-circuits the feature when the app was installed via F-Droid.


πŸ” Verify Your Download

Official releases are signed with the same key. The SHA-256 fingerprint of the signing certificate is:

21:53:E6:6A:EA:E3:09:50:5C:8A:1C:21:76:66:B2:E4:64:01:28:29:0C:81:FF:E2:A4:0D:FF:75:E4:ED:62:A9

Check an APK with the Android SDK's apksigner:

apksigner verify --print-certs app-release.apk

The SHA-256 digest line in the output should match the fingerprint above. If it doesn't, don't install the file. A build signed with a different key is not an official release. Besides the security risk, it might break remote features such as update checks, the VPN service, log saving, and remote notifications.

You should only install packages from the project's official sources: GitHub Releases, F-Droid, and APKPure.


πŸ› οΈ Building from Source

Pure Java, no Kotlin, no Compose, no Firebase or Google Play Services. Just AndroidX and Material.

git clone https://github.com/m-farhan-hamim/NetShield-DNS-Resolver-by-PSBDx.git
cd NetShield-DNS-Resolver-by-PSBDx
./gradlew :app:assembleDebug

A release build works without any secrets configured (it just produces an unsigned APK):

./gradlew :app:assembleRelease

For a locally signed release build, set these environment variables:

Variable Purpose
KEYSTORE_PATH Path to your keystore file
RELEASE_STORE_PASSWORD Keystore password
RELEASE_KEYALIAS Key alias inside the keystore
RELEASE_KEY_PASSWORD Key password

⚠️ Building or signing with your own key can break remote features. If you modify the signing key, or re-sign the app with your own key, features that rely on the official release signature might stop working. This includes:

  • πŸ”„ App update checks
  • πŸ”’ VPN service
  • πŸ“ Log saving
  • πŸ”” Remote notifications

Android also refuses to update an installed app that was signed with a different key, so switching between official and self-signed builds means uninstalling first (and losing app data). For non-official builds, the project may still run locally but receive limited or no remote functionality.

πŸ—οΈ CI and Releases

The release job in .github/workflows/build.yml builds a signed production APK and AAB on every push to main/master (and on manual workflow_dispatch runs), using these GitHub Actions secrets:

  • KEYSTORE_BASE64: your upload keystore, base64-encoded (base64 -w0 your-key.jks > keystore.b64 on Linux/macOS)
  • RELEASE_KEYALIAS: the key alias inside that keystore
  • RELEASE_KEY_PASSWORD: the key's password
  • RELEASE_STORE_PASSWORD: the keystore's password

Pull requests from forks can't access these secrets, so they only get the unsigned debug build. That's expected. Push a tag matching versionName in app/build.gradle.kts (for example 3.0.0) and the workflow also publishes a GitHub Release with the signed APK attached. That's what the in-app update checker compares against.


🀝 Contributing

Contributions are welcome.

  1. Fork the repo and create a branch:
    git checkout -b feature/my-change
  2. Make your changes and test with ./gradlew :app:assembleDebug
  3. Open a pull request describing what you changed and why.

Found a bug or have an idea? Open an issue.


πŸ“œ License

Licensed under the GNU General Public License v3.0 or later.
See LICENSE for the full text.

Free and open source.


πŸ’¬ About / Disclaimer

This app was built by PSBDx (M. Farhan Hamim).
Significant use of ✨ Google AI (Gemini) and 🧠 Anthropic Claude was made in its development.

Made with ❀️ by PSBDx