Skip to main content

macblock

CI PyPI License: MIT

Local DNS sinkhole for macOS using dnsmasq on 127.0.0.1:53, with automatic system DNS configuration and split-DNS preservation.

Why?

I like Pi-Hole, but I don't necessarily want to deploy a whole box on a network for DNS adblock, or have the whole network go through it. I also wanted a better solution than running Pi-Hole in a container on MacOS, which felt like adding a whole lot of overhead for a relatively lightweight service. After some searching, I found I could configure dnsmasq myself and run a fairly simple sinkhole as a service. macblock is a CLI and long-running management service that make the installation, configuration, and management of a dnsmasq-based DNS sinkhole on MacOS easy.

Vibe-coding disclaimer

Most of this project was vibe-coded with careful code review and analysis of what the daemon touches. Every effort was made to ensure that the services here are using root as little as possible. If you find any holes I missed, please open an issue or a PR!

Features

  • Blocks ads, trackers, and malware at the DNS level
  • Automatically configures DNS for managed network services
  • Preserves VPN/corporate split-DNS routing
  • Pause/resume with automatic timers
  • Whitelist/blacklist management
  • Multiple blocklist sources (StevenBlack, HaGeZi, OISD) or a custom URL

Install

Via Homebrew (recommended)

brew install SpyicyDev/formulae/macblock

Or, if you prefer adding the tap explicitly:

brew tap SpyicyDev/formulae
brew install macblock

Via PyPI

This installs the macblock CLI, but you still need dnsmasq available on your system (recommended via Homebrew):

brew install dnsmasq
python3 -m pip install macblock

Quick start

macblock performs privileged operations (launchd + system DNS changes). You can run root-required commands with sudo, or omit it and let macblock auto-elevate.

sudo macblock install
sudo macblock enable
macblock status

Usage

macblock <command> [flags]

Global flags

  • -h, --help: show help for a command
  • -V, --version: show version

Commands

Status & diagnostics:

  • macblock status: show current status
  • macblock doctor: run diagnostics and health checks
  • macblock logs [--component daemon|dnsmasq] [--lines N] [--follow] [--stream auto|stdout|stderr]: view logs
  • macblock test <domain>: test resolution against the local resolver

Control:

  • sudo macblock enable: enable DNS blocking
  • sudo macblock disable: disable DNS blocking
  • sudo macblock pause <duration>: temporarily disable (e.g. 10m, 2h, 1d)
  • sudo macblock resume: resume blocking

Installation & updates:

  • sudo macblock install [--force] [--skip-update]: install system integration
  • sudo macblock uninstall [--force]: remove system integration
  • sudo macblock update [--source <name|url>] [--sha256 <hash>]: download + compile blocklist and reload dnsmasq

Configuration:

  • macblock sources list: list available blocklist sources
  • sudo macblock sources set <source>: set blocklist source (updates state only; run sudo macblock update to download/compile/apply)
  • macblock upstreams list: list configured fallback upstream DNS servers (if any)
  • sudo macblock upstreams set [ip ...]: set fallback upstream DNS servers (prompts if none provided)
  • sudo macblock upstreams reset: reset fallback upstream DNS servers to built-in defaults
  • macblock allow list: list whitelisted domains
  • sudo macblock allow add|remove <domain>: manage whitelist
  • macblock deny list: list blacklisted domains
  • sudo macblock deny add|remove <domain>: manage blacklist

Tip: macblock <command> --help shows per-command usage.

How it works

  1. dnsmasq listens on 127.0.0.1:53 and serves DNS.
  2. The macblock daemon watches for network changes and reconciles state.
  3. When enabled, macblock sets DNS to 127.0.0.1 for a set of managed macOS network services (it intentionally skips VPN-ish services/devices).
  4. macblock generates dnsmasq upstream routing by preferring DHCP nameservers from the default-route interface, and falling back to system resolvers (scutil --dns), so domain-specific resolvers (VPN/corporate split-DNS) keep working.
  5. Blocked domains are answered as NXDOMAIN via dnsmasq rules.
