Bluebox
A fast, transparent DNS interceptor for local networks. Bluebox acts as a parental control / ad-blocking DNS filter that works without requiring any client configuration.
Features
- Transparent DNS Interception: Uses ARP spoofing to intercept DNS queries from all devices on the network
- Domain Blocking: Block domains by exact match or wildcard patterns (e.g.,
*.ads.com) - Response Caching: Caches DNS responses to improve performance
- Zero Client Configuration: Devices don't need any DNS settings changed
- Traffic Forwarding: Non-DNS traffic is forwarded to the real gateway transparently
- Graceful Shutdown: Restores ARP tables when stopping to avoid network disruption
How It Works
┌─────────────────────────────────────────────────────────────────┐
│ Local Network │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Phone │ │ Laptop │ │ Tablet │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ │ DNS queries (port 53) │ │
│ └────────────────┼────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Bluebox │◄─── ARP: "I am the gateway" │
│ │ (Raspberry Pi) │ │
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────┴─────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌───────────────┐ │
│ │ DNS blocked │ │ Forward other │ │
│ │ → localhost │ │ traffic to │ │
│ │ │ │ real gateway │ │
│ │ DNS allowed │ └───────┬───────┘ │
│ │ → upstream │ │ │
│ └─────────────┘ ▼ │
│ ┌──────────────┐ │
│ │ Router │ │
│ │ (Gateway) │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────────────┘
ARP Spoofing Explained
- Discovery: Bluebox discovers the gateway (router) IP and MAC address
- ARP Poisoning: Periodically sends ARP replies to all devices claiming to be the gateway
- Interception: Devices send their traffic to Bluebox thinking it's the gateway
- DNS Filtering: DNS queries (port 53) are intercepted and filtered
- Forwarding: All other traffic is forwarded to the real gateway
Installation
Prerequisites
Native Installation:
- Root/sudo privileges (required for raw packet capture and ARP)
- Linux (Debian/Ubuntu for .deb packages, or any Linux for musl builds)
Docker Installation:
- Docker with
--cap-add=NET_ADMINand--cap-add=NET_RAWcapabilities --network hostmode to access the host's network interfaces
Pre-built Binaries
Download pre-built binaries from the Releases page:
| Platform | Binary | Notes |
|---|---|---|
| Linux x86_64 (glibc) | bluebox-linux-amd64 |
Standard Linux |
| Linux aarch64 (glibc) | bluebox-linux-arm64 |
Raspberry Pi 4+, ARM servers |
| Linux x86_64 (musl) | bluebox-linux-amd64-musl |
Static binary, works on any Linux |
| Linux aarch64 (musl) | bluebox-linux-arm64-musl |
Static binary for ARM |
Debian/Ubuntu (.deb package)
The easiest way to install on Debian-based systems:
# Download the .deb for your architecture
# or for ARM64 (Raspberry Pi 4+)
# Install
The .deb package includes:
- Binary at
/usr/bin/bluebox - Example config at
/etc/bluebox/config.toml - Systemd service file
- Dedicated
blueboxuser/group for security
After installation:
# Edit the configuration
# Enable and start the service
Docker
The easiest way to run Bluebox in a containerized environment:
# Pull the latest image
# Run with default configuration
# Run with custom configuration
Important Docker Notes:
--cap-add=NET_ADMINand--cap-add=NET_RAWare required for packet capture and ARP spoofing--network hostis required to access the host's network interfaces- Without these permissions, Bluebox cannot intercept DNS queries
Docker Compose
Create a docker-compose.yml:
version: '3.8'
services:
bluebox:
image: ghcr.io/jdrouet/bluebox:latest
container_name: bluebox
network_mode: host
cap_add:
- NET_ADMIN
- NET_RAW
volumes:
- ./config.toml:/etc/bluebox/config.toml:ro
# Optional: cache directory for remote blocklists
- bluebox-cache:/var/cache/bluebox
environment:
- RUST_LOG=info
- CONFIG_PATH=/etc/bluebox/config.toml
restart: unless-stopped
volumes:
bluebox-cache:
Usage:
# Start the service
# View logs
# Check status
# Restart after config changes
# Stop the service
# Stop and remove volumes
Example with metrics enabled:
version: '3.8'
services:
bluebox:
image: ghcr.io/jdrouet/bluebox:latest
container_name: bluebox
network_mode: host
cap_add:
- NET_ADMIN
- NET_RAW
volumes:
- ./config.toml:/etc/bluebox/config.toml:ro
- bluebox-cache:/var/cache/bluebox
environment:
- RUST_LOG=info
- CONFIG_PATH=/etc/bluebox/config.toml
restart: unless-stopped
# Expose metrics port (if metrics are enabled in config)
# Note: with network_mode: host, this is informational only
expose:
- "9090"
# Optional: Add Prometheus for metrics collection
prometheus:
image: prom/prometheus:latest
container_name: prometheus
network_mode: host
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
restart: unless-stopped
volumes:
bluebox-cache:
prometheus-data:
With this setup, create a prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'bluebox'
static_configs:
- targets:
Building the Docker Image
To build the image yourself:
# For multi-architecture builds
Building from Source
Requirements: Rust 1.75+ (edition 2024)
The binary will be at target/release/bluebox.
Raspberry Pi Setup
-
Install Rust on your Raspberry Pi:
| -
Clone and build:
-
Copy the binary and config:
-
Run as a systemd service (see Systemd Service below)
Alternatively, download the pre-built bluebox_arm64.deb package for Raspberry Pi 4+.
Configuration
Create a config.toml file:
# Network interface (optional, auto-detected if not specified)
# interface = "eth0"
# Upstream DNS resolver
= "1.1.1.1:53"
# Cache TTL in seconds
= 300
# Domains to block (exact match or wildcard)
= [
# Social media
"*.facebook.com",
"facebook.com",
"*.instagram.com",
"instagram.com",
"*.tiktok.com",
"tiktok.com",
# Ads and tracking
"*.doubleclick.net",
"*.googlesyndication.com",
"*.googleadservices.com",
"*.facebook-dns.com",
"*.adnxs.com",
]
# External blocklist sources (optional)
# Load blocklists from files or remote URLs
[[]]
= "steven-black-hosts"
= true
= { = "remote", = "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" }
= "hosts"
= 24
[[]]
= "local-custom"
= true
= { = "file", = "/etc/bluebox/custom-blocklist.txt" }
= "domains"
# ARP spoofing for transparent interception
[]
= true
# gateway_ip = "192.168.1.1" # Optional, auto-detected
= 2
= true
= true
Configuration Options
| Option | Description | Default |
|---|---|---|
interface |
Network interface to use | Auto-detect |
upstream_resolver |
Upstream DNS server | Required |
cache_ttl_seconds |
How long to cache DNS responses | 300 |
blocklist |
List of domains/patterns to block | [] |
blocklist_sources |
External blocklist sources (see below) | [] |
buffer_pool_size |
Size of packet buffer pool | 64 |
channel_capacity |
Packet queue capacity | 1000 |
Blocklist Sources
You can load blocklists from local files or remote URLs. Each source has the following options:
| Option | Description | Default |
|---|---|---|
name |
Unique identifier for this source | Required |
enabled |
Whether to use this source | true |
source.type |
file or remote |
Required |
source.path |
Path to local file (for file type) |
- |
source.url |
URL to fetch (for remote type) |
- |
format |
File format: domains, hosts, or adblock |
domains |
refresh_interval_hours |
How often to refresh remote sources | - |
Supported formats:
domains- One domain per linehosts- Standard hosts file format (e.g.,0.0.0.0 example.com)adblock- AdBlock filter syntax (future support)
ARP Spoof Options
| Option | Description | Default |
|---|---|---|
enabled |
Enable transparent interception | false |
gateway_ip |
Gateway IP to impersonate | Auto-detect |
spoof_interval_secs |
Seconds between ARP packets | 2 |
restore_on_shutdown |
Restore ARP tables on exit | true |
forward_traffic |
Forward non-DNS traffic | true |
Usage
Basic Usage (Passive Mode)
Without ARP spoofing, devices must be configured to use Bluebox as their DNS server:
Transparent Mode (ARP Spoofing)
With ARP spoofing enabled, no client configuration is needed:
# Edit config.toml to enable arp_spoof
Systemd Service
If you installed via the .deb package, the systemd service is already set up. Just enable and start it:
For manual installations, create /etc/systemd/system/bluebox.service:
[Unit]
Description=Bluebox DNS Interceptor and Cache
Documentation=https://github.com/jeremie/bluebox
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=bluebox
Group=bluebox
ExecStart=/usr/bin/bluebox --config /etc/bluebox/config.toml
Restart=on-failure
RestartSec=5
# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/cache/bluebox
# Required for binding to port 53 and ARP spoofing
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN
[Install]
WantedBy=multi-user.target
You'll also need to create the user and directories:
Then enable and start:
Architecture
src/
├── main.rs # Entry point, orchestration
├── lib.rs # Library exports
├── config.rs # Configuration loading
├── error.rs # Error types
├── dns/
│ ├── blocker.rs # Domain blocking logic
│ └── resolver.rs # Upstream DNS resolution
├── cache/
│ └── dns_cache.rs # Response caching (Moka)
├── network/
│ ├── arp.rs # ARP spoofing
│ ├── forward.rs # Traffic forwarding
│ ├── capture.rs # Packet capture (pnet)
│ ├── packet.rs # Packet construction
│ └── buffer.rs # Buffer pooling
└── server.rs # Query handling
Design Principles
- Trait-based abstractions: All components have traits for easy testing/mocking
- Minimal allocations: Buffer pooling to reduce heap allocations
- Async I/O: Tokio for efficient async operations
- Zero-copy where possible: Direct packet manipulation
Testing
# Run all tests
# Run with logging
RUST_LOG=debug
# Run benchmarks
Security Considerations
- Root Required: Bluebox needs root privileges for raw packet capture and ARP
- Network Scope: Only use on networks you own or have permission to manage
- ARP Spoofing: This technique is commonly used for parental controls and enterprise monitoring, but could be misused - use responsibly
- Graceful Shutdown: Always let Bluebox shut down gracefully (Ctrl+C) to restore ARP tables
Roadmap
Implemented
- DNS query interception and filtering
- Domain blocking (exact + wildcard)
- Response caching with TTL
- ARP spoofing for transparent interception
- Traffic forwarding for non-DNS packets
- Gateway auto-detection
- Graceful shutdown with ARP restoration
- External blocklist sources (file and remote URL)
- Multiple blocklist formats (domains, hosts, adblock)
Planned
- Web UI for configuration and statistics
- Per-device policies (allow/block specific devices)
- DNS-over-HTTPS (DoH) upstream support
- Statistics and logging dashboard
- Scheduled blocking (e.g., no social media 9pm-7am)
- DHCP server mode (alternative to ARP spoofing)
- IPv6 support for ARP spoofing (NDP)
Troubleshooting
"Failed to find network interface"
Make sure you're running as root:
"Failed to detect gateway"
Manually specify the gateway in config:
[]
= true
= "192.168.1.1" # Your router's IP
Devices lose internet after starting Bluebox
This usually means traffic forwarding isn't working. Check:
forward_traffic = truein config- The gateway MAC was discovered (check logs for "Discovered gateway MAC")
- IP forwarding is enabled:
sudo sysctl net.ipv4.ip_forward=1
Network doesn't recover after stopping Bluebox
If you kill Bluebox with kill -9 instead of Ctrl+C, ARP tables won't be restored. Fix by:
# Clear ARP cache on affected devices, or
# Restart their network interface, or
# Wait for ARP cache to expire (usually 1-5 minutes)
Docker: "Operation not permitted" or "Permission denied"
Make sure you're running with the required capabilities:
Without these capabilities, Bluebox cannot:
- Open raw sockets for packet capture
- Send ARP packets
- Modify network interfaces
Docker: "Failed to find network interface"
When using --network host, Docker containers have access to the host's network interfaces. If you're specifying an interface in config.toml, make sure it exists on the host:
# List available interfaces on host
Docker: Container exits immediately
Check the logs:
Common issues:
- Missing required capabilities (
NET_ADMIN,NET_RAW) - Invalid configuration file path
- Interface specified in config doesn't exist
License
MIT
Contributing
See CONTRIBUTING.md for guidelines.