Skip to content

First query

This page walks through an end-to-end lab test: a client sends a DNS query to Conduit dataplane, Conduit forwards to a pool backend, and the answer returns to the client. It assumes you completed Install and run and wrote the minimal config from Minimal configuration.

The control plane is not required for this exercise — you only need the conduit binary, a config file, an upstream resolver, and dig.

What you are proving

Step Component
1 Client (dig) sends a query to Conduit’s listener
2 Conduit accepts the query on the dataplane
3 Conduit selects the default pool and forwards to its backend
4 The upstream answers; Conduit returns the response to the client

For the full pipeline (policy, route, forward), see Architecture and packet path.

Lab layout

The minimal configuration example uses loopback ports that avoid UDP 5353 (often mDNS on Linux):

Role Address
Conduit DNS listener (UDP) 127.0.0.1:15353
Pool backend (upstream mock) 127.0.0.1:5300

Use two terminals for Conduit and the upstream, plus a third for dig (or reuse one terminal for dig after the services are up).

Prerequisites

  • dig — usually from the bind9-dnsutils package on Ubuntu/Debian
  • dnsmasq — lightweight DNS forwarder used here as a loopback upstream mock
  • A reachable recursive resolver for dnsmasq to forward to (for example 8.8.8.8 or your site resolver)

Set the upstream once per shell session:

export UPSTREAM_DNS="8.8.8.8"   # replace with a resolver you can reach

Save the minimal config as conduit.yaml (or use conduit.minimal.yaml from a release tarball) and validate it:

conduitctl validate --file conduit.yaml

On success the command prints ok and exits with status 0.

1. Start the upstream (backend)

Conduit does not answer from a built-in cache in this setup — something must listen on the pool backend address (127.0.0.1:5300 in the minimal file). In terminal A, start dnsmasq as a forwarder to $UPSTREAM_DNS:

dnsmasq -d \
  --port=5300 \
  --bind-interfaces \
  --listen-address=127.0.0.1 \
  --server="$UPSTREAM_DNS" \
  --no-hosts --no-resolv --log-queries --log-facility=-

Leave this process running. If the port is already in use, pick another loopback port, update pools[].backends[].address in conduit.yaml to match, and re-run conduitctl validate --file conduit.yaml.

2. Start Conduit

In terminal B, start the dataplane with your config path as the only argument after the binary:

# from a release tarball directory:
./conduit conduit.yaml

# or after building from source:
target/release/conduit conduit.yaml

Expect a log line similar to:

Starting listening on 127.0.0.1:15353 udp

If Conduit exits immediately, check stderr for config errors (see If the query fails).

3. Send a query

In terminal C (or the same shell once Conduit and dnsmasq are up), query through Conduit, not directly against dnsmasq:

dig @127.0.0.1 -p 15353 +time=3 +tries=1 example.com A

+time=3 and +tries=1 keep lab failures quick when a backend is down.

What success looks like

  • dig status NOERROR
  • An ANSWER SECTION with at least one A record for example.com (exact addresses depend on $UPSTREAM_DNS)
  • Terminal A (dnsmasq) shows a forwarded query in its log output

Short output check:

dig @127.0.0.1 -p 15353 +time=3 +tries=1 +short example.com A

Prints one or more IPv4 addresses when the path is healthy.

If the query fails

Symptom Likely cause What to check
connection timed out / no response Conduit not listening Conduit running? Listener address 127.0.0.1:15353 in config? Firewall blocking loopback?
SERVFAIL Upstream or forward path dnsmasq running on 127.0.0.1:5300? Pool backend address matches? $UPSTREAM_DNS reachable from the host?
REFUSED Wrong target port Querying Conduit on 15353, not dnsmasq on 5300
Conduit exits on start Invalid config conduitctl validate --file conduit.yaml; fix errors printed to stderr

Confirm the backend port is open:

ss -ulnp | grep -E '5300|15353'

You should see listeners on both ports when dnsmasq and Conduit are up.

Re-validate after any config edit:

conduitctl validate --file conduit.yaml

Optional: query with TCP

The minimal example enables UDP only. To test TCP, add a TCP listener alongside UDP in conduit.yaml:

listeners:
  listeners:
    - address: "127.0.0.1:15353"
      protocol: udp
    - address: "127.0.0.1:15353"
      protocol: tcp

Restart Conduit, then:

dig @127.0.0.1 -p 15353 +tcp +time=3 +tries=1 example.com A

Next steps