flowchart TD
  U[User] -->|macblock CLI| CLI[macblock]
  CLI -->|writes/updates| ST[(state.json)]

  LD[launchd] --> D[macblock daemon]
  D -->|reads/writes| ST
  D -->|sets per-service DNS to 127.0.0.1| SCD[System DNS config]
  D -->|generates upstream.conf from DHCP/scutil| UP[(upstream.conf)]

  SCD --> DNS[dnsmasq on 127.0.0.1:53]
  UP --> DNS
  DNS -->|forwards allowed queries| R[Upstream resolvers]

  NC[Network change events] --> D

Note: Encrypted DNS (DoH/DoT) can bypass macblock; macblock doctor warns if detected.

macblock test behavior

macblock test <domain> runs dig against 127.0.0.1:53 and uses the compiled block rules to interpret NXDOMAIN:

  • If the domain matches a block rule, NXDOMAIN is reported as BLOCKED.
  • If the domain does not match a block rule, NXDOMAIN is reported as does not exist.

If you don't have dig, install it with:

brew install bind

Uninstall

See docs/UNINSTALL.md.

Quick version:

sudo macblock uninstall

# If installed via Homebrew
brew uninstall macblock dnsmasq

# If installed via PyPI
python3 -m pip uninstall macblock

Filesystem footprint

macblock keeps its on-disk footprint intentionally small and predictable:

  • /Library/Application Support/macblock/: persistent state + configuration
    • state.json, version, blocklist.*, whitelist.txt, blacklist.txt, dns.exclude_services, upstream.fallbacks, etc/dnsmasq.conf
  • /Library/Logs/macblock/: service logs (managed by launchd)
    • daemon.{out,err}.log, dnsmasq.{out,err}.log
  • /var/db/macblock/: runtime state (safe to delete; will be recreated)
    • upstream.conf, upstream.info.json, daemon.pid, daemon.ready, daemon.last_apply, dnsmasq/dnsmasq.pid
  • /Library/LaunchDaemons/: launchd plists
    • com.local.macblock.daemon.plist, com.local.macblock.dnsmasq.plist

macblock also modifies system DNS settings via networksetup.

Service classification and overrides

macblock chooses a set of “managed” network services to apply DNS changes to (and intentionally skips VPN-ish services/devices) using a heuristic.

If a service is being managed when you don't want it to be (or vice-versa), you can override selection by creating:

  • /Library/Application Support/macblock/dns.exclude_services

Format:

  • One exact service name per line.
  • Blank lines are ignored.
  • Lines starting with # are comments.

To find the exact service names on your system:

/usr/sbin/networksetup -listallnetworkservices

Example:

# Keep macblock from touching these services
Tailscale Tunnel
My VPN

Troubleshooting

  • Run macblock doctor first.
  • View logs: macblock logs --component daemon --stream stderr or macblock logs --component dnsmasq --stream stderr.
  • Verify DNS state: scutil --dns (macblock uses this to preserve split DNS).
  • Port conflict on :53: sudo lsof -i :53 -P -n.

Attribution

macblock can download third-party blocklists from:

Please review each upstream project's license/terms. macblock does not vendor or redistribute these lists in this repository.

Security

See SECURITY.md for the threat model and privileged footprint.

Development

Tooling:

brew install just direnv

Then:

direnv allow
just sync
just ci

License

MIT

Metadata

Release files for macblock 0.2.10

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for macblock 0.2.10
File Size Uploaded
macblock-0.2.10.tar.gz 59.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for macblock 0.2.10
File Interpreter ABI Platform
macblock-0.2.10-py3-none-any.whl Python 3 none any Details

Total release size: 112.3 kB

Release files / macblock-0.2.10.tar.gz

Download URL macblock-0.2.10.tar.gz
Size 59.3 kB
Tags Source
SHA-256 checksum
How to use checksums
6906d574ccec85fb9f9328ef99792bdce7667da09e8b5fd117c3c8d6b75c2408
BLAKE2b-256 checksum
How to use checksums
34826fd827a09520037ea0be44f0c42b2c6fe367ee7ef403636893ef243e228d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 16, 2026.

Transparency log

Release files / macblock-0.2.10-py3-none-any.whl

Download URL macblock-0.2.10-py3-none-any.whl
Size 53.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
112ed2d8d01e6167b9479ec2545e1bdea6c3df6b02c5b08798156c9abfd2493a
BLAKE2b-256 checksum
How to use checksums
7a2c2a0284f26fd4ddd990f965311e04387b9ff2fb9239f0a6d48d3e6701bd1d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Feb 16, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.10 This release

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page