How to Efficiently Search Linux DNS Cache Using a Bash Script for IT Professionals

In today’s IT landscape, efficient network management is crucial. A key component of this management is DNS (Domain Name System) caching, which can significantly enhance network performance by reducing the time it takes to resolve domain names.

For IT professionals, particularly those managing multiple systems, understanding and utilizing DNS cache information is vital. This blog post will explore a Bash script designed to search DNS cache entries on Linux systems, providing a detailed breakdown of how it works, its use cases, and best practices for implementation.

Background

DNS caching stores the results of DNS queries locally on a device, which allows for quicker responses to subsequent requests for the same domain names. While servers generally do not have DNS cache services enabled by default, certain desktop environments like GNOME or KDE often do, using services like systemd-resolved or dnsmasq.

This script is designed to help IT professionals and Managed Service Providers (MSPs) search and retrieve DNS cache entries on Linux systems. The ability to search through DNS cache entries can be crucial for troubleshooting network issues, investigating potential security incidents, or simply optimizing network performance.

By providing a systematic way to access and filter these entries, the script helps streamline tasks that might otherwise require more complex or time-consuming methods.

The Script:

#!/usr/bin/env bash

# Description: Find DNS Cache entries on a Linux system. Supports systemd-resolved and dnsmasq(requires log-facility to be configured).
#
# Servers usually do not have a DNS cache service installed by default.
# systemd-resolved is commonly installed along with most Desktop Environments, such as GNOME and KDE.
#
# Release Notes: Initial Release
#   By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
#   Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
#   Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
#   Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
#   Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
#   Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
#   Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
#   EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).

# A comma separated list of keywords to search for in the DNS cache. Example: "google,comcast,cloudflare"
keywords_to_search=$1
# A multiline custom field to save the DNS cache entries.
multiline_custom_field=$2

# Check if the multilineCustomField is set
if [[ -n "${multilineCustomField}" && "${multilineCustomField}" != "null" ]]; then
    multiline_custom_field=$multilineCustomField
fi

# Check if the keywordsToSearch is set
if [[ -n "${keywordsToSearch}" && "${keywordsToSearch}" != "null" ]]; then
    keywords_to_search=$keywordsToSearch
fi

# Check if the keywords_to_search is set
if [[ -z "${keywords_to_search}" ]]; then
    echo "[Info] keywords_to_search is not set."
    exit 1
else
    # Split the keywords_to_search into an array
    OLDIFS=$IFS
    IFS=',' read -r -a keywords <<<"${keywords_to_search}"
    IFS=$OLDIFS
    # Trim trailing and leading whitespace from each keyword
    keywords=("${keywords[@]/ /}")

fi

# Check if the multiline_custom_field is set
if [[ -z "${multiline_custom_field}" ]]; then
    echo "[Info] multilineCustomField is not set."
fi

# Check if ninjarmm-cli command exists in the default path
ninjarmm_cli="/opt/NinjaRMMAgent/programdata/ninjarmm-cli"
if [[ -z $ninjarmm_cli ]]; then
    echo "[Error] The ninjarmm-cli command does not exist in the default path. Please ensure the NinjaRMM agent is installed before running this script."
    exit 1
else
    # ninjarmm-cli command exists in the default path
    echo -n
fi

# Check that we are running as root
if [[ $EUID -ne 0 ]]; then
    echo "[Error] This script must be run as root."
    exit 1
fi

# Check for which dns cache service is installed
if [ "$(command -v resolvectl)" ]; then
    # resolvectl is installed
    dns_cache_service="resolvectl"
elif [ "$(command -v dnsmasq)" ]; then
    # dnsmasq is installed
    dns_cache_service="dnsmasq"
else
    # no dns cache service is installed
    echo "[Error] No DNS cache service is installed on this system that this script supports."
    echo ""
    echo "[Info] Supported DNS cache services: systemd-resolved, dnsmasq"
    echo "[Info] systemd-resolved commonly installed along with a Desktop Environment."
    echo "[Info] Servers usually do not have a DNS cache service installed by default."
    echo ""
    echo "[Info] Installing a DNS cache is not recommended on servers."
    exit 1
fi

