Created
November 2, 2025 22:54
-
-
Save scarlion1/fb992017e18f9af7e8d2be1a28bfddef to your computer and use it in GitHub Desktop.
Revisions
-
scarlion1 created this gist
Nov 2, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,142 @@ # OpenWrt Dnsmasq Cache Viewer A lightweight shell script for OpenWrt routers to dump and display the dnsmasq DNS cache in a clean, formatted table. Works with basic busybox/ash environment. ## Features * Triggers dnsmasq cache dump via SIGUSR1 * Extracts and formats the most recent cache dump from logs * Displays cache statistics (queries, memory usage, server stats) * Works with OpenWrt's ujail-wrapped dnsmasq processes ## Requirements * OpenWrt router with dnsmasq * Dnsmasq logging enabled (`log-queries` option) * Log file at `/var/log/dnsmasq` (or modify `LOGFILE` variable) * Busybox/ash shell environment ## Assumptions 1. In my testing, even with a large 8000-item cache, all the lines dumped to the logfile had the same timestamp. Thus, the script assumes the dump lines will be prefixed with the same timestamp. This may not be the case for older, slower systems or larger caches. 2. Also in my testing, the other lines in the log files, before and after the dump, always had different timestamps. Thus, the script assumes there won't be any extraneous lines with the same timestamp as the dump lines. This may not be the case in newer, faster systems or systems that are very busy. Good luck! 3. It is assumed that SIGUSR1 has already been sent to the dnsmasq process. A helper command for that is provided below. ## Installation 1. Copy `show_dnsmasq_cache.sh` to your OpenWrt router (e.g., `/usr/bin/`) 2. Make it executable: ```bash chmod +x /usr/bin/show_dnsmasq_cache.sh ``` ## Usage ### Command Line #### 1\. Dump the cache: ```bash kill -USR1 $(pidof dnsmasq | awk '{print $1}') ``` #### 2\. Run the script: ```bash show_dnsmasq_cache.sh ``` ### OpenWrt Web Interface (LuCI) If you have the **Custom Commands** package installed, you can add these as buttons in the web interface: #### 1\. Install Custom Commands (if not already installed) ```bash opkg update opkg install luci-app-commands ``` #### 2\. Add Custom Command to Trigger Cache Dump Navigate to: **System → Custom Commands → Configure → Add** - **Description:** `Dump DNS Cache` - **Command:** `sh -c 'kill -USR1 $(pidof dnsmasq | awk "{print \$1}")'` - **Custom arguments:** Could be helpful for targeting different PID's? Leave off until you come up with something. - **Public access:** Recommend leaving this off. #### 3\. Add Custom Command to View Cache - **Description:** `Show DNS Cache` - **Command:** `show_dnsmasq_cache.sh` - **Custom arguments:** Enable. Could be helpful for parsing the output further, for example looking for specific domain. - **Public access:** Also recommend leaving this off. **Usage Flow:** 1. Click "Dump DNS Cache" button (wait \~1 second) 2. Click "Show DNS Cache" button to view the formatted output ## Output Example (I have dnsmasq configured to forward to local DNS Proxy for Adguard DoQ/DoT/DoH) ``` Dnsmasq cache stat's & contents as of: Nov 2 11:00:10 time 1762106410 cache size 4000, 0/905 cache insertions re-used unexpired cache entries. queries forwarded 376, queries answered locally 732 pool memory in use 1540, max 5412, allocated 6600 child processes for TCP requests: in use 0, highest since last SIGUSR1 0, max allowed 20. server 127.0.0.1#5354: queries sent 347, retried 0, failed 3, nxdomain replies 26, avg. latency 62ms server ::1#5354: queries sent 138, retried 0, failed 2, nxdomain replies 2, avg. latency 258ms Host Address Flags Expires Source ------------------------------ ---------------------------------------- ---------- ------------------------ ------------ example.com 93.184.216.34 4F Wed Nov 5 11:00:10 2025 www.example.com example.com CF Wed Nov 5 11:00:10 2025 ipv6.example.com 2606:2800:220:1:248:1893:25c8:1946 6F Wed Nov 5 11:00:10 2025 _http._tcp.example.com <SRV> TF Wed Nov 5 11:00:10 2025 zazu.lan 192.168.1.9 4FR D Mon Nov 3 02:25:25 2025 zazu.lan 2600:d0d0:15:dead::123 6FRI H /tmp/hosts/odhcpd zazu.lan b16:bad:b1d1::123 6FRI H /tmp/hosts/odhcpd ``` ## Column Descriptions * **Host**: The queried hostname * **Address**: IP address, CNAME target, or special value (e.g., `<SRV>`, `<HTTPS>`) * **Flags**: Cache entry flags * 4 - IPv4 address * 6 - IPv6 address * C - CNAME * F - forward (name->address) mapping * R - reverse (address->name) mapping * I - immortal (no expiry time) * D - originates from DHCP * N - negative (name known not to have address) * X - no such domain (name known not to exist) * H - originates from /etc/hosts. * **Expires**: Expiration date/time of the cache entry * **Source**: Source of the DNS record (if applicable) ## Troubleshooting ### No output or "Could not find 'time' line" error * Ensure dnsmasq logging is enabled in `/etc/config/dhcp`: ``` option logqueries '1' ``` * Verify log file location matches `LOGFILE` variable in script * Manually trigger cache dump: `killall -USR1 dnsmasq` * Check log file: `tail /var/log/dnsmasq` ### Duplicate cache dumps * The script automatically targets only the actual dnsmasq process (not the ujail wrapper) * If issues persist, check PIDs: `pidof dnsmasq` ### Formatting issues * Check that your dnsmasq version outputs standard cache dump format ## Technical Details ### How It Works 1. **Signal dnsmasq**: Sends SIGUSR1 to the dnsmasq process to trigger cache dump 2. **Find latest dump**: Searches for the most recent "time" line in the log 3. **Extract timestamp**: Preserves exact syslog timestamp format (handles single-digit days) 4. **Filter logs**: Uses grep to extract only lines matching that timestamp 5. **Format output**: Removes syslog prefix while preserving column spacing ### Why the `sh -c` wrapper for the kill command? OpenWrt's Custom Commands interface aggressively quotes command arguments, breaking pipes and command substitution. Wrapping in `sh -c` forces the entire command to be executed as a single shell string. ## Files * `show_dnsmasq_cache.sh` - Main script to display formatted cache * `README.md` - This file ## License Public domain ## Contributing Found a bug or have an improvement? Feel free to modify and share! ## Credits Tested and developed on OpenWrt 24.10 in busybox/ash environment by scarlion1@GitHub, with assistance from Claude Sonnet 4.5 provided by Abacus.AI. Check them out for affordable, unparalleled services and access to every LLM for only $10/mo. Use my referral link https://chatllm.abacus.ai/YwBngMwYCw and I'll give you a cookie. This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,27 @@ #!/bin/ash # Script to parse dnsmasq cache & stat's using timestamp-matching logic. LOGFILE="/var/log/dnsmasq" # Find the *very last* "time" line in the log. This is our key. LAST_TIME_LINE=$(grep ": time " "$LOGFILE" | tail -n 1) # Check if we actually found a dump if [ -z "$LAST_TIME_LINE" ]; then echo "Error: Could not find 'time' line in dnsmasq log." echo "Please check that logqueries is enabled and logging to $LOGFILE" exit 1 fi # Extract the literal timestamp preserving exact spacing # Use sed to extract everything before the hostname # (first 15 chars for syslog format) TIMESTAMP=$(echo "$LAST_TIME_LINE" | cut -c 1-15) # Print a header with timestamp echo "Dnsmasq cache stat's & contents as of: $TIMESTAMP" # Grep the log file for *only* lines matching that exact timestamp. # Remove the timestamp and dnsmasq prefix while preserving spacing. grep "^$TIMESTAMP" "$LOGFILE" | sed 's/^[A-Za-z]* *[0-9]* [0-9:]* [^ ]* dnsmasq\[[0-9]*\]: //'