Skip to content

Instantly share code, notes, and snippets.

@scarlion1
Created November 2, 2025 22:54
Show Gist options
  • Select an option

  • Save scarlion1/fb992017e18f9af7e8d2be1a28bfddef to your computer and use it in GitHub Desktop.

Select an option

Save scarlion1/fb992017e18f9af7e8d2be1a28bfddef to your computer and use it in GitHub Desktop.
OpenWrt Dnsmasq Cache Viewer for Custom Commands (luci-app-commands)

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:
chmod +x /usr/bin/show_dnsmasq_cache.sh

Usage

Command Line

1. Dump the cache:

kill -USR1 $(pidof dnsmasq | awk '{print $1}')

2. Run the script:

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)

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.

#!/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]*\]: //'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment