whodis

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 38 Imported by: 0

README

Whodis logo

whodis

A WHOIS alternative that actually understands modern domain infrastructure.
Whodis starts with authoritative RDAP, falls back to WHOIS when needed, follows RWhois referrals, and turns the result into something you can read.

Build status Latest release Release downloads MIT license Linux, macOS, and Windows

Homepage · Download · Install · Quick start · Issues

Classic whois gives you a protocol-era text dump. Whodis 1.0 accepts a domain, IP address, network, or ASN, discovers the right RDAP, WHOIS, or RWhois authority, and organizes the answer into a responsive terminal dashboard. It also grows into a full domain workstation when you need it: inventory DNS, compare resolvers, verify DNSSEC, trace delegation, diagnose web and mail service, or export a stable machine-readable report.

Output made for humans—and scripts

  • Responsive terminal dashboard — a spreadsheet-like panel grid that uses the available width without repeating contacts, notices, or nameservers.
  • Multiple personalities — dashboard, semantic tree, retro GeekBoys ASCII, and portable plain text are one switch away.
  • Structured output — versioned JSON and YAML support automation, while portable Markdown turns operation results into a readable report.
  • Focused batch tables — check many targets, select fields such as expiration and registrar, and write directly to a file.
  • Raw source access — preserve the original RDAP JSON, WHOIS, or RWhois response when one unmodified registration lookup is what you need.
  • Native desktop workbench — Lookup, DNS Inventory, DNS Query, Compare, Delegation, Diagnose, Services, Findings, Contacts, and Raw views without a browser or a separately installed CLI.

See it in action

Registration overview · Live RDAP lookup for cyberbrand.net

Whodis registration lookup for cyberbrand.net

Whodis DNS scan showing public records for cyberbrand.netWhodis diagnosis showing DNS, web, TLS, mail, and policy findings for cyberbrand.net
Public DNS inventory Domain diagnosis

Concurrent batch lookup · Check and export many domains in one run

Whodis batch lookup showing four completed domain checks

The terminal dashboard rearranges the same normalized data into a wide mosaic or a narrow single-column view. Long registry notices are deduplicated and summarized; --details expands them.

Install

Whodis releases two independent applications from one codebase:

  • whodis is the small CLI for shells, scripts, SSH sessions, and servers.
  • whodis-gui is the native desktop app. It bundles a private Whodis engine and does not require the CLI on PATH.

Linux and macOS CLI

curl -fsSL https://github.com/Alex9001/whodis/releases/latest/download/install.sh | sh

The installer detects the operating system and CPU, verifies SHA-256 against the release checksums, and installs whodis into /usr/local/bin. It asks for sudo only when the destination is not writable.

Windows CLI

Run this in PowerShell; an administrator window is not required:

irm https://github.com/Alex9001/whodis/releases/latest/download/install.ps1 | iex

The installer verifies the archive, installs under local application data, and adds the directory to the user PATH. Open a new terminal and type whodis.

Go, archives, and Arch Linux

go install github.com/Alex9001/whodis/cmd/whodis@latest

Prebuilt CLI archives are published for Linux, macOS, Windows, FreeBSD, and OpenBSD on amd64 and supported arm64 targets. Source-built AUR definitions for whodis and whodis-gui are ready; the maintainer's one-time account and key steps are in AUR_HANDOFF.md.

Each release also carries installable .deb, .rpm, .apk, and Arch Linux packages. An optional non-root multi-architecture container is published to GitHub Container Registry:

docker run --rm ghcr.io/alex9001/whodis example.com

Desktop app

Download whodis-gui from the latest GitHub Release:

  • Linux: run the amd64 or arm64 AppImage.
  • Windows: use the per-user setup executable or portable ZIP.
  • macOS: open the universal DMG and drag Whodis into Applications.

Desktop packages are not code-signed or notarized. Windows SmartScreen and macOS Gatekeeper will warn on first launch. Verify the published SHA-256 checksum or GitHub build attestation, then use More info → Run anyway on Windows or Open Anyway in macOS Privacy & Security settings.

Quick start

Registration stays effortless:

whodis google.com
whodis 8.8.8.8
whodis AS15169

Ask for the operation you want when you need more:

# Registration plus a practical public-DNS inventory, including MX
whodis scan example.com

# Arbitrary DNS types or numeric TYPE values
whodis dns query example.com A AAAA MX HTTPS TYPE257

# Compare normalized answers from recursive and authoritative resolvers
whodis dns compare example.com A

# Follow delegation iteratively from a root server
whodis dns trace example.com NS

# Bounded DNS, reachability, HTTP, TLS, SMTP, and mail-policy checks
whodis diagnose example.com

A full DNS client, not a decorative lookup

whodis dns query accepts named or numeric record types and classes. Resolver URIs select the transport explicitly:

Resolver form Transport
system, 1.1.1.1, udp://1.1.1.1 UDP with automatic TCP retry on truncation
tcp://1.1.1.1 DNS over TCP
tls://dns.example or dot://… DNS over TLS
https://…/dns-query DNS over HTTPS
h3://…/dns-query DNS over HTTP/3
doq://dns.example DNS over QUIC
sdns://… DNSCrypt stamp

Responses retain header flags, timing, transport, resolver identity, answer, authority, additional records, raw wire bytes, EDNS Extended DNS Errors, and a DNSSEC state. EDNS controls include buffer size, DO, NSID, explicit ECS, cookie, padding, checking-disabled, and recursion behavior.

whodis dns query example.com MX TXT --resolver tls://dns.quad9.net --dnssec

whodis dns compare example.com A \
  --resolver https://cloudflare-dns.com/dns-query \
  --resolver tls://dns.google \
  --strategy consensus

whodis dns transfer example.com --ixfr --serial 12345 --tls

Compare ignores TTL and answer order when deciding whether resolvers disagree. Trace follows referrals from embedded root hints and reports glue, missing glue, lame delegation, and DNSSEC delegation state. AXFR and IXFR are always explicit, bounded by a record safety limit, and support TSIG and TLS.

With --dnssec, Whodis locally verifies positive signed answer RRsets and their DNSKEY/DS chain against embedded IANA root trust anchors. It reports secure, insecure, bogus, or indeterminate rather than blindly trusting a resolver's AD bit.

Optional worldwide DNS views

Globalping is strictly opt-in because it sends the target and location request to a third-party service and may consume API quota:

whodis dns query example.com A --globalping --from US --from Europe --limit 3
whodis diagnose example.com --remote

Set GLOBALPING_TOKEN when using authenticated quota. Whodis has no telemetry, account system, or background network activity of its own.

Diagnose without becoming a port scanner

whodis diagnose uses only endpoints derived from the target and its published configuration. Work is time-bounded and capped:

  • DNS inventory with local DNSSEC validation and iterative delegation tracing
  • representative IPv4 and IPv6 reachability
  • apex and www HTTP/HTTPS status and redirect chains
  • TLS identity, certificate dates, cipher, version, and ALPN
  • sampled MX SMTP greeting, EHLO capabilities, STARTTLS, and TLS verification
  • SPF, DMARC, MTA-STS, and TLS-RPT discovery, plus MTA-STS policy retrieval
  • DNS-advertised SRV, SVCB, and HTTPS service endpoints
  • optional local path trace with --trace

Findings are deterministic pass, info, warning, or error observations with evidence. There is deliberately no opaque overall score and no arbitrary port-range scanner.

Batch checks and files

Most registration and workstation commands accept several targets and preserve input order while using bounded concurrency:

whodis expires google.com yahoo.com
whodis get expiration,registrar,status -i domains.txt -o results.txt
whodis diagnose example.com example.net --json -o diagnosis.json
printf 'google.com\nyahoo.com\n' | whodis expires

Use --jobs 1 through --jobs 32 to control concurrency. Individual failures remain attributed to their input and do not erase successful results. Existing files are protected unless --force is supplied. .json, .yaml, .md, and .txt output names select their formats automatically.

Choose defaults once

Run the interactive wizard:

whodis config

It configures six preferences: output layout, color, notice detail, default DNS resolver, multi-resolver strategy, and DNSSEC requests. Press Enter to retain a choice or review everything before saving. Direct commands are available for automation:

whodis config set format tree
whodis config set resolver 'https://cloudflare-dns.com/dns-query'
whodis config set strategy consensus
whodis config set dnssec on
whodis config get resolver
whodis config reset

Command-line options always override saved defaults; --no-dnssec provides an explicit one-run override. Generate shell completion with whodis completion bash|zsh|fish|powershell.

Command shape

whodis <target>
whodis registration <target...>
whodis scan <domain...>
whodis dns query <name> [TYPE...]
whodis dns compare <name> [TYPE...]
whodis dns trace <name> [TYPE]
whodis dns transfer <zone>
whodis diagnose <domain...>
whodis expires <target...>
whodis get <fields> <target...>

Add --dashboard, --tree, --geekboys, --plain, --json, --yaml, or --markdown to select output. whodis help dns, whodis help diagnose, and whodis help advanced document operation-specific controls. The older scan and axfr spellings remain available for compatibility.

How registration routing works

Whodis caches IANA's RDAP bootstrap registries for domains, IPv4, IPv6, and ASNs. Domain routes use the longest registry suffix; IP routes use the longest network prefix; ASN routes use the published number ranges. HTTPS endpoints are preferred and alternate endpoints are tried before changing protocol.

When no RDAP service is published, Whodis asks whois.iana.org for the authoritative WHOIS server and follows a bounded referral chain. It follows a published rwhois:// referral automatically. A direct authority can be forced with whodis rdap|whois|rwhois ... --server; RWhois direct mode requires the server because no global RWhois bootstrap exists.

Automatic routing falls back only for an unavailable or unusable service. Authoritative not-found and rate-limit responses remain visible. --try-both widens diagnostic fallback and --strict disables it.

Go SDK and report schema

The supported public API is renderer-independent. The CLI and GUI both call the same concurrency-safe Engine and provider boundaries:

engine := whodis.NewEngine(whodis.EngineOptions{})
report, err := engine.Run(ctx, whodis.Request{
    Operation: whodis.OperationDNSQuery,
    Target:    "example.com",
    DNS:       whodis.DNSOptions{Types: []string{"A", "AAAA", "MX"}},
})
err = whodis.RenderReport(os.Stdout, report, whodis.FormatJSON, whodis.RenderOptions{})

Report schema version 3 keeps registration, DNS, diagnosis, findings, and provider-scoped errors independent, so one failed registry or probe does not erase useful results. Engine.RunBatch preserves input order, accepts bounded workers, supports cancellation, and emits progress callbacks. Registration, DNS, and Diagnose providers are interfaces for embedding and deterministic tests.

The established Client, LookupResult schema v2, Render, and legacy batch API remain available for registration-focused integrations. The native GUI's private newline-delimited JSON-RPC protocol is version 2 and carries schema-v3 reports, progress, cancel, in-memory result tokens, and exports.

Development and release integrity

git clone https://github.com/Alex9001/whodis.git
cd whodis
go test -race ./...
go vet ./...
go run ./cmd/whodis example.com

The desktop build additionally needs CMake, Ninja, Qt 6 Core/Gui/Widgets/Test, and a C++17 compiler; source builds require Go 1.25 or newer. See desktop/README.md. Tests use fixtures and in-memory protocol sessions rather than consuming public registry or Globalping quota.

Release automation cross-builds the pure-Go CLI, builds native desktop bundles, runs race and vulnerability checks, generates SHA-256 checksums and SBOMs, and attests release provenance. Releases remain split into CLI and GUI assets so a server never needs to install Qt.

Current limitations

  • RWhois has no global bootstrap registry. Automatic discovery needs a published RDAP port43 hint or WHOIS ReferralServer; otherwise use an explicit rwhois --server authority.
  • DNS inventory checks a maintained set of practical owner names and record types; DNS has no universal record-list operation. Only a successful AXFR is a complete zone, and most public authoritative servers correctly refuse it.
  • Local DNSSEC validation currently validates positive signed answer chains. Authenticated denial proofs for NXDOMAIN/NODATA are reported as indeterminate rather than overstated as secure.
  • Path tracing can require operating-system ICMP permissions. Whodis reports a scoped warning when the host does not allow the native probe.
  • Diagnose samples bounded representative addresses, MX hosts, and advertised services. It is evidence collection, not continuous monitoring or an exhaustive security audit.
  • Raw source output is limited to registration responses. Multi-target and workstation operations use human-readable or structured report formats.
  • Authenticated registry accounts, proprietary registry APIs, web scraping, generic port scanning, telemetry, mobile apps, and app-store distribution are intentionally out of scope.
  • Desktop packages are currently unsigned and distributed through GitHub Releases.

