Fox Red Labs / Builds / Networking
A DNS ad blocker on a Wi-Fi board
The CC35X1 answers DNS on your network. Names on a 71,492-name blocklist get 0.0.0.0; everything else is forwarded to your router. Nothing changes until you point one device at it.
HardNo wiringabout half an hour (estimate, not timed)
Parts and steps
You need
- LP-EM-CC35X1 LaunchPad development kit the Wi-Fi board that answers DNS
- LP-XDS110ET debugger Buy programs the board
Get a blocklist.TERMINAL
Download the hosts file.
cd ports/dns-sinkhole curl -fsS -o hosts.txt https://raw.githubusercontent.com/StevenBlack/hosts/master/hostsYou should see:
hosts.txtexists and lists tens of thousands of names.Make the table.TERMINAL
Hash and sort the names: 5 bytes per domain.
python3 gen_blocklist.py hosts.txt -o blocklist.binYou should see:
blocklist.binis about 349 kB.Build and sign.TERMINAL
Build the full blocker. The Wi-Fi name comes from the Mac's saved networks and the password from a file you name. It takes about two minutes.
APP=min ./build.shbuilds stage 1, which answers 192.0.2.1 to every name.Replace <file with WIFI_PASSWORD=...> before you run this.
APP=full BLOCKLIST=$PWD/blocklist.bin WIFI_ENV=<file with WIFI_PASSWORD=...> ./build.shYou should see: The script prints the build folder with
ex/freertos/ticlang/toolbox/tool_settings.json.Program the board.TERMINAL
Program the signed build with the Wi-Fi Toolbox, then reset the board. Add
-param1 <probe serial>when more than one probe is connected.Replace <build folder> before you run this.
/Applications/ti/simplelink_wifi_toolbox_macos_4_3_23/simplelink-wifi-toolbox programmer -i XDS110 programming --tool_settings <build folder>/ex/freertos/ticlang/toolbox/tool_settings.jsonYou should see: The programmer reports success; the console at 115200 baud shows the board's address.
Ask the board.TERMINAL
Ask for a listed name and an unlisted one. Your Mac's settings do not change.
Replace <board ip> before you run this.
dig @<board ip> doubleclick.net dig @<board ip> www.python.orgYou should see: The first answer is 0.0.0.0. The second is the real address.
Point one device at it, then undo it.BROWSER
Set one device's DNS server to the board's address in its network settings. To go back, set it to automatic. The board is not inline, so unplugging it only affects devices pointed at it.
Replace <board ip> before you run this.
curl http://<board ip>/You should see: The counters page shows blocked and forwarded names rising as that device browses.
Or hand it to a coding assistant
Paste this in a terminal. It hands off to an AI assistant.
git clone --depth 1 --filter=blob:none https://github.com/Fox-Red-Labs/fox-red-labs.git && cd fox-red-labs
./start.sh cc35x1 dns-ad-blocker --assistant claudegit clone --depth 1 --filter=blob:none https://github.com/Fox-Red-Labs/fox-red-labs.git && cd fox-red-labs
py start.py cc35x1 dns-ad-blocker --assistant claudeIt runs the steps above and reports what it saw.
Not Claude Code? Copy this prompt instead.
If something goes wrong
| Curl fails | Check the network and run it again. |
| Python reports a syntax error | Use Python 3.12 or newer (.python-version). |
| It cannot read the network name | MacOS hides it from command-line tools: set it in the file you pass as WIFI_ENV. |
| The programmer fails with error -260 on every call | Remove any BoosterPack and replug the probe cable. |
| Dig times out | Check the board joined your network: the console prints its address, and a router may hand it a new one, so reserve it. |
More troubleshooting
| The device loses the network | Set its DNS back to automatic. |
What to build next
Every build. The code for all of them is in the GitHub repository.
Evidence and limitsThe CC35X1 blocks 71,492 names from a 349 kB table in flash and answers a blocked name in a median 6 ms. Ran on 1 board. Results, sources, timing and limits.
Expected result: The board answers 0.0.0.0 for blocklisted names and the real address for the rest.
What this shows
- A 71,492-name blocklist fits the board as a sorted table of 5-byte hashes searched in place in flash: 349 kB of flash and 0.7 kB of RAM.
- A blocked name is answered in a median 6 ms.
What this does not establish, and limits
What this does not establish
- No DNSSEC: answers are relayed as the upstream gave them, not validated.
- Nobody ran it as a household's only resolver for days.
Limits to keep in mind
- Exact name match only: a listed name does not block its subdomains.
- IPv4 and UDP only, no caching, 16 queries in flight, a 2.5 s forward timeout.
- A 40-bit hash means an unlisted name matches with a probability of about 7e-8. The largest list the application slot takes is about 304,000 names (link arithmetic, not booted).
Sources
Versions, sizes and timing
| Blocked name | median 6 ms, 95th percentile 20 ms | README notes |
|---|---|---|
| Forwarded name | median 70 ms, 95th percentile 172 ms (router directly: 52 and 99) | README notes |
| Forwarding defences | random 16-bit ID from the hardware generator, a fresh random UDP port per query, random upper and lower case in the name | README notes |
Evidence
- From a Mac on the same Wi-Fi, 100 queries each: blocked names answered in a median 6 ms (95th percentile 20); forwarded names in a median 70 ms (95th percentile 172) against 52 ms (99) to the router directly. README notes
- The list of 71,492 domains is 349 kB of flash and 0.7 kB of RAM. the data (CSV)
Other boards
- MSPM0G3507, MSPM0L1306, CC2340R5, F2800137Not for this chip no radio
What the status words mean
Works ran here and did what it shouldCould work some of it ran; real porting effort is left; hover for whatNot for this chip the chip or its vendor software cannot; hover for why
Result grid
Works ran here and did what it shouldShould work it builds; only naming, packaging or build glue is in the way; hover for whichCould work some of it ran; real porting effort is left; hover for whatNot for this chip the chip or its vendor software cannot; hover for why
Experiments (1)
| Status | What was tried | Result |
|---|---|---|
| Works | Can a TI LP-EM-CC35X1 act as a DNS ad blocker for the devices pointed at it? CC35X1, 2026-10-20 | A DNS sinkhole with 71,492 blocked domains as a 349 kB hash table in flash answers blocked names in a median 6 ms and forwarded names in a median 70 ms against 52 ms asking the gateway directly, from the CC35X1. |
Source files
Code brought from elsewhere
This project uses code that was written for other chips or tools. Each links to how to get it running.
- DNS ad blocker (sinkhole) on the LP-EM-CC35X1 Works The CC35X1 answers DNS on UDP port 53: names on a blocklist get 0.0.0.0 and the rest is forwarded to your gateway.
Get the code and tell us how it wentThe clone command, the board folder with its AGENTS.md, reports from others, and the three report forms.
Get the code
Clone the repository and open the board's folder below. AGENTS.md is a plain text file of notes for AI coding assistants, and llms.txt at the root indexes the site for one.
git clone https://github.com/Fox-Red-Labs/fox-red-labs.git
- LP-EM-CC35X1: folder
cc35x1/.- README: the board's lab notebook (what was run, in order)
- Notes for an AI coding assistant working in this repository: notes for an AI assistant; copy it into your own project if you use one
- FAQ: errors and fixes
Code is BSD-3-Clause, writing is CC BY 4.0; third-party folders keep their own licenses.
Built it? Tell us
Built this, or got stuck? Report it on GitHub with a few short answers. Your report shows here in your words, marked as yours. A failure that repeats on the bench gets its fix here.