Local-only, open-source content blocker for macOS + Android. No backend, no accounts, no sync — DNS-level blocking for adult/gambling/piracy/VPN-bypass, scheduled social media, streaks, and quotes to keep you off your screen.
See the codeLocal-only, open-source content blocker for macOS + Android. No backend, no accounts, no sync. Blocks adult content, gambling, piracy, and VPN/proxy/DNS-bypass at the DNS level, always-on; social media is blocked nightly (8pm–9am) with a manual daytime toggle; communication apps (WhatsApp, Messenger, Telegram, Botim) are always exempt. Uninstall is deliberately slow, not deliberately impossible.
macOS — dfdaemon is a small local DNS resolver (Swift, raw UDP sockets, a reversed-label trie
for O(number of labels) domain lookups regardless of blocklist size) bound to 127.0.0.1:53,
installed as a root LaunchDaemon. The Mac's system DNS is pointed at it. Blocked domains get
NXDOMAIN; SafeSearch domains get rewritten to their forced-safe-search IP (resolved live, not
hardcoded, since some providers' addresses rotate); everything else is forwarded to whatever DNS
servers your network already had configured. dfmenubar is a SwiftUI menu-bar app showing status
and the disable/toggle controls — it talks to the daemon only through shared JSON state files, never
directly, so it can stay fully unprivileged.
Android — BlockerVpnService is a full-capture local VPN (Kotlin). It has to capture all
traffic, not just DNS — Android gives a captured app no fallback route to the real network for
anything the VPN doesn't explicitly route, so a DNS-only VPN would silently kill the rest of the
device's connectivity. DNS (UDP/53) gets the block/allow/SafeSearch logic; everything else is
relayed transparently through a minimal userspace TCP/UDP NAT (TcpNat.kt / UdpNat.kt) so normal
browsing keeps working. WhatsApp/Messenger/Telegram/Botim are excluded from the VPN entirely via
addDisallowedApplication.
Both platforms load the same category rules from the same blocklist sources — HaGeZi's hosted lists
for adult/gambling/piracy/bypass, and this repo's own hand-maintained shared/social-domains.txt
for social media (needs per-platform precision a generic list can't give: block Instagram's feed,
never block WhatsApp).
docs/troubleshooting.md#uninstalling).docs/privacy.md.macos/ — dfdaemon (the DNS resolver), dfmenubar (SwiftUI status/control UI), LaunchDaemon
plist, install + blocklist-update scriptsandroid/ — VpnService-based filter + TCP/UDP relay, sideloaded APK (no Play Store)shared/ — the hand-maintained social-media domain list both platforms usedocs/ — MVP scope, privacy, troubleshootingdocs/privacy.md.docs/privacy.md.docs/troubleshooting.md for why.Prebuilt installers are attached to each GitHub Release — no Xcode or Android Studio required.
macOS:
distraction-free.pkg from the latest release..pkg and choose Open instead, which offers a
bypass the normal double-click doesn't.Prefer the old zip+script method, or don't want to run an unsigned installer? distraction-free-macos.zip
is still attached to every release — download it, unzip, and run ./install-release.sh from Terminal
instead. Both do the same install; the .pkg just does it without opening Terminal.
Android:
distraction-free-android.apk from the latest release on the
phone itself (or transfer it over).New releases build automatically from a git tag (vX.Y.Z) via
.github/workflows/release.yml.
macOS: cd macos && ./Scripts/install.sh (builds in release mode, asks for your password once
to install the LaunchDaemon and point your Mac's DNS at it).
Android: open android/ in Android Studio, build and install the debug APK, grant the VPN
permission when prompted, and — for real bypass-resistance — enable **Settings → VPN → Always-on VPN
MVP built and smoke-tested: DNS blocking, subdomain matching, forwarding, and SafeSearch rewriting are verified working on both platforms. Full page-load testing on Android was constrained by the dev sandbox's emulator networking (see commit history / session notes) rather than the app itself — worth a real-device pass before relying on it daily.
Bug reports, feature ideas, and PRs are welcome — see CONTRIBUTING.md for how to build from source, what "tested" means for a project with no automated test suite yet, and the project's few real conventions. File a bug with reproduction steps (and an exported diagnostic log, if relevant) rather than a one-line "it's broken."
The in-app "Disable protection" button is deliberately a fake 24h countdown that never completes — that's the whole point. There's no in-app uninstall. To actually remove it:
macOS (run each line in Terminal; the sudo ones will prompt for your password):
sudo launchctl bootout system/com.distractionfree.daemon 2>/dev/null
sudo launchctl bootout system/com.distractionfree.blocklist-update 2>/dev/null
launchctl bootout gui/$(id -u)/com.distractionfree.menubar 2>/dev/null
sudo networksetup -setdnsservers Wi-Fi empty # replace Wi-Fi with your active network service
sudo rm -f /Library/LaunchDaemons/com.distractionfree.daemon.plist
sudo rm -f /Library/LaunchDaemons/com.distractionfree.blocklist-update.plist
rm -f ~/Library/LaunchAgents/com.distractionfree.menubar.plist
sudo rm -rf /usr/local/opt/distraction-free /usr/local/etc/distraction-free /usr/local/var/distraction-free
sudo rm -f /usr/local/bin/dfmenubar
Android: Settings → Apps → Distraction Free → Uninstall. (Or, to keep the app but stop the VPN immediately instead of waiting on the fake countdown, force-stop it from the same screen — a genuine OS-level override, same as macOS root access, that this app can't and shouldn't try to prevent.)
MIT.
33 commits
Kotlin
59.2%
Swift
29.3%
Shell
11.6%
Local-only, open-source content blocker for macOS + Android. No backend, no accounts, no sync — DNS-level blocking for adult/gambling/piracy/VPN-bypass, scheduled social media, streaks, and quotes to keep you off your screen.
See the codeLocal-only, open-source content blocker for macOS + Android. No backend, no accounts, no sync. Blocks adult content, gambling, piracy, and VPN/proxy/DNS-bypass at the DNS level, always-on; social media is blocked nightly (8pm–9am) with a manual daytime toggle; communication apps (WhatsApp, Messenger, Telegram, Botim) are always exempt. Uninstall is deliberately slow, not deliberately impossible.
macOS — dfdaemon is a small local DNS resolver (Swift, raw UDP sockets, a reversed-label trie
for O(number of labels) domain lookups regardless of blocklist size) bound to 127.0.0.1:53,
installed as a root LaunchDaemon. The Mac's system DNS is pointed at it. Blocked domains get
NXDOMAIN; SafeSearch domains get rewritten to their forced-safe-search IP (resolved live, not
hardcoded, since some providers' addresses rotate); everything else is forwarded to whatever DNS
servers your network already had configured. dfmenubar is a SwiftUI menu-bar app showing status
and the disable/toggle controls — it talks to the daemon only through shared JSON state files, never
directly, so it can stay fully unprivileged.
Android — BlockerVpnService is a full-capture local VPN (Kotlin). It has to capture all
traffic, not just DNS — Android gives a captured app no fallback route to the real network for
anything the VPN doesn't explicitly route, so a DNS-only VPN would silently kill the rest of the
device's connectivity. DNS (UDP/53) gets the block/allow/SafeSearch logic; everything else is
relayed transparently through a minimal userspace TCP/UDP NAT (TcpNat.kt / UdpNat.kt) so normal
browsing keeps working. WhatsApp/Messenger/Telegram/Botim are excluded from the VPN entirely via
addDisallowedApplication.
Both platforms load the same category rules from the same blocklist sources — HaGeZi's hosted lists
for adult/gambling/piracy/bypass, and this repo's own hand-maintained shared/social-domains.txt
for social media (needs per-platform precision a generic list can't give: block Instagram's feed,
never block WhatsApp).
docs/troubleshooting.md#uninstalling).docs/privacy.md.macos/ — dfdaemon (the DNS resolver), dfmenubar (SwiftUI status/control UI), LaunchDaemon
plist, install + blocklist-update scriptsandroid/ — VpnService-based filter + TCP/UDP relay, sideloaded APK (no Play Store)shared/ — the hand-maintained social-media domain list both platforms usedocs/ — MVP scope, privacy, troubleshootingdocs/privacy.md.docs/privacy.md.docs/troubleshooting.md for why.Prebuilt installers are attached to each GitHub Release — no Xcode or Android Studio required.
macOS:
distraction-free.pkg from the latest release..pkg and choose Open instead, which offers a
bypass the normal double-click doesn't.Prefer the old zip+script method, or don't want to run an unsigned installer? distraction-free-macos.zip
is still attached to every release — download it, unzip, and run ./install-release.sh from Terminal
instead. Both do the same install; the .pkg just does it without opening Terminal.
Android:
distraction-free-android.apk from the latest release on the
phone itself (or transfer it over).New releases build automatically from a git tag (vX.Y.Z) via
.github/workflows/release.yml.
macOS: cd macos && ./Scripts/install.sh (builds in release mode, asks for your password once
to install the LaunchDaemon and point your Mac's DNS at it).
Android: open android/ in Android Studio, build and install the debug APK, grant the VPN
permission when prompted, and — for real bypass-resistance — enable **Settings → VPN → Always-on VPN
MVP built and smoke-tested: DNS blocking, subdomain matching, forwarding, and SafeSearch rewriting are verified working on both platforms. Full page-load testing on Android was constrained by the dev sandbox's emulator networking (see commit history / session notes) rather than the app itself — worth a real-device pass before relying on it daily.
Bug reports, feature ideas, and PRs are welcome — see CONTRIBUTING.md for how to build from source, what "tested" means for a project with no automated test suite yet, and the project's few real conventions. File a bug with reproduction steps (and an exported diagnostic log, if relevant) rather than a one-line "it's broken."
The in-app "Disable protection" button is deliberately a fake 24h countdown that never completes — that's the whole point. There's no in-app uninstall. To actually remove it:
macOS (run each line in Terminal; the sudo ones will prompt for your password):
sudo launchctl bootout system/com.distractionfree.daemon 2>/dev/null
sudo launchctl bootout system/com.distractionfree.blocklist-update 2>/dev/null
launchctl bootout gui/$(id -u)/com.distractionfree.menubar 2>/dev/null
sudo networksetup -setdnsservers Wi-Fi empty # replace Wi-Fi with your active network service
sudo rm -f /Library/LaunchDaemons/com.distractionfree.daemon.plist
sudo rm -f /Library/LaunchDaemons/com.distractionfree.blocklist-update.plist
rm -f ~/Library/LaunchAgents/com.distractionfree.menubar.plist
sudo rm -rf /usr/local/opt/distraction-free /usr/local/etc/distraction-free /usr/local/var/distraction-free
sudo rm -f /usr/local/bin/dfmenubar
Android: Settings → Apps → Distraction Free → Uninstall. (Or, to keep the app but stop the VPN immediately instead of waiting on the fake countdown, force-stop it from the same screen — a genuine OS-level override, same as macOS root access, that this app can't and shouldn't try to prevent.)
MIT.
33 commits
Kotlin
59.2%
Swift
29.3%
Shell
11.6%