License

MIT © 2026 Aleksandr Oreshkin. See LICENSE.

Documentation

Overview

Package whodis provides protocol-aware registration-data lookups.

Its public API intentionally has no terminal or GUI dependency, so the same Client can power the command-line tool, native desktop app, and other clients.

Index

Constants

View Source
const ReportSchemaVersion = 3

ReportSchemaVersion is the version of Whodis's public JSON report schema. Version 3 is operation-oriented: independent registration, DNS, and diagnostic results can coexist without one failed provider erasing another.

Variables

This section is empty.

Functions

func Render

func Render(writer io.Writer, result LookupResult, format Format, options RenderOptions) error

Render writes one successful result in the requested format.

func RenderBatch added in v0.6.0

func RenderBatch(writer io.Writer, batch BatchResult, format Format, options BatchRenderOptions) error

RenderBatch writes a completed batch. Empty Fields preserves complete registration results; non-empty Fields activates the compact projection.

func RenderBatchReport added in v1.0.0

func RenderBatchReport(writer io.Writer, batch BatchReport, format Format, options RenderOptions) error

RenderBatchReport writes schema-v3 reports in request order.

func RenderReport added in v1.0.0

func RenderReport(writer io.Writer, report Report, format Format, options RenderOptions) error

RenderReport writes one schema-v3 engine report. Registration-only reports retain the established Whodis layouts; workstation operations use compact, sectioned tables with the same output-format contract.

func ValidateDNSOptions added in v1.0.0

func ValidateDNSOptions(options DNSOptions) error

ValidateDNSOptions validates public DNS settings without performing network activity. It is useful to configuration UIs and SDK callers.

Types

type AddressProbe added in v1.0.0

type AddressProbe struct {
	Address   string        `json:"address" yaml:"address"`
	Network   string        `json:"network" yaml:"network"`
	Method    string        `json:"method" yaml:"method"`
	Port      uint16        `json:"port,omitempty" yaml:"port,omitempty"`
	Reachable bool          `json:"reachable" yaml:"reachable"`
	Duration  time.Duration `json:"duration_ns" yaml:"duration_ns"`
	Error     string        `json:"error,omitempty" yaml:"error,omitempty"`
}

AddressProbe captures one bounded reachability check.

type BatchError added in v0.6.0

type BatchError struct {
	Kind    ErrorKind `json:"kind" yaml:"kind"`
	Message string    `json:"message" yaml:"message"`
}

BatchError is the safe-to-serialize form of a lookup failure.

type BatchItem added in v0.6.0

type BatchItem struct {
	Input  string        `json:"input" yaml:"input"`
	Result *LookupResult `json:"result,omitempty" yaml:"result,omitempty"`
	Error  *BatchError   `json:"error,omitempty" yaml:"error,omitempty"`
}

BatchItem retains the original input so an invalid target and a successful canonicalized target can be displayed together without losing attribution. Exactly one of Result and Error is set after LookupBatch completes.

type BatchLookupOptions added in v0.6.0

type BatchLookupOptions struct {
	LookupOptions LookupOptions
	Workers       int
	// OnProgress is called once for each completed item. Calls are serialized
	// in completion order and never overlap. The callback may be nil.
	OnProgress func(BatchProgress)
}

BatchLookupOptions controls a concurrent group of independent lookups. Workers defaults to four when it is zero. Per-item lookup errors are returned in BatchResult rather than stopping the rest of the batch.

type BatchProgress added in v0.6.0

type BatchProgress struct {
	Index     int
	Completed int
	Total     int
	Item      BatchItem
}

BatchProgress describes one completed item in an active batch lookup. Index is the item's original input position, while Completed counts all items completed so far regardless of input order.

type BatchRenderOptions added in v0.6.0

type BatchRenderOptions struct {
	RenderOptions
	Fields []ProjectionField
}

BatchRenderOptions controls rendering of batch results. Fields selects the compact projection mode; an empty list renders complete lookup results.

type BatchReport added in v1.0.0

type BatchReport struct {
	SchemaVersion int      `json:"schema_version" yaml:"schema_version"`
	Reports       []Report `json:"reports" yaml:"reports"`
}

BatchReport preserves request order and partial failures.

type BatchRequest added in v1.0.0

type BatchRequest struct {
	Requests   []Request
	Workers    int
	OnProgress func(ProgressEvent)
}

BatchRequest controls a bounded group of independent engine requests.

type BatchResult added in v0.6.0

type BatchResult struct {
	SchemaVersion int         `json:"schema_version" yaml:"schema_version"`
	Items         []BatchItem `json:"items" yaml:"items"`
}

BatchResult is the serializable response returned by Client.LookupBatch. Embedded LookupResult values retain their own schema version.

func (BatchResult) HasErrors added in v0.6.0

func (r BatchResult) HasErrors() bool

HasErrors reports whether any item in the completed batch failed.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is safe to reuse for multiple sequential or concurrent lookups.

func NewClient

func NewClient(options ClientOptions) *Client

NewClient creates a protocol-aware lookup client. It makes no network requests until Route or Lookup is called.

func (*Client) Lookup

func (c *Client) Lookup(ctx context.Context, input string, options LookupOptions) (LookupResult, error)

Lookup resolves one target and returns a stable, renderer-independent model.

func (*Client) LookupBatch added in v0.6.0

func (c *Client) LookupBatch(ctx context.Context, inputs []string, options BatchLookupOptions) (BatchResult, error)

LookupBatch resolves each input independently with bounded concurrency. It preserves order and duplicates, and records an error on the affected item rather than failing the entire operation.

func (*Client) Route

func (c *Client) Route(ctx context.Context, input string, options LookupOptions) (RouteDecision, error)

Route decides which known authority should receive a lookup without making a registration-data query. WHOIS route discovery may query IANA's referral service when the selected protocol is WHOIS.

type ClientOptions

type ClientOptions struct {
	Timeout        time.Duration
	CacheDirectory string
	Adapters       []ProtocolAdapter
}