# Check if the dns_cache_service is resolvectl
if [[ "${dns_cache_service}" == "resolvectl" ]]; then
    systemdVersion=$(systemctl --version | head -1 | awk '{ print $2}')
    if [ "$systemdVersion" -lt 254 ]; then
        echo "[Error] The version of systemd is less than 254. The resolvectl show-cache command is not available. Currently system version is ${systemdVersion}."
        exit 1
    fi
    # Get the DNS cache entries from resolvectl
    # https://github.com/systemd/systemd/pull/28012
    if ! dns_cache=$(resolvectl show-cache 2>/dev/null); then
        # Check if the systemd-resolved service is active
        if [[ $(systemctl is-active systemd-resolved) != "active" ]]; then
            echo "[Warn] The systemd-resolved service is not active."
        # Check /etc/resolv.conf that the nameserver is set to the default IP address 127.0.0.53 for systemd-resolved to work
        elif ! grep -q "^nameserver 127.0.0.53" /etc/resolv.conf; then
            echo "[Warn] The nameserver in /etc/resolv.conf is not set to an IP address 127.0.0.53 ."
            echo "[Info] The nameserver in /etc/resolv.conf should be set to an IP address 127.0.0.53 for systemd-resolved to work."
        else
            echo "[Warn] Failed to get the DNS cache entries. Is systemd-resolved installed, configured, and running?"
        fi
        echo ""
        echo "[Info] Supported DNS cache services: systemd-resolved, dnsmasq"
        echo "[Info] systemd-resolved commonly installed along with a Desktop Environment."
        echo "[Info] Servers usually do not have a DNS cache service installed by default."
        echo ""
        echo "[Info] Installing a DNS cache is not recommended on servers."
        exit 0
    fi

    dns_cache_entries=""
    # Get the DNS cache entries from resolvectl based on the keywords provided
    for keyword in "${keywords[@]}"; do
        # Example DNS cache entry:
        # consto.com IN A 123.123.123.123
        # consto.com IN AAAA 2001:0db8:85a3:0000:0000:8a2e:0370:7334
        dns_cache_entries+="DNS Cache Records Matching: ${keyword}"
        dns_cache_entries+=$'\n' # newline
        dns_cache_entries+=$(echo "$dns_cache" | grep -i -E "${keyword}")
        dns_cache_entries+=$'\n' # newline
    done
    # Print the DNS cache entries
    echo "" # newline
    echo "$dns_cache_entries"
# Check if the dns_cache_service is dnsmasq
elif [[ "${dns_cache_service}" == "dnsmasq" ]]; then
    if [ -f "/etc/dnsmasq.conf" ]; then
        echo "[Info] dnsmasq configuration file exists."
    else
        echo "[Warn] The dnsmasq configuration file does not exist and is likely not installed or configured."
        echo ""
        echo "[Info] Supported DNS cache services: systemd-resolved, dnsmasq"
        echo "[Info] systemd-resolved commonly installed along with a Desktop Environment."
        echo "[Info] Servers usually do not have a DNS cache service installed by default."
        echo ""
        echo "[Info] Installing a DNS cache is not recommended on servers."
        exit 0
    fi
    # Check that log-queries is enabled in the dnsmasq configuration file
    if ! grep -q "log-queries" /etc/dnsmasq.conf; then
        echo "[Warn] The 'log-queries' option is not enabled in the dnsmasq configuration file."
        echo ""
        echo "[Info] Supported DNS cache services: systemd-resolved, dnsmasq"
        echo "[Info] systemd-resolved commonly installed along with a Desktop Environment."
        echo "[Info] Servers usually do not have a DNS cache service installed by default."
        echo ""
        echo "[Info] Installing a DNS cache is not recommended on servers."
        exit 0
    fi
    # Get the log-facility from the dnsmasq configuration file
    log_facility=$(grep -E "^log-facility" /etc/dnsmasq.conf | awk '{print $2}')
    if [[ -z "${log_facility}" ]]; then
        echo "[Warn] The 'log-facility' option is not set in the dnsmasq configuration file."
        echo ""
        echo "[Info] Supported DNS cache services: systemd-resolved, dnsmasq"
        echo "[Info] systemd-resolved commonly installed along with a Desktop Environment."
        echo "[Info] Servers usually do not have a DNS cache service installed by default."
        echo ""
        echo "[Info] Installing a DNS cache is not recommended on servers."
        exit 0
    fi
    # Check that log_facility is a valid file
    if [[ ! -f "${log_facility}" ]]; then
        echo "[Error] The log facility file '${log_facility}' does not exist."
        echo ""
        echo "[Info] Supported DNS cache services: systemd-resolved, dnsmasq"
        echo "[Info] systemd-resolved commonly installed along with a Desktop Environment."
        echo "[Info] Servers usually do not have a DNS cache service installed by default."
        echo ""
        echo "[Info] Installing a DNS cache is not recommended on servers."
        exit 1
    fi
    # Get the DNS cache entries from log_facility
    # Example log_facility file:
    # Jan  1 00:00:00 dnsmasq[12345]: query[A] example.com from
    for keyword in "${keywords[@]}"; do
        # Get the DNS cache entries from the log_facility file
        # The awk command parses the log_facility file and extracts the time, query, and host
        if ! dns_cache_entries=$(grep -i -E "${keyword}" "${log_facility}" | awk 'BEGIN {OFS = ",";}$5 == "query[A]" {time = mktime(sprintf("%04d %02d %02d %s\n",strftime("%Y", systime()),(match("JanFebMarAprMayJunJulAugSepOctNovDec",$1)+2)/3,$2,gensub(":", " ", "g", $3)));query = $6;host = $8;print time, host, query;}'); then
            echo "[Error] Failed to get the DNS cache entries."
            echo "$dns_cache_entries"
            echo ""
            echo "[Info] Supported DNS cache services: systemd-resolved, dnsmasq"
            echo "[Info] systemd-resolved commonly installed along with a Desktop Environment."
            echo "[Info] Servers usually do not have a DNS cache service installed by default."
            echo ""
            echo "[Info] Installing a DNS cache is not recommended on servers."
            exit 1
        fi
    done
    echo "$dns_cache_entries"
