esp32-c3-adblock README

The project's README from github.com/M-Abozaid/esp32-c3-adblock. As one markdown file: README.md.

esp32-c3-adblock

A Pi-hole-style DNS ad-blocker that runs on a $2 ESP32-C3 — no PSRAM required.

📰 Featured on Tom's Hardware, XDA Developers, and Korben.

The trick everyone misses: you don't need to keep the blocklist in RAM. Store the domains as sorted 40-bit hashes in flash and binary-search them. 140,000+ domains fit in 0.7 MB of flash and are matched in ~10 ms, using **50 KB of RAM**.

query in ──▶ extract domain ──▶ FNV-1a hash (+ parent suffixes)
         ──▶ binary-search the flash hash table
              ├─ hit  ──▶ answer 0.0.0.0   (sinkholed)
              └─ miss ──▶ forward to upstream resolver, relay the reply

Why this is interesting

Most ESP32 DNS sinkholes load the blocklist (domain strings) into RAM, so they demand PSRAM. This project stores fixed 5-byte (40-bit) hashes in flash instead:

string-in-RAM approach this (hash-in-flash)
Hardware ESP32 + PSRAM (~$8) ESP32-C3, no PSRAM (~$2)
141k domains ~2.5 MB of RAM 0.67 MB of flash
RAM used most of it ~50 KB
Lookup string compare 18 flash reads (10 ms incl. WiFi RTT)
Collisions n/a 0 at 141k (1 at 537k)

Why 40 bits? It's the sweet spot for this flash budget. Collisions follow the birthday bound — at 141k domains you get ~0, at 537k about 1 (i.e. one unlucky domain gets over-blocked). Dropping to 32 bits would save 20% of the flash but cost ~7 collisions at 250k; going to 64 bits wastes 3 bytes per domain to solve a problem you don't have.

The same trick works on bigger chips — it isn't a C3 workaround. On a 16 MB ESP32-S3 these hashes hold ~2.7M domains vs ~466k for strings in 8 MB of PSRAM. Hashes in flash beat strings in PSRAM basically everywhere; the C3 just makes it undeniable.

Hardware

Enclosure

A printable case for the C3 SuperMini: hardware/esp32-c3-supermini-enclosure.stl

Printing notes:

Build & flash (PlatformIO)

One USB flash to get going — after that, firmware and blocklist both update over WiFi (see below).

⚠️ Use a current PlatformIO — the VSCode PlatformIO extension's bundled core, or pip install -U platformio in a venv. The distro/apt platformio package (e.g. 4.3.4) is too old and fails with AttributeError: ... 'resultcallback' (issue #4). A one-click browser installer is on the way (hosting TBD).

# 1. (optional) set WiFi creds at compile time — or skip this and use the
#    on-device setup portal (below). secrets.h is gitignored, stays local.
cp src/secrets.example.h src/secrets.h
#    then edit src/secrets.h -> WIFI_SSID / WIFI_PASS

# 2. build the blocklist hash table (default = StevenBlack base + Hagezi Light,
#    ~140k domains, WhatsApp/social safe)
python3 tools/build_blocklist.py data/blocklist.bin

# 3. flash firmware + the blocklist filesystem (the one and only USB flash)
pio run -t upload
pio run -t uploadfs

# 4. watch it boot, note the IP / open the dashboard
pio device monitor          # -> http://c3adblock.local

WiFi setup (no re-flash needed)

If it can't connect (or you never set secrets.h), it starts an open access point C3-AdBlock-XXXX with a captive portal — join it from a phone, pick your network, type the password, done. To move it to a new network later: open http://c3adblock.local/forgetwifi, or hold the BOOT button while powering on, and the setup portal comes back.

Over-the-air updates (no more USB)

The dashboard at http://c3adblock.local does it all:

4 MB flash tradeoff: firmware OTA needs two app slots, which leaves 1.3 MB for the blocklist (**250k domains max**). The aggressive 537k "ultimate" list only fits the single-app partition table (no firmware OTA). Pick your tradeoff in partitions.csv.

Use it

Point a device's DNS at the C3's IP, or add it as a secondary resolver behind your main DNS. Test:

dig @<c3-ip> doubleclick.net   # -> 0.0.0.0  (blocked)
dig @<c3-ip> github.com        # -> real IP  (forwarded)

Gotchas (learned the hard way)

Done / how it could grow

Credits

Inspired by s60sc/ESP32_AdBlocker — the "answer 0.0.0.0 for blocklisted domains" idea. This is an independent from-scratch implementation focused on the hash-in-flash optimization for PSRAM-less chips.

License

MIT — see LICENSE.

esp32-c3-adblock (M-Abozaid/esp32-c3-adblock)

Searching Database…

Что это?Это прошивка DNS-блокировщика рекламы в стиле Pi-hole, которая работает на чипе ESP32-C3 за 2 доллара без PSRAM, храня до 537 тысяч заблокированных доменов в виде компактных хэшей во флеше, а не в RAM.
Это софт, который я ставлю на существующее железо, или нужно что-то купить?Это прошивка, которую вы льёте на дешёвую плату ESP32-C3 (например, C3 SuperMini), после чего она работает как самостоятельное сетевое устройство со своей веб-панелью.
Как собрать и прошить её?Используйте PlatformIO, чтобы один раз собрать и прошить её по USB; дальше и прошивка, и блок-лист обновляются по WiFi через веб-панель устройства.
Какие инструменты нужны перед прошивкой?Нужна актуальная установка PlatformIO (ядро из расширения VSCode или свежая установка через pip), поскольку старые пакеты PlatformIO из дистрибутивов/apt не работают.
В чём подвох огромного блок-листа на 537 тысяч доменов?Полный «ультимативный» список на 537 тысяч доменов влезает только в таблицу разделов single-app, что отключает OTA-обновления прошивки; при включённой OTA в оставшейся флеше помещается лишь около 250 тысяч доменов.
Кому стоит собрать это вместо Pi-hole на Raspberry Pi?Всем, кому нужен крошечный, дешёвый и энергоэффективный DNS-блокировщик рекламы, втыкаемый прямо в свободный USB-порт роутера, вместо полноценного сервера Pi-hole.
Зачем хранить блок-лист хэшами во флеше, а не строками доменов в RAM?Это полностью избавляет от потребности в PSRAM: 141 тысяча доменов занимает около 0,67 МБ флеша и около 50 КБ RAM в виде 40-битных хэшей против примерно 2,5 МБ RAM для сырых строк доменов, а поиск идёт бинарным поиском во флеше (около 10 мс).
Как настраивается WiFi без хардкода учётных данных?Если подключиться не удаётся или сохранённых учётных данных нет, он поднимает открытую точку доступа с именем C3-AdBlock-XXXX и captive portal, где вы выбираете свою сеть и вводите пароль; зажатая кнопка BOOT при включении заново открывает этот портал настройки.
Что умеет веб-панель?Она показывает счётчики блокировок/разрешений по клиентам, позволяет забанить клиента или добавить свои заблокированные домены и обрабатывает OTA-загрузку как прошивки, так и файла blocklist.bin.
Есть риск, что легитимный домен заблокируют по ошибке?Да, небольшой: 40-битные хэши имеют малую вероятность коллизий — при 141 тысяче доменов их примерно ноль, а на полном списке в 537 тысяч ожидается около одной коллизии, то есть какой-то несчастный домен может быть заблокирован сверх меры.
Creator
M-Abozaid
Size
1.5 MB
Stars
3.2K
Age
3mo
Commits · 90 Days