ClientOptions configures a reusable lookup client.

type DNSDifference added in v1.0.0

type DNSDifference struct {
	Resolver string   `json:"resolver" yaml:"resolver"`
	Missing  []string `json:"missing,omitempty" yaml:"missing,omitempty"`
	Extra    []string `json:"extra,omitempty" yaml:"extra,omitempty"`
}

DNSDifference is one normalized disagreement between resolvers.

type DNSFlags added in v1.0.0

type DNSFlags struct {
	Response           bool `json:"response" yaml:"response"`
	Authoritative      bool `json:"authoritative" yaml:"authoritative"`
	Truncated          bool `json:"truncated" yaml:"truncated"`
	RecursionDesired   bool `json:"recursion_desired" yaml:"recursion_desired"`
	RecursionAvailable bool `json:"recursion_available" yaml:"recursion_available"`
	AuthenticatedData  bool `json:"authenticated_data" yaml:"authenticated_data"`
	CheckingDisabled   bool `json:"checking_disabled" yaml:"checking_disabled"`
}

DNSFlags is the stable subset of a DNS message header useful to callers.

type DNSMessage added in v1.0.0

type DNSMessage struct {
	Name           string        `json:"name" yaml:"name"`
	Type           string        `json:"type" yaml:"type"`
	Class          string        `json:"class" yaml:"class"`
	Resolver       string        `json:"resolver" yaml:"resolver"`
	Transport      string        `json:"transport" yaml:"transport"`
	Server         string        `json:"server" yaml:"server"`
	Duration       time.Duration `json:"duration_ns" yaml:"duration_ns"`
	ID             uint16        `json:"id" yaml:"id"`
	Opcode         string        `json:"opcode" yaml:"opcode"`
	Rcode          string        `json:"rcode" yaml:"rcode"`
	Flags          DNSFlags      `json:"flags" yaml:"flags"`
	Answer         []DNSRecord   `json:"answer,omitempty" yaml:"answer,omitempty"`
	Authority      []DNSRecord   `json:"authority,omitempty" yaml:"authority,omitempty"`
	Additional     []DNSRecord   `json:"additional,omitempty" yaml:"additional,omitempty"`
	ExtendedErrors []string      `json:"extended_errors,omitempty" yaml:"extended_errors,omitempty"`
	DNSSEC         string        `json:"dnssec" yaml:"dnssec"`
	Raw            []byte        `json:"raw,omitempty" yaml:"raw,omitempty"`
	Error          string        `json:"error,omitempty" yaml:"error,omitempty"`
}

DNSMessage captures one complete DNS exchange, including every response section and transport metadata.

type DNSMode added in v0.5.0

type DNSMode string

DNSMode controls optional DNS enrichment for a lookup. A zero-value LookupOptions leaves DNS disabled; DNSAuto remains available for callers that want domain-only discovery without special-casing non-domain targets.

const (
	DNSAuto DNSMode = "auto"
	DNSOff  DNSMode = "off"
	DNSScan DNSMode = "scan"
	DNSAXFR DNSMode = "axfr"
)

type DNSOperationResult added in v1.0.0

type DNSOperationResult struct {
	Mode        string                 `json:"mode" yaml:"mode"`
	Messages    []DNSMessage           `json:"messages,omitempty" yaml:"messages,omitempty"`
	Inventory   *DNSResult             `json:"inventory,omitempty" yaml:"inventory,omitempty"`
	Differences []DNSDifference        `json:"differences,omitempty" yaml:"differences,omitempty"`
	Trace       []DNSTraceHop          `json:"trace,omitempty" yaml:"trace,omitempty"`
	Transfer    *DNSResult             `json:"transfer,omitempty" yaml:"transfer,omitempty"`
	Warnings    []string               `json:"warnings,omitempty" yaml:"warnings,omitempty"`
	Remote      []RemoteDNSMeasurement `json:"remote,omitempty" yaml:"remote,omitempty"`
}

DNSOperationResult is the common result for every DNS engine operation.

type DNSOptions added in v1.0.0

type DNSOptions struct {
	Types                []string         `json:"types,omitempty" yaml:"types,omitempty"`
	Class                string           `json:"class,omitempty" yaml:"class,omitempty"`
	Resolvers            []string         `json:"resolvers,omitempty" yaml:"resolvers,omitempty"`
	Strategy             ResolverStrategy `json:"strategy,omitempty" yaml:"strategy,omitempty"`
	Recursive            *bool            `json:"recursive,omitempty" yaml:"recursive,omitempty"`
	CheckingDisabled     bool             `json:"checking_disabled,omitempty" yaml:"checking_disabled,omitempty"`
	AuthoritativeOnly    bool             `json:"authoritative_only,omitempty" yaml:"authoritative_only,omitempty"`
	EDNS                 EDNSOptions      `json:"edns,omitempty" yaml:"edns,omitempty"`
	Transfer             TransferOptions  `json:"transfer,omitempty" yaml:"transfer,omitempty"`
	Globalping           bool             `json:"globalping,omitempty" yaml:"globalping,omitempty"`
	GlobalpingLocations  []string         `json:"globalping_locations,omitempty" yaml:"globalping_locations,omitempty"`
	GlobalpingLimit      int              `json:"globalping_limit,omitempty" yaml:"globalping_limit,omitempty"`
	GlobalpingToken      string           `json:"-" yaml:"-"`
	GlobalpingEndpoint   string           `json:"-" yaml:"-"`
	GlobalpingHTTPClient *http.Client     `json:"-" yaml:"-"`
}

DNSOptions controls query, inventory, comparison, trace, and transfer.

type DNSProvider added in v1.0.0

DNSProvider is the dependency-injection boundary for DNS operations.

type DNSRecord added in v0.5.0

type DNSRecord struct {
	Name  string `json:"name" yaml:"name"`
	Type  string `json:"type" yaml:"type"`
	TTL   uint32 `json:"ttl" yaml:"ttl"`
	Value string `json:"value" yaml:"value"`
}

DNSRecord is one public DNS resource record. Value is canonical DNS RDATA text, suitable for display and zone-file-oriented export.

type DNSResult added in v0.5.0

