digツールはdoggoが便利

Table of Contents

背景・動機

インフラ構築する時にdigを叩くことは必須なのだが、2025年にdigコマンドをそのまま使うのは流石に辛い。 もう少しリッチなものがないか調べた所、doggoが良さそうだったので導入してみた。

試したこと・やったこと

0. ツール選定

Rust製のツールに dog というものがあるが、最終更新が2021年前と期間が空いてる。

後継にあたるツールがないかなと思って調査した所、Golang製の doggo というツールがあった。

It’s totally inspired by dog which is written in Rust. I wanted to add some features to it but since I don’t know Rust, I found it as a nice opportunity to experiment with writing a DNS Client from scratch in Go myself. Hence the name dog + go => doggo.

Nixでパッケージングされているし、CLIとしての完成度も高く、アクティブなプロジェクトだったので導入した。

1. home-manager module用意

特に設定項目がないのでshell completionだけ有効にしている。

{
  pkgs,
  lib,
  config,
  ...
}:
let
  cfg = config.programs.doggo;
in
with lib;
{
  options.programs.doggo = {
    enable = mkEnableOption "Command-line DNS Client for Humans. Written in Golang";
    package = mkPackageOption pkgs "doggo" { };

    enableBashIntegration = lib.hm.shell.mkBashIntegrationOption { inherit config; };

    enableZshIntegration = lib.hm.shell.mkZshIntegrationOption { inherit config; };

    enableFishIntegration = lib.hm.shell.mkFishIntegrationOption { inherit config; };
  };

  config = mkIf cfg.enable {
    home.packages = [ cfg.package ];

    programs = {
      bash.initExtra = mkIf (cfg.enableBashIntegration && cfg.package != null) ''
        eval "$(${getExe cfg.package} completions bash)"
      '';

      zsh.initContent = mkIf (cfg.enableZshIntegration && cfg.package != null) ''
        eval "$(${getExe cfg.package} completions zsh)"
      '';

      fish.interactiveShellInit = mkIf (cfg.enableFishIntegration && cfg.package != null) ''
        ${getExe cfg.package} completions fish | source
      '';
    };
  };
}

あとは programs.doggo.enable = true; で有効にするだけで使えるようになる。

2. 実際に使ってみる

helpを引くとquicやtlsにも対応してることが分かる。

NAME:
  doggo üê∂ DNS Client for Humans

USAGE:
  doggo [--] [query options] [arguments...]

VERSION:
  v1.1.2 - unknown

EXAMPLES:
  doggo mrkaran.dev                             Query a domain using defaults.
  doggo mrkaran.dev CNAME                       Query for a CNAME record.
  doggo mrkaran.dev MX @9.9.9.9                 Uses a custom DNS resolver.
  doggo -q mrkaran.dev -t MX -n 1.1.1.1         Using named arguments.
  doggo mrkaran.dev --aa --ad                   Query with Authoritative Answer and Authenticated Data flags set.
  doggo mrkaran.dev --cd --do                   Query with Checking Disabled and DNSSEC OK flags set.
  doggo mrkaran.dev --gp-from Germany           Query using Globalping API from a specific location.

FREE FORM ARGUMENTS:
  Supply hostnames, query types, and classes without flags. Example:
  doggo mrkaran.dev A @1.1.1.1

TRANSPORT OPTIONS:
  Specify the protocol with a URL-type scheme.
  UDP is used if no scheme is specified.
  @udp://     eg: @1.1.1.1                                                        initiates a UDP query to 1.1.1.1:53.
  @tcp://     eg: @tcp://1.1.1.1                                                  initiates a TCP query to 1.1.1.1:53.
  @https://   eg: @https://cloudflare-dns.com/dns-query                           initiates a DOH query to Cloudflare via DoH.
  @tls://     eg: @tls://1.1.1.1                                                  initiates a DoT query to 1.1.1.1:853.
  @sdns://    initiates a DNSCrypt or DoH query using a DNS stamp.
  @quic://    initiates a DOQ query.

SUBCOMMANDS:
  completions [bash|zsh|fish]   Generate the shell completion script for the specified shell.

