Dns
Host name resolution, DNS queries, and DNS record values.
lookup resolves a host name to the addresses used to connect to it,
resolve queries DNS records of one type, and reverse looks up the names
of an address. Runtime packages provide the Dns service from the host
platform's resolver, whose lookup uses the operating system resolver
(getaddrinfo) and therefore also reads the hosts file and other system
sources, not only DNS. AddressResolver builds on lookup to resolve
host:port endpoints.
Constants
Every supported record type.
Signature
declare const recordTypes: Arr.NonEmptyReadonlyArray<RecordType>Constructors
Creates a Dns service from platform resolver operations.
Details
Lookup and query names are parsed and normalized, and reverse lookup
addresses are parsed, before platform callbacks receive them. Invalid names
and addresses fail with BadName.
The constructor filters lookups by the requested address family, keeps only
records of the requested type, removes duplicates, and turns empty results
into NotFound failures. reverse receives the names of an address and
keeps those that are valid host names, failing with InvalidResponse when
there are names but none is valid. Without a reverse operation, the names
are those of the PTR records at the address's reverseName, and failures of
that query are reported as failures of reverse.
Only lookup is required. Platforms that can resolve addresses but cannot
query records, such as browsers, omit resolve; record queries, and reverse
lookups without a reverse operation, then fail with Unsupported.
Signature
declare function make(impl: { readonly lookup: (host: DomainName, family: IpFamily | undefined) => Effect<readonly Array<IpAddress>, DnsError>; readonly resolve?: (name: DomainName, type: RecordType) => Effect<readonly Array<DnsRecord>, DnsError>; readonly reverse?: (address: IpAddress) => Effect<readonly Array<string>, DnsError>;}): { lookup<F extends IpFamily>(host: DomainNameInput, options: { readonly family: F; }): Effect<readonly [FamilyAddress<F>, FamilyAddress<F>], DnsError>; lookup(host: DomainNameInput, options?: LookupOptions): Effect<readonly [IpAddress, IpAddress], DnsError>; resolve<T extends RecordType>(name: DomainNameInput, type: T): Effect<readonly [RecordFor<T>, RecordFor<T>], DnsError>; reverse(address: IpAddressInput): Effect<readonly [DomainName, DomainName], DnsError>;}Creates a checked DNS record of a record type from its fields.
Details
Every field is checked at runtime: addresses must belong to the record's
address family, names must be normalized domain names, priorities, weights,
and ports must be 16-bit unsigned integers, the SOA serial and timers must be
32-bit unsigned integers (the timers in whole seconds), the TLSA fields must
be 8-bit unsigned integers with non-empty data, which is copied, TXT
records need at least one chunk, and CAA property tags must be alphanumeric.
Fields that do not belong to the record type are ignored.
Signature
declare function makeRecord<T extends RecordType>(type: T, fields: RecordFields<T>): Result<RecordFor<T>, NetAddressError>Example Creating a service record
import { Result } from "effect"import { Dns, Host } from "effect/net"
const record = Result.getOrThrow(Dns.makeRecord("SRV", { target: Host.domainNameFromStringUnsafe("db.internal"), port: 5432, priority: 10, weight: 5}))Dns.formatRecord(record) // => "SRV 10 5 5432 db.internal"Creates a Dns service that answers from fixed data.
When to use
Use to test code that depends on Dns, or to provide fixed names on
platforms without a resolver.
Details
Names without matching addresses or records fail with NotFound. CNAME
records are returned by CNAME queries but are not followed.
See
Signature
declare function makeStatic(zone: StaticZone): Result<{ lookup<F extends IpFamily>(host: DomainNameInput, options: { readonly family: F; }): Effect<readonly [FamilyAddress<F>, FamilyAddress<F>], DnsError>; lookup(host: DomainNameInput, options?: LookupOptions): Effect<readonly [IpAddress, IpAddress], DnsError>; resolve<T extends RecordType>(name: DomainNameInput, type: T): Effect<readonly [RecordFor<T>, RecordFor<T>], DnsError>; reverse(address: IpAddressInput): Effect<readonly [DomainName, DomainName], DnsError>;}, NetAddressError>Example Looking up a name with a static resolver
import { Effect, Result } from "effect"import { Dns, NetAddress } from "effect/net"
const dns = Result.getOrThrow(Dns.makeStatic({ hosts: { "db.internal": ["10.0.0.5"] }}))
const program = dns.lookup("db.internal").pipe( Effect.map((addresses) => addresses.map(NetAddress.formatIp)))
await Effect.runPromise(program) // => ["10.0.0.5"]Converts a name server to the internet address to query. Strings are parsed
like nameServerFromString, internet addresses and address parts with a
port are converted like NetAddress.inetAddressFromInput, and other IP
address inputs are converted like NetAddress.ipFromInput and use port 53.
Signature
declare function nameServerFromInput(input: string | Ipv4Address | Ipv6Address | InetAddressV4 | InetAddressV6 | readonly [number, number, number, number] | Uint8Array<ArrayBufferLike> | readonly [number, number, number, number, number, number, number, number] | Uint8Array<ArrayBufferLike> | InetAddressParts<IpAddressInput>): Result<InetAddress, NetAddressError>Converting
Returns the reverse-lookup domain name for an IP address, in in-addr.arpa
for IPv4 or ip6.arpa for IPv6.
Signature
declare function reverseName(address: IpAddress): DomainNameExample Building reverse-lookup names
import { Dns, NetAddress } from "effect/net"
Dns.reverseName(NetAddress.ipFromStringUnsafe("192.0.2.1")) // => "1.2.0.192.in-addr.arpa"Decoding
Parses the address of a name server: an IP address, which uses port 53, or an IP address and port.
Details
IPv6 addresses with a port are written in brackets, and IPv6 addresses without one are not.
Signature
declare function nameServerFromString(input: string): Result<InetAddress, NetAddressError>Example Parsing name server addresses
import { Result } from "effect"import { Dns, NetAddress } from "effect/net"
const format = (input: string) => Result.map(Dns.nameServerFromString(input), NetAddress.formatInet)
format("192.0.2.53") // => Result.succeed("192.0.2.53:53")format("2001:db8::53") // => Result.succeed("[2001:db8::53]:53")format("[2001:db8::53]:5353") // => Result.succeed("[2001:db8::53]:5353")Result.isFailure(format("ns.example")) // => trueEncoding
Formats a record in DNS presentation format, prefixed by its type.
Signature
declare function formatRecord(self: DnsRecord): stringErrors
A failed lookup, query, or reverse lookup.
Signature
declare class DnsError extends YieldableError<this> & { readonly _tag: "DnsError";} & Readonly<{ readonly cause?: unknown; readonly hostname: string; readonly method: "reverse" | "lookup" | "resolve"; readonly reason: DnsErrorReason; readonly recordType?: RecordType;}> { constructor(args: { readonly cause?: unknown; readonly hostname: string; readonly method: "reverse" | "lookup" | "resolve"; readonly reason: DnsErrorReason; readonly recordType?: RecordType; }); isTemporary: boolean; message: string;}DnsErrorReason
typeThe normalized reason for a failed name resolution.
Details
NotFound: no records were found, either because the name does not exist or because it has no records of the requested type or address family. Like Go'sDNSError.IsNotFound, the two cases are not distinguished because not every platform resolver can tell them apart.Timeout,Temporary, andServerFailure: transient failures that may succeed when retried.Refused: the server refused the query or could not be reached.BadName: the name was rejected as malformed.InvalidResponse: the platform returned data that could not be converted into record values.Unsupported: the platform does not support the operation or record type.
Signature
type DnsErrorReason = "NotFound" | "Timeout" | "Temporary" | "Refused" | "ServerFailure" | "BadName" | "InvalidResponse" | "Unsupported" | "Unknown"Guards
Layers
Creates a layer that provides a Dns service answering from fixed data.
See
- makeStatic for the resolution rules
Signature
declare function layerStatic(zone: StaticZone): Layer<Dns, NetAddressError>Models
An IPv4 address record.
Signature
interface A extends RecordProto<"A"> { readonly address: Ipv4Address;}An IPv6 address record.
Signature
interface Aaaa extends RecordProto<"AAAA"> { readonly address: Ipv6Address;}A certification authority authorization record.
Signature
interface Caa extends RecordProto<"CAA"> { readonly critical: boolean; readonly tag: string; readonly value: string;}A canonical name (alias) record.
Signature
interface Cname extends RecordProto<"CNAME"> { readonly target: DomainName;}Any supported DNS record value.
Details
Records are immutable values tagged by record type, compared and hashed by their fields. They hold the record data only: owner names and TTLs are not included because platform resolvers do not report them consistently. Names returned by platform services are fully qualified and end with a dot, so passing them back to the resolver does not apply search domains.
Signature
type DnsRecord = A | Aaaa | Caa | Cname | Mx | Naptr | Ns | Ptr | Soa | Srv | Tlsa | TxtLookupOptions
interfaceOptions for address lookups. Without a family, addresses of both families
are returned.
Signature
interface LookupOptions { readonly family?: IpFamily;}A mail exchange record.
Signature
interface Mx extends RecordProto<"MX"> { readonly exchange: DomainName; readonly priority: number;}A naming authority pointer record.
Signature
interface Naptr extends RecordProto<"NAPTR"> { readonly flags: string; readonly order: number; readonly preference: number; readonly regexp: string; readonly replacement: DomainName; readonly service: string;}A name server record.
Signature
interface Ns extends RecordProto<"NS"> { readonly host: DomainName;}A pointer record, used for reverse lookups and DNS service discovery.
Details
host is a fully qualified name. It is a host name for reverse lookups,
but may be a DNS-SD service instance name containing spaces or other
characters, such as EPSON TM-m30III._ipp._tcp.local.. Labels are UTF-8
text, with dots and backslashes inside a label escaped as \. and \\.
Signature
interface Ptr extends RecordProto<"PTR"> { readonly host: string;}RecordFields
typeThe fields of a record type, without its _tag.
See
Signature
type RecordFields<T extends RecordType> = T extends RecordType ? Omit<RecordFor<T>, keyof RecordProto<T>> : neverThe record value for a record type.
Signature
type RecordFor<T extends RecordType> = Extract<DnsRecord, { readonly _tag: T;}>RecordType
typeThe type of a DNS record, such as "A" or "SRV".
Signature
type RecordType = "A" | "AAAA" | "CAA" | "CNAME" | "MX" | "NAPTR" | "NS" | "PTR" | "SOA" | "SRV" | "TLSA" | "TXT"A start of authority record.
Details
admin is the administrator mailbox written as a domain name, such as
hostmaster.example.com. A dot inside the mailbox's local part is escaped,
as in john\.doe.example.com, so admin is a plain string rather than a
Host.DomainName. Labels are UTF-8 text, with dots and backslashes inside
a label escaped as \. and \\.
Signature
interface Soa extends RecordProto<"SOA"> { readonly admin: string; readonly expire: Duration; readonly minimum: Duration; readonly primary: DomainName; readonly refresh: Duration; readonly retry: Duration; readonly serial: number;}A service location record.
Signature
interface Srv extends RecordProto<"SRV"> { readonly port: number; readonly priority: number; readonly target: DomainName; readonly weight: number;}StaticZone
interfaceFixed names, addresses, and records for a static resolver.
Details
hosts works like a hosts file: its entries are used by lookup and
reverse, but not by resolve. records holds DNS records by owner name and
is used by all three operations. Names are normalized like
Host.domainNameFromString, and a trailing dot is ignored. Addresses are
converted like NetAddress.ipFromInput.
Signature
interface StaticZone { readonly hosts?: ReadonlyRecord<string, readonly Array<IpAddressInput>>; readonly records?: ReadonlyRecord<string, readonly Array<DnsRecord>>;}A TLS authentication record (RFC 6698), which pins the certificate or public
key that a TLS service presents, for DNS-Based Authentication of Named
Entities (DANE). Records are published at a name made of the service's port
and protocol, such as _443._tcp.example.com.
Details
certUsage says how the record constrains the certificate chain (0 to 3:
PKIX-TA, PKIX-EE, DANE-TA, DANE-EE), selector whether data matches the
full certificate (0) or its public key (1), and matchingType whether
data holds the selected content itself (0) or its SHA-256 (1) or SHA-512
(2) digest. Unassigned values are kept as they are.
Gotchas
data is a copy of the bytes the record was made from, but typed arrays
cannot be frozen; treat it as read-only, because changing it changes the
record's equality.
Signature
interface Tlsa extends RecordProto<"TLSA"> { readonly certUsage: number; readonly data: Uint8Array; readonly matchingType: number; readonly selector: number;}A text record. DNS stores text as one or more character strings, which are
kept as separate chunks; protocols such as SPF read them joined, for example
with record.chunks.join("").
Details
Platform services decode each character string as UTF-8, replacing bytes
that are not valid UTF-8 with U+FFFD, and formatRecord writes chunks back
as UTF-8 bytes.
Signature
interface Txt extends RecordProto<"TXT"> { readonly chunks: readonly [string, string];}Services
Service that resolves names to addresses, queries DNS records, and looks up the names of addresses.
Details
Every operation either returns at least one result or fails with a DnsError.
Signature
declare class Dns extends Shape<"effect/net/Dns", { lookup<F extends IpFamily>(host: DomainNameInput, options: { readonly family: F; }): Effect<readonly [FamilyAddress<F>, FamilyAddress<F>], DnsError>; lookup(host: DomainNameInput, options?: LookupOptions): Effect<readonly [IpAddress, IpAddress], DnsError>; resolve<T extends RecordType>(name: DomainNameInput, type: T): Effect<readonly [RecordFor<T>, RecordFor<T>], DnsError>; reverse(address: IpAddressInput): Effect<readonly [DomainName, DomainName], DnsError>;}, this> { constructor(_: never);}Unsafe
Creates a trusted DNS record of a record type from its fields, throwing on failure.
Signature
declare function makeRecordUnsafe<T extends RecordType>(type: T, fields: RecordFields<T>): RecordFor<T>