type DNSResult struct {
	Method      string      `json:"method" yaml:"method"`
	Complete    bool        `json:"complete" yaml:"complete"`
	Nameservers []string    `json:"nameservers,omitempty" yaml:"nameservers,omitempty"`
	Records     []DNSRecord `json:"records,omitempty" yaml:"records,omitempty"`
	Warnings    []string    `json:"warnings,omitempty" yaml:"warnings,omitempty"`
}

DNSResult records records discovered alongside registration data. Complete is true only when an untruncated authoritative AXFR completed successfully. Pattern scans intentionally remain incomplete: DNS has no reliable general mechanism to enumerate arbitrary owner names in a zone.

type DNSTraceHop added in v1.0.0

type DNSTraceHop struct {
	Zone        string        `json:"zone" yaml:"zone"`
	Server      string        `json:"server" yaml:"server"`
	Duration    time.Duration `json:"duration_ns" yaml:"duration_ns"`
	Rcode       string        `json:"rcode" yaml:"rcode"`
	Nameservers []string      `json:"nameservers,omitempty" yaml:"nameservers,omitempty"`
	Addresses   []string      `json:"addresses,omitempty" yaml:"addresses,omitempty"`
	DNSSEC      string        `json:"dnssec" yaml:"dnssec"`
	Glue        string        `json:"glue,omitempty" yaml:"glue,omitempty"`
	Lame        bool          `json:"lame,omitempty" yaml:"lame,omitempty"`
	Error       string        `json:"error,omitempty" yaml:"error,omitempty"`
}

DNSTraceHop is one iterative delegation step.

type DiagnoseOptions added in v1.0.0

type DiagnoseOptions struct {
	DNS          DNSOptions    `json:"dns,omitempty" yaml:"dns,omitempty"`
	Timeout      time.Duration `json:"-" yaml:"-"`
	Trace        bool          `json:"trace,omitempty" yaml:"trace,omitempty"`
	Remote       bool          `json:"remote,omitempty" yaml:"remote,omitempty"`
	MaxAddresses int           `json:"max_addresses,omitempty" yaml:"max_addresses,omitempty"`
}

DiagnoseOptions controls bounded, domain-derived connectivity checks. Ports are obtained from established protocols and advertised DNS service records; this API is intentionally not a general-purpose port scanner.

type DiagnoseProvider added in v1.0.0

type DiagnoseProvider interface {
	Diagnose(context.Context, string, DiagnoseOptions) (*DiagnosisReport, error)
}

DiagnoseProvider is the dependency-injection boundary for domain checks.

type DiagnosisReport added in v1.0.0

type DiagnosisReport struct {
	Domain       string              `json:"domain" yaml:"domain"`
	DNS          *DNSOperationResult `json:"dns,omitempty" yaml:"dns,omitempty"`
	Delegation   *DNSOperationResult `json:"delegation,omitempty" yaml:"delegation,omitempty"`
	Reachability []AddressProbe      `json:"reachability,omitempty" yaml:"reachability,omitempty"`
	HTTP         []HTTPProbe         `json:"http,omitempty" yaml:"http,omitempty"`
	TLS          []TLSProbe          `json:"tls,omitempty" yaml:"tls,omitempty"`
	Mail         []MailProbe         `json:"mail,omitempty" yaml:"mail,omitempty"`
	Services     []ServiceProbe      `json:"services,omitempty" yaml:"services,omitempty"`
	Path         []PathHop           `json:"path,omitempty" yaml:"path,omitempty"`
	Policies     map[string][]string `json:"policies,omitempty" yaml:"policies,omitempty"`
	Findings     []Finding           `json:"findings,omitempty" yaml:"findings,omitempty"`
	Warnings     []string            `json:"warnings,omitempty" yaml:"warnings,omitempty"`
}

DiagnosisReport is the structured output of the bounded diagnosis engine.

type EDNSOptions added in v1.0.0

type EDNSOptions struct {
	BufferSize uint16 `json:"buffer_size,omitempty" yaml:"buffer_size,omitempty"`
	DNSSEC     bool   `json:"dnssec,omitempty" yaml:"dnssec,omitempty"`
	NSID       bool   `json:"nsid,omitempty" yaml:"nsid,omitempty"`
	ECS        string `json:"ecs,omitempty" yaml:"ecs,omitempty"`
	Cookie     string `json:"cookie,omitempty" yaml:"cookie,omitempty"`
	Padding    uint16 `json:"padding,omitempty" yaml:"padding,omitempty"`
}

EDNSOptions configures the OPT pseudo-record used for DNS queries.

type Engine added in v1.0.0

type Engine struct {
	// contains filtered or unexported fields
}

Engine coordinates independent providers behind one public API.

func NewEngine added in v1.0.0

func NewEngine(options EngineOptions) *Engine

NewEngine creates a domain-workstation engine without performing network activity. Nil providers are replaced by Whodis's built-in implementations.

func (*Engine) Run added in v1.0.0

func (engine *Engine) Run(ctx context.Context, request Request) (Report, error)

Run performs exactly one requested operation. A successfully returned report may contain scoped errors alongside partial results; an error is reserved for invalid requests or a canceled/deadline-exceeded operation with no result.

func (*Engine) RunBatch added in v1.0.0

func (engine *Engine) RunBatch(ctx context.Context, batch BatchRequest) (BatchReport, error)

RunBatch performs independent requests with bounded concurrency while preserving input order.

type EngineOptions added in v1.0.0

type EngineOptions struct {
	Client       *Client
	Registration RegistrationProvider
	DNS          DNSProvider
	Diagnose     DiagnoseProvider
	Timeout      time.Duration
}

EngineOptions configures a reusable, concurrency-safe engine.

type Entity

type Entity struct {
	Roles        []string `json:"roles,omitempty" yaml:"roles,omitempty"`
	Handle       string   `json:"handle,omitempty" yaml:"handle,omitempty"`
	Name         string   `json:"name,omitempty" yaml:"name,omitempty"`
	Organization string   `json:"organization,omitempty" yaml:"organization,omitempty"`
	Email        string   `json:"email,omitempty" yaml:"email,omitempty"`
	Phone        string   `json:"phone,omitempty" yaml:"phone,omitempty"`
}

Entity contains public contact or organization information. Fields that are redacted by a registry remain absent rather than being invented.

type ErrorKind

type ErrorKind string