QUERY OPTIONS:
  -q, --query=HOSTNAME          Hostname to query the DNS records for (eg mrkaran.dev).
  -t, --type=TYPE               Type of the DNS Record (A, MX, NS etc).
  -n, --nameserver=ADDR         Address of a specific nameserver to send queries to (9.9.9.9, 8.8.8.8 etc).
  -c, --class=CLASS             Network class of the DNS record (IN, CH, HS etc).
  -x, --reverse                 Performs a DNS Lookup for an IPv4 or IPv6 address. Sets the query type and class to PTR and IN respectively.
  --any                         Query all supported DNS record types (A, AAAA, CNAME, MX, NS, PTR, SOA, SRV, TXT, CAA).

RESOLVER OPTIONS:
  --strategy=STRATEGY           Specify strategy to query nameserver listed in etc/resolv.conf. (all, random, first).
  --ndots=INT                   Specify ndots parameter. Takes value from /etc/resolv.conf if using the system namesever or 1 otherwise.
  --search                      Use the search list defined in resolv.conf. Defaults to true. Set --search=false to disable search list.
  --timeout=DURATION            Specify timeout for the resolver to return a response (e.g., 5s, 400ms, 1m).
  -4, --ipv4                    Use IPv4 only.
  -6, --ipv6                    Use IPv6 only.
  --tls-hostname=HOSTNAME       Provide a hostname for verification of the certificate if the provided DoT nameserver is an IP.
  --skip-hostname-verification  Skip TLS Hostname Verification in case of DOT Lookups.

QUERY FLAGS:
  --aa                          Set Authoritative Answer flag.
  --ad                          Set Authenticated Data flag.
  --cd                          Set Checking Disabled flag.
  --rd                          Set Recursion Desired flag (default: true).
  --z                           Set Z flag (reserved for future use).
  --do                          Set DNSSEC OK flag.

EDNS OPTIONS:
  --nsid                        Request Name Server Identifier (NSID) to identify the nameserver.
  --cookie                      Request DNS Cookie for enhanced security and protection against spoofing.
  --padding                     Request EDNS padding for privacy. Helps mitigate traffic analysis attacks.
  --ede                         Request Extended DNS Errors for detailed error information.
  --ecs=SUBNET                  EDNS Client Subnet (e.g., '192.0.2.0/24' or '2001:db8::/32'). Send client subnet for geo-aware responses.

OUTPUT OPTIONS:
  -J, --json                    Format the output as JSON.
  --short                       Short output format. Shows only the response section.
  --color                       Defaults to true. Set --color=false to disable colored output.
  --debug                       Enable debug logging.
  --time                        Shows how long the response took from the server.

GLOBALPING OPTIONS:
  --gp-from=Germany             Query using Globalping API from a specific location.
  --gp-limit=INT                Limit the number of probes to use from Globalping.

雑に takeokunn.org のNSを引くとこんな感じで出力される。