fi

# Set the multiline_custom_field
if [[ -n "$multiline_custom_field" ]]; then
    if [[ -x "$ninjarmm_cli" ]]; then
        if hideOutput=$(echo "$dns_cache_entries" | "$ninjarmm_cli" set --stdin "$multiline_custom_field" 2>&1); then
            echo "[Info] Successfully set custom field: $multiline_custom_field"
        else
            echo "[Error] Failed to set custom field: $multiline_custom_field. Custom Field does not exist or does not have write permissions."
            exit 1
        fi
    else
        echo "[Error] NinjaRMM CLI not found or not executable"
        exit 1
    fi
fi

 

Access over 300+ scripts in the NinjaOne Dojo

Get Access

Detailed Breakdown

The script is structured to handle different DNS caching services (systemd-resolved and dnsmasq) that might be present on a Linux system. Here’s a step-by-step explanation of how the script functions:

1. Parameter Setup:

  • The script begins by accepting two parameters: keywords_to_search and multiline_custom_field.
  • keywords_to_search is a comma-separated list of keywords that the script will use to search through DNS cache entries. The script checks if these parameters are set and initializes them accordingly.

2. Environment Check:

  • It checks if the ninjarmm-cli command is available, which is required for the script to interact with the NinjaRMM platform.
  • It verifies if the script is executed with root privileges, as root access is necessary to query DNS caches.

3. DNS Cache Service Detection:

  • The script detects whether systemd-resolved or dnsmasq is installed and active on the system. If neither service is found, the script terminates with an appropriate error message, informing the user that no supported DNS cache service is installed.

4. Handling systemd-resolved:

  • If systemd-resolved is detected, the script checks the version of systemd to ensure it supports the show-cache command (introduced in version 254).
  • The script then queries the DNS cache using resolvectl show-cache and filters the results based on the keywords provided.

5. Handling dnsmasq:

  • If dnsmasq is detected, the script verifies the presence and configuration of the dnsmasq.conf file, ensuring that DNS query logging is enabled.
  • It then searches the log file specified in dnsmasq.conf for DNS queries that match the provided keywords.

6. Output Handling:

  • The script collects and formats the DNS cache entries that match the keywords.
  • If the multiline_custom_field parameter is provided, the script attempts to set this field in NinjaRMM using the ninjarmm-cli command.

Potential Use Cases

Imagine a scenario where an IT professional is tasked with investigating suspicious network activity. They notice unusual traffic patterns and suspect that certain domains are being queried frequently.

Using this script, they can quickly search through the DNS cache for specific keywords (e.g., suspicious domain names) and retrieve relevant entries. This information can then be used to block these domains, adjust firewall settings, or investigate further.

Another scenario could involve optimizing network performance. An MSP managing multiple client networks might use this script to identify frequently accessed domains cached on various systems.

By analyzing these cache entries, the MSP could recommend setting up local DNS servers or caching policies to reduce latency and improve user experience.

Comparisons

While there are other methods to search DNS cache entries on Linux systems, such as manually inspecting log files or using tools like grep in combination with system logs, this script offers a more streamlined and automated approach.

It not only detects the appropriate DNS caching service but also handles potential configuration issues, making it a more user-friendly option, especially for those managing multiple systems.

FAQs

  • What happens if no DNS cache service is installed? The script will terminate and provide a message indicating that no supported DNS cache service is installed, recommending against installing one on servers.
  • Can this script be used on servers? While technically possible, it’s generally not recommended to run DNS cache services on servers, as highlighted by the script’s output messages.
  • Why do I need root privileges to run this script? Accessing DNS cache entries typically requires elevated permissions, which is why the script checks for root access.

Implications

The ability to search and analyze DNS cache entries has significant implications for network security and performance. By quickly identifying and reacting to unusual or malicious domain queries, IT professionals can mitigate potential threats before they escalate. Moreover, regular analysis of DNS cache can help optimize network configurations, leading to improved overall efficiency.

Recommendations

When using this script, ensure that you:

  • Run it with root privileges to avoid permission issues.
  • Verify that systemd-resolved or dnsmasq is properly configured on your system.
  • Regularly update your system to ensure compatibility with the latest features (e.g., systemd version 254 or higher).
  • Use meaningful and relevant keywords to filter DNS cache entries effectively.

Final Thoughts

This DNS cache search script is a powerful tool for IT professionals, especially when integrated with NinjaOne’s management platform. By automating the process of retrieving and analyzing DNS cache entries, it allows for more efficient network management and security monitoring. NinjaOne’s robust suite of tools can further enhance this script’s utility, providing comprehensive solutions for IT management tasks.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

Watch Demo×
×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).