ErrorKind allows command-line callers and future UIs to handle lookup failures without string matching.

const (
	ErrorInvalidInput ErrorKind = "invalid_input"
	ErrorNotFound     ErrorKind = "not_found"
	ErrorRateLimited  ErrorKind = "rate_limited"
	ErrorDiscovery    ErrorKind = "discovery"
	ErrorUnavailable  ErrorKind = "unavailable"
	ErrorProtocol     ErrorKind = "protocol"
)

type Event

type Event struct {
	Action string `json:"action" yaml:"action"`
	Date   string `json:"date" yaml:"date"`
}

Event is a dated registration event such as registration or expiration.

type FallbackMode

type FallbackMode string

FallbackMode controls whether Whodis tries the other protocol after its knowledge-based primary route fails.

const (
	FallbackUnavailable FallbackMode = "unavailable"
	FallbackNone        FallbackMode = "none"
	FallbackAnyError    FallbackMode = "any-error"
)

type Finding added in v1.0.0

type Finding struct {
	ID       string            `json:"id" yaml:"id"`
	Severity Severity          `json:"severity" yaml:"severity"`
	Title    string            `json:"title" yaml:"title"`
	Summary  string            `json:"summary" yaml:"summary"`
	Evidence map[string]string `json:"evidence,omitempty" yaml:"evidence,omitempty"`
}

Finding is one deterministic diagnostic observation. Whodis intentionally does not collapse findings into an opaque overall score.

type Format

type Format string

Format is an output representation for a LookupResult.

const (
	FormatPretty   Format = "pretty"
	FormatTree     Format = "tree"
	FormatGeekBoys Format = "geekboys"
	FormatPlain    Format = "plain"
	FormatJSON     Format = "json"
	FormatYAML     Format = "yaml"
	FormatMarkdown Format = "markdown"
	FormatRaw      Format = "raw"
)

func ParseFormat

func ParseFormat(value string) (Format, error)

ParseFormat validates a CLI-facing output format. Common descriptions of the human-facing renderers are accepted as friendly aliases.

type HTTPProbe added in v1.0.0

type HTTPProbe struct {
	URL       string        `json:"url" yaml:"url"`
	Status    int           `json:"status,omitempty" yaml:"status,omitempty"`
	FinalURL  string        `json:"final_url,omitempty" yaml:"final_url,omitempty"`
	Redirects []string      `json:"redirects,omitempty" yaml:"redirects,omitempty"`
	Duration  time.Duration `json:"duration_ns" yaml:"duration_ns"`
	Server    string        `json:"server,omitempty" yaml:"server,omitempty"`
	Error     string        `json:"error,omitempty" yaml:"error,omitempty"`
}

HTTPProbe captures one HTTP endpoint and its final response.

type Kind

type Kind string

Kind is the kind of registration object represented by a Target.

const (
	KindDomain Kind = "domain"
	KindIP     Kind = "ip"
	KindASN    Kind = "asn"
)

type LookupError

type LookupError struct {
	Kind    ErrorKind
	Message string
	Cause   error
}

LookupError wraps a failure with an actionable classification.

func (*LookupError) Error

func (e *LookupError) Error() string

func (*LookupError) Unwrap

func (e *LookupError) Unwrap() error

type LookupOptions

type LookupOptions struct {
	Protocol         Protocol
	Fallback         FallbackMode
	Server           string
	Timeout          time.Duration
	RefreshBootstrap bool
	DNSMode          DNSMode
	DNSResolver      string
}

LookupOptions controls one lookup. A zero-value options struct uses the knowledge-based automatic protocol router, unavailable-only fallback, and no live DNS enrichment.

type LookupResult

type LookupResult struct {
	SchemaVersion int            `json:"schema_version" yaml:"schema_version"`
	Query         Target         `json:"query" yaml:"query"`
	Route         RouteDecision  `json:"route" yaml:"route"`
	FallbackFrom  *RouteDecision `json:"fallback_from,omitempty" yaml:"fallback_from,omitempty"`
	RetrievedAt   time.Time      `json:"retrieved_at" yaml:"retrieved_at"`
	Object        Object         `json:"object" yaml:"object"`
	Sources       []Source       `json:"sources" yaml:"sources"`
	DNS           *DNSResult     `json:"dns,omitempty" yaml:"dns,omitempty"`
}

LookupResult is the serializable response returned by Client.Lookup.

type MailProbe added in v1.0.0

type MailProbe struct {
	Host         string        `json:"host" yaml:"host"`
	Preference   uint16        `json:"preference" yaml:"preference"`
	Address      string        `json:"address,omitempty" yaml:"address,omitempty"`
	Reachable    bool          `json:"reachable" yaml:"reachable"`
	Greeting     string        `json:"greeting,omitempty" yaml:"greeting,omitempty"`
	Capabilities []string      `json:"capabilities,omitempty" yaml:"capabilities,omitempty"`
	STARTTLS     bool          `json:"starttls" yaml:"starttls"`
	TLSVerified  bool          `json:"tls_verified,omitempty" yaml:"tls_verified,omitempty"`
	TLSVersion   string        `json:"tls_version,omitempty" yaml:"tls_version,omitempty"`
	Duration     time.Duration `json:"duration_ns" yaml:"duration_ns"`
	Error        string        `json:"error,omitempty" yaml:"error,omitempty"`
}

MailProbe captures one MX SMTP greeting and advertised capabilities.

type Notice

type Notice struct {
	Title       string   `json:"title,omitempty" yaml:"title,omitempty"`
	Description []string `json:"description,omitempty" yaml:"description,omitempty"`
	Links       []string `json:"links,omitempty" yaml:"links,omitempty"`
}

Notice is a registry-supplied legal or service notice.

type Object