$ doggo takeokunn.org NS
NAME                     TYPE  CLASS  TTL    ADDRESS                  NAMESERVER
takeokunn.org.           NS    IN     3600s  bob.ns.cloudflare.com.   192.168.2.1:53
takeokunn.org.           NS    IN     3600s  mina.ns.cloudflare.com.  192.168.2.1:53
bob.ns.cloudflare.com.   A     IN     3041s  108.162.193.104          192.168.2.1:53
bob.ns.cloudflare.com.   A     IN     3041s  172.64.33.104            192.168.2.1:53
bob.ns.cloudflare.com.   A     IN     3041s  173.245.59.104           192.168.2.1:53
mina.ns.cloudflare.com.  A     IN     3366s  108.162.194.251          192.168.2.1:53
mina.ns.cloudflare.com.  A     IN     3366s  162.159.38.251           192.168.2.1:53
mina.ns.cloudflare.com.  A     IN     3366s  172.64.34.251            192.168.2.1:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2606:4700:58::adf5:3b68  192.168.2.1:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2803:f800:50::6ca2:c168  192.168.2.1:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2a06:98c1:50::ac40:2168  192.168.2.1:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2606:4700:50::a29f:26fb  192.168.2.1:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2803:f800:50::6ca2:c2fb  192.168.2.1:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2a06:98c1:50::ac40:22fb  192.168.2.1:53
takeokunn.org.           NS    IN     3600s  bob.ns.cloudflare.com.   192.168.2.1:53
takeokunn.org.           NS    IN     3600s  mina.ns.cloudflare.com.  192.168.2.1:53
bob.ns.cloudflare.com.   A     IN     3041s  108.162.193.104          192.168.2.1:53
bob.ns.cloudflare.com.   A     IN     3041s  172.64.33.104            192.168.2.1:53
bob.ns.cloudflare.com.   A     IN     3041s  173.245.59.104           192.168.2.1:53
mina.ns.cloudflare.com.  A     IN     3366s  108.162.194.251          192.168.2.1:53
mina.ns.cloudflare.com.  A     IN     3366s  162.159.38.251           192.168.2.1:53
mina.ns.cloudflare.com.  A     IN     3366s  172.64.34.251            192.168.2.1:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2606:4700:58::adf5:3b68  192.168.2.1:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2803:f800:50::6ca2:c168  192.168.2.1:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2a06:98c1:50::ac40:2168  192.168.2.1:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2606:4700:50::a29f:26fb  192.168.2.1:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2803:f800:50::6ca2:c2fb  192.168.2.1:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2a06:98c1:50::ac40:22fb  192.168.2.1:53
takeokunn.org.           NS    IN     3600s  mina.ns.cloudflare.com.  [2408:210:102:4b00:32be:3bff:fe16:7102]:53
takeokunn.org.           NS    IN     3600s  bob.ns.cloudflare.com.   [2408:210:102:4b00:32be:3bff:fe16:7102]:53
bob.ns.cloudflare.com.   A     IN     3041s  108.162.193.104          [2408:210:102:4b00:32be:3bff:fe16:7102]:53
bob.ns.cloudflare.com.   A     IN     3041s  172.64.33.104            [2408:210:102:4b00:32be:3bff:fe16:7102]:53
bob.ns.cloudflare.com.   A     IN     3041s  173.245.59.104           [2408:210:102:4b00:32be:3bff:fe16:7102]:53
mina.ns.cloudflare.com.  A     IN     3366s  108.162.194.251          [2408:210:102:4b00:32be:3bff:fe16:7102]:53
mina.ns.cloudflare.com.  A     IN     3366s  162.159.38.251           [2408:210:102:4b00:32be:3bff:fe16:7102]:53
mina.ns.cloudflare.com.  A     IN     3366s  172.64.34.251            [2408:210:102:4b00:32be:3bff:fe16:7102]:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2606:4700:58::adf5:3b68  [2408:210:102:4b00:32be:3bff:fe16:7102]:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2803:f800:50::6ca2:c168  [2408:210:102:4b00:32be:3bff:fe16:7102]:53
bob.ns.cloudflare.com.   AAAA  IN     3041s  2a06:98c1:50::ac40:2168  [2408:210:102:4b00:32be:3bff:fe16:7102]:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2606:4700:50::a29f:26fb  [2408:210:102:4b00:32be:3bff:fe16:7102]:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2803:f800:50::6ca2:c2fb  [2408:210:102:4b00:32be:3bff:fe16:7102]:53
mina.ns.cloudflare.com.  AAAA  IN     3366s  2a06:98c1:50::ac40:22fb  [2408:210:102:4b00:32be:3bff:fe16:7102]:53

json出力も可能。

$ doggo --json takeokunn.org A | jq .responses.[0]
{
  "answers": [
    {
      "name": "takeokunn.org.",
      "type": "A",
      "class": "IN",
      "ttl": "261s",
      "address": "185.199.111.153",
      "status": "",
      "rtt": "9ms",
      "nameserver": "192.168.2.1:53"
    },
    {
      "name": "takeokunn.org.",
      "type": "A",
      "class": "IN",
      "ttl": "261s",
      "address": "185.199.110.153",
      "status": "",
      "rtt": "9ms",
      "nameserver": "192.168.2.1:53"
    },
    {
      "name": "takeokunn.org.",
      "type": "A",
      "class": "IN",
      "ttl": "261s",
      "address": "185.199.108.153",
      "status": "",
      "rtt": "9ms",
      "nameserver": "192.168.2.1:53"
    },
    {
      "name": "takeokunn.org.",
      "type": "A",
      "class": "IN",
      "ttl": "261s",
      "address": "185.199.109.153",
      "status": "",
      "rtt": "9ms",
      "nameserver": "192.168.2.1:53"
    }
  ],
  "authorities": null,
  "questions": [
    {
      "name": "takeokunn.org.",
      "type": "A",
      "class": "IN"
    }
  ]
}

得られた結果・所感

digよりも圧倒的に読み易くなったし、tlsやquicにも対応してるのはありがたい。

今後の展開・検討事項

digツールは自分でも自作できるのでいつかやってみたい。