type Object struct {
	Kind         Kind                `json:"kind" yaml:"kind"`
	Handle       string              `json:"handle,omitempty" yaml:"handle,omitempty"`
	Name         string              `json:"name,omitempty" yaml:"name,omitempty"`
	UnicodeName  string              `json:"unicode_name,omitempty" yaml:"unicode_name,omitempty"`
	Status       []string            `json:"status,omitempty" yaml:"status,omitempty"`
	Events       []Event             `json:"events,omitempty" yaml:"events,omitempty"`
	Nameservers  []string            `json:"nameservers,omitempty" yaml:"nameservers,omitempty"`
	Entities     []Entity            `json:"entities,omitempty" yaml:"entities,omitempty"`
	Registrar    string              `json:"registrar,omitempty" yaml:"registrar,omitempty"`
	Registry     string              `json:"registry,omitempty" yaml:"registry,omitempty"`
	DNSSEC       string              `json:"dnssec,omitempty" yaml:"dnssec,omitempty"`
	StartAddress string              `json:"start_address,omitempty" yaml:"start_address,omitempty"`
	EndAddress   string              `json:"end_address,omitempty" yaml:"end_address,omitempty"`
	CIDR         []string            `json:"cidr,omitempty" yaml:"cidr,omitempty"`
	Country      string              `json:"country,omitempty" yaml:"country,omitempty"`
	NetworkType  string              `json:"network_type,omitempty" yaml:"network_type,omitempty"`
	ASN          string              `json:"asn,omitempty" yaml:"asn,omitempty"`
	ASNName      string              `json:"asn_name,omitempty" yaml:"asn_name,omitempty"`
	ASNType      string              `json:"asn_type,omitempty" yaml:"asn_type,omitempty"`
	Notices      []Notice            `json:"notices,omitempty" yaml:"notices,omitempty"`
	Extras       map[string][]string `json:"extras,omitempty" yaml:"extras,omitempty"`
}

Object is Whodis's stable normalized registration-data model. Extras keeps protocol or registry-specific values that do not fit the common fields.

type Operation added in v1.0.0

type Operation string

Operation identifies one engine operation.

const (
	OperationRegistration Operation = "registration"
	OperationDNSQuery     Operation = "dns.query"
	OperationDNSInventory Operation = "dns.inventory"
	OperationDNSCompare   Operation = "dns.compare"
	OperationDNSTrace     Operation = "dns.trace"
	OperationDNSTransfer  Operation = "dns.transfer"
	OperationDiagnose     Operation = "diagnose"
)

type OperationError added in v1.0.0

type OperationError struct {
	Operation Operation `json:"operation" yaml:"operation"`
	Provider  string    `json:"provider,omitempty" yaml:"provider,omitempty"`
	Kind      ErrorKind `json:"kind" yaml:"kind"`
	Message   string    `json:"message" yaml:"message"`
}

OperationError is a serializable, provider-scoped failure. Reports may contain errors and useful results at the same time.

type PathHop added in v1.0.0

type PathHop struct {
	Hop      int           `json:"hop" yaml:"hop"`
	Address  string        `json:"address,omitempty" yaml:"address,omitempty"`
	Duration time.Duration `json:"duration_ns,omitempty" yaml:"duration_ns,omitempty"`
	Reached  bool          `json:"reached" yaml:"reached"`
	Error    string        `json:"error,omitempty" yaml:"error,omitempty"`
}

PathHop is one hop from an explicitly requested local network path trace.

type ProgressEvent added in v1.0.0

type ProgressEvent struct {
	RequestID string    `json:"request_id,omitempty" yaml:"request_id,omitempty"`
	Operation Operation `json:"operation" yaml:"operation"`
	Target    string    `json:"target" yaml:"target"`
	Stage     string    `json:"stage" yaml:"stage"`
	Completed int       `json:"completed,omitempty" yaml:"completed,omitempty"`
	Total     int       `json:"total,omitempty" yaml:"total,omitempty"`
}

ProgressEvent is emitted at stable operation boundaries. Callbacks are serialized by Engine.RunBatch and should return quickly.

type ProjectionField added in v0.6.0

type ProjectionField string

ProjectionField is a stable, script-friendly view of a normalized result.

const (
	FieldExpiration   ProjectionField = "expiration"
	FieldRegistration ProjectionField = "registration"
	FieldUpdated      ProjectionField = "updated"
	FieldRegistrar    ProjectionField = "registrar"
	FieldRegistry     ProjectionField = "registry"
	FieldStatus       ProjectionField = "status"
	FieldNameservers  ProjectionField = "nameservers"
	FieldDNSSEC       ProjectionField = "dnssec"
	FieldProtocol     ProjectionField = "protocol"
)

func ParseProjectionField added in v0.6.0

func ParseProjectionField(value string) (ProjectionField, error)

ParseProjectionField validates a CLI- or UI-facing field name.

type Protocol

type Protocol string

Protocol is a registration-data transport.

const (
	ProtocolAuto   Protocol = "auto"
	ProtocolRDAP   Protocol = "rdap"
	ProtocolWHOIS  Protocol = "whois"
	ProtocolRWHOIS Protocol = "rwhois"
)

type ProtocolAdapter

type ProtocolAdapter interface {
	Protocol() Protocol
	Lookup(ctx context.Context, target Target, route RouteDecision) (Object, []Source, error)
}

ProtocolAdapter is the extension point for registration-data protocols. Implementations are supplied to NewClient rather than loaded through Go's platform-limited plugin mechanism.

type RegistrationProvider added in v1.0.0

type RegistrationProvider interface {
	Lookup(context.Context, string, LookupOptions) (LookupResult, error)
}

RegistrationProvider is the dependency-injection boundary for normalized registration lookup implementations.

type RemoteDNSMeasurement added in v1.0.0

type RemoteDNSMeasurement struct {
	MeasurementID string        `json:"measurement_id" yaml:"measurement_id"`
	Status        string        `json:"status" yaml:"status"`
	Probe         string        `json:"probe,omitempty" yaml:"probe,omitempty"`
	Location      string        `json:"location,omitempty" yaml:"location,omitempty"`
	Resolver      string        `json:"resolver,omitempty" yaml:"resolver,omitempty"`
	Rcode         string        `json:"rcode,omitempty" yaml:"rcode,omitempty"`
	Duration      time.Duration `json:"duration_ns,omitempty" yaml:"duration_ns,omitempty"`
	Answers       []DNSRecord   `json:"answers,omitempty" yaml:"answers,omitempty"`
	Raw           string        `json:"raw,omitempty" yaml:"raw,omitempty"`
	Error         string        `json:"error,omitempty" yaml:"error,omitempty"`
}

RemoteDNSMeasurement is one explicitly requested Globalping probe result.

type RenderOptions

type RenderOptions struct {
	Color   string
	Width   int
	Details bool
}

RenderOptions changes presentation only; it never changes lookup behavior.

type Report added in v1.0.0

type Report struct {
	SchemaVersion int                 `json:"schema_version" yaml:"schema_version"`
	Operation     Operation           `json:"operation" yaml:"operation"`
	Query         Target              `json:"query" yaml:"query"`
	RetrievedAt   time.Time           `json:"retrieved_at" yaml:"retrieved_at"`
	Registration  *LookupResult       `json:"registration,omitempty" yaml:"registration,omitempty"`
	DNS           *DNSOperationResult `json:"dns,omitempty" yaml:"dns,omitempty"`
	Diagnosis     *DiagnosisReport    `json:"diagnosis,omitempty" yaml:"diagnosis,omitempty"`
	Findings      []Finding           `json:"findings,omitempty" yaml:"findings,omitempty"`
	Errors        []OperationError    `json:"errors,omitempty" yaml:"errors,omitempty"`
}

Report is the renderer-independent v3 result returned by Engine.Run.

type Request added in v1.0.0

type Request struct {
	ID           string              `json:"id,omitempty" yaml:"id,omitempty"`
	Operation    Operation           `json:"operation" yaml:"operation"`
	Target       string              `json:"target" yaml:"target"`
	Registration LookupOptions       `json:"registration,omitempty" yaml:"registration,omitempty"`
	DNS          DNSOptions          `json:"dns,omitempty" yaml:"dns,omitempty"`
	Diagnose     DiagnoseOptions     `json:"diagnose,omitempty" yaml:"diagnose,omitempty"`
	Timeout      time.Duration       `json:"-" yaml:"-"`
	OnProgress   func(ProgressEvent) `json:"-" yaml:"-"`
}

Request is the stable public input to Engine.Run.

type ResolverStrategy added in v1.0.0

type ResolverStrategy string

ResolverStrategy controls how multiple configured resolvers are used.

const (
	ResolverFirst     ResolverStrategy = "first"
	ResolverAll       ResolverStrategy = "all"
	ResolverFastest   ResolverStrategy = "fastest"
	ResolverRandom    ResolverStrategy = "random"
	ResolverConsensus ResolverStrategy = "consensus"
)

type RouteDecision

type RouteDecision struct {
	Protocol        Protocol `json:"protocol" yaml:"protocol"`
	Endpoint        string   `json:"endpoint" yaml:"endpoint"`
	Alternates      []string `json:"alternates,omitempty" yaml:"alternates,omitempty"`
	DiscoverySource string   `json:"discovery_source" yaml:"discovery_source"`
	Reason          string   `json:"reason" yaml:"reason"`
}

RouteDecision records why an authority and protocol were selected.

type ServiceProbe added in v1.0.0

type ServiceProbe struct {
	Source    string        `json:"source" yaml:"source"`
	Name      string        `json:"name" yaml:"name"`
	Target    string        `json:"target" yaml:"target"`
	Port      uint16        `json:"port" yaml:"port"`
	Reachable bool          `json:"reachable" yaml:"reachable"`
	Duration  time.Duration `json:"duration_ns" yaml:"duration_ns"`
	Error     string        `json:"error,omitempty" yaml:"error,omitempty"`
}

ServiceProbe captures a DNS-advertised SRV, SVCB, or HTTPS service.

type Severity added in v1.0.0

type Severity string

Severity is the deterministic outcome of a diagnostic finding.

const (
	SeverityPass    Severity = "pass"
	SeverityInfo    Severity = "info"
	SeverityWarning Severity = "warning"
	SeverityError   Severity = "error"
)

type Source

type Source struct {
	Protocol  Protocol `json:"protocol" yaml:"protocol"`
	Endpoint  string   `json:"endpoint" yaml:"endpoint"`
	Authority string   `json:"authority,omitempty" yaml:"authority,omitempty"`
	Raw       string   `json:"-" yaml:"-"`
}

Source is one registry response used to construct a result.

type TLSProbe added in v1.0.0

type TLSProbe struct {
	Address     string        `json:"address" yaml:"address"`
	ServerName  string        `json:"server_name" yaml:"server_name"`
	Version     string        `json:"version,omitempty" yaml:"version,omitempty"`
	CipherSuite string        `json:"cipher_suite,omitempty" yaml:"cipher_suite,omitempty"`
	ALPN        string        `json:"alpn,omitempty" yaml:"alpn,omitempty"`
	Subject     string        `json:"subject,omitempty" yaml:"subject,omitempty"`
	Issuer      string        `json:"issuer,omitempty" yaml:"issuer,omitempty"`
	DNSNames    []string      `json:"dns_names,omitempty" yaml:"dns_names,omitempty"`
	NotBefore   time.Time     `json:"not_before,omitempty" yaml:"not_before,omitempty"`
	NotAfter    time.Time     `json:"not_after,omitempty" yaml:"not_after,omitempty"`
	Duration    time.Duration `json:"duration_ns" yaml:"duration_ns"`
	Verified    bool          `json:"verified" yaml:"verified"`
	Error       string        `json:"error,omitempty" yaml:"error,omitempty"`
}

TLSProbe captures the negotiated TLS identity and protocol.

type Target

type Target struct {
	Original  string `json:"original" yaml:"original"`
	Canonical string `json:"canonical" yaml:"canonical"`
	Kind      Kind   `json:"kind" yaml:"kind"`
}

Target is a validated, canonical lookup input.

func ParseTarget

func ParseTarget(input string) (Target, error)

ParseTarget classifies and canonicalizes one user supplied lookup target.

type TransferOptions added in v1.0.0

type TransferOptions struct {
	Type       string `json:"type,omitempty" yaml:"type,omitempty"`
	Serial     uint32 `json:"serial,omitempty" yaml:"serial,omitempty"`
	TSIGName   string `json:"tsig_name,omitempty" yaml:"tsig_name,omitempty"`
	TSIGSecret string `json:"-" yaml:"-"`
	TSIGAlgo   string `json:"tsig_algorithm,omitempty" yaml:"tsig_algorithm,omitempty"`
	TLS        bool   `json:"tls,omitempty" yaml:"tls,omitempty"`
}

TransferOptions configures an explicit AXFR or IXFR request.

Directories

Path Synopsis
cmd
